mirror of
https://github.com/bigchaindb/js-bigchaindb-driver.git
synced 2024-06-16 09:33:19 +02:00
Compare commits
429 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
17d3a02cb3 | ||
|
f9a4675726 | ||
|
7a12ee7eb9 | ||
|
eee8da4b78 | ||
|
2f3b2dbca1 | ||
|
334a3f4d2d | ||
|
1864f6fbb4 | ||
|
2ffbe99a2b | ||
|
ae13da59b4 | ||
|
30c15b962b | ||
|
1ba488b28f | ||
|
fbc3d79d98 | ||
|
46599f5446 | ||
|
8c0c72622d | ||
|
c5fe1346b9 | ||
|
dc353ee5bc | ||
|
38819a5934 | ||
|
34289b0640 | ||
|
1f95bec2be | ||
|
7c1e8be400 | ||
|
6aeece49cb | ||
|
71a231a50a | ||
|
76c877c649 | ||
|
f020a35ea2 | ||
|
9b395c14a6 | ||
|
d29b9c2566 | ||
|
6aa5f0100c | ||
|
1779f6eef4 | ||
|
44dfc8f825 | ||
|
d5fd300cfc | ||
|
71fe66c1f5 | ||
|
af90b97460 | ||
|
b177ca0de4 | ||
|
858acf2693 | ||
|
d26f667feb | ||
|
c98cc8e499 | ||
|
2a104eb86b | ||
|
90a2cb2608 | ||
|
84bd4efe03 | ||
|
5f6bef65c5 | ||
|
cd5c529324 | ||
|
7fe904061a | ||
|
902885f7d1 | ||
|
abaa40b269 | ||
|
611624fd7a | ||
|
3d49a6755e | ||
|
978585d649 | ||
|
43c541d6d7 | ||
|
272e6d6ae0 | ||
|
736b2adc37 | ||
|
dc7634c9db | ||
|
42112acd3e | ||
|
656de69c64 | ||
|
597ac56f1f | ||
|
1b9bafa097 | ||
|
e3cca78886 | ||
|
23c3fa50ef | ||
|
551180bceb | ||
|
86d02c2f04 | ||
|
90466cf6ae | ||
|
cc3aa3fdd3 | ||
|
f5cd60e63d | ||
|
317bdd4d0f | ||
|
41ce1178c7 | ||
|
ba87737d97 | ||
|
d5894deec4 | ||
|
3c76d3bb21 | ||
|
1f27cd2300 | ||
|
57a3e89871 | ||
|
e76c6227f8 | ||
|
ad7763f76c | ||
|
b3909b0f04 | ||
|
f0df142efb | ||
|
6dbafa8fad | ||
|
344702200d | ||
|
a4d8ff531b | ||
|
54ecf63a82 | ||
|
f5c2e92c69 | ||
|
4b0d5c40b6 | ||
|
b2e4ef55bf | ||
|
f08ea00142 | ||
|
34233584e1 | ||
|
ea572804e3 | ||
|
d4dae793e9 | ||
|
667e2c9c71 | ||
|
5a966f6ab2 | ||
|
a3d1824a03 | ||
|
ba81d1b9be | ||
|
69e9814ba5 | ||
|
b37bdcded5 | ||
|
1fe3d3e08d | ||
|
4fbcdc19c5 | ||
|
f9570378d2 | ||
|
c33724e3bf | ||
|
561a2960b7 | ||
|
b7a9c960a2 | ||
|
e4d0efd967 | ||
|
994c8ef163 | ||
|
4fbac054b1 | ||
|
15e50ba96e | ||
|
21eb6a0850 | ||
|
b30bdfddbd | ||
|
78ebbe3d6d | ||
|
885c2478ad | ||
|
6db30fda33 | ||
|
355dd62a60 | ||
|
ffe25a6d80 | ||
|
3c82ae47da | ||
|
a99ccd57f1 | ||
|
f5debab03a | ||
|
11892a1f6b | ||
|
885766520e | ||
|
2afbd3b398 | ||
|
b30578d9ab | ||
|
bd8db702c4 | ||
|
30f7ecd389 | ||
|
e0cde66749 | ||
|
ad8a889ecc | ||
|
f4d1f93a5b | ||
|
7d978286f5 | ||
|
80bf01eb55 | ||
|
cc203c514b | ||
|
54dfcf637f | ||
|
27509dcb89 | ||
|
4555e251e5 | ||
|
124586dcbc | ||
|
5a88c03513 | ||
|
9f0ef2525b | ||
|
3710992441 | ||
|
62629df926 | ||
|
5a9f3905c7 | ||
|
a3be6c63a6 | ||
|
074b4f0871 | ||
|
48f7584374 | ||
|
64713d3742 | ||
|
aaad21895f | ||
|
1b21c28d7d | ||
|
28d9cfc0fa | ||
|
b315b8fe68 | ||
|
8628a91c49 | ||
|
9f727b55d9 | ||
|
180a7c2dc0 | ||
|
08c826de25 | ||
|
4a38192f76 | ||
|
944f047060 | ||
|
ba4b488dca | ||
|
9f5ac7445b | ||
|
2d8bdcf311 | ||
|
71b2f0d934 | ||
|
ea4f9e4464 | ||
|
28bcc02f30 | ||
|
96fd99e076 | ||
|
fadc1bd567 | ||
9dfd7e20bf | |||
6376e538ab | |||
64b3272dd0 | |||
3fc4958f63 | |||
6a637f33e2 | |||
4a212b29be | |||
56166698f1 | |||
cbd2536cca | |||
1bbfe7b27b | |||
|
9189ba7b52 | ||
|
b4e273de75 | ||
|
5c977696ba | ||
|
3dbee074a9 | ||
df0b3d5888 | |||
|
156fc5ffcb | ||
|
409e79e4f3 | ||
|
9077d6ce34 | ||
|
34c82a1ae8 | ||
a3ff691310 | |||
|
d0724b60f5 | ||
d3630109d3 | |||
edcc837cee | |||
|
aedfe02230 | ||
7932c9a1af | |||
bc8c9f8f98 | |||
bf3794d243 | |||
|
d080674c6f | ||
|
d812e64b30 | ||
|
387a9be5af | ||
|
b089d4b009 | ||
|
206e4cec5f | ||
|
437de5ffa3 | ||
|
eb1559d2f9 | ||
|
2b665dc5ca | ||
|
2021639139 | ||
|
5993c4cd6b | ||
|
446583d019 | ||
|
7d68195c74 | ||
|
9642928e75 | ||
|
b62471a709 | ||
|
4639acbd34 | ||
|
80811b8c7a | ||
9163284b4a | |||
|
5f32d685c1 | ||
|
36f88bc712 | ||
|
bb44ec4d2e | ||
2ecc484ec8 | |||
5c106a2ff3 | |||
81ef5978b8 | |||
691fadfd98 | |||
4570b24a5d | |||
fbb9b9536f | |||
03014b08f0 | |||
3527b1cff5 | |||
e0d82b8778 | |||
364f0a25d3 | |||
a149ef9125 | |||
b6a1a13bf8 | |||
|
0c8a9c6c4c | ||
|
b2d34c87a2 | ||
ba43fe48bb | |||
|
5cb24cff84 | ||
|
6c275da1bc | ||
|
c127b1c2a9 | ||
|
e2da49751c | ||
|
22e0a59dcd | ||
|
107c8b0d6e | ||
|
9023d061dd | ||
|
7699e14705 | ||
|
7079b752e0 | ||
|
618c2526f8 | ||
|
a905260e07 | ||
|
bc32780630 | ||
|
55dbaf878a | ||
|
be9980e01c | ||
|
57bb70074e | ||
|
bd8fbec5fd | ||
|
150b625997 | ||
|
3d232c6fc2 | ||
|
67b048a965 | ||
|
0d091d0a31 | ||
|
5a96c7fdbe | ||
|
51ffdfe0b9 | ||
|
0d9d04eb8b | ||
|
99a049056b | ||
|
b4e31fe786 | ||
|
abe1c89025 | ||
|
2f2169d156 | ||
|
2451ed2ae6 | ||
|
a1b25b1140 | ||
5affc1f85d | |||
f1b0c31b3a | |||
6a90cf4b9c | |||
|
fa6cae6487 | ||
|
c3e1244e52 | ||
|
ba37c1e37f | ||
|
61e9697569 | ||
|
d0559e5c38 | ||
|
069405d317 | ||
|
428edad6eb | ||
|
e1e2950dd9 | ||
|
824daaeccc | ||
|
ffcd0163fa | ||
|
f7278c5eff | ||
|
e4871728cc | ||
|
90dbc20ded | ||
|
1a6db37fc9 | ||
|
6db5b8fedc | ||
|
5daea889fa | ||
|
c7b55e5ad3 | ||
|
745ddf9527 | ||
|
0a7e207fef | ||
|
87f36946f0 | ||
|
01deae78cd | ||
|
10fab5323a | ||
|
1aa295830d | ||
|
2deba0cad8 | ||
|
3d62df3dc5 | ||
|
c371e3bfad | ||
|
2738f6bdef | ||
|
072edb054c | ||
|
015bf1b07f | ||
|
843d85bc03 | ||
|
3725afa4a0 | ||
|
633a0562fe | ||
|
43a67ae26e | ||
|
674d1022de | ||
|
4dd006b8cb | ||
|
0d1bc2209b | ||
|
b05dc84ff8 | ||
|
879ae68d0c | ||
|
2348a49965 | ||
|
e745b5948d | ||
|
ebf5f6a408 | ||
|
bc574c2b9d | ||
|
c169eb5d48 | ||
8f5864e32a | |||
|
a3012bcc34 | ||
|
4ec535670c | ||
|
4f90fb30d5 | ||
e432ad2182 | |||
ddacac9eee | |||
002b1bf3a0 | |||
|
c8fff0245e | ||
|
91d9cf5663 | ||
|
0960a5adb4 | ||
|
1076d2d2ab | ||
|
84bbd46d01 | ||
|
1044a01fb4 | ||
|
ad03590347 | ||
|
da4c4a942b | ||
|
ba7f19448c | ||
|
7fbac23dc2 | ||
|
1cacace1b7 | ||
|
6d57f5b2da | ||
|
e4893c36bb | ||
|
6031868245 | ||
|
9f385c440d | ||
|
e0f11ec415 | ||
a8250d632c | |||
|
2df643b8a7 | ||
|
d05f7ef3e6 | ||
|
fee4530d5c | ||
|
e99b4b9874 | ||
|
5cdcf3bac1 | ||
|
76614e9e84 | ||
|
13632c62bc | ||
|
af86eb7f80 | ||
|
dfe221031e | ||
|
16174442d5 | ||
|
76867e1de7 | ||
|
6416718102 | ||
|
4f48f1768e | ||
|
4a349013b2 | ||
|
fb7dd5580a | ||
|
132c139899 | ||
|
bb5b4ce05e | ||
|
5686a118fe | ||
|
dd2a52bf1f | ||
a1301861b4 | |||
703d23004f | |||
5b0ebbe3a0 | |||
|
8908e6635a | ||
|
3842c48daa | ||
|
3b509b5a48 | ||
|
42de727882 | ||
|
202bf16d09 | ||
|
35e1073a2f | ||
|
9b05b7354f | ||
|
c793ffbb71 | ||
|
d7c3276e12 | ||
|
2e1c43bf92 | ||
|
c8cdf5eadd | ||
|
61179c167b | ||
|
aba3c7d4bc | ||
|
0f0fd3d525 | ||
|
5f2ee8c0d8 | ||
|
6c313eac0e | ||
|
0b65d3d741 | ||
|
f1d4c47c98 | ||
|
a6606e26ac | ||
|
1dc8bb9883 | ||
|
8804998546 | ||
|
df484832ed | ||
|
8e7c213fb9 | ||
|
320a41a30a | ||
|
922524e2ed | ||
|
1d58986039 | ||
|
c46dde75ee | ||
|
6d5224601f | ||
|
370171adf7 | ||
|
c606f64abe | ||
|
f4333a92c1 | ||
|
2fa812940a | ||
|
49fe2e879e | ||
|
25054cc136 | ||
|
791de0d760 | ||
|
22bebc7e2f | ||
|
ad89f6f89c | ||
|
b77d296069 | ||
|
f82cbd6526 | ||
|
e1be5ba598 | ||
|
7cb60a7dc0 | ||
|
366a46f8a7 | ||
|
c939977c90 | ||
|
6703fd8839 | ||
|
ce9e88bac3 | ||
|
42c037c6ac | ||
|
823d340d61 | ||
|
6c01d37576 | ||
|
fd75499f24 | ||
|
db4054e1b2 | ||
|
f2fbdc79ce | ||
|
b97cce72f9 | ||
|
0d91af5d8f | ||
|
e34917ea2b | ||
|
d284ced256 | ||
|
4eae98e463 | ||
|
146f1f5e13 | ||
|
431da5ac95 | ||
|
f2e7e1606b | ||
|
dfaf97e5ce | ||
|
6f6c21dacf | ||
7f532ee94f | |||
|
4102ef8c21 | ||
|
202ae6060b | ||
|
7ac13b2045 | ||
|
cce49f1d12 | ||
|
a2ff15e282 | ||
|
f0fda97057 | ||
|
a5509a0171 | ||
|
5ec5df7e1d | ||
|
484a3eb608 | ||
|
4931b62e8e | ||
|
c8de30ba57 | ||
|
178cc116f5 | ||
|
c2f4a6e5e2 | ||
|
c1ddbf479a | ||
|
f3df9ed6c7 | ||
|
b0b0d157cb | ||
|
4154078305 | ||
|
ceedf91774 | ||
|
3c0209f3cd | ||
|
d714306c9d | ||
|
8048399a0b | ||
|
6dc11b5455 | ||
|
bb3d478b41 | ||
|
2fd3fcf8ce | ||
|
d0f4342f6f | ||
|
d6e33b807a | ||
|
51585b1b05 | ||
|
b665752c8c | ||
|
f82706ecbb | ||
|
529c18a753 | ||
|
49c91a0916 | ||
|
a7b09941e2 |
56
.babelrc
56
.babelrc
|
@ -1,31 +1,29 @@
|
|||
{
|
||||
"presets": [
|
||||
"@ava/stage-4",
|
||||
"@ava/transform-test-files",
|
||||
"es2015-no-commonjs"
|
||||
],
|
||||
|
||||
"plugins": [
|
||||
"transform-export-extensions",
|
||||
"transform-object-assign",
|
||||
"transform-object-rest-spread"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
|
||||
"env": {
|
||||
"bundle": {
|
||||
"plugins": [
|
||||
["transform-runtime", {
|
||||
"polyfill": true,
|
||||
"regenerator": false
|
||||
}]
|
||||
]
|
||||
},
|
||||
"cjs": {
|
||||
"plugins": [
|
||||
"add-module-exports",
|
||||
"transform-es2015-modules-commonjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": [
|
||||
"> 0.25%, not dead",
|
||||
"not IE 11",
|
||||
"maintained node versions"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-export-default-from",
|
||||
"@babel/plugin-transform-object-assign",
|
||||
"@babel/plugin-proposal-object-rest-spread",
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
"absoluteRuntime": false,
|
||||
"corejs": 3,
|
||||
"helpers": true,
|
||||
"regenerator": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"sourceMaps": true
|
||||
}
|
||||
|
|
13
.ci/travis-before-install.sh
Executable file
13
.ci/travis-before-install.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
# Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
|
||||
sudo rm /usr/local/bin/docker-compose
|
||||
curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
chmod +x docker-compose
|
||||
sudo mv docker-compose /usr/local/bin
|
13
.ci/travis-before-script.sh
Executable file
13
.ci/travis-before-script.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
# Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
|
||||
set -e -x
|
||||
|
||||
docker-compose up -d bigchaindb
|
||||
|
||||
npm install
|
||||
gem install cowsay
|
||||
npm install -g codecov
|
9
.ci/travis-install.sh
Executable file
9
.ci/travis-install.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
# Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
|
||||
set -e -x
|
||||
|
||||
docker-compose build --no-cache bigchaindb
|
|
@ -1,3 +1,6 @@
|
|||
dist
|
||||
node_modules
|
||||
coverage
|
||||
media
|
||||
docs
|
||||
compose
|
231
.eslintrc.js
Normal file
231
.eslintrc.js
Normal file
|
@ -0,0 +1,231 @@
|
|||
module.exports = {
|
||||
extends: ['eslint:recommended', 'airbnb-base', 'plugin:import/recommended'],
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: { requireConfigFile: false },
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
settings: {
|
||||
'import/ignore': ['node_modules', '.(scss|css)$', '.(jpe?g|png|gif|svg)'],
|
||||
},
|
||||
rules: {
|
||||
/**
|
||||
* Possible Errors
|
||||
* http://eslint.org/docs/rus/#possible-errors
|
||||
*/
|
||||
|
||||
// Allow dangling commas for multiline arrays and objects
|
||||
// http://eslint.org/docs/rules/comma-dangle
|
||||
'comma-dangle': [1, 'only-multiline'],
|
||||
|
||||
// Warn against use of console for non-error logging
|
||||
// http://eslint.org/docs/rules/no-console
|
||||
'no-console': [1, { allow: ['error'] }],
|
||||
|
||||
// Allow use of Object.prototypes builtins directly
|
||||
// http://eslint.org/docs/rules/no-prototype-builtins
|
||||
'no-prototype-builtins': [0],
|
||||
|
||||
/**
|
||||
* Best Practices
|
||||
* http://eslint.org/docs/rules/#best-practices
|
||||
*/
|
||||
|
||||
// Allow else clauses after an if with a return
|
||||
// http://eslint.org/docs/rules/no-else-return
|
||||
'no-else-return': [0],
|
||||
|
||||
// Disallow reassignment of function parameters (but allow assigning to parameter's properties)
|
||||
// http://eslint.org/docs/rules/no-param-reassign.html
|
||||
'no-param-reassign': [2, { props: false }],
|
||||
|
||||
/**
|
||||
* Variables
|
||||
* http://eslint.org/docs/rules/#variables
|
||||
*/
|
||||
|
||||
// Disallow use of variables and classes before they are defined
|
||||
// http://eslint.org/docs/rules/no-use-before-define
|
||||
'no-use-before-define': [2, { functions: false, classes: true }],
|
||||
|
||||
// Disallow declaration of variables that are not used in the code, unless they are prefixed by
|
||||
// `ignored` (useful for creating subset objects through destructuring and rest objects)
|
||||
// http://eslint.org/docs/rules/no-unused-vars
|
||||
'no-unused-vars': [
|
||||
2,
|
||||
{
|
||||
vars: 'local',
|
||||
args: 'after-used',
|
||||
varsIgnorePattern: 'ignored.+',
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* Stylelistic Issues
|
||||
* (http://eslint.org/docs/rules/#stylistic-issues)
|
||||
*/
|
||||
|
||||
// Enforce 4-space indents, except for switch cases
|
||||
// http://eslint.org/docs/rules/indent
|
||||
'indent': [2, 4, { SwitchCase: 1, VariableDeclarator: 1 }],
|
||||
|
||||
// Specify the maximum length of a code line to be 100
|
||||
// http://eslint.org/docs/rules/max-len
|
||||
'max-len': [
|
||||
2,
|
||||
{
|
||||
code: 105, // Use 105 to give some leeway for *just* slightly longer lines when convienient
|
||||
ignorePattern: '^(import|export) .* from .*$',
|
||||
ignoreComments: false,
|
||||
ignoreTrailingComments: true,
|
||||
ignoreUrls: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Require capitalization when using `new`, but don't require capitalized functions to be called
|
||||
// with new
|
||||
// http://eslint.org/docs/rules/new-cap
|
||||
'new-cap': [2, { newIsCap: true, capIsNew: false }],
|
||||
|
||||
// Allow the continue statement
|
||||
// http://eslint.org/docs/rules/no-continue
|
||||
'no-continue': [0],
|
||||
|
||||
// Disallow un-paren'd mixes of different operators if they're not of the same precendence
|
||||
// http://eslint.org/docs/rules/no-mixed-operators
|
||||
'no-mixed-operators': [
|
||||
2,
|
||||
{
|
||||
groups: [
|
||||
['+', '-', '*', '/', '%', '**'],
|
||||
['&', '|', '^', '~', '<<', '>>', '>>>'],
|
||||
['==', '!=', '===', '!==', '>', '>=', '<', '<='],
|
||||
['&&', '||'],
|
||||
['in', 'instanceof'],
|
||||
],
|
||||
allowSamePrecedence: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Allow use of unary increment/decrement operators
|
||||
// http://eslint.org/docs/rules/no-plusplus
|
||||
'no-plusplus': [0],
|
||||
|
||||
// Always allow dangling underscores
|
||||
// http://eslint.org/docs/rules/no-underscore-dangle
|
||||
'no-underscore-dangle': [0],
|
||||
|
||||
// Require unix-style line breaks
|
||||
// http://eslint.org/docs/rules/linebreak-style
|
||||
'linebreak-style': [2, 'unix'],
|
||||
|
||||
// Require operators to always be at the end of a line, except for the ternary operator
|
||||
// http://eslint.org/docs/rules/operator-linebreak
|
||||
'operator-linebreak': [
|
||||
2,
|
||||
'after',
|
||||
{ overrides: { '?': 'ignore', ':': 'ignore' } },
|
||||
],
|
||||
|
||||
// Require properties to be consistently quoted. Force numbers to be quoted, as they can have
|
||||
// weird behaviour during the coercion into a string)
|
||||
// http://eslint.org/docs/rules/quote-props
|
||||
'quote-props': [
|
||||
2,
|
||||
'consistent',
|
||||
{ keywords: false, unnecessary: true, numbers: true },
|
||||
],
|
||||
|
||||
// Require spaces before parens for anonymous function declarations
|
||||
// http://eslint.org/docs/rules/space-before-function-paren
|
||||
'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }],
|
||||
|
||||
// Require a space immediately following the // or /* in a comment for most comments
|
||||
// http://eslint.org/docs/rules/spaced-comment
|
||||
'spaced-comment': [
|
||||
2,
|
||||
'always',
|
||||
{
|
||||
line: {
|
||||
exceptions: ['-', '+'],
|
||||
},
|
||||
block: {
|
||||
exceptions: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// We don't like semicolons so kill them
|
||||
// http://eslint.org/docs/rules/semi
|
||||
'semi': [2, 'never'],
|
||||
|
||||
/**
|
||||
* Import rules
|
||||
* https://github.com/benmosher/eslint-plugin-import#rules
|
||||
*/
|
||||
|
||||
// Ensure named imports coupled with named exports
|
||||
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#when-not-to-use-it
|
||||
'import/named': 2,
|
||||
|
||||
// Ensure default import coupled with default export
|
||||
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it
|
||||
'import/default': 2,
|
||||
|
||||
// Disallow namespace (wildcard) imports
|
||||
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md
|
||||
'import/no-namespace': 2,
|
||||
|
||||
// Enforce imports to not specify a trailing .js extension
|
||||
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md
|
||||
'import/extensions': [2, { js: 'never' }],
|
||||
|
||||
// Enforce module import order: builtin -> external -> internal
|
||||
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md
|
||||
'import/order': [
|
||||
2,
|
||||
{
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
['internal', 'parent', 'sibling', 'index'],
|
||||
],
|
||||
},
|
||||
],
|
||||
'import/no-extraneous-dependencies': ['error', { 'devDependencies': true }],
|
||||
/**
|
||||
* ES6-specific Issues
|
||||
* (http://eslint.org/docs/rules/#ecmascript-6)
|
||||
*/
|
||||
'arrow-body-style': [0],
|
||||
'arrow-parens': [0],
|
||||
'arrow-spacing': [0],
|
||||
'constructor-super': [0],
|
||||
'generator-star-spacing': [0],
|
||||
'no-class-assign': [0],
|
||||
'no-confusing-arrow': [0],
|
||||
'no-const-assign': [0],
|
||||
'no-dupe-class-members': [0],
|
||||
'no-duplicate-imports': [0],
|
||||
'no-new-symbol': [0],
|
||||
'no-restricted-imports': [0],
|
||||
'no-this-before-super': [0],
|
||||
'no-useless-computed-key': [0],
|
||||
'no-useless-constructor': [0],
|
||||
'no-useless-rename': [0],
|
||||
'no-var': [0],
|
||||
'object-shorthand': [0],
|
||||
'prefer-arrow-callback': [0],
|
||||
'prefer-const': [0],
|
||||
'prefer-reflect': [0],
|
||||
'prefer-rest-params': [0],
|
||||
'prefer-spread': [0],
|
||||
'prefer-template': [0],
|
||||
'require-yield': [0],
|
||||
'rest-spread-spacing': [0],
|
||||
'sort-imports': [0],
|
||||
'template-curly-spacing': [0],
|
||||
'yield-star-spacing': [0],
|
||||
},
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"extends": "ascribe"
|
||||
}
|
68
.github/workflows/ci.yml
vendored
Normal file
68
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- API.md
|
||||
- docs/*.rst
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- ready_for_review
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- API.md
|
||||
- docs/*.rst
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release' || github.event_name == 'push' || !github.event.pull_request.draft
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout the commit
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
|
||||
- name: Cache dependencies
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Run BigChainDB node
|
||||
run: |
|
||||
echo Building and starting up docker containers
|
||||
docker-compose -f ./docker-compose.yml up -d
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
HUSKY_SKIP_INSTALL: 'true'
|
||||
run: npm install
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
# ensure BCDB node is up and running
|
||||
- run: sleep 20
|
||||
|
||||
- name: Test
|
||||
run: npm run test
|
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -8,8 +8,11 @@
|
|||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
*.sublime-workspace
|
||||
.DS_Store
|
||||
.vscode
|
||||
|
||||
.env
|
||||
.genv
|
||||
|
||||
node_modules
|
||||
dist
|
||||
|
@ -17,3 +20,7 @@ package-lock.json
|
|||
coverage
|
||||
coverage.lcov
|
||||
.nyc_output
|
||||
yarn.lock
|
||||
docs/build/
|
||||
docs/_build/
|
||||
docs/build/
|
||||
|
|
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
_
|
24
.npmignore
24
.npmignore
|
@ -0,0 +1,24 @@
|
|||
*.seed
|
||||
*.log
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.gz
|
||||
.idea
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
*.sublime-workspace
|
||||
.DS_Store
|
||||
.vscode
|
||||
|
||||
.env
|
||||
.genv
|
||||
|
||||
node_modules
|
||||
package-lock.json
|
||||
coverage
|
||||
coverage.lcov
|
||||
.nyc_output
|
||||
yarn.lock
|
||||
|
||||
docs/build/
|
34
.travis.yml
34
.travis.yml
|
@ -1,3 +1,7 @@
|
|||
# Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
|
@ -5,25 +9,29 @@ services:
|
|||
|
||||
language: node_js
|
||||
|
||||
node_js: 7
|
||||
node_js:
|
||||
- 10
|
||||
- 12
|
||||
- 14
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
before_install:
|
||||
- docker run -d -p 27017:27017 mongo:3.4 --replSet=bigchain-rs
|
||||
- docker run -d -p 9984:9984
|
||||
-e BIGCHAINDB_KEYPAIR_PUBLIC=8wHUvvraRo5yEoJAt66UTZaFq9YZ9tFFwcauKPDtjkGw
|
||||
-e BIGCHAINDB_KEYPAIR_PRIVATE=5C5Cknco7YxBRP9AgB1cbUVTL4FAcooxErLygw1DeG2D
|
||||
-e BIGCHAINDB_DATABASE_BACKEND=mongodb
|
||||
-e BIGCHAINDB_DATABASE_HOST=172.17.0.1
|
||||
bigchaindb/bigchaindb:1.0.0rc1
|
||||
start
|
||||
- gem install cowsay
|
||||
- npm install -g codecov
|
||||
env:
|
||||
global:
|
||||
- DOCKER_COMPOSE_VERSION=1.28.5
|
||||
|
||||
script: yarn test
|
||||
before_install:
|
||||
- .ci/travis-before-install.sh
|
||||
|
||||
install:
|
||||
- .ci/travis-install.sh
|
||||
|
||||
before_script:
|
||||
- .ci/travis-before-script.sh
|
||||
|
||||
script: npm test
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
|
565
API.md
565
API.md
|
@ -2,217 +2,540 @@
|
|||
|
||||
### Table of Contents
|
||||
|
||||
- [Ed25519Keypair](#ed25519keypair)
|
||||
- [makeEd25519Condition](#makeed25519condition)
|
||||
- [makeSha256Condition](#makesha256condition)
|
||||
- [makeThresholdCondition](#makethresholdcondition)
|
||||
- [makeCreateTransaction](#makecreatetransaction)
|
||||
- [makeOutput](#makeoutput)
|
||||
- [makeTransferTransaction](#maketransfertransaction)
|
||||
- [serializeTransactionIntoCanonicalString](#serializetransactionintocanonicalstring)
|
||||
- [signTransaction](#signtransaction)
|
||||
- [ccJsonLoad](#ccjsonload)
|
||||
- [ccJsonify](#ccjsonify)
|
||||
- [getBlock](#getblock)
|
||||
- [getStatus](#getstatus)
|
||||
- [getTransaction](#gettransaction)
|
||||
- [listBlocks](#listblocks)
|
||||
- [listOutputs](#listoutputs)
|
||||
- [listTransactions](#listtransactions)
|
||||
- [listVotes](#listvotes)
|
||||
- [pollStatusAndFetchTransaction](#pollstatusandfetchtransaction)
|
||||
- [postTransaction](#posttransaction)
|
||||
- [Ed25519Keypair][1]
|
||||
- [Parameters][2]
|
||||
- [Properties][3]
|
||||
- [Connection][4]
|
||||
- [Parameters][5]
|
||||
- [getBlock][6]
|
||||
- [Parameters][7]
|
||||
- [getTransaction][8]
|
||||
- [Parameters][9]
|
||||
- [listBlocks][10]
|
||||
- [Parameters][11]
|
||||
- [listOutputs][12]
|
||||
- [Parameters][13]
|
||||
- [listTransactions][14]
|
||||
- [Parameters][15]
|
||||
- [postTransaction][16]
|
||||
- [Parameters][17]
|
||||
- [postTransactionSync][18]
|
||||
- [Parameters][19]
|
||||
- [postTransactionAsync][20]
|
||||
- [Parameters][21]
|
||||
- [postTransactionCommit][22]
|
||||
- [Parameters][23]
|
||||
- [searchAssets][24]
|
||||
- [Parameters][25]
|
||||
- [searchMetadata][26]
|
||||
- [Parameters][27]
|
||||
- [Transaction][28]
|
||||
- [serializeTransactionIntoCanonicalString][29]
|
||||
- [Parameters][30]
|
||||
- [makeCreateTransaction][31]
|
||||
- [Parameters][32]
|
||||
- [makeEd25519Condition][33]
|
||||
- [Parameters][34]
|
||||
- [makeOutput][35]
|
||||
- [Parameters][36]
|
||||
- [makeSha256Condition][37]
|
||||
- [Parameters][38]
|
||||
- [makeThresholdCondition][39]
|
||||
- [Parameters][40]
|
||||
- [makeTransferTransaction][41]
|
||||
- [Parameters][42]
|
||||
- [signTransaction][43]
|
||||
- [Parameters][44]
|
||||
- [delegateSignTransaction][45]
|
||||
- [Parameters][46]
|
||||
- [delegateSignTransactionAsync][47]
|
||||
- [Parameters][48]
|
||||
- [ccJsonLoad][49]
|
||||
- [Parameters][50]
|
||||
- [ccJsonify][51]
|
||||
- [Parameters][52]
|
||||
|
||||
## Ed25519Keypair
|
||||
|
||||
**Parameters**
|
||||
[src/Ed25519Keypair.js:16-21][53]
|
||||
|
||||
- `secret` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** A seed that will be used as a key derivation function
|
||||
Type: [Object][54]
|
||||
|
||||
**Properties**
|
||||
### Parameters
|
||||
|
||||
- `publicKey` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)**
|
||||
- `privateKey` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)**
|
||||
- `seed` **[Buffer][55]?** A seed that will be used as a key derivation function
|
||||
|
||||
## makeEd25519Condition
|
||||
### Properties
|
||||
|
||||
**Parameters**
|
||||
- `publicKey` **[string][56]**
|
||||
- `privateKey` **[string][56]**
|
||||
|
||||
- `publicKey` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** base58 encoded Ed25519 public key for the recipient of the Transaction
|
||||
- `json` **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** If true returns a json object otherwise a crypto-condition type (optional, default `true`)
|
||||
## Connection
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Ed25519 Condition (that will need to wrapped in an Output)
|
||||
[src/connection.js:21-199][57]
|
||||
|
||||
## makeSha256Condition
|
||||
### Parameters
|
||||
|
||||
**Parameters**
|
||||
- `nodes`
|
||||
- `headers` **[Object][54]** Common headers for every request (optional, default `{}`)
|
||||
- `timeout` **float** Optional timeout in secs (optional, default `DEFAULT_TIMEOUT`)
|
||||
|
||||
- `preimage` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Preimage to be hashed and wrapped in a crypto-condition
|
||||
- `json` **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** If true returns a json object otherwise a crypto-condition type (optional, default `true`)
|
||||
### getBlock
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Preimage-Sha256 Condition (that will need to wrapped in an Output)
|
||||
[src/connection.js:79-85][58]
|
||||
|
||||
## makeThresholdCondition
|
||||
#### Parameters
|
||||
|
||||
**Parameters**
|
||||
- `blockHeight`
|
||||
|
||||
- `threshold` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)**
|
||||
- `subconditions` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** (optional, default `[]`)
|
||||
- `json` **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** If true returns a json object otherwise a crypto-condition type (optional, default `true`)
|
||||
### getTransaction
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Sha256 Threshold Condition (that will need to wrapped in an Output)
|
||||
[src/connection.js:90-96][59]
|
||||
|
||||
## makeCreateTransaction
|
||||
#### Parameters
|
||||
|
||||
**Parameters**
|
||||
- `transactionId`
|
||||
|
||||
- `asset` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Created asset's data
|
||||
- `metadata` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Metadata for the Transaction
|
||||
- `outputs` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>** Array of Output objects to add to the Transaction.
|
||||
### listBlocks
|
||||
|
||||
[src/connection.js:102-108][60]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transactionId`
|
||||
- `status`
|
||||
|
||||
### listOutputs
|
||||
|
||||
[src/connection.js:114-126][61]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `publicKey`
|
||||
- `spent`
|
||||
|
||||
### listTransactions
|
||||
|
||||
[src/connection.js:132-139][62]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `assetId`
|
||||
- `operation`
|
||||
|
||||
### postTransaction
|
||||
|
||||
[src/connection.js:144-146][63]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction`
|
||||
|
||||
### postTransactionSync
|
||||
|
||||
[src/connection.js:151-156][64]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction`
|
||||
|
||||
### postTransactionAsync
|
||||
|
||||
[src/connection.js:161-166][65]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction`
|
||||
|
||||
### postTransactionCommit
|
||||
|
||||
[src/connection.js:171-176][66]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction`
|
||||
|
||||
### searchAssets
|
||||
|
||||
[src/connection.js:181-187][67]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `search`
|
||||
|
||||
### searchMetadata
|
||||
|
||||
[src/connection.js:192-198][68]
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `search`
|
||||
|
||||
## Transaction
|
||||
|
||||
[src/transaction.js:16-288][69]
|
||||
|
||||
Construct Transactions
|
||||
|
||||
### serializeTransactionIntoCanonicalString
|
||||
|
||||
[src/transaction.js:22-29][70]
|
||||
|
||||
Canonically serializes a transaction into a string by sorting the keys
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction`
|
||||
- `null` **[Object][54]** (transaction)
|
||||
|
||||
Returns **[string][56]** a canonically serialized Transaction
|
||||
|
||||
### makeCreateTransaction
|
||||
|
||||
[src/transaction.js:80-87][71]
|
||||
|
||||
Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by
|
||||
the `issuers`.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `asset` **[Object][54]** Created asset's data
|
||||
- `metadata` **[Object][54]** Metadata for the Transaction
|
||||
- `outputs` **[Array][72]<[Object][54]>** Array of Output objects to add to the Transaction.
|
||||
Think of these as the recipients of the asset after the transaction.
|
||||
For `CREATE` Transactions, this should usually just be a list of
|
||||
Outputs wrapping Ed25519 Conditions generated from the issuers' public
|
||||
keys (so that the issuers are the recipients of the created asset).
|
||||
- `issuers` **...[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)>** Public key of one or more issuers to the asset being created by this
|
||||
- `issuers` **...[Array][72]<[string][56]>** Public key of one or more issuers to the asset being created by this
|
||||
Transaction.
|
||||
Note: Each of the private keys corresponding to the given public
|
||||
keys MUST be used later (and in the same order) when signing the
|
||||
Transaction (`signTransaction()`).
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
Returns **[Object][54]** Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
sending it off!
|
||||
|
||||
## makeOutput
|
||||
### makeEd25519Condition
|
||||
|
||||
**Parameters**
|
||||
[src/transaction.js:96-101][73]
|
||||
|
||||
- `condition` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`)
|
||||
- `amount` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Amount of the output (optional, default `1`)
|
||||
Create an Ed25519 Cryptocondition from an Ed25519 public key
|
||||
to put into an Output of a Transaction
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** An Output usable in a Transaction
|
||||
#### Parameters
|
||||
|
||||
## makeTransferTransaction
|
||||
- `publicKey` **[string][56]** base58 encoded Ed25519 public key for the recipient of the Transaction
|
||||
- `json` **[boolean][74]** If true returns a json object otherwise a crypto-condition type (optional, default `true`)
|
||||
|
||||
**Parameters**
|
||||
Returns **[Object][54]** Ed25519 Condition (that will need to wrapped in an Output)
|
||||
|
||||
- `unspentTransaction` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Previous Transaction you have control over (i.e. can fulfill
|
||||
its Output Condition)
|
||||
- `metadata` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Metadata for the Transaction
|
||||
- `outputs` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>** Array of Output objects to add to the Transaction.
|
||||
### makeOutput
|
||||
|
||||
[src/transaction.js:111-131][75]
|
||||
|
||||
Create an Output from a Condition.
|
||||
Note: Assumes the given Condition was generated from a
|
||||
single public key (e.g. a Ed25519 Condition)
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `condition` **[Object][54]** Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`)
|
||||
- `amount` **[string][56]** Amount of the output (optional, default `'1'`)
|
||||
|
||||
Returns **[Object][54]** An Output usable in a Transaction
|
||||
|
||||
### makeSha256Condition
|
||||
|
||||
[src/transaction.js:139-143][76]
|
||||
|
||||
Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `preimage` **[string][56]** Preimage to be hashed and wrapped in a crypto-condition
|
||||
- `json` **[boolean][74]** If true returns a json object otherwise a crypto-condition type (optional, default `true`)
|
||||
|
||||
Returns **[Object][54]** Preimage-Sha256 Condition (that will need to wrapped in an Output)
|
||||
|
||||
### makeThresholdCondition
|
||||
|
||||
[src/transaction.js:152-162][77]
|
||||
|
||||
Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `threshold` **[number][78]**
|
||||
- `subconditions` **[Array][72]** (optional, default `[]`)
|
||||
- `json` **[boolean][74]** If true returns a json object otherwise a crypto-condition type (optional, default `true`)
|
||||
|
||||
Returns **[Object][54]** Sha256 Threshold Condition (that will need to wrapped in an Output)
|
||||
|
||||
### makeTransferTransaction
|
||||
|
||||
[src/transaction.js:185-206][79]
|
||||
|
||||
Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills
|
||||
the `fulfilledOutputs` of `unspentTransaction`.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `unspentOutputs`
|
||||
- `outputs` **[Array][72]<[Object][54]>** Array of Output objects to add to the Transaction.
|
||||
Think of these as the recipients of the asset after the transaction.
|
||||
For `TRANSFER` Transactions, this should usually just be a list of
|
||||
Outputs wrapping Ed25519 Conditions generated from the public keys of
|
||||
the recipients.
|
||||
- `fulfilledOutputs` **...[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Indices of the Outputs in `unspentTransaction` that this
|
||||
- `metadata` **[Object][54]** Metadata for the Transaction
|
||||
- `unspentTransaction` **[Object][54]** Previous Transaction you have control over (i.e. can fulfill
|
||||
its Output Condition)
|
||||
- `OutputIndices` **...[number][78]** Indices of the Outputs in `unspentTransaction` that this
|
||||
Transaction fulfills.
|
||||
Note that the public keys listed in the fulfilled Outputs
|
||||
must be used (and in the same order) to sign the Transaction
|
||||
Note that listed public keys listed must be used (and in
|
||||
the same order) to sign the Transaction
|
||||
(`signTransaction()`).
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
Returns **[Object][54]** Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
sending it off!
|
||||
|
||||
## serializeTransactionIntoCanonicalString
|
||||
### signTransaction
|
||||
|
||||
**Parameters**
|
||||
[src/transaction.js:219-243][80]
|
||||
|
||||
- `transaction`
|
||||
- `null` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** (transaction)
|
||||
Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction`
|
||||
that's been signed.
|
||||
Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as
|
||||
an exercise for the user.
|
||||
|
||||
Returns **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** a canonically serialized Transaction
|
||||
#### Parameters
|
||||
|
||||
## signTransaction
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `transaction` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Transaction to sign. `transaction` is not modified.
|
||||
- `privateKeys` **...[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Private keys associated with the issuers of the `transaction`.
|
||||
- `transaction` **[Object][54]** Transaction to sign. `transaction` is not modified.
|
||||
- `privateKeys` **...[string][56]** Private keys associated with the issuers of the `transaction`.
|
||||
Looped through to iteratively sign any Input Fulfillments found in
|
||||
the `transaction`.
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** The signed version of `transaction`.
|
||||
Returns **[Object][54]** The signed version of `transaction`.
|
||||
|
||||
### delegateSignTransaction
|
||||
|
||||
[src/transaction.js:252-265][81]
|
||||
|
||||
Delegate signing of the given `transaction` returning a new copy of `transaction`
|
||||
that's been signed.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction` **[Object][54]** Transaction to sign. `transaction` is not modified.
|
||||
- `signFn` **[Function][82]** Function signing the transaction, expected to return the fulfillment.
|
||||
|
||||
Returns **[Object][54]** The signed version of `transaction`.
|
||||
|
||||
### delegateSignTransactionAsync
|
||||
|
||||
[src/transaction.js:274-287][83]
|
||||
|
||||
Delegate signing of the given `transaction` returning a new copy of `transaction`
|
||||
that's been signed.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `transaction` **[Object][54]** Transaction to sign. `transaction` is not modified.
|
||||
- `signFn` **[Function][82]** Function signing the transaction, expected to resolve the fulfillment.
|
||||
|
||||
Returns **[Promise][84]<[Object][54]>** The signed version of `transaction`.
|
||||
|
||||
## ccJsonLoad
|
||||
|
||||
**Parameters**
|
||||
[src/utils/ccJsonLoad.js:13-44][85]
|
||||
|
||||
- `conditionJson` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||
Loads a crypto-condition class (Fulfillment or Condition) from a BigchainDB JSON object
|
||||
|
||||
### Parameters
|
||||
|
||||
- `conditionJson` **[Object][54]**
|
||||
|
||||
Returns **cc.Condition** Ed25519 Condition (that will need to wrapped in an Output)
|
||||
|
||||
## ccJsonify
|
||||
|
||||
**Parameters**
|
||||
[src/utils/ccJsonify.js:12-65][86]
|
||||
|
||||
- `fulfillment` **cc.Fulfillment** base58 encoded Ed25519 public key for the recipient of the Transaction
|
||||
Serializes a crypto-condition class (Condition or Fulfillment) into a BigchainDB-compatible JSON
|
||||
|
||||
Returns **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Ed25519 Condition (that will need to wrapped in an Output)
|
||||
### Parameters
|
||||
|
||||
## getBlock
|
||||
- `fulfillment` **cc.Fulfillment** base58 encoded Ed25519 public key for recipient of the Transaction
|
||||
|
||||
**Parameters**
|
||||
Returns **[Object][54]** Ed25519 Condition (that will need to wrapped in an Output)
|
||||
|
||||
- `blockId`
|
||||
[1]: #ed25519keypair
|
||||
|
||||
## getStatus
|
||||
[2]: #parameters
|
||||
|
||||
**Parameters**
|
||||
[3]: #properties
|
||||
|
||||
- `tx_id`
|
||||
[4]: #connection
|
||||
|
||||
## getTransaction
|
||||
[5]: #parameters-1
|
||||
|
||||
**Parameters**
|
||||
[6]: #getblock
|
||||
|
||||
- `txId`
|
||||
[7]: #parameters-2
|
||||
|
||||
## listBlocks
|
||||
[8]: #gettransaction
|
||||
|
||||
**Parameters**
|
||||
[9]: #parameters-3
|
||||
|
||||
- `$0` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||
- `$0.tx_id`
|
||||
- `$0.status`
|
||||
- `tx_id`
|
||||
- `status`
|
||||
[10]: #listblocks
|
||||
|
||||
## listOutputs
|
||||
[11]: #parameters-4
|
||||
|
||||
**Parameters**
|
||||
[12]: #listoutputs
|
||||
|
||||
- `$0` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||
- `$0.public_key`
|
||||
- `$0.unspent`
|
||||
- `onlyJsonResponse`
|
||||
- `public_key`
|
||||
- `unspent`
|
||||
[13]: #parameters-5
|
||||
|
||||
## listTransactions
|
||||
[14]: #listtransactions
|
||||
|
||||
**Parameters**
|
||||
[15]: #parameters-6
|
||||
|
||||
- `$0` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||
- `$0.asset_id`
|
||||
- `$0.operation`
|
||||
- `asset_id`
|
||||
- `operation`
|
||||
[16]: #posttransaction
|
||||
|
||||
## listVotes
|
||||
[17]: #parameters-7
|
||||
|
||||
**Parameters**
|
||||
[18]: #posttransactionsync
|
||||
|
||||
- `block_id`
|
||||
[19]: #parameters-8
|
||||
|
||||
## pollStatusAndFetchTransaction
|
||||
[20]: #posttransactionasync
|
||||
|
||||
**Parameters**
|
||||
[21]: #parameters-9
|
||||
|
||||
- `tx_id`
|
||||
[22]: #posttransactioncommit
|
||||
|
||||
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)**
|
||||
[23]: #parameters-10
|
||||
|
||||
## postTransaction
|
||||
[24]: #searchassets
|
||||
|
||||
**Parameters**
|
||||
[25]: #parameters-11
|
||||
|
||||
- `transaction`
|
||||
[26]: #searchmetadata
|
||||
|
||||
[27]: #parameters-12
|
||||
|
||||
[28]: #transaction
|
||||
|
||||
[29]: #serializetransactionintocanonicalstring
|
||||
|
||||
[30]: #parameters-13
|
||||
|
||||
[31]: #makecreatetransaction
|
||||
|
||||
[32]: #parameters-14
|
||||
|
||||
[33]: #makeed25519condition
|
||||
|
||||
[34]: #parameters-15
|
||||
|
||||
[35]: #makeoutput
|
||||
|
||||
[36]: #parameters-16
|
||||
|
||||
[37]: #makesha256condition
|
||||
|
||||
[38]: #parameters-17
|
||||
|
||||
[39]: #makethresholdcondition
|
||||
|
||||
[40]: #parameters-18
|
||||
|
||||
[41]: #maketransfertransaction
|
||||
|
||||
[42]: #parameters-19
|
||||
|
||||
[43]: #signtransaction
|
||||
|
||||
[44]: #parameters-20
|
||||
|
||||
[45]: #delegatesigntransaction
|
||||
|
||||
[46]: #parameters-21
|
||||
|
||||
[47]: #delegatesigntransactionasync
|
||||
|
||||
[48]: #parameters-22
|
||||
|
||||
[49]: #ccjsonload
|
||||
|
||||
[50]: #parameters-23
|
||||
|
||||
[51]: #ccjsonify
|
||||
|
||||
[52]: #parameters-24
|
||||
|
||||
[53]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/Ed25519Keypair.js#L16-L21 "Source code on GitHub"
|
||||
|
||||
[54]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||
|
||||
[55]: https://nodejs.org/api/buffer.html
|
||||
|
||||
[56]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||
|
||||
[57]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L21-L199 "Source code on GitHub"
|
||||
|
||||
[58]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L79-L85 "Source code on GitHub"
|
||||
|
||||
[59]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L90-L96 "Source code on GitHub"
|
||||
|
||||
[60]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L102-L108 "Source code on GitHub"
|
||||
|
||||
[61]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L114-L126 "Source code on GitHub"
|
||||
|
||||
[62]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L132-L139 "Source code on GitHub"
|
||||
|
||||
[63]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L144-L146 "Source code on GitHub"
|
||||
|
||||
[64]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L151-L156 "Source code on GitHub"
|
||||
|
||||
[65]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L161-L166 "Source code on GitHub"
|
||||
|
||||
[66]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L171-L176 "Source code on GitHub"
|
||||
|
||||
[67]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L181-L187 "Source code on GitHub"
|
||||
|
||||
[68]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L192-L198 "Source code on GitHub"
|
||||
|
||||
[69]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L16-L288 "Source code on GitHub"
|
||||
|
||||
[70]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L22-L29 "Source code on GitHub"
|
||||
|
||||
[71]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L80-L87 "Source code on GitHub"
|
||||
|
||||
[72]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
|
||||
|
||||
[73]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L96-L101 "Source code on GitHub"
|
||||
|
||||
[74]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||
|
||||
[75]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L111-L131 "Source code on GitHub"
|
||||
|
||||
[76]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L139-L143 "Source code on GitHub"
|
||||
|
||||
[77]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L152-L162 "Source code on GitHub"
|
||||
|
||||
[78]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
||||
|
||||
[79]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L185-L206 "Source code on GitHub"
|
||||
|
||||
[80]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L219-L243 "Source code on GitHub"
|
||||
|
||||
[81]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L252-L265 "Source code on GitHub"
|
||||
|
||||
[82]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
|
||||
|
||||
[83]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L274-L287 "Source code on GitHub"
|
||||
|
||||
[84]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||||
|
||||
[85]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/utils/ccJsonLoad.js#L13-L44 "Source code on GitHub"
|
||||
|
||||
[86]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/utils/ccJsonify.js#L12-L65 "Source code on GitHub"
|
||||
|
|
|
@ -1,46 +1,7 @@
|
|||
# Contributor Code of Conduct
|
||||
<!---
|
||||
Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
--->
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, sexual identity and orientation, or species—no picking on Wrigley for being a buffalo!
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at conduct@bigchaindb.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
See [https://github.com/bigchaindb/bigchaindb/blob/master/CODE_OF_CONDUCT.md](https://github.com/bigchaindb/bigchaindb/blob/master/CODE_OF_CONDUCT.md)
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
|
||||
.. Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
.. highlight:: shell
|
||||
|
||||
============
|
||||
|
|
4
LICENSE-docs
Normal file
4
LICENSE-docs
Normal file
|
@ -0,0 +1,4 @@
|
|||
The official BigchainDB documentation, _except for the short code snippets
|
||||
embedded within it_, is licensed under a Creative Commons Attribution-
|
||||
ShareAlike 4.0 International license, the full text of which can be found
|
||||
at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
123
README.md
123
README.md
|
@ -1,42 +1,72 @@
|
|||
<!---
|
||||
Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
--->
|
||||
|
||||
# [![js-bigchaindb-driver](media/repo-banner@2x.png)](https://www.bigchaindb.com)
|
||||
|
||||
> Official JavaScript driver for [BigchainDB](https://github.com/bigchaindb/bigchaindb) with some naive helpers to get you on your way making transactions in Node.js and the browser.
|
||||
> Official JavaScript driver for [BigchainDB](https://github.com/bigchaindb/bigchaindb) to create transactions in Node.js and the browser.
|
||||
|
||||
[![Join the chat at https://gitter.im/bigchaindb/js-bigchaindb-driver](https://badges.gitter.im/bigchaindb/js-bigchaindb-driver.svg)](https://gitter.im/bigchaindb/js-bigchaindb-driver?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![npm](https://img.shields.io/npm/v/bigchaindb-driver.svg)](https://www.npmjs.com/package/bigchaindb-driver)
|
||||
[![codecov](https://codecov.io/gh/bigchaindb/js-bigchaindb-driver/branch/master/graph/badge.svg)](https://codecov.io/gh/bigchaindb/js-bigchaindb-driver)
|
||||
[![js ascribe](https://img.shields.io/badge/js-ascribe-39BA91.svg)](https://github.com/ascribe/javascript)
|
||||
[![Build Status](https://travis-ci.org/bigchaindb/js-bigchaindb-driver.svg?branch=master)](https://travis-ci.org/bigchaindb/js-bigchaindb-driver)
|
||||
[![Build Status](https://travis-ci.com/bigchaindb/js-bigchaindb-driver.svg?branch=master)](https://travis-ci.com/bigchaindb/js-bigchaindb-driver)
|
||||
[![Greenkeeper badge](https://badges.greenkeeper.io/bigchaindb/js-bigchaindb-driver.svg)](https://greenkeeper.io/)
|
||||
|
||||
- [Main Documentation](https://docs.bigchaindb.com/projects/js-driver/en/latest/usage.html)
|
||||
- [Driver API reference](API.md)
|
||||
|
||||
## Compatibility
|
||||
|
||||
| BigchainDB Server | BigchainDB JavaScript Driver |
|
||||
| ----------------- |------------------------------|
|
||||
| `0.10` | `0.1.x` |
|
||||
| `1.0` | `0.2.x` |
|
||||
| `1.0.0` | `0.3.x` |
|
||||
| `1.3.x` | `3.x.x` |
|
||||
| `>= 2.0.0` | `4.x.x` |
|
||||
|
||||
## Breaking changes
|
||||
|
||||
## Contents
|
||||
- **Version 4.0** of BigchainDB JavaScript Driver makes the driver compatible with BigchainDB 2.0. There are new functions for sending off transactions along with other changes. Check [older versions](https://docs.bigchaindb.com/projects/js-driver/en/latest/readme.html#features)
|
||||
- **Version 3.2** of BigchainDB JavaScript Driver introduces a new way of creating transfer transactions. Check [older versions](https://docs.bigchaindb.com/projects/js-driver/en/latest/readme.html#features)
|
||||
|
||||
* [Installation and Usage with package managers (npm/yarn)](#installation-and-usage-with-package-managers-npmyarn)
|
||||
* [Example: Create a transaction](#example-create-a-transaction)
|
||||
* [Use a pre-built image (browser only)](#use-a-pre-built-image-browser-only)
|
||||
* [Documentation](#bigchaindb-documentation)
|
||||
* [Authors](#authors)
|
||||
* [License](#license)
|
||||
## Table of Contents
|
||||
|
||||
## Installation and Usage with package managers (npm/yarn)
|
||||
- [Installation and Usage](#installation-and-usage)
|
||||
- [Example: Create a transaction](#example-create-a-transaction)
|
||||
- [Browser usage](#browser-usage)
|
||||
- [BigchainDB Documentation](#bigchaindb-documentation)
|
||||
- [Speed Optimizations](#speed-optimizations)
|
||||
- [Development](#development)
|
||||
- [Release Process](#release-process)
|
||||
- [Authors](#authors)
|
||||
- [Licenses](#licenses)
|
||||
|
||||
---
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
```bash
|
||||
npm install bigchaindb-driver
|
||||
```
|
||||
|
||||
```js
|
||||
const driver = require('bigchaindb-driver')
|
||||
// or ES6+
|
||||
import driver from 'bigchaindb-driver'
|
||||
```
|
||||
|
||||
### Example: Create a transaction
|
||||
|
||||
```js
|
||||
const driver = require('bigchaindb-driver')
|
||||
const base58 = require('bs58');
|
||||
const crypto = require('crypto');
|
||||
const { Ed25519Sha256 } = require('crypto-conditions');
|
||||
|
||||
// BigchainDB server instance or IPDB (e.g. https://test.ipdb.io/api/v1/)
|
||||
// BigchainDB server instance (e.g. https://example.com/api/v1/)
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
|
||||
// Create a new keypair.
|
||||
|
@ -62,15 +92,30 @@ const tx = driver.Transaction.makeCreateTransaction(
|
|||
// Sign the transaction with private keys
|
||||
const txSigned = driver.Transaction.signTransaction(tx, alice.privateKey)
|
||||
|
||||
// Or use delegateSignTransaction to provide your own signature function
|
||||
function signTransaction() {
|
||||
// get privateKey from somewhere
|
||||
const privateKeyBuffer = Buffer.from(base58.decode(alice.privateKey))
|
||||
return function sign(serializedTransaction, input, index) {
|
||||
const transactionUniqueFulfillment = input.fulfills ? serializedTransaction
|
||||
.concat(input.fulfills.transaction_id)
|
||||
.concat(input.fulfills.output_index) : serializedTransaction
|
||||
const transactionHash = crypto.createHash('sha3-256').update(transactionUniqueFulfillment).digest()
|
||||
const ed25519Fulfillment = new Ed25519Sha256();
|
||||
ed25519Fulfillment.sign(transactionHash, privateKeyBuffer);
|
||||
return ed25519Fulfillment.serializeUri();
|
||||
};
|
||||
}
|
||||
const txSigned = driver.Transaction.delegateSignTransaction(tx, signTransaction())
|
||||
|
||||
// Send the transaction off to BigchainDB
|
||||
const conn = new driver.Connection(API_PATH)
|
||||
|
||||
conn.postTransaction(txSigned)
|
||||
.then(() => conn.pollStatusAndFetchTransaction(txSigned.id))
|
||||
conn.postTransactionCommit(txSigned)
|
||||
.then(retrievedTx => console.log('Transaction', retrievedTx.id, 'successfully posted.'))
|
||||
```
|
||||
|
||||
## Use a pre-built image (browser only)
|
||||
### Browser usage
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
|
@ -79,10 +124,10 @@ conn.postTransaction(txSigned)
|
|||
<meta charset="utf-8">
|
||||
<title>BigchainDB boilerplate</title>
|
||||
<!-- Adjust version to your needs -->
|
||||
<script src="https://unpkg.com/bigchaindb-driver@0.2.0/dist/browser/bigchaindb-driver.window.min.js"></script>
|
||||
<script src="https://unpkg.com/bigchaindb-driver@4.2.0/dist/browser/bigchaindb-driver.window.min.js"></script>
|
||||
|
||||
<script>
|
||||
// BigchainDB server instance or IPDB (e.g. https://test.ipdb.io/api/v1/)
|
||||
// BigchainDB server instance (e.g. https://example.com/api/v1/)
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
|
||||
// Create a new keypair.
|
||||
|
@ -111,8 +156,7 @@ conn.postTransaction(txSigned)
|
|||
// Send the transaction off to BigchainDB
|
||||
let conn = new BigchainDB.Connection(API_PATH)
|
||||
|
||||
conn.postTransaction(txSigned)
|
||||
.then(() => conn.pollStatusAndFetchTransaction(txSigned.id))
|
||||
conn.postTransactionCommit(txSigned)
|
||||
.then(res => {
|
||||
const elem = document.getElementById('lastTransaction')
|
||||
elem.href = API_PATH + 'transactions/' + txSigned.id
|
||||
|
@ -131,6 +175,7 @@ conn.postTransaction(txSigned)
|
|||
|
||||
## BigchainDB Documentation
|
||||
|
||||
- [The Hitchhiker's Guide to BigchainDB](https://www.bigchaindb.com/developers/guide/)
|
||||
- [HTTP API Reference](https://docs.bigchaindb.com/projects/server/en/latest/http-client-server-api.html)
|
||||
- [The Transaction Model](https://docs.bigchaindb.com/projects/server/en/latest/data-models/transaction-model.html?highlight=crypto%20conditions)
|
||||
- [Inputs and Outputs](https://docs.bigchaindb.com/projects/server/en/latest/data-models/inputs-outputs.html)
|
||||
|
@ -144,26 +189,32 @@ This implementation plays "safe" by using JS-native (or downgradable) libraries
|
|||
* [chloride](https://github.com/dominictarr/chloride), or its underlying [sodium](https://github.com/paixaop/node-sodium) library
|
||||
* [node-sha3](https://github.com/phusion/node-sha3) -- **MAKE SURE** to use [steakknife's fork](https://github.com/steakknife/node-sha3) if [the FIPS 202 upgrade](https://github.com/phusion/node-sha3/pull/25) hasn't been merged (otherwise, you'll run into all kinds of hashing problems)
|
||||
|
||||
## Development
|
||||
|
||||
```js
|
||||
git clone git@github.com:bigchaindb/js-bigchaindb-driver.git
|
||||
cd js-bigchaindb-driver/
|
||||
|
||||
npm i
|
||||
npm run dev
|
||||
```
|
||||
|
||||
After updating source files in `src/`, make sure to update the API documentation. The following command will scan all source files and create the Markdown output into `./API.md`:
|
||||
|
||||
```bash
|
||||
npm run doc
|
||||
```
|
||||
|
||||
## Release Process
|
||||
|
||||
See the file named [RELEASE_PROCESS.md](RELEASE_PROCESS.md).
|
||||
|
||||
## Authors
|
||||
|
||||
* inspired by [`js-bigchaindb-quickstart`](https://github.com/sohkai/js-bigchaindb-quickstart) of @sohkhai [thanks]
|
||||
* BigchainDB <dev@bigchaindb.com>
|
||||
* BigchainDB <contact@ipdb.global>
|
||||
* BigchainDB contributors
|
||||
|
||||
## License
|
||||
## Licenses
|
||||
|
||||
```
|
||||
Copyright 2017 BigchainDB GmbH
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
```
|
||||
See [LICENSE](LICENSE) and [LICENSE-docs](LICENSE-docs).
|
||||
|
|
91
RELEASE_PROCESS.md
Normal file
91
RELEASE_PROCESS.md
Normal file
|
@ -0,0 +1,91 @@
|
|||
<!---
|
||||
Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
--->
|
||||
|
||||
# Our Release Process
|
||||
|
||||
## Notes
|
||||
|
||||
BigchainDB follows
|
||||
[the Python form of Semantic Versioning](https://packaging.python.org/tutorials/distributing-packages/#choosing-a-versioning-scheme)
|
||||
(i.e. MAJOR.MINOR.PATCH),
|
||||
which is almost identical
|
||||
to [regular semantic versioning](http://semver.org/), but there's no hyphen, e.g.
|
||||
|
||||
- `0.9.0` for a typical final release
|
||||
- `4.5.2a1` not `4.5.2-a1` for the first Alpha release
|
||||
- `3.4.5rc2` not `3.4.5-rc2` for Release Candidate 2
|
||||
|
||||
**Note:** For Git tags (which are used to identify releases on GitHub), we append a `v` in front.
|
||||
|
||||
We follow [BEP-1](https://github.com/bigchaindb/BEPs/tree/master/1), which is our variant of C4, the Collective Code Construction Contract, so a release is just a [tagged commit](https://git-scm.com/book/en/v2/Git-Basics-Tagging) on the `master` branch, i.e. a label for a particular Git commit.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Make sure you have a recent version of node and npm.
|
||||
1. `npm install`
|
||||
1. Update all npm package dependencies, where possible. You might have to freeze some versions. Run all tests locally (`npm run test`) and make sure they pass. Make a pull request (to be merged into the `master` branch) and make sure all tests are passing there (in Travis). Merge the pull request.
|
||||
1. Make sure your local `master` branch is in sync with GitHub: `git checkout master` and `git pull`
|
||||
1. Do a test build:
|
||||
|
||||
`npm run build`
|
||||
|
||||
If that fails, then get it working.
|
||||
1. We use the [release-it](https://www.npmjs.com/package/release-it) package (from npm) to automate most of the release. Make sure you have a recent version.
|
||||
1. Login to npm using your npm credentials, so you can publish a new [bigchaindb-driver](https://www.npmjs.com/package/bigchaindb-driver) package there. (The npm account must have permission to do so).
|
||||
|
||||
`npm login`
|
||||
|
||||
1. release-it needs a Github personal access token so it can interact with GitHub on your behalf. To get one, go to:
|
||||
|
||||
[https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
|
||||
and then make that token available as an environment variable, e.g.
|
||||
|
||||
`export GITHUB_TOKEN="f941e0..."`
|
||||
|
||||
1. Do the release:
|
||||
|
||||
- For a patch release, do `npm run release`
|
||||
- For a minor release, do `npm run release-minor`
|
||||
- For a major release, do `npm run release-major`
|
||||
|
||||
If your npm account is using two-factor authentication,
|
||||
you will have to append a one-time password (OTP) like `--npm.otp=123456`.
|
||||
The above command will automatically do a bunch of things:
|
||||
|
||||
- bump the project version in `package.json`, then git commit and git push it.
|
||||
- create a new Git tag of the form `v{verson}`, e.g. `v1.2.3`
|
||||
- create a new [GitHub release](https://github.com/bigchaindb/js-bigchaindb-driver/releases).
|
||||
- publish a new npm release
|
||||
|
||||
To see all the arguments passed to `release-it`, search for "release" in [package.json](package.json). The arguments are documented in the [release-it GitHub repo](https://github.com/release-it/release-it).
|
||||
|
||||
1. Make sure everything worked as expected.
|
||||
|
||||
- Was the version number bumped properly in [package.json](package.json)?
|
||||
- Was a new Git tag created? See the [list of tags](https://github.com/bigchaindb/js-bigchaindb-driver/tags).
|
||||
- Was a new GitHub release created? See the [list of releases](https://github.com/bigchaindb/js-bigchaindb-driver/releases).
|
||||
- Was a new npm package published on npm? [Check on npmjs.com](https://www.npmjs.com/package/bigchaindb-driver).
|
||||
|
||||
1. You can edit the description of the GitHub release to add or remove details.
|
||||
|
||||
If the docs were updated since the last release, [login to readthedocs.org](https://readthedocs.org/accounts/login/) and go to the **BigchainDB JavaScript Driver** project, then:
|
||||
|
||||
1. Click on "Builds", select "latest" from the drop-down menu, then click the "Build Version:" button.
|
||||
1. Wait for the build of "latest" to finish. This can take a few minutes.
|
||||
1. Go to Admin --> Advanced Settings
|
||||
and make sure that "Default branch:" (i.e. what "latest" points to)
|
||||
is set to the new release's tag, e.g. `v0.9.1`.
|
||||
(It won't be an option if you didn't wait for the build of "latest" to finish.)
|
||||
Then scroll to the bottom and click "Save".
|
||||
1. Go to Admin --> Versions
|
||||
and under **Choose Active Versions**, do these things:
|
||||
|
||||
1. Make sure that the new version's tag is "Active" and "Public"
|
||||
1. Make sure the **stable** branch is _not_ active.
|
||||
1. Scroll to the bottom of the page and click "Save".
|
||||
|
||||
Congratulations, you have released a new version of the BigchainDB JavaScript Driver!
|
12
compose/Dockerfile
Normal file
12
compose/Dockerfile
Normal file
|
@ -0,0 +1,12 @@
|
|||
FROM python:3.6
|
||||
|
||||
RUN apt-get update && apt-get install -y vim
|
||||
|
||||
RUN mkdir -p /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN pip install --upgrade pip ipdb ipython
|
||||
|
||||
COPY . /usr/src/app/
|
||||
|
||||
RUN pip install git+https://github.com/bigchaindb/bigchaindb.git
|
17
compose/tendermint/tmdata/config.toml
Normal file
17
compose/tendermint/tmdata/config.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
proxy_app = "tcp://bigchaindb:46658"
|
||||
moniker = "anonymous"
|
||||
fast_sync = true
|
||||
db_backend = "leveldb"
|
||||
log_level = "state:debug,*:error"
|
||||
|
||||
[consensus]
|
||||
create_empty_blocks = false
|
||||
|
||||
[rpc]
|
||||
laddr = "tcp://0.0.0.0:46657"
|
||||
|
||||
[p2p]
|
||||
laddr = "tcp://0.0.0.0:46656"
|
43
docker-compose.yml
Normal file
43
docker-compose.yml
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
version: '2.1'
|
||||
|
||||
services:
|
||||
mongodb:
|
||||
image: mongo:3.6
|
||||
ports:
|
||||
- "27017"
|
||||
command: mongod
|
||||
bigchaindb:
|
||||
depends_on:
|
||||
- mongodb
|
||||
- tendermint
|
||||
image: bigchaindb/bigchaindb:master
|
||||
environment:
|
||||
BIGCHAINDB_DATABASE_HOST: mongodb
|
||||
BIGCHAINDB_DATABASE_PORT: 27017
|
||||
BIGCHAINDB_SERVER_BIND: 0.0.0.0:9984
|
||||
BIGCHAINDB_WSSERVER_HOST: 0.0.0.0
|
||||
BIGCHAINDB_TENDERMINT_HOST: tendermint
|
||||
BIGCHAINDB_TENDERMINT_PORT: 26657
|
||||
ports:
|
||||
- "9984:9984"
|
||||
- "9985:9985"
|
||||
- "26658"
|
||||
healthcheck:
|
||||
test: ["CMD", "bash", "-c", "curl http://bigchaindb:9984 && curl http://tendermint:26657/abci_query"]
|
||||
interval: 3s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
command: -l DEBUG start
|
||||
tendermint:
|
||||
image: tendermint/tendermint:v0.31.5
|
||||
# volumes:
|
||||
# - ./tmdata:/tendermint
|
||||
entrypoint: ''
|
||||
ports:
|
||||
- "26656"
|
||||
- "26657"
|
||||
command: sh -c "tendermint init && tendermint node --consensus.create_empty_blocks=false --proxy_app=tcp://bigchaindb:26658"
|
32
docs/Makefile
Normal file
32
docs/Makefile
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = BigchainDBJavascriptDriver
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
@echo
|
||||
@echo "Removed $(BUILDDIR)/html."
|
||||
|
||||
.PHONY: html
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(SOURCEDIR) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
8
docs/README.md
Normal file
8
docs/README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
<!---
|
||||
Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
--->
|
||||
|
||||
# BigchainDBJavaScriptDriverDocs
|
||||
BigchainDB JavaScript Driver Documentation with Sphinx
|
36
docs/make.bat
Normal file
36
docs/make.bat
Normal file
|
@ -0,0 +1,36 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=python -msphinx
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
set SPHINXPROJ=BigchainDBJavascriptDriver
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
|
||||
echo.then set the SPHINXBUILD environment variable to point to the full
|
||||
echo.path of the 'sphinx-build' executable. Alternatively you may add the
|
||||
echo.Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
3
docs/requirements.txt
Normal file
3
docs/requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Sphinx~=1.0
|
||||
recommonmark>=0.4.0
|
||||
sphinx-rtd-theme>=0.2.4
|
BIN
docs/source/.conf.py.swp
Normal file
BIN
docs/source/.conf.py.swp
Normal file
Binary file not shown.
87
docs/source/advanced.rst
Normal file
87
docs/source/advanced.rst
Normal file
|
@ -0,0 +1,87 @@
|
|||
|
||||
.. Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
=================
|
||||
Advanced Examples
|
||||
=================
|
||||
|
||||
Crypto Conditions
|
||||
-----------------
|
||||
|
||||
Let's start with a basic use case example. Alice bought a bicycle for €240.
|
||||
She will use the bike for a year and will give it to her daughter afterwards.
|
||||
First, we create an asset registering the bicycle:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txCreateAliceSimple = driver.Transaction.makeCreateTransaction(
|
||||
{'asset': 'bicycle'},
|
||||
{'purchase_price': '€240'},
|
||||
[
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
const txCreateAliceSimpleSigned = driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||
|
||||
After a year, she decides it's time to transfer the bicycle to her daughter Carly.
|
||||
However, Alice wants to maintain the right over the bike so she can possibly sell it. If she would transfer the bicycle to Carly, she won't be able to do this.
|
||||
So, Alice needs a crypto conditions that defines that she or her daughter can sign the ``TRANSFER`` transaction to a possible buyer.
|
||||
|
||||
We need to define a threshold as well. This defines how many persons have to sign the transaction to ``TRANSFER`` it.
|
||||
In this case, we define two subconditions with the public keys from Alice and Carly. Next, we set the threshold to **one**.
|
||||
This means that just one of the subconditions has to sign the transaction to transfer it.
|
||||
This can be the mother Alice, or Carly herself.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
// Create condition for Alice and Carly
|
||||
let subConditionFrom = driver.Transaction.makeEd25519Condition(alice.publicKey, false)
|
||||
let subConditionTo = driver.Transaction.makeEd25519Condition(carly.publicKey, false)
|
||||
|
||||
// Create condition object with threshold and subconditions
|
||||
let condition = driver.Transaction.makeThresholdCondition(1, [subConditionFrom, subConditionTo])
|
||||
|
||||
// Generate output with condition added
|
||||
let output = driver.Transaction.makeOutput(condition)
|
||||
|
||||
// Add Carly to the output.public_keys field so she is the owner
|
||||
output.public_keys = [carly.publicKey]
|
||||
|
||||
let transaction = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: txCreateAliceSimpleSigned, output_index: 0 }],
|
||||
[output],
|
||||
{'meta': 'Transfer to new user with conditions'}
|
||||
);
|
||||
|
||||
// Add alice as previous owner
|
||||
transaction.inputs[0].owners_before = [alice.publicKey]
|
||||
|
||||
// Because the addition of crypto conditions, the id for the transaction has to be regenerated
|
||||
delete transaction.id
|
||||
transaction.id = sha3.sha3_256
|
||||
.create()
|
||||
.update(driver.Transaction.serializeTransactionIntoCanonicalString(transaction))
|
||||
.hex()
|
||||
|
||||
// Alice has to sign this transfer because she is still the owner of the created asset
|
||||
let signedCryptoConditionTx = driver.Transaction.signTransaction(transaction, alice.privateKey)
|
||||
|
||||
As you can see, we need to generate a new transactionId because we have added crypto conditions.
|
||||
We do this with the js-sha3 package, you need to install this package through ``npm``:
|
||||
|
||||
``npm install --save js-sha3``
|
||||
|
||||
Don't forget to import the package in your code:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
import * as sha3 from 'js-sha3'
|
||||
|
||||
|
||||
If you would like to see a more complex example, please have a look [here](https://github.com/bigchaindb/project-jannowitz/blob/code-examples/js-examples/crypto-conditions.js)
|
||||
|
||||
.. TODO: Document Utils when finished
|
189
docs/source/conf.py
Normal file
189
docs/source/conf.py
Normal file
|
@ -0,0 +1,189 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
#
|
||||
# BigchainDB Javascript Driver documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Aug 2 15:39:03 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
import datetime
|
||||
import sphinx_rtd_theme
|
||||
|
||||
from recommonmark.parser import CommonMarkParser
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['ntemplates']
|
||||
|
||||
source_parsers = {
|
||||
'.md': CommonMarkParser,
|
||||
}
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = ['.rst', '.md']
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'BigchainDB Javascript Driver'
|
||||
now = datetime.datetime.now()
|
||||
copyright = str(now.year) + ', BigchainDB Contributors'
|
||||
author = 'BigchainDB Contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.0.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
# html_static_path = ['nstatic']
|
||||
# Commented out this option because Sphinx can not find the path
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'about.html',
|
||||
'navigation.html',
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
'donate.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'BigchainDBJavascriptDriverdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'BigchainDBJavascriptDriver.tex', 'BigchainDB Javascript Driver Documentation',
|
||||
'BigchainDB', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'bigchaindbjavascriptdriver', 'BigchainDB Javascript Driver Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'BigchainDBJavascriptDriver', 'BigchainDB Javascript Driver Documentation',
|
||||
author, 'BigchainDBJavascriptDriver', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
23
docs/source/index.rst
Normal file
23
docs/source/index.rst
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
.. Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
BigchainDB Javascript Driver Documentation
|
||||
==========================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
← Back to All BigchainDB Docs <https://bigchaindb.readthedocs.io/en/latest/index.html>
|
||||
readme
|
||||
quickstart
|
||||
usage
|
||||
advanced
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
14
docs/source/quickstart.rst
Normal file
14
docs/source/quickstart.rst
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
.. Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
=========================
|
||||
Quickstart / Installation
|
||||
=========================
|
||||
|
||||
Installation with package manager npm:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ npm install bigchaindb-driver
|
120
docs/source/readme.rst
Normal file
120
docs/source/readme.rst
Normal file
|
@ -0,0 +1,120 @@
|
|||
|
||||
.. Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
BigchainDB JavaScript Driver
|
||||
============================
|
||||
|
||||
.. image:: https://img.shields.io/npm/v/bigchaindb-driver.svg
|
||||
:target: https://www.npmjs.com/package/bigchaindb-driver
|
||||
|
||||
.. image:: https://codecov.io/gh/bigchaindb/js-bigchaindb-driver/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/bigchaindb/js-bigchaindb-driver
|
||||
|
||||
.. image:: https://img.shields.io/badge/js-ascribe-39BA91.svg
|
||||
:target: https://github.com/ascribe/javascript
|
||||
|
||||
.. image:: https://travis-ci.com/bigchaindb/js-bigchaindb-driver.svg?branch=master
|
||||
:target: https://travis-ci.com/bigchaindb/js-bigchaindb-driver
|
||||
|
||||
.. image:: https://badges.greenkeeper.io/bigchaindb/js-bigchaindb-driver.svg
|
||||
:target: https://greenkeeper.io/
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Support for preparing, fulfilling, and sending transactions to a BigchainDB
|
||||
node.
|
||||
* Retrieval of transactions by id.
|
||||
* Getting status of a transaction by id.
|
||||
|
||||
Compatibility Matrix
|
||||
--------------------
|
||||
|
||||
+-----------------------+----------------------------------+
|
||||
| **BigchainDB Server** | **BigchainDB Javascript Driver** |
|
||||
+=======================+==================================+
|
||||
| ``0.10`` | ``0.1.x`` |
|
||||
+-----------------------+----------------------------------+
|
||||
| ``1.0`` | ``0.3.x`` |
|
||||
+-----------------------+----------------------------------+
|
||||
| ``1.3`` | ``3.x.x`` |
|
||||
+-----------------------+----------------------------------+
|
||||
| ``2.0`` | ``4.x.x`` |
|
||||
+-----------------------+----------------------------------+
|
||||
|
||||
|
||||
|
||||
Older versions
|
||||
--------------------
|
||||
|
||||
**Version 4.x.x**
|
||||
|
||||
As part of the changes in the BigchainDB 2.0 server, some endpoints were
|
||||
modified. In order to be consistent with them, the JS driver does not have
|
||||
anymore the `pollStatusAndFetchTransaction()` method as there are three
|
||||
different ways of posting a transaction:
|
||||
|
||||
- `commit` using the `postTransaction` or the `postTransactionCommit`: the response will return after the transaction is committed to a block.
|
||||
- `sync` using the `postTransactionSync`: the response will return after the transaction is validated.
|
||||
- `async` using the `postTransactionAsync`: the response will return immediately and not wait to see if the transaction is valid.
|
||||
|
||||
By default in the docs we will use the `postTransactionCommit` as is way of
|
||||
being sure that the transaction is validated and commited to a block, so
|
||||
there will not be any issue if you try to do any other action with the asset immediately.
|
||||
|
||||
Note: In order to not create breaking changes, both methods `postTransaction` and `postTransactionCommit` are kept although
|
||||
they do exactly the same
|
||||
|
||||
|
||||
**Version 3.2.x**
|
||||
|
||||
For versions below 3.2, a transfer transaction looked like:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const createTranfer = BigchainDB.Transaction.makeTransferTransaction(
|
||||
txCreated,
|
||||
metadata, [BigchainDB.Transaction.makeOutput(
|
||||
BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
0
|
||||
)
|
||||
|
||||
const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer,
|
||||
keypair.privateKey)
|
||||
|
||||
|
||||
In order to upgrade and do it compatible with the new driver version, this
|
||||
transaction should be now:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const createTranfer = BigchainDB.Transaction.makeTransferTransaction(
|
||||
[{ tx: txCreated, output_index: 0 }],
|
||||
[BigchainDB.Transaction.makeOutput(
|
||||
BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
metaData
|
||||
)
|
||||
|
||||
const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer,
|
||||
keypair.privateKey)
|
||||
|
||||
|
||||
The upgrade allows to create transfer transaction spending outputs that belong
|
||||
to different transactions. So for instance is now possible to create a transfer
|
||||
transaction spending two outputs from two different create transactions:
|
||||
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const createTranfer = BigchainDB.Transaction.makeTransferTransaction(
|
||||
[{ tx: txCreated1, output_index: 0 },
|
||||
{ tx: txCreated2, output_index: 0}],
|
||||
[BigchainDB.Transaction.makeOutput(
|
||||
BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
metaData
|
||||
)
|
||||
|
||||
const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer,
|
||||
keypair.privateKey)
|
795
docs/source/usage.rst
Normal file
795
docs/source/usage.rst
Normal file
|
@ -0,0 +1,795 @@
|
|||
|
||||
.. Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
====================
|
||||
Basic Usage Examples
|
||||
====================
|
||||
|
||||
For the examples on this page, we assume you've
|
||||
:doc:`installed the bigchaindb_driver JavaScript package <quickstart>`,
|
||||
and you have determined the BigchainDB Root URL (issue: move this to general docs)
|
||||
of the node or cluster you want to connect to.
|
||||
|
||||
This example guides you through creating and transferring an asset.
|
||||
We walk through the code explaining its use, some pieces are left out
|
||||
because they have no real use (e.g. definition of global variable)
|
||||
*Full working code* can be found at the bottom of this document.
|
||||
The following code are just snippets.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
We begin by importing the BigchainDB driver:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
|
||||
Next, we define a constant containing the API path.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
|
||||
Create a Connection with BigchainDB
|
||||
-----------------------------------
|
||||
|
||||
A simple connection with a BigchainDB node can be established like this:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const conn = new driver.Connection(API_PATH)
|
||||
|
||||
If the BigchainDB node requires special HTTP request headers
|
||||
(such as ``app_id`` and ``app_key``),
|
||||
they can be included like this:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const conn = new driver.Connection(API_PATH, {
|
||||
app_id: 'app_id_value',
|
||||
app_key: 'app_key_value'
|
||||
})
|
||||
|
||||
A more complex connection can be created if the BigchainDB network
|
||||
has several nodes, each with a different API path and different required headers.
|
||||
The connection strategy will be the one specified in BEP-14_.
|
||||
|
||||
.. _BEP-14: https://github.com/bigchaindb/BEPs/tree/master/14#connection-strategy
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const conn = new driver.Connection([
|
||||
API_PATH_1, // the first node does not use custom headers, only common headers
|
||||
{endpoint: API_PATH_2,
|
||||
headers: {app_id: 'your_app_id',
|
||||
app_key: 'your_app_key'}},
|
||||
{endpoint: API_PATH_3,
|
||||
headers: {app_id: 'your_app_id',
|
||||
app_key: 'your_app_key',
|
||||
extra_header: 'extra value'}},
|
||||
{endpoint: API_PATH_4,
|
||||
headers: {app_id: 'your_app_id',
|
||||
app_key: 'your_app_key',
|
||||
other_header: 'other value'}},
|
||||
{endpoint: API_PATH_5,
|
||||
headers: {custom_auth: 'custom token'}],
|
||||
{'sender_id': 'ab-12769'} // common header sent to all nodes
|
||||
)
|
||||
|
||||
Cryptographic Identities Generation
|
||||
-----------------------------------
|
||||
|
||||
Alice and Bob are represented by public/private key pairs. The private key is
|
||||
used to sign transactions, meanwhile the public key is used to verify that a
|
||||
signed transaction was indeed signed by the one who claims to be the signee.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const alice = new driver.Ed25519Keypair()
|
||||
const bob = new driver.Ed25519Keypair()
|
||||
|
||||
Digital Asset Definition
|
||||
------------------------
|
||||
|
||||
As an example, let’s consider the creation and transfer of a digital asset
|
||||
that represents a bicycle:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const assetdata = {
|
||||
'bicycle': {
|
||||
'serial_number': 'abcd1234',
|
||||
'manufacturer': 'Bicycle Inc.',
|
||||
}
|
||||
}
|
||||
|
||||
We'll suppose that the bike belongs to Alice, and that it eventually will be
|
||||
transferred to Bob.
|
||||
|
||||
In general, you are free to define any JSON object you which to store for the
|
||||
``'data'`` property (assetdata).
|
||||
|
||||
Metadata Definition (*optional*)
|
||||
--------------------------------
|
||||
|
||||
You can `optionally` add metadata to a transaction. Any JSON object is accepted.
|
||||
|
||||
For example, the bicycle will be transferred on earth which is metadata:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const metadata = {'planet': 'earth'}
|
||||
|
||||
Asset Creation
|
||||
--------------
|
||||
|
||||
We're now ready to create the digital asset. First, let's make a 'CREATE'
|
||||
transaction:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txCreateAliceSimple = driver.Transaction.makeCreateTransaction(
|
||||
assetdata,
|
||||
metadata,
|
||||
|
||||
// A transaction needs an output
|
||||
[ driver.Transaction.makeOutput(
|
||||
driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
Transaction needs an array of Output objects.
|
||||
Think of these as the recipients of the asset after the transaction.
|
||||
For `CREATE` Transactions, this should usually just be a list of
|
||||
Outputs wrapping Ed25519 Conditions generated from the issuers' public
|
||||
keys (so that the issuers are the recipients of the created asset).
|
||||
|
||||
``alice.publicKey`` can be considered as the Input for the transaction.
|
||||
Each input spends/transfers a previous output by satisfying/fulfilling
|
||||
the crypto-conditions on that output. A CREATE transaction should have
|
||||
exactly one input. A TRANSFER transaction should have at least one input (i.e. ≥1).
|
||||
|
||||
Sign the transaction with private key of Alice to fulfill it:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||
|
||||
And sent over to a BigchainDB node:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||
|
||||
Notice the transaction ``id``:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
txid = txCreateAliceSimpleSigned.id
|
||||
|
||||
Asset Transfer
|
||||
--------------
|
||||
|
||||
Imagine some time goes by, during which Alice is happy with her bicycle, and
|
||||
one day, she meets Bob, who is interested in acquiring her bicycle. The timing
|
||||
is good for Alice as she had been wanting to get a new bicycle.
|
||||
|
||||
To transfer the bicycle (asset) to Bob, Alice must consume the transaction's output in
|
||||
which the Bicycle asset was created.
|
||||
|
||||
Alice could retrieve the transaction:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
conn.getTransaction(txCreateAliceSimpleSigned.id)
|
||||
|
||||
First, let's prepare the transaction to be transferred.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txTransferBob = driver.Transaction.makeTransferTransaction(
|
||||
// signedTx to transfer and output index
|
||||
[{ tx: txCreateAliceSimpleSigned, output_index: 0 }],
|
||||
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))],
|
||||
|
||||
// metadata
|
||||
{price: '100 euro'}
|
||||
);
|
||||
|
||||
The function ``makeTransferTransaction()`` needs following parameters:
|
||||
|
||||
- Unspent outputs: Array of `unspent transactions outputs`. Each item contains `Transaction` itself and index of `unspent output` for that `Transaction`.
|
||||
- Array of output objects to add to the transaction: Think of these as the recipients of the asset after the transaction. For `TRANSFER` transactions, this should usually just be a list of outputs wrapping Ed25519 conditions generated from the public keys of the recipients.
|
||||
- Metadata for transaction (e.g. price of sold bike)
|
||||
|
||||
Fulfill transaction by signing it with Alice's private key.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
driver.Transaction.signTransaction(txTransferBob, alice.privateKey);
|
||||
|
||||
And sent over to a BigchainDB node:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
conn.postTransactionCommit(txTransferBobSigned)
|
||||
|
||||
Check the status again:
|
||||
|
||||
|
||||
Bob is the new owner:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
console.log('Is Bob the owner?', txTransferBobSigned['outputs'][0]['public_keys'][0] == bob.publicKey)
|
||||
// Output: true
|
||||
|
||||
Alice is the former owner:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
console.log('Was Alice the previous owner?', txTransferBobSigned['inputs'][0]['owners_before'][0] == alice.publicKey )
|
||||
// Output: true
|
||||
|
||||
|
||||
Querying for Assets
|
||||
-------------------
|
||||
|
||||
BigchainDB allows you to query for assets using simple text search. This search is applied to all the strings inside the asset payload and returns all the assets that match a given text search string.
|
||||
|
||||
BigchainDB also allows you to query for metadata, but there are some differences. The response of the text search call, beside retrieving the asset or metadata in each case, it consist of:
|
||||
- In the assets search the call returns the asset id which is the same id of the transaction that created the asset.
|
||||
- In the metadata search the call returns the transaction id that contains this metadata.
|
||||
|
||||
Let’s assume that we created 3 assets that look like this:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
assets = [
|
||||
{'data': {'bicycle': {'serial_number': 'abc', manufacturer: 'Bicycle Inc.'}}},
|
||||
{'data': {'bicycle': {'serial_number': 'cde', manufacturer: 'Bicycle Inc.'}}},
|
||||
{'data': {'bicycle': {'serial_number': 'fgh', manufacturer: 'Bicycle Inc.'}}}
|
||||
]
|
||||
|
||||
Let’s perform a text search for all assets that contain the word 'Bicycle Inc.':
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
conn.searchAssets('Bicycle Inc.')
|
||||
.then(assets => console.log('Found assets with serial number Bicycle Inc.:', assets))
|
||||
|
||||
Which leads to following result:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
[
|
||||
{
|
||||
'data': {'bicycle': {'serial_number': 'abc', manufacturer: 'Bicycle Inc.'}},
|
||||
'id': '7582d7a81652d0230fefb47dafc360ff09b2c2566b68f05c3a004d57e7fe7610'
|
||||
},
|
||||
{
|
||||
'data': {'bicycle': {'serial_number': 'cde', manufacturer: 'Bicycle Inc.'}},
|
||||
'id': 'e40f4b6ac70b9c1b3b237ec13f4174384fd4d54d36dfde25520171577c49caa4'
|
||||
},
|
||||
{
|
||||
'data': {'bicycle': {'serial_number': 'fgh', manufacturer: 'Bicycle Inc.'}},
|
||||
'id': '748f6c30daaf771c9020d84db9ad8ac4d1f7c8de7013db55e16f10ba090f7013'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
This call returns all the assets that match the string 'Bicycle Inc.', sorted by text score, as well as the asset id.
|
||||
|
||||
|
||||
Querying for Metadata
|
||||
---------------------
|
||||
|
||||
Similar as querying for assets, in BigchainDB you can query for metadata using simple text search.
|
||||
This search is applied to all the strings inside the metadata payload and returns all the metadata payloads that match a given text search string.
|
||||
|
||||
Having 3 metadata objets that look like this:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
metadata = [
|
||||
{'state': {'price': 145, 'eur/us': '1.32'}},
|
||||
{'state': {'price': 236, 'eur/us': '1.15'}},
|
||||
{'state': {'price': 102, 'eur/us': '1.32'}},
|
||||
]
|
||||
|
||||
Let’s perform a text search for all metadata that contains the word '1.32':
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
conn.searchMetadata('1.32')
|
||||
.then(assets => console.log('Found assets with serial number Bicycle Inc.:', assets))
|
||||
|
||||
Which leads to following result:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
[
|
||||
{
|
||||
'metadata': {'state': {'price': 145, 'eur/us': '1.32'}},
|
||||
'id': '14045a0e27ea971f8ac88762d2d74518d3a21f3f0fcd9d8a9a3b644b689cf3eb'
|
||||
},
|
||||
{
|
||||
'metadata': {'state': {'price': 102, 'eur/us': '1.32'}},
|
||||
'id': '6dd91f4700b3f66c55c50be009018e96f026d37f565d042d1aedfb322623d17d'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
This call returns all the metadata objects that match the string '1.32', sorted by text score, as well as the transaction id corresponding to each metadata object.
|
||||
|
||||
|
||||
|
||||
Recap: Asset Creation & Transfer
|
||||
--------------------------------
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
|
||||
// BigchainDB server instance or testnetwork (e.g. https://example.com/api/v1/)
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
|
||||
// Create a new keypair for Alice and Bob
|
||||
const alice = new driver.Ed25519Keypair()
|
||||
const bob = new driver.Ed25519Keypair()
|
||||
|
||||
console.log('Alice: ', alice.publicKey)
|
||||
console.log('Bob: ', bob.publicKey)
|
||||
|
||||
// Define the asset to store, in this example
|
||||
// we store a bicycle with its serial number and manufacturer
|
||||
const assetdata = {
|
||||
'bicycle': {
|
||||
'serial_number': 'cde',
|
||||
'manufacturer': 'Bicycle Inc.',
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata contains information about the transaction itself
|
||||
// (can be `null` if not needed)
|
||||
// E.g. the bicycle is fabricated on earth
|
||||
const metadata = {'planet': 'earth'}
|
||||
|
||||
// Construct a transaction payload
|
||||
const txCreateAliceSimple = driver.Transaction.makeCreateTransaction(
|
||||
assetdata,
|
||||
metadata,
|
||||
|
||||
// A transaction needs an output
|
||||
[ driver.Transaction.makeOutput(
|
||||
driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
// Sign the transaction with private keys of Alice to fulfill it
|
||||
const txCreateAliceSimpleSigned = driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||
|
||||
// Send the transaction off to BigchainDB
|
||||
const conn = new driver.Connection(API_PATH)
|
||||
|
||||
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||
.then(retrievedTx => console.log('Transaction', retrievedTx.id, 'successfully posted.'))
|
||||
// With the postTransactionCommit if the response is correct, then the transaction
|
||||
// is valid and commited to a block
|
||||
|
||||
// Transfer bicycle to Bob
|
||||
.then(() => {
|
||||
const txTransferBob = driver.Transaction.makeTransferTransaction(
|
||||
// signedTx to transfer and output index
|
||||
[{ tx: txCreateAliceSimpleSigned, output_index: 0 }],
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))],
|
||||
// metadata
|
||||
{price: '100 euro'}
|
||||
)
|
||||
|
||||
// Sign with alice's private key
|
||||
let txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
||||
console.log('Posting signed transaction: ', txTransferBobSigned)
|
||||
|
||||
// Post with commit so transaction is validated and included in a block
|
||||
return conn.postTransactionCommit(txTransferBobSigned)
|
||||
})
|
||||
.then(tx => {
|
||||
console.log('Response from BDB server:', tx)
|
||||
console.log('Is Bob the owner?', tx['outputs'][0]['public_keys'][0] == bob.publicKey)
|
||||
console.log('Was Alice the previous owner?', tx['inputs'][0]['owners_before'][0] == alice.publicKey )
|
||||
})
|
||||
// Search for asset based on the serial number of the bicycle
|
||||
.then(() => conn.searchAssets('Bicycle Inc.'))
|
||||
.then(assets => console.log('Found assets with serial number Bicycle Inc.:', assets))
|
||||
|
||||
|
||||
Ed25519Keypair Seed Functionality
|
||||
---------------------------------
|
||||
|
||||
BigchainDB JavaScript driver allows you to create a keypair based on a seed.
|
||||
The constructor accepts a 32 byte seed. One of the ways to create a seed from
|
||||
a string (e.g. a passphrase) is the one used by ``bip39``, specifically the function ``mnemonicToSeed``.
|
||||
|
||||
Install bip39 with npm: ``npm install bip39``
|
||||
|
||||
Next, require ``bip39`` in your file like this: ``var bip39 = require('bip39')``
|
||||
|
||||
At last, we can create the keypair based on a string. The function will transform the string to a byte array.
|
||||
As our constructor ``Ed25519Keypair()`` only accepts a seed of 32 bytes, we slice the first 32 bytes: ``slice(0,32)``.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
var keypair = new driver.Ed25519Keypair(bip39.mnemonicToSeed("yourString").slice(0, 32))
|
||||
|
||||
You can use the ``Ed25519Keypair()`` constructor as well without seed.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
var keypair = new driver.Ed25519Keypair()
|
||||
|
||||
|
||||
|
||||
Websocket Event Stream API Usage
|
||||
--------------------------------
|
||||
|
||||
The Event Stream API enables new ways to interact with BigchainDB,
|
||||
making it possible for your application to subscribe
|
||||
to all newly–confirmed transactions that are happening in the system.
|
||||
Below piece of code can be opened in your web browser.
|
||||
It will connect to your websocket (if you are using the testnet, redefine
|
||||
``var wsUri ='wss://insert-testnet-subdomain-here.com:443/api/v1/streams/valid_transactions'``).
|
||||
This web page will display all validated transactions.
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>WebSocket BigchainDB</title>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
|
||||
<!-- jQuery library -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||
|
||||
<!-- Latest compiled JavaScript -->
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
|
||||
<!-- Websocket Script -->
|
||||
<script language="javascript" type="text/javascript">
|
||||
|
||||
var wsUri = "ws://localhost:9985/api/v1/streams/valid_transactions";
|
||||
var output;
|
||||
var alertbox;
|
||||
|
||||
function init()
|
||||
{
|
||||
output = document.getElementById("output");
|
||||
alertbox = document.getElementById("alert-box");
|
||||
setWebSocket();
|
||||
}
|
||||
|
||||
function setWebSocket()
|
||||
{
|
||||
websocket = new WebSocket(wsUri);
|
||||
websocket.onopen = function(evt) { onOpen(evt) };
|
||||
websocket.onclose = function(evt) { onClose(evt) };
|
||||
websocket.onmessage = function(evt) { onMessage(evt) };
|
||||
websocket.onerror = function(evt) { onError(evt) };
|
||||
}
|
||||
|
||||
function onOpen(evt)
|
||||
{
|
||||
writeAlertMessage("CONNECTED");
|
||||
}
|
||||
|
||||
function onClose(evt)
|
||||
{
|
||||
writeAlertMessage("DISCONNECTED");
|
||||
}
|
||||
|
||||
function onMessage(evt)
|
||||
{
|
||||
writeToScreen('<a href="#" class="list-group-item"><h4 class="list-group-item-heading">Valid Transaction</h4><p class="list-group-item-text">' + evt.data + '</p></a>');
|
||||
}
|
||||
|
||||
function onError(evt)
|
||||
{
|
||||
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
|
||||
}
|
||||
|
||||
function closeConnection(evt)
|
||||
{
|
||||
websocket.close()
|
||||
}
|
||||
|
||||
function writeToScreen(message)
|
||||
{
|
||||
var pre = document.createElement("p");
|
||||
pre.style.wordWrap = "break-word";
|
||||
pre.innerHTML = message;
|
||||
output.appendChild(pre);
|
||||
}
|
||||
|
||||
function writeAlertMessage(message)
|
||||
{
|
||||
var alert = document.createElement("div");
|
||||
alert.className = "alert alert-success";
|
||||
alert.setAttribute("role", "alert");
|
||||
alert.innerHTML = message;
|
||||
alertbox.appendChild(alert);
|
||||
}
|
||||
|
||||
/* Initialize websocket and attach all events */
|
||||
window.addEventListener("load", init, false);
|
||||
|
||||
/* Event called on closing browser or refreshing page to close connection */
|
||||
window.addEventListener("beforeunload", closeConnection, false);
|
||||
|
||||
</script>
|
||||
|
||||
<!-- HTML Template -->
|
||||
<div class="container">
|
||||
<h2>WebSocket API Stream Valid Transactions BigchainDB</h2>
|
||||
|
||||
<!-- Box for displaying all alerts -->
|
||||
<div id="alert-box"></div>
|
||||
|
||||
<!-- Div for attachting all outputs -->
|
||||
<div id="output" class="list-group"></div>
|
||||
</div>
|
||||
|
||||
|
||||
Besides that, a NodeJs version has been created to display the validated transactions.
|
||||
All transactions are printed to the console. To use this piece of code, you will need the ``ws`` (WebSocket package) through npm: ``npm install --save ws``.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const WebSocket = require('ws')
|
||||
|
||||
const ws = new WebSocket('ws://localhost:9985/api/v1/streams/valid_transactions')
|
||||
|
||||
ws.on('open', () => {
|
||||
console.log("CONNECTED")
|
||||
});
|
||||
|
||||
ws.on('message', (data) => {
|
||||
let json = JSON.parse(data)
|
||||
console.log("\nTransactionId: ", json.transaction_id)
|
||||
console.log("AssetId: ", json.asset_id)
|
||||
console.log("BlockId: ", json.block_id)
|
||||
});
|
||||
|
||||
|
||||
Difference unspent and spent output
|
||||
-----------------------------------
|
||||
An unspent output is simply an output of a transaction which isn't yet an input of another transaction.
|
||||
So, if we transfer an asset, the output becomes spent, because it becomes the input of the transfer transaction.
|
||||
The transfer transactions its output becomes unspent now until he transfers the asset again to somebody else.
|
||||
|
||||
We will demonstrate this with a piece of code where we transfer a bicycle from Alice to Bob,
|
||||
and further we transfer it from Bob to Chris. Expectations:
|
||||
|
||||
* Output for Alice is spent
|
||||
* Output for Bob is spent
|
||||
* Output for Chris is unspent (he is the last person in transaction chain)
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
const conn = new driver.Connection(API_PATH)
|
||||
|
||||
const alice = new driver.Ed25519Keypair()
|
||||
const bob = new driver.Ed25519Keypair()
|
||||
const chris = new driver.Ed25519Keypair()
|
||||
|
||||
console.log('Alice: ', alice.publicKey)
|
||||
console.log('Bob: ', bob.publicKey)
|
||||
console.log('Chris: ', chris.publicKey)
|
||||
|
||||
// Define the asset to store, in this example
|
||||
// we store a bicycle with its serial number and manufacturer
|
||||
assetdata = {
|
||||
'bicycle': {
|
||||
'serial_number': 'cde',
|
||||
'manufacturer': 'Bicycle Inc.',
|
||||
}
|
||||
}
|
||||
|
||||
var txTransferBobSigned;
|
||||
|
||||
// Construct a transaction payload
|
||||
const txCreateAliceSimple = driver.Transaction.makeCreateTransaction(
|
||||
assetdata,
|
||||
{'meta': 'meta'},
|
||||
// A transaction needs an output
|
||||
[ driver.Transaction.makeOutput(
|
||||
driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
// Sign the transaction with private keys of Alice to fulfill it
|
||||
const txCreateAliceSimpleSigned = driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||
console.log('\n\nPosting signed create transaction for Alice:\n', txCreateAliceSimpleSigned)
|
||||
|
||||
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||
|
||||
// Transfer bicycle from Alice to Bob
|
||||
.then(() => {
|
||||
const txTransferBob = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: txCreateAliceSimpleSigned, output_index: 0 }],
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))],
|
||||
{'newOwner': 'Bob'}
|
||||
)
|
||||
|
||||
// Sign with alice's private key
|
||||
txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
||||
console.log('\n\nPosting signed transaction to Bob:\n', txTransferBobSigned)
|
||||
|
||||
// Post with commit so transaction is validated and included in a block
|
||||
return conn.postTransactionCommit(txTransferBobSigned)
|
||||
})
|
||||
|
||||
// Second transfer of bicycle from Bob to Chris
|
||||
.then(tx => {
|
||||
const txTransferChris = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: txTransferBobSigned, output_index: 0 }],
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(chris.publicKey))],
|
||||
{'newOwner': 'Chris'}
|
||||
)
|
||||
|
||||
// Sign with bob's private key
|
||||
let txTransferChrisSigned = driver.Transaction.signTransaction(txTransferChris, bob.privateKey)
|
||||
console.log('\n\nPosting signed transaction to Chris:\n', txTransferChrisSigned)
|
||||
|
||||
// Post with commit so transaction is validated and included in a block
|
||||
return conn.postTransactionCommit(txTransferChrisSigned)
|
||||
})
|
||||
.then(() => conn.listOutputs(alice.publicKey, true))
|
||||
.then(listSpentOutputs => {
|
||||
console.log("\nSpent outputs for Alice: ", listSpentOutputs.length) // Spent outputs: 1
|
||||
return conn.listOutputs(alice.publicKey, false)
|
||||
})
|
||||
.then(listUnspentOutputs => {
|
||||
console.log("Unspent outputs for Alice: ", listUnspentOutputs.length) // Unspent outputs: 0
|
||||
return conn.listOutputs(bob.publicKey, true)
|
||||
})
|
||||
.then(listSpentOutputs => {
|
||||
console.log("\nSpent outputs for Bob: ", listSpentOutputs.length) // Spent outputs: 1
|
||||
return conn.listOutputs(bob.publicKey, false)
|
||||
})
|
||||
.then(listUnspentOutputs => {
|
||||
console.log("Unspent outputs for Bob: ", listUnspentOutputs.length) // Unspent outputs: 0
|
||||
return conn.listOutputs(chris.publicKey, true)
|
||||
})
|
||||
.then(listSpentOutputs => {
|
||||
console.log("\nSpent outputs for Chris: ", listSpentOutputs.length) // Spent outputs: 0
|
||||
return conn.listOutputs(chris.publicKey, false)
|
||||
})
|
||||
.then(listUnspentOutputs => {
|
||||
console.log("Unspent outputs for Chris: ", listUnspentOutputs.length) // Unspent outputs: 1
|
||||
})
|
||||
.catch(res => {console.log(res)})
|
||||
|
||||
Output of above code looks like this. As you can see, Chris has no spent output, but one unspent output.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
Spent outputs for Alice: 1
|
||||
Unspent outputs for Alice: 0
|
||||
|
||||
Spent outputs for Bob: 1
|
||||
Unspent outputs for Bob: 0
|
||||
|
||||
Spent outputs for Chris: 0
|
||||
Unspent outputs for Chris: 1
|
||||
|
||||
Divisible Assets
|
||||
----------------
|
||||
|
||||
All assets in BigchainDB become implicitly divisible if a transaction contains more than one of that asset (we’ll see how this happens shortly).
|
||||
|
||||
Let's assume we have created a token to pay each other for small transactions like a beer or some food between friends.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const token = {
|
||||
'value': '1 euro'
|
||||
}
|
||||
|
||||
Let's create the asset. Note that we give an extra parameter to the ``makeOutput()`` function.
|
||||
We give it the parameter ``'4'`` to indicate that we want to create 4 tokens.
|
||||
**Pay attention to give the function a String instead of a plain Number.**
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txCreateAliceDivisible = driver.Transaction.makeCreateTransaction(
|
||||
token,
|
||||
{metaDataMessage: 'I am specific to this create transaction'},
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey), '4')],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
Alice goes dining at Bob and Carly. She decides to give a small fee to Bob and Carly.
|
||||
Alice decides to issue 4 tokens as a payment for her food: one to Bob, two to Carly and one to herself.
|
||||
Why one to herself? If you decide to fulfill an output, you have to spend all tokens.
|
||||
So if you want to keep one token for yourself, you have to transfer it to yourself.
|
||||
As you can see, we fulfill the first output of the create transaction (it's 0 because we start counting from 0).
|
||||
This gives us 4 tokens to transfer.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txTransferDivisible = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: txCreateAliceDivisibleSigned, output_index: 0 }],
|
||||
[
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(carly.publicKey), '2'),
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey), '1'),
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey), '1')
|
||||
],
|
||||
{
|
||||
metaDataMessage: 'I am specific to this transfer transaction'
|
||||
}
|
||||
);
|
||||
|
||||
To make the use of the last parameter of ``makeTransferTransaction()`` function more clear, we will do another transfer.
|
||||
We will fulfill the first and second output of the create transaction (0, 1) because Carly and Bob decide to redistribute some money.
|
||||
|
||||
* Output 0 represents 2 tokens for Carly
|
||||
* Output 1 represents 1 token for Bob
|
||||
|
||||
This gives us 3 tokens to redistribute. I want to give 1 token to Carly and 2 tokens Alice.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txTransferDivisibleInputs = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: txTransferDivisibleSigned, output_index: 0 }, { tx: txTransferDivisibleSigned, output_index: 1 }],
|
||||
[
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(carly.publicKey), '1'),
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey), '2')
|
||||
],
|
||||
{
|
||||
metaDataMessage: 'I am specific to this transfer transaction'
|
||||
}
|
||||
);
|
||||
|
||||
Because we want to fulfill two outputs (Carly and Bob), we have to sign the transfer transaction in the same order:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
const txTransferDivisibleInputsSigned = driver.Transaction.signTransaction(
|
||||
txTransferDivisibleInputs,
|
||||
carly.privateKey, bob.privateKey)
|
||||
|
||||
Here is a better overview of the flow of the tokens.
|
||||
|
||||
+-----------+------------+-----------------+
|
||||
| **Owner** | **Amount** | **Transaction** |
|
||||
+===========+============+=================+
|
||||
| ``Alice`` | 4 | ``CREATE`` |
|
||||
+-----------+------------+-----------------+
|
||||
| ``Alice`` | 1 | ``TRANSFER 1`` |
|
||||
+-----------+------------+-----------------+
|
||||
| ``Bob`` | 1 | ``TRANSFER 1`` |
|
||||
+-----------+------------+-----------------+
|
||||
| ``Carly`` | 2 | ``TRANSFER 1`` |
|
||||
+-----------+------------+-----------------+
|
||||
| ``Alice`` | 3 | ``TRANSFER 2`` |
|
||||
+-----------+------------+-----------------+
|
||||
| ``Bob`` | 0 | ``TRANSFER 2`` |
|
||||
+-----------+------------+-----------------+
|
||||
| ``Carly`` | 1 | ``TRANSFER 2`` |
|
||||
+-----------+------------+-----------------+
|
||||
|
||||
|
||||
.. TODO:
|
||||
.. - Add lexer: https://stackoverflow.com/questions/4259105/which-sphinx-code-block-language-to-use-for-json
|
||||
.. - Add divisible assets example
|
||||
.. - Add more readable code with promises possibly.
|
|
@ -1,10 +1,16 @@
|
|||
# Updating js-bigchaindb-driver from v0.1.x to v0.2.0
|
||||
<!---
|
||||
Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
--->
|
||||
|
||||
# Updating js-bigchaindb-driver from v0.1.x to v0.3.0
|
||||
|
||||
The latest version of js-bigchaindb-driver contains breaking changes to its
|
||||
external API. In this document, we enumerate all changes to allow you to make
|
||||
upgrades efficiently.
|
||||
|
||||
Note that upgrading the js-bigchaindb-driver to v0.2.0 was done to enable
|
||||
Note that upgrading the js-bigchaindb-driver to v0.3.0 was done to enable
|
||||
functionality included in the latest (v1.0) BigchainDB release. A full list of
|
||||
BigchainDB v1.0's breaking changes can be found
|
||||
[here](https://github.com/bigchaindb/bigchaindb/blob/17913dca682ff105540c0ea73365f1763efc2083/docs/upgrade-guides/v0.10--%3Ev1.0.md).
|
||||
|
@ -97,7 +103,7 @@ The driver is now bundled automatically each time we publish it to npm.com. We
|
|||
now ship packages for `commonjs`, `commonjs2`, `amd`, `umd`, `window` and
|
||||
node.js. Thanks to unpkg.com, we're also able to provide all these packages on
|
||||
a CDN. A link to all the bundles can be found
|
||||
[here](https://unpkg.com/bigchaindb-driver@0.2.0/dist/browser/).
|
||||
[here](https://unpkg.com/bigchaindb-driver@0.3.0/dist/browser/).
|
||||
|
||||
|
||||
A few notes:
|
16
examples/.babelrc
Normal file
16
examples/.babelrc
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"presets": [["@babel/preset-env"]],
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-async-generators",
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
"absoluteRuntime": false,
|
||||
"helpers": true,
|
||||
"regenerator": true
|
||||
}
|
||||
],
|
||||
"@babel/plugin-transform-regenerator",
|
||||
"@babel/plugin-transform-async-to-generator"
|
||||
]
|
||||
}
|
1
examples/.gitignore
vendored
Normal file
1
examples/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules
|
32
examples/README.md
Normal file
32
examples/README.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!---
|
||||
Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
--->
|
||||
|
||||
# Quick Notes
|
||||
`dotenv` is listed as a dependencies in `package.json`.
|
||||
If you want to use this, add a `.env` file to the root of this project (same level as this `README.md` file)
|
||||
and replace the variables to fit your specific config.
|
||||
|
||||
```
|
||||
BIGCHAINDB_API_PATH=https://test.bigchaindb.com/api/v1/
|
||||
BIGCHAINDB_APP_ID=<your-app-id>
|
||||
BIGCHAINDB_APP_KEY=<your-app-key>
|
||||
```
|
||||
|
||||
# Usage
|
||||
`npm install` -> Installs all required dependencies to run these examples.
|
||||
|
||||
## Different Examples
|
||||
**Basic Usage**: Create asset and transfer it to new owner.
|
||||
-> `npm start`
|
||||
|
||||
**Async/Await Basic Usage**: Basic usage example rewritten with async/await.
|
||||
-> `npm run basic-async`
|
||||
|
||||
**Querying for Assets**: Query for assetdata or metadata.
|
||||
-> `npm run query-assets`
|
||||
|
||||
**Seed/Keypair Functionality**: Create keypair with bip39 library.
|
||||
-> `npm run seed-func`
|
38
examples/package.json
Normal file
38
examples/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "js-driver-bigchaindb-examples",
|
||||
"version": "1.0.0",
|
||||
"main": "src/basic-usage.js",
|
||||
"scripts": {
|
||||
"build": "npm run clean && babel src -d dist",
|
||||
"serve": "node dist/basic-usage.js",
|
||||
"clean": "rimraf ./dist",
|
||||
"start": "nodemon src/basic-usage.js --exec babel-node",
|
||||
"query-assets": "nodemon src/query-assets.js --exec babel-node",
|
||||
"seed-func": "nodemon src/seed-func.js --exec babel-node",
|
||||
"basic-async": "nodemon src/basic-usage-async-await.js --exec babel-node"
|
||||
},
|
||||
"author": "BigchainDB",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.13.0",
|
||||
"@babel/core": "^7.13.8",
|
||||
"@babel/eslint-parser": "^7.13.8",
|
||||
"@babel/node": "7.13.0",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.13.0",
|
||||
"@babel/plugin-transform-regenerator": "^7.12.13",
|
||||
"@babel/plugin-transform-runtime": "^7.13.9",
|
||||
"@babel/preset-env": "^7.13.9",
|
||||
"@babel/register": "^7.13.8",
|
||||
"babel-loader": "^8.2.2",
|
||||
"nodemon": "^2.0.7",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"repository": "/",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"bigchaindb-driver": "^4.1.2",
|
||||
"bip39": "^3.0.3",
|
||||
"dotenv": "^8.2.0"
|
||||
}
|
||||
}
|
62
examples/src/basic-usage-async-await.js
Normal file
62
examples/src/basic-usage-async-await.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable import/no-unresolved */
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
require('dotenv').config()
|
||||
|
||||
// ======== Preparation ======== //
|
||||
const conn = new driver.Connection('https://test.ipdb.io/api/v1/', {
|
||||
header1: 'header1_value',
|
||||
header2: 'header2_value'
|
||||
})
|
||||
|
||||
const alice = new driver.Ed25519Keypair()
|
||||
const bob = new driver.Ed25519Keypair()
|
||||
|
||||
const assetdata = {
|
||||
'bicycle': {
|
||||
'serial_number': 'abcd1234',
|
||||
'manufacturer': 'Bicycle Inc.',
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = { 'planet': 'earth' }
|
||||
|
||||
// Call async basic usage function
|
||||
basicUsage()
|
||||
|
||||
async function basicUsage() {
|
||||
// ======== Create Transaction Bicycle ======== //
|
||||
const txCreateAliceSimple = driver.Transaction.makeCreateTransaction(
|
||||
assetdata,
|
||||
metadata,
|
||||
[
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
const txCreateAliceSimpleSigned =
|
||||
driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||
|
||||
// ======== POST CREATE Transaction ======== //
|
||||
const createdTx = await conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||
|
||||
// ======== POST TRANSFER Transaction ======== //
|
||||
const txTransferBob = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: createdTx, output_index: 0 }],
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))],
|
||||
{ price: '100 euro' }
|
||||
)
|
||||
|
||||
const txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
||||
|
||||
await conn.postTransactionCommit(txTransferBobSigned)
|
||||
|
||||
// ======== Querying Assets ======== //
|
||||
const assets = await conn.searchAssets('Bicycle Inc.')
|
||||
console.log(assets) // eslint-disable-line no-console
|
||||
}
|
63
examples/src/basic-usage.js
Normal file
63
examples/src/basic-usage.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable import/no-unresolved */
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
require('dotenv').config()
|
||||
|
||||
// ======== Preparation ======== //
|
||||
const conn = new driver.Connection('https://test.ipdb.io/api/v1/', {
|
||||
header1: 'header1_value',
|
||||
header2: 'header2_value'
|
||||
})
|
||||
|
||||
const alice = new driver.Ed25519Keypair()
|
||||
const bob = new driver.Ed25519Keypair()
|
||||
|
||||
const assetdata = {
|
||||
'bicycle': {
|
||||
'serial_number': 'abcd1234',
|
||||
'manufacturer': 'Bicycle Inc.',
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = { 'planet': 'earth' }
|
||||
|
||||
// ======== Create Transaction Bicycle ======== //
|
||||
const txCreateAliceSimple = driver.Transaction.makeCreateTransaction(
|
||||
assetdata,
|
||||
metadata,
|
||||
[
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
const txCreateAliceSimpleSigned =
|
||||
driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||
|
||||
// ======== Post Transaction and Fetch Result ======== //
|
||||
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||
// ======== Transfer Bicycle to Bob ======== //
|
||||
.then((fetchedTx) => {
|
||||
const txTransferBob = driver.Transaction.makeTransferTransaction(
|
||||
[{ tx: fetchedTx, output_index: 0 }],
|
||||
[driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))],
|
||||
{ price: '100 euro' }
|
||||
)
|
||||
|
||||
// Sign transfer transaction with Alice's private key
|
||||
const txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
||||
|
||||
return conn.postTransactionCommit(txTransferBobSigned)
|
||||
})
|
||||
.then(tx => {
|
||||
console.log('Is Bob the owner?', tx.outputs[0].public_keys[0] === bob.publicKey) // eslint-disable-line no-console
|
||||
console.log('Was Alice the previous owner?', tx.inputs[0].owners_before[0] === alice.publicKey) // eslint-disable-line no-console
|
||||
})
|
||||
|
||||
// ======== Search Asset by Serial Number ======== //
|
||||
.then(() => conn.searchAssets('Bicycle Inc.'))
|
||||
.then(assets => console.log('Found assets with serial number Bicycle Inc.:', assets)) // eslint-disable-line no-console
|
50
examples/src/query-assets.js
Normal file
50
examples/src/query-assets.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable import/no-unresolved */
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
require('dotenv').config()
|
||||
|
||||
// ======== Preparation ======== //
|
||||
const conn = new driver.Connection('https://example.com/api/v1/', {
|
||||
header1: 'header1_value',
|
||||
header2: 'header2_value'
|
||||
})
|
||||
|
||||
const alice = new driver.Ed25519Keypair()
|
||||
|
||||
// ======== Asset Array ======== //
|
||||
const assetArray = []
|
||||
assetArray.push({ 'bicycle': { 'serial_number': 'abc', 'manufacturer': 'BicyclesInc' } })
|
||||
assetArray.push({ 'bicycle': { 'serial_number': 'cde', 'manufacturer': 'BicyclesInc' } })
|
||||
assetArray.push({ 'bicycle': { 'serial_number': 'fgh', 'manufacturer': 'BicyclesInc' } })
|
||||
|
||||
const metadata = { 'planet': 'Pluto' }
|
||||
|
||||
// ======== Create Transactions for bicycles ======== //
|
||||
function createTx(assetdata) {
|
||||
const txCreate = driver.Transaction.makeCreateTransaction(
|
||||
assetdata,
|
||||
metadata,
|
||||
[
|
||||
driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey))
|
||||
],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
const txCreateSigned = driver.Transaction.signTransaction(txCreate, alice.privateKey)
|
||||
return conn.postTransactionCommit(txCreateSigned)
|
||||
}
|
||||
|
||||
// ======== Execute all promises in order to post transactions and fetch them ======== //
|
||||
Promise.all(assetArray.map(createTx))
|
||||
|
||||
// ======== Querying Assets for Assetdata ======== //
|
||||
.then(() => conn.searchAssets('BicyclesInc'))
|
||||
.then(assets => console.log('Found assets with serial number "BicyclesInc":', assets)) // eslint-disable-line no-console
|
||||
|
||||
// ======== Querying Assets for Metadata ======== //
|
||||
.then(() => conn.searchMetadata('Pluto'))
|
||||
.then(assets => console.log('Found assets with metadata "Pluto":', assets)) // eslint-disable-line no-console
|
40
examples/src/seed-func.js
Normal file
40
examples/src/seed-func.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable import/no-unresolved */
|
||||
|
||||
import bip39 from 'bip39'
|
||||
|
||||
const driver = require('bigchaindb-driver')
|
||||
|
||||
// ======== Create Keypair ======== //
|
||||
/**
|
||||
* Use a passphrase to derive a keypair
|
||||
* If you use the same seed -> you will derive the same keypair
|
||||
*
|
||||
* mnemnoicToSeed() transforms the passphrase you gave as an input
|
||||
* to a byteArray
|
||||
*
|
||||
* BigchainDB however only accepts an input length of 32 characters
|
||||
* so we have to slice this to give it as input for driver.Ed25519Keypair()
|
||||
*
|
||||
* Is it safe to slice? Yes, a seed of length 32 is very safe according
|
||||
* to related papers discussing this.
|
||||
*/
|
||||
const passphrase = 'This is a random passphrase'
|
||||
const seed = bip39.mnemonicToSeed(passphrase).slice(0, 32)
|
||||
|
||||
const keypair = new driver.Ed25519Keypair(seed)
|
||||
|
||||
console.log(`Public Key: ${keypair.publicKey} - Private Key: ${keypair.privateKey}`) // eslint-disable-line no-console
|
||||
|
||||
// ======== Other Bip39 Functionality not related to BigchainDB ======== //
|
||||
|
||||
/* Create Random passphrase */
|
||||
const mnemonic = bip39.generateMnemonic()
|
||||
console.log('Random passphrase: ', mnemonic) // eslint-disable-line no-console
|
||||
|
||||
/* Validate mnemnoic */
|
||||
console.log(bip39.validateMnemonic(mnemonic)) // eslint-disable-line no-console
|
||||
console.log(bip39.validateMnemonic('some random strings together but to short')) // eslint-disable-line no-console
|
155
package.json
155
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bigchaindb-driver",
|
||||
"version": "0.2.0",
|
||||
"version": "4.3.0",
|
||||
"description": "Node.js driver for BigchainDB",
|
||||
"homepage": "https://www.bigchaindb.com/",
|
||||
"bugs": "https://github.com/bigchaindb/js-bigchaindb-driver/issues",
|
||||
|
@ -10,73 +10,83 @@
|
|||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "BigchainDB",
|
||||
"files": [
|
||||
"dist",
|
||||
"types"
|
||||
],
|
||||
"main": "./dist/node/index.js",
|
||||
"browser": "./dist/browser/bigchaindb-driver.cjs2.min.js",
|
||||
"types": "./types/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"lint": "eslint ./",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"build": "npm run clean && npm run build:cjs && npm run build:dist",
|
||||
"build:bundle": "webpack",
|
||||
"build:cjs": "cross-env BABEL_ENV=cjs babel ./src -d dist/node",
|
||||
"build:dist": "cross-env NODE_ENV=production webpack -p",
|
||||
"clean": "rimraf dist/bundle dist/node",
|
||||
"test": "npm run lint && nyc ava test/ && npm run thanks && npm run report-coverage",
|
||||
"build:dist": "cross-env NODE_ENV=production webpack",
|
||||
"dev": "webpack -w",
|
||||
"clean": "rimraf dist/bundle dist/browser dist/node",
|
||||
"test": "npm run lint && nyc ava && npm run report-coverage",
|
||||
"thanks": "cowsay Hi, thanks for your interest in BigchainDB. We appreciate your contribution!",
|
||||
"release": "./node_modules/release-it/bin/release.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||
"release-minor": "./node_modules/release-it/bin/release.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||
"release-major": "./node_modules/release-it/bin/release.js major --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||
"prepublishOnly": "npm update && npm run build",
|
||||
"precommit": "lint-staged",
|
||||
"report-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"eslint"
|
||||
]
|
||||
"release": "read -p 'GITHUB_TOKEN: ' GITHUB_TOKEN && export GITHUB_TOKEN=$GITHUB_TOKEN && release-it --src.tagName='v%s'",
|
||||
"release-minor": "release-it minor --non-interactive",
|
||||
"release-major": "release-it major --non-interactive",
|
||||
"prepublishOnly": "npm run build",
|
||||
"report-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov",
|
||||
"doc": "documentation build src/index.js -f md -o API.md -g --markdown-toc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "^0.20.0",
|
||||
"babel-cli": "^6.22.2",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-loader": "^7.0.0",
|
||||
"babel-plugin-add-module-exports": "^0.2.1",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.23.0",
|
||||
"babel-plugin-transform-export-extensions": "^6.22.0",
|
||||
"babel-plugin-transform-object-assign": "^6.22.0",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-es2015-no-commonjs": "0.0.2",
|
||||
"babel-preset-latest": "^6.22.0",
|
||||
"babel-runtime": "^6.22.0",
|
||||
"cross-env": "^5.0.1",
|
||||
"eslint": "^3.14.1",
|
||||
"eslint-config-ascribe": "^3.0.4",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
"husky": "^0.14.0",
|
||||
"lint-staged": "^4.0.0",
|
||||
"nyc": "^11.0.2",
|
||||
"release-it": "^2.7.3",
|
||||
"rimraf": "^2.5.4",
|
||||
"sinon": "^2.3.4",
|
||||
"webpack": "^3.0.0"
|
||||
"@ava/babel": "^2.0.0",
|
||||
"@babel/cli": "^7.17.0",
|
||||
"@babel/core": "^7.17.2",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.16.7",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.16.7",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.16.8",
|
||||
"@babel/plugin-transform-object-assign": "^7.16.7",
|
||||
"@babel/plugin-transform-regenerator": "^7.16.7",
|
||||
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/register": "^7.17.0",
|
||||
"ava": "^3.15.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"buffer": "^6.0.3",
|
||||
"codecov": "^3.8.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"documentation": "^13.2.5",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.3.4",
|
||||
"nyc": "^15.1.0",
|
||||
"release-it": "^14.12.4",
|
||||
"rewire": "^6.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"sinon": "^13.0.1",
|
||||
"terser-webpack-plugin": "^5.3.1",
|
||||
"webpack": "^5.68.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"browser-resolve": "^1.11.2",
|
||||
"bs58": "^4.0.0",
|
||||
"buffer": "^5.0.2",
|
||||
"clone": "^2.1.0",
|
||||
"core-js": "^2.4.1",
|
||||
"decamelize": "^1.2.0",
|
||||
"es6-promise": "^4.0.5",
|
||||
"fetch-ponyfill": "^4.0.0",
|
||||
"five-bells-condition": "^5.0.1",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"js-sha3": "^0.6.0",
|
||||
"js-utility-belt": "^1.5.0",
|
||||
"@babel/runtime-corejs3": "^7.17.2",
|
||||
"abort-controller": "^3.0.0",
|
||||
"bs58": "^4.0.1",
|
||||
"clone": "^2.1.2",
|
||||
"core-js": "^3.21.0",
|
||||
"crypto-conditions": "2.2.1",
|
||||
"decamelize": "^5.0.0",
|
||||
"es6-promise": "^4.2.8",
|
||||
"fetch-ponyfill": "^7.1.0",
|
||||
"js-sha3": "^0.8.0",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
"query-string": "^4.3.4",
|
||||
"sprintf-js": "^1.0.3",
|
||||
"tweetnacl": "^1.0.0",
|
||||
"yarn": "^0.24.5"
|
||||
"query-string": "^7.1.1",
|
||||
"sprintf-js": "^1.1.2",
|
||||
"tweetnacl": "^1.0.3"
|
||||
},
|
||||
"keywords": [
|
||||
"bigchaindb",
|
||||
|
@ -85,9 +95,15 @@
|
|||
"decentralized",
|
||||
"dapp"
|
||||
],
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"eslint"
|
||||
]
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
"test/*.js"
|
||||
"test/**/*.js",
|
||||
"!test/constants.js"
|
||||
],
|
||||
"source": [
|
||||
"**/*.{js,jsx}",
|
||||
|
@ -99,8 +115,29 @@
|
|||
"tap": true,
|
||||
"powerAssert": false,
|
||||
"require": [
|
||||
"babel-register"
|
||||
"@babel/register"
|
||||
],
|
||||
"babel": "inherit"
|
||||
"babel": true
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"release-it": {
|
||||
"github": {
|
||||
"release": true
|
||||
},
|
||||
"git": {
|
||||
"tagName": "v${version}"
|
||||
},
|
||||
"hooks": {
|
||||
"before:init": [
|
||||
"npm run test"
|
||||
]
|
||||
},
|
||||
"npm": {
|
||||
"publish": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
38
plugins/add-vendors-plugin.js
Normal file
38
plugins/add-vendors-plugin.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable strict, no-console, object-shorthand, import/no-extraneous-dependencies */
|
||||
|
||||
const { ConcatSource } = require('webpack-sources')
|
||||
|
||||
module.exports = class AddVendorsPlugin {
|
||||
constructor(base) {
|
||||
this.base = base
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
compiler.hooks.emit.tapAsync(
|
||||
`AddVendorsPlugin ${this.base}`,
|
||||
(compilation, callback) => {
|
||||
const main = compilation.assets[`main.${this.base}`]
|
||||
const mainMap = compilation.assets[`main.${this.base}.map`]
|
||||
const vendor = compilation.assets[`vendors.${this.base}`]
|
||||
|
||||
if (main && vendor) {
|
||||
const compiledAsset = new ConcatSource(main._value[0])
|
||||
compiledAsset.add(vendor)
|
||||
compiledAsset.add(main._value[1])
|
||||
compilation.assets = {}
|
||||
compilation.assets[this.base] = compiledAsset
|
||||
} else if (main && mainMap) {
|
||||
compilation.assets = {}
|
||||
compilation.assets[this.base] = main
|
||||
compilation.assets[`${this.base}.map`] = mainMap
|
||||
}
|
||||
|
||||
callback()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,17 +1,21 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import base58 from 'bs58'
|
||||
import nacl from 'tweetnacl'
|
||||
import { sign } from 'tweetnacl'
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @class Keypair Ed25519 keypair in base58 (as BigchainDB expects base58 keys)
|
||||
* Ed25519 keypair in base58 (as BigchainDB expects base58 keys)
|
||||
* @type {Object}
|
||||
* @param {Buffer} [seed] A seed that will be used as a key derivation function
|
||||
* @property {string} publicKey
|
||||
* @property {string} privateKey
|
||||
*/
|
||||
export default function Ed25519Keypair(seed) {
|
||||
const keyPair = seed ? nacl.sign.keyPair.fromSeed(seed) : nacl.sign.keyPair()
|
||||
this.publicKey = base58.encode(keyPair.publicKey)
|
||||
const keyPair = seed ? sign.keyPair.fromSeed(seed) : sign.keyPair()
|
||||
this.publicKey = base58.encode(Buffer.from(keyPair.publicKey))
|
||||
// tweetnacl's generated secret key is the secret key + public key (resulting in a 64-byte buffer)
|
||||
this.privateKey = base58.encode(keyPair.secretKey.slice(0, 32))
|
||||
this.privateKey = base58.encode(Buffer.from(keyPair.secretKey.slice(0, 32)))
|
||||
}
|
||||
|
|
|
@ -1,16 +1,78 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
// TODO: remove abort-controller when using Node >=15
|
||||
import AbortController from 'abort-controller'
|
||||
import { Promise } from 'es6-promise'
|
||||
import fetchPonyfill from 'fetch-ponyfill'
|
||||
import { vsprintf } from 'sprintf-js'
|
||||
|
||||
import formatText from './format_text'
|
||||
|
||||
import stringifyAsQueryParam from './stringify_as_query_param'
|
||||
|
||||
const fetch = fetchPonyfill({ Promise })
|
||||
|
||||
const fetch = fetchPonyfill(Promise)
|
||||
export function ResponseError(message, status, requestURI) {
|
||||
this.name = 'ResponseError'
|
||||
this.message = message
|
||||
this.status = status
|
||||
this.requestURI = requestURI
|
||||
this.stack = new Error().stack
|
||||
}
|
||||
|
||||
ResponseError.prototype = new Error()
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Timeout function following https://github.com/github/fetch/issues/175#issuecomment-284787564
|
||||
* @param {integer} obj Source object
|
||||
* @param {Promise} filter Array of key names to select or function to invoke per iteration
|
||||
* @param {AbortController} controller AbortController instance bound to fetch
|
||||
* @return {Object} TimeoutError if the time was consumed, otherwise the Promise will be resolved
|
||||
*/
|
||||
function timeout(ms, promise, controller) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const nodeTimeout = setTimeout(() => {
|
||||
controller.abort()
|
||||
const errorObject = {
|
||||
message: 'TimeoutError',
|
||||
}
|
||||
reject(new Error(errorObject))
|
||||
}, ms)
|
||||
promise
|
||||
.then((res) => {
|
||||
clearTimeout(nodeTimeout)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
clearTimeout(nodeTimeout)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Promise} res Source object
|
||||
* @return {Promise} Promise that will resolve with the response if its status was 2xx;
|
||||
* otherwise rejects with the response
|
||||
*/
|
||||
function handleResponse(res) {
|
||||
// If status is not a 2xx (based on Response.ok), assume it's an error
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch
|
||||
if (!(res && res.ok)) {
|
||||
throw new ResponseError(
|
||||
'HTTP Error: Requested page not reachable',
|
||||
`${res.status} ${res.statusText}`,
|
||||
res.url
|
||||
)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* imported from https://github.com/bigchaindb/js-utility-belt/
|
||||
*
|
||||
* Global fetch wrapper that adds some basic error handling and ease of use enhancements.
|
||||
|
@ -24,33 +86,44 @@ const fetch = fetchPonyfill(Promise)
|
|||
* @param {string} url Url to request. Can be specified as a sprintf format string (see
|
||||
* https://github.com/alexei/sprintf.js) that will be resolved using
|
||||
* `config.urlTemplateSpec`.
|
||||
* @param {object} config Additional configuration, mostly passed to fetch as its 'init' config
|
||||
* @param {Object} config Additional configuration, mostly passed to fetch as its 'init' config
|
||||
* (see https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch#Parameters).
|
||||
* @param {*} config.jsonBody Json payload to the request. Will automatically be
|
||||
* JSON.stringify()-ed and override `config.body`.
|
||||
* @param {string|object} config.query Query parameter to append to the end of the url.
|
||||
* @param {string|Object} config.query Query parameter to append to the end of the url.
|
||||
* If specified as an object, keys will be
|
||||
* decamelized into snake case first.
|
||||
* @param {*[]|object} config.urlTemplateSpec Format spec to use to expand the url (see sprintf).
|
||||
* @param {*[]|Object} config.urlTemplateSpec Format spec to use to expand the url (see sprintf).
|
||||
* @param {*} config.* All other options are passed through to fetch.
|
||||
* @param {integer} requestTimeout Timeout for a single request
|
||||
*
|
||||
* @return {Promise} Promise that will resolve with the response if its status was 2xx;
|
||||
* otherwise rejects with the response
|
||||
* @return {Promise} If requestTimeout the timeout function will be called. Otherwise resolve the
|
||||
* Promise with the handleResponse function
|
||||
*/
|
||||
export default function baseRequest(url, { jsonBody, query, urlTemplateSpec, ...fetchConfig } = {}) {
|
||||
export default function baseRequest(
|
||||
url,
|
||||
{
|
||||
jsonBody, query, urlTemplateSpec, ...fetchConfig
|
||||
} = {},
|
||||
requestTimeout = 0
|
||||
) {
|
||||
let expandedUrl = url
|
||||
|
||||
if (urlTemplateSpec != null) {
|
||||
if (Array.isArray(urlTemplateSpec) && urlTemplateSpec.length) {
|
||||
// Use vsprintf for the array call signature
|
||||
expandedUrl = vsprintf(url, urlTemplateSpec)
|
||||
} else if (urlTemplateSpec &&
|
||||
typeof urlTemplateSpec === 'object' &&
|
||||
Object.keys(urlTemplateSpec).length) {
|
||||
} else if (
|
||||
urlTemplateSpec &&
|
||||
typeof urlTemplateSpec === 'object' &&
|
||||
Object.keys(urlTemplateSpec).length
|
||||
) {
|
||||
expandedUrl = formatText(url, urlTemplateSpec)
|
||||
} else if (process.env.NODE_ENV !== 'production') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Supplied urlTemplateSpec was not an array or object. Ignoring...')
|
||||
console.warn(
|
||||
'Supplied urlTemplateSpec was not an array or object. Ignoring...'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,13 +142,16 @@ export default function baseRequest(url, { jsonBody, query, urlTemplateSpec, ...
|
|||
fetchConfig.body = JSON.stringify(jsonBody)
|
||||
}
|
||||
|
||||
return fetch.fetch(expandedUrl, fetchConfig)
|
||||
.then((res) => {
|
||||
// If status is not a 2xx (based on Response.ok), assume it's an error
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch
|
||||
if (!(res && res.ok)) {
|
||||
throw res
|
||||
}
|
||||
return res
|
||||
})
|
||||
if (requestTimeout) {
|
||||
const controller = new AbortController()
|
||||
const { signal } = controller
|
||||
return timeout(
|
||||
requestTimeout,
|
||||
fetch.fetch(expandedUrl, { ...fetchConfig, signal }),
|
||||
controller
|
||||
)
|
||||
.then(handleResponse)
|
||||
} else {
|
||||
return fetch.fetch(expandedUrl, fetchConfig).then(handleResponse)
|
||||
}
|
||||
}
|
||||
|
|
201
src/connection.js
Normal file
201
src/connection.js
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import Transport from './transport'
|
||||
|
||||
const HEADER_BLACKLIST = ['content-type']
|
||||
const DEFAULT_NODE = 'http://localhost:9984/api/v1/'
|
||||
const DEFAULT_TIMEOUT = 20000 // The default value is 20 seconds
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String, Array} nodes Nodes for the connection. String possible to be backwards compatible
|
||||
* with version before 4.1.0 version
|
||||
* @param {Object} headers Common headers for every request
|
||||
* @param {float} timeout Optional timeout in secs
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
export default class Connection {
|
||||
// This driver implements the BEP-14 https://github.com/bigchaindb/BEPs/tree/master/14
|
||||
constructor(nodes, headers = {}, timeout = DEFAULT_TIMEOUT) {
|
||||
// Copy object
|
||||
this.headers = { ...headers }
|
||||
|
||||
// Validate headers
|
||||
Object.keys(headers).forEach(header => {
|
||||
if (HEADER_BLACKLIST.includes(header.toLowerCase())) {
|
||||
throw new Error(`Header ${header} is reserved and cannot be set.`)
|
||||
}
|
||||
})
|
||||
|
||||
this.normalizedNodes = []
|
||||
if (!nodes) {
|
||||
this.normalizedNodes.push(Connection.normalizeNode(DEFAULT_NODE, this.headers))
|
||||
} else if (Array.isArray(nodes)) {
|
||||
nodes.forEach(node => {
|
||||
this.normalizedNodes.push(Connection.normalizeNode(node, this.headers))
|
||||
})
|
||||
} else {
|
||||
this.normalizedNodes.push(Connection.normalizeNode(nodes, this.headers))
|
||||
}
|
||||
|
||||
this.transport = new Transport(this.normalizedNodes, timeout)
|
||||
}
|
||||
|
||||
static normalizeNode(node, headers) {
|
||||
if (typeof node === 'string') {
|
||||
return { 'endpoint': node, 'headers': headers }
|
||||
} else {
|
||||
const allHeaders = { ...headers, ...node.headers }
|
||||
return { 'endpoint': node.endpoint, 'headers': allHeaders }
|
||||
}
|
||||
}
|
||||
|
||||
static getApiUrls(endpoint) {
|
||||
return {
|
||||
'blocks': 'blocks',
|
||||
'blocksDetail': 'blocks/%(blockHeight)s',
|
||||
'outputs': 'outputs',
|
||||
'transactions': 'transactions',
|
||||
'transactionsSync': 'transactions?mode=sync',
|
||||
'transactionsAsync': 'transactions?mode=async',
|
||||
'transactionsCommit': 'transactions?mode=commit',
|
||||
'transactionsDetail': 'transactions/%(transactionId)s',
|
||||
'assets': 'assets',
|
||||
'metadata': 'metadata'
|
||||
}[endpoint]
|
||||
}
|
||||
|
||||
_req(path, options = {}) {
|
||||
return this.transport.forwardRequest(path, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param blockHeight
|
||||
*/
|
||||
getBlock(blockHeight) {
|
||||
return this._req(Connection.getApiUrls('blocksDetail'), {
|
||||
urlTemplateSpec: {
|
||||
blockHeight
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionId
|
||||
*/
|
||||
getTransaction(transactionId) {
|
||||
return this._req(Connection.getApiUrls('transactionsDetail'), {
|
||||
urlTemplateSpec: {
|
||||
transactionId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionId
|
||||
* @param status
|
||||
*/
|
||||
listBlocks(transactionId) {
|
||||
return this._req(Connection.getApiUrls('blocks'), {
|
||||
query: {
|
||||
transaction_id: transactionId,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publicKey
|
||||
* @param spent
|
||||
*/
|
||||
listOutputs(publicKey, spent) {
|
||||
const query = {
|
||||
public_key: publicKey
|
||||
}
|
||||
// NOTE: If `spent` is not defined, it must not be included in the
|
||||
// query parameters.
|
||||
if (spent !== undefined) {
|
||||
query.spent = spent.toString()
|
||||
}
|
||||
return this._req(Connection.getApiUrls('outputs'), {
|
||||
query
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param assetId
|
||||
* @param operation
|
||||
*/
|
||||
listTransactions(assetId, operation) {
|
||||
return this._req(Connection.getApiUrls('transactions'), {
|
||||
query: {
|
||||
asset_id: assetId,
|
||||
operation
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transaction
|
||||
*/
|
||||
postTransaction(transaction) {
|
||||
return this.postTransactionCommit(transaction)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transaction
|
||||
*/
|
||||
postTransactionSync(transaction) {
|
||||
return this._req(Connection.getApiUrls('transactionsSync'), {
|
||||
method: 'POST',
|
||||
jsonBody: transaction
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transaction
|
||||
*/
|
||||
postTransactionAsync(transaction) {
|
||||
return this._req(Connection.getApiUrls('transactionsAsync'), {
|
||||
method: 'POST',
|
||||
jsonBody: transaction
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transaction
|
||||
*/
|
||||
postTransactionCommit(transaction) {
|
||||
return this._req(Connection.getApiUrls('transactionsCommit'), {
|
||||
method: 'POST',
|
||||
jsonBody: transaction
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param search
|
||||
*/
|
||||
searchAssets(search, limit = 10) {
|
||||
return this._req(Connection.getApiUrls('assets'), {
|
||||
query: {
|
||||
search,
|
||||
limit
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param search
|
||||
*/
|
||||
searchMetadata(search, limit = 10) {
|
||||
return this._req(Connection.getApiUrls('metadata'), {
|
||||
query: {
|
||||
search,
|
||||
limit
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
import request from '../request'
|
||||
|
||||
|
||||
const HEADER_BLACKLIST = ['content-type']
|
||||
|
||||
|
||||
export default class Connection {
|
||||
constructor(path, headers = {}) {
|
||||
this.path = path
|
||||
this.headers = Object.assign({}, headers)
|
||||
|
||||
Object.keys(headers).forEach(header => {
|
||||
if (HEADER_BLACKLIST.includes(header.toLowerCase())) {
|
||||
throw new Error(`Header ${header} is reserved and cannot be set.`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getApiUrls(endpoint) {
|
||||
return this.path + {
|
||||
'blocks': 'blocks',
|
||||
'blocksDetail': 'blocks/%(blockId)s',
|
||||
'outputs': 'outputs',
|
||||
'statuses': 'statuses',
|
||||
'transactions': 'transactions',
|
||||
'transactionsDetail': 'transactions/%(transactionId)s',
|
||||
'assets': 'assets',
|
||||
'votes': 'votes'
|
||||
}[endpoint]
|
||||
}
|
||||
|
||||
_req(path, options = {}) {
|
||||
// NOTE: `options.headers` could be undefined, but that's OK.
|
||||
options.headers = Object.assign({}, options.headers, this.headers)
|
||||
return request(path, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param blockId
|
||||
*/
|
||||
getBlock(blockId) {
|
||||
return this._req(this.getApiUrls('blocksDetail'), {
|
||||
urlTemplateSpec: {
|
||||
blockId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param transactionId
|
||||
*/
|
||||
getStatus(transactionId) {
|
||||
return this._req(this.getApiUrls('statuses'), {
|
||||
query: {
|
||||
transaction_id: transactionId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param transactionId
|
||||
*/
|
||||
getTransaction(transactionId) {
|
||||
return this._req(this.getApiUrls('transactionsDetail'), {
|
||||
urlTemplateSpec: {
|
||||
transactionId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param transactionId
|
||||
* @param status
|
||||
*/
|
||||
listBlocks(transactionId, status) {
|
||||
return this._req(this.getApiUrls('blocks'), {
|
||||
query: {
|
||||
transaction_id: transactionId,
|
||||
status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param publicKey
|
||||
* @param spent
|
||||
* @param onlyJsonResponse
|
||||
*/
|
||||
listOutputs(publicKey, spent, onlyJsonResponse = true) {
|
||||
const query = {
|
||||
public_key: publicKey
|
||||
}
|
||||
// NOTE: If `spent` is not defined, it must not be included in the
|
||||
// query parameters.
|
||||
if (spent !== undefined) {
|
||||
query.spent = spent.toString()
|
||||
}
|
||||
return this._req(this.getApiUrls('outputs'), {
|
||||
query
|
||||
}, onlyJsonResponse)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param assetId
|
||||
* @param operation
|
||||
*/
|
||||
listTransactions(assetId, operation) {
|
||||
return this._req(this.getApiUrls('transactions'), {
|
||||
query: {
|
||||
asset_id: assetId,
|
||||
operation
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param blockId
|
||||
*/
|
||||
listVotes(blockId) {
|
||||
return this._req(this.getApiUrls('votes'), {
|
||||
query: {
|
||||
block_id: blockId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param txId
|
||||
* @return {Promise}
|
||||
*/
|
||||
pollStatusAndFetchTransaction(txId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timer = setInterval(() => {
|
||||
this.getStatus(txId)
|
||||
.then((res) => {
|
||||
if (res.status === 'valid') {
|
||||
clearInterval(timer)
|
||||
this.getTransaction(txId)
|
||||
.then((res_) => {
|
||||
resolve(res_)
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
clearInterval(timer)
|
||||
reject(err)
|
||||
})
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* @param transaction
|
||||
*/
|
||||
postTransaction(transaction) {
|
||||
return this._req(this.getApiUrls('transactions'), {
|
||||
method: 'POST',
|
||||
jsonBody: transaction
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
*
|
||||
* @param search
|
||||
*/
|
||||
searchAssets(search) {
|
||||
return this._req(this.getApiUrls('assets'), {
|
||||
query: {
|
||||
search
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
import { sprintf } from 'sprintf-js'
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import { sprintf } from 'sprintf-js'
|
||||
|
||||
// Regexes taken from or inspired by sprintf-js
|
||||
const Regex = {
|
||||
|
@ -11,7 +14,7 @@ const Regex = {
|
|||
|
||||
/**
|
||||
* imported from https://github.com/bigchaindb/js-utility-belt/
|
||||
*
|
||||
* @private
|
||||
* Formats strings similarly to C's sprintf, with the addition of '${...}' formats.
|
||||
*
|
||||
* Makes a first pass replacing '${...}' formats before passing the expanded string and other
|
||||
|
@ -47,6 +50,7 @@ export default function formatText(s, ...argv) {
|
|||
let interpolationLeft = replacement
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Interpolation algorithm inspired by sprintf-js.
|
||||
*
|
||||
* Goes through the replacement string getting the left-most key or index to interpolate
|
||||
|
@ -69,7 +73,7 @@ export default function formatText(s, ...argv) {
|
|||
// Assigning in the conditionals here makes the code less bloated
|
||||
/* eslint-disable no-cond-assign */
|
||||
while ((interpolationLeft = interpolationLeft.substring(curMatch[0].length)) &&
|
||||
value != null) {
|
||||
value != null) {
|
||||
if ((curMatch = Regex.KEY_ACCESS.exec(interpolationLeft))) {
|
||||
value = value[curMatch[1]]
|
||||
} else if ((curMatch = Regex.INDEX_ACCESS.exec(interpolationLeft))) {
|
||||
|
@ -84,9 +88,7 @@ export default function formatText(s, ...argv) {
|
|||
// If there's anything left to interpolate by the end then we've failed to interpolate
|
||||
// the entire replacement string.
|
||||
if (interpolationLeft.length) {
|
||||
throw new SyntaxError(
|
||||
`[formatText] failed to parse named argument key: ${replacement}`
|
||||
)
|
||||
throw new SyntaxError(`[formatText] failed to parse named argument key: ${replacement}`)
|
||||
}
|
||||
|
||||
return value
|
||||
|
|
14
src/index.js
14
src/index.js
|
@ -1,5 +1,13 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
export Ed25519Keypair from './Ed25519Keypair'
|
||||
import Ed25519Keypair from './Ed25519Keypair'
|
||||
import Connection from './connection'
|
||||
import Transaction from './transaction'
|
||||
import ccJsonLoad from './utils/ccJsonLoad'
|
||||
import ccJsonify from './utils/ccJsonify'
|
||||
|
||||
export * as Transaction from './transaction'
|
||||
export Connection from './connection'
|
||||
export {
|
||||
ccJsonLoad, ccJsonify, Connection, Ed25519Keypair, Transaction
|
||||
}
|
||||
|
|
120
src/request.js
120
src/request.js
|
@ -1,42 +1,118 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import baseRequest from './baseRequest'
|
||||
import sanitize from './sanitize'
|
||||
|
||||
|
||||
const DEFAULT_REQUEST_CONFIG = {
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
}
|
||||
|
||||
const BACKOFF_DELAY = 500 // 0.5 seconds
|
||||
const ERROR_FROM_SERVER = 'HTTP Error: Requested page not reachable'
|
||||
/**
|
||||
* @private
|
||||
* Small wrapper around js-utility-belt's request that provides url resolving,
|
||||
* default settings, and response handling.
|
||||
*/
|
||||
export default function request(url, config = {}, onlyJsonResponse = true) {
|
||||
// Load default fetch configuration and remove any falsy query parameters
|
||||
const requestConfig = Object.assign({}, DEFAULT_REQUEST_CONFIG, config, {
|
||||
query: config.query && sanitize(config.query)
|
||||
})
|
||||
const apiUrl = url
|
||||
|
||||
if (requestConfig.jsonBody) {
|
||||
requestConfig.headers = Object.assign({}, requestConfig.headers, {
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
export default class Request {
|
||||
constructor(node) {
|
||||
this.node = node
|
||||
this.backoffTime = null
|
||||
this.retries = 0
|
||||
this.connectionError = null
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return Promise.reject(new Error('Request was not given a url.'))
|
||||
async request(urlPath, config, timeout, maxBackoffTime) {
|
||||
if (!urlPath) {
|
||||
return Promise.reject(new Error('Request was not given a url.'))
|
||||
}
|
||||
// Load default fetch configuration and remove any falsy query parameters
|
||||
const requestConfig = {
|
||||
...this.node.headers,
|
||||
...DEFAULT_REQUEST_CONFIG,
|
||||
...config,
|
||||
query: config.query && sanitize(config.query)
|
||||
}
|
||||
const apiUrl = this.node.endpoint + urlPath
|
||||
if (requestConfig.jsonBody) {
|
||||
requestConfig.headers = { ...requestConfig.headers, 'Content-Type': 'application/json' }
|
||||
}
|
||||
|
||||
// If connectionError occurs, a timestamp equal to now +
|
||||
// `backoffTimedelta` is assigned to the object.
|
||||
// Next time the function is called, it either
|
||||
// waits till the timestamp is passed or raises `TimeoutError`.
|
||||
// If `ConnectionError` occurs two or more times in a row,
|
||||
// the retry count is incremented and the new timestamp is calculated
|
||||
// as now + the `backoffTimedelta`
|
||||
// The `backoffTimedelta` is the minimum between the default delay
|
||||
// multiplied by two to the power of the
|
||||
// number of retries or timeout/2 or 10. See Transport class for that
|
||||
// If a request is successful, the backoff timestamp is removed,
|
||||
// the retry count is back to zero.
|
||||
|
||||
const backoffTimedelta = this.getBackoffTimedelta()
|
||||
|
||||
if (timeout != null && timeout < backoffTimedelta) {
|
||||
const errorObject = {
|
||||
message: 'TimeoutError'
|
||||
}
|
||||
throw errorObject
|
||||
}
|
||||
if (backoffTimedelta > 0) {
|
||||
await Request.sleep(backoffTimedelta)
|
||||
}
|
||||
|
||||
const requestTimeout = timeout ? timeout - backoffTimedelta : timeout
|
||||
return baseRequest(apiUrl, requestConfig, requestTimeout)
|
||||
.then((res) => {
|
||||
this.connectionError = null
|
||||
return res.json()
|
||||
})
|
||||
.catch(err => {
|
||||
// ConnectionError
|
||||
this.connectionError = err
|
||||
})
|
||||
.finally(() => {
|
||||
this.updateBackoffTime(maxBackoffTime)
|
||||
})
|
||||
}
|
||||
|
||||
return baseRequest(apiUrl, requestConfig)
|
||||
.then((res) => onlyJsonResponse ? res.json() : // eslint-disable-line no-confusing-arrow
|
||||
{
|
||||
json: res.json(),
|
||||
url: res.url
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
throw err
|
||||
updateBackoffTime(maxBackoffTime) {
|
||||
if (!this.connectionError) {
|
||||
this.retries = 0
|
||||
this.backoffTime = null
|
||||
} else if (this.connectionError.message === ERROR_FROM_SERVER) {
|
||||
// If status is not a 2xx (based on Response.ok), throw error
|
||||
this.retries = 0
|
||||
this.backoffTime = null
|
||||
throw this.connectionError
|
||||
} else {
|
||||
// Timeout or no connection could be stablished
|
||||
const backoffTimedelta = Math.min(BACKOFF_DELAY * (2 ** this.retries), maxBackoffTime)
|
||||
this.backoffTime = Date.now() + backoffTimedelta
|
||||
this.retries += 1
|
||||
if (this.connectionError.message === 'TimeoutError') {
|
||||
throw this.connectionError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getBackoffTimedelta() {
|
||||
if (!this.backoffTime) {
|
||||
return 0
|
||||
}
|
||||
return (this.backoffTime - Date.now())
|
||||
}
|
||||
|
||||
static sleep(ms) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,41 @@
|
|||
import coreIncludes from 'core-js/library/fn/array/includes'
|
||||
import coreObjectEntries from 'core-js/library/fn/object/entries'
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import 'core-js/features/array/includes'
|
||||
import 'core-js/features/object/entries'
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Abstraction for selectFromObject and omitFromObject for DRYness.
|
||||
* Set isInclusion to true if the filter should be for including the filtered items (ie. selecting
|
||||
* only them vs omitting only them).
|
||||
*/
|
||||
function filterFromObject(obj, filter, { isInclusion = true } = {}) {
|
||||
if (filter && Array.isArray(filter)) {
|
||||
return applyFilterOnObject(obj, isInclusion ? ((_, key) => coreIncludes(filter, key))
|
||||
: ((_, key) => !coreIncludes(filter, key)))
|
||||
return applyFilterOnObject(obj, isInclusion ? (val => filter.includes(val))
|
||||
: (val => !filter.includes(val)))
|
||||
} else if (filter && typeof filter === 'function') {
|
||||
// Flip the filter fn's return if it's for inclusion
|
||||
return applyFilterOnObject(obj, isInclusion ? filter
|
||||
: (...args) => !filter(...args))
|
||||
: (...args) => !filter(...args))
|
||||
} else {
|
||||
throw new Error('The given filter is not an array or function. Exclude aborted')
|
||||
throw new Error('The given filter is not an array or function. Filter aborted')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Returns a filtered copy of the given object's own enumerable properties (no inherited
|
||||
* properties), keeping any keys that pass the given filter function.
|
||||
*/
|
||||
function applyFilterOnObject(obj, filterFn) {
|
||||
if (filterFn == null) {
|
||||
return Object.assign({}, obj)
|
||||
return { ...obj }
|
||||
}
|
||||
|
||||
const filteredObj = {}
|
||||
coreObjectEntries(obj).forEach(([key, val]) => {
|
||||
Object.entries(obj).forEach(([key, val]) => {
|
||||
if (filterFn(val, key)) {
|
||||
filteredObj[key] = val
|
||||
}
|
||||
|
@ -40,24 +45,26 @@ function applyFilterOnObject(obj, filterFn) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Similar to lodash's _.pick(), this returns a copy of the given object's
|
||||
* own and inherited enumerable properties, selecting only the keys in
|
||||
* the given array or whose value pass the given filter function.
|
||||
* @param {object} obj Source object
|
||||
* @param {array|function} filter Array of key names to select or function to invoke per iteration
|
||||
* @return {object} The new object
|
||||
* @param {Object} obj Source object
|
||||
* @param {Array|function} filter Array of key names to select or function to invoke per iteration
|
||||
* @return {Object} The new object
|
||||
*/
|
||||
function selectFromObject(obj, filter) {
|
||||
return filterFromObject(obj, filter)
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Glorified selectFromObject. Takes an object and returns a filtered shallow copy that strips out
|
||||
* any properties that are falsy (including coercions, ie. undefined, null, '', 0, ...).
|
||||
* Does not modify the passed in object.
|
||||
*
|
||||
* @param {object} obj Javascript object
|
||||
* @return {object} Sanitized Javascript object
|
||||
* @param {Object} obj Javascript object
|
||||
* @return {Object} Sanitized Javascript object
|
||||
*/
|
||||
export default function sanitize(obj) {
|
||||
return selectFromObject(obj, (val) => !!val)
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import sha3 from 'js-sha3'
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
import { sha3_256 } from 'js-sha3'
|
||||
|
||||
export default function sha256Hash(data) {
|
||||
return sha3.sha3_256
|
||||
return sha3_256
|
||||
.create()
|
||||
.update(data)
|
||||
.hex()
|
||||
}
|
||||
/* eslint-enable camelcase */
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import coreObjectEntries from 'core-js/library/fn/object/entries'
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import 'core-js/features/object/entries'
|
||||
import decamelize from 'decamelize'
|
||||
import queryString from 'query-string'
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* imported from https://github.com/bigchaindb/js-utility-belt/
|
||||
*
|
||||
* Takes a key-value dictionary (ie. object) and converts it to a query-parameter string that you
|
||||
|
@ -24,7 +28,7 @@ import queryString from 'query-string'
|
|||
*
|
||||
* ?page=1&page_size=10
|
||||
*
|
||||
* @param {object} obj Query params dictionary
|
||||
* @param {Object} obj Query params dictionary
|
||||
* @param {function} [transform=decamelize] Transform function for each of the param keys
|
||||
* @return {string} Query param string
|
||||
*/
|
||||
|
@ -33,7 +37,7 @@ export default function stringifyAsQueryParam(obj, transform = decamelize) {
|
|||
return ''
|
||||
}
|
||||
|
||||
const transformedKeysObj = coreObjectEntries(obj).reduce((paramsObj, [key, value]) => {
|
||||
const transformedKeysObj = Object.entries(obj).reduce((paramsObj, [key, value]) => {
|
||||
paramsObj[transform(key)] = value
|
||||
return paramsObj
|
||||
}, {})
|
||||
|
|
287
src/transaction.js
Normal file
287
src/transaction.js
Normal file
|
@ -0,0 +1,287 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import stableStringify from 'json-stable-stringify'
|
||||
import clone from 'clone'
|
||||
import base58 from 'bs58'
|
||||
import { Ed25519Sha256, PreimageSha256, ThresholdSha256 } from 'crypto-conditions'
|
||||
import ccJsonify from './utils/ccJsonify'
|
||||
import sha256Hash from './sha256Hash'
|
||||
|
||||
/**
|
||||
* Construct Transactions
|
||||
*/
|
||||
export default class Transaction {
|
||||
/**
|
||||
* Canonically serializes a transaction into a string by sorting the keys
|
||||
* @param {Object} (transaction)
|
||||
* @return {string} a canonically serialized Transaction
|
||||
*/
|
||||
static serializeTransactionIntoCanonicalString(transaction) {
|
||||
// BigchainDB signs fulfillments by serializing transactions into a
|
||||
// "canonical" format where
|
||||
const tx = clone(transaction)
|
||||
// TODO: set fulfillments to null
|
||||
// Sort the keys
|
||||
return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1))
|
||||
}
|
||||
|
||||
static makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) {
|
||||
return {
|
||||
fulfillment,
|
||||
fulfills,
|
||||
'owners_before': publicKeys,
|
||||
}
|
||||
}
|
||||
|
||||
static makeTransactionTemplate() {
|
||||
const txTemplate = {
|
||||
id: null,
|
||||
operation: null,
|
||||
outputs: [],
|
||||
inputs: [],
|
||||
metadata: null,
|
||||
asset: null,
|
||||
version: '2.0',
|
||||
}
|
||||
return txTemplate
|
||||
}
|
||||
|
||||
static makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) {
|
||||
const tx = Transaction.makeTransactionTemplate()
|
||||
tx.operation = operation
|
||||
tx.asset = asset
|
||||
tx.metadata = metadata
|
||||
tx.inputs = inputs
|
||||
tx.outputs = outputs
|
||||
return tx
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by
|
||||
* the `issuers`.
|
||||
* @param {Object} asset Created asset's data
|
||||
* @param {Object} metadata Metadata for the Transaction
|
||||
* @param {Object[]} outputs Array of Output objects to add to the Transaction.
|
||||
* Think of these as the recipients of the asset after the transaction.
|
||||
* For `CREATE` Transactions, this should usually just be a list of
|
||||
* Outputs wrapping Ed25519 Conditions generated from the issuers' public
|
||||
* keys (so that the issuers are the recipients of the created asset).
|
||||
* @param {...string[]} issuers Public key of one or more issuers to the asset being created by this
|
||||
* Transaction.
|
||||
* Note: Each of the private keys corresponding to the given public
|
||||
* keys MUST be used later (and in the same order) when signing the
|
||||
* Transaction (`signTransaction()`).
|
||||
* @returns {Object} Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
* sending it off!
|
||||
*/
|
||||
static makeCreateTransaction(asset, metadata, outputs, ...issuers) {
|
||||
const assetDefinition = {
|
||||
data: asset || null,
|
||||
}
|
||||
const inputs = issuers.map((issuer) => Transaction.makeInputTemplate([issuer]))
|
||||
|
||||
return Transaction.makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Ed25519 Cryptocondition from an Ed25519 public key
|
||||
* to put into an Output of a Transaction
|
||||
* @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction
|
||||
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
|
||||
* @returns {Object} Ed25519 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
static makeEd25519Condition(publicKey, json = true) {
|
||||
const publicKeyBuffer = base58.decode(publicKey)
|
||||
const ed25519Fulfillment = new Ed25519Sha256()
|
||||
ed25519Fulfillment.setPublicKey(publicKeyBuffer)
|
||||
return json ? ccJsonify(ed25519Fulfillment) : ed25519Fulfillment
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Output from a Condition.
|
||||
* Note: Assumes the given Condition was generated from a
|
||||
* single public key (e.g. a Ed25519 Condition)
|
||||
* @param {Object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`)
|
||||
* @param {string} amount Amount of the output
|
||||
* @returns {Object} An Output usable in a Transaction
|
||||
*/
|
||||
static makeOutput(condition, amount = '1') {
|
||||
if (typeof amount !== 'string') {
|
||||
throw new TypeError('`amount` must be of type string')
|
||||
}
|
||||
const publicKeys = []
|
||||
const getPublicKeys = details => {
|
||||
if (details.type === 'ed25519-sha-256') {
|
||||
if (!publicKeys.includes(details.public_key)) {
|
||||
publicKeys.push(details.public_key)
|
||||
}
|
||||
} else if (details.type === 'threshold-sha-256') {
|
||||
details.subconditions.map(getPublicKeys)
|
||||
}
|
||||
}
|
||||
getPublicKeys(condition.details)
|
||||
return {
|
||||
condition,
|
||||
amount,
|
||||
public_keys: publicKeys,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction
|
||||
* @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition
|
||||
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
|
||||
* @returns {Object} Preimage-Sha256 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
static makeSha256Condition(preimage, json = true) {
|
||||
const sha256Fulfillment = new PreimageSha256()
|
||||
sha256Fulfillment.setPreimage(Buffer.from(preimage))
|
||||
return json ? ccJsonify(sha256Fulfillment) : sha256Fulfillment
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction
|
||||
* @param {number} threshold
|
||||
* @param {Array} [subconditions=[]]
|
||||
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
|
||||
* @returns {Object} Sha256 Threshold Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
static makeThresholdCondition(threshold, subconditions = [], json = true) {
|
||||
const thresholdCondition = new ThresholdSha256()
|
||||
thresholdCondition.setThreshold(threshold)
|
||||
subconditions.forEach((subcondition) => {
|
||||
// TODO: add support for Condition
|
||||
thresholdCondition.addSubfulfillment(subcondition)
|
||||
// ? Should be thresholdCondition.addSubcondition(subcondition)
|
||||
})
|
||||
|
||||
return json ? ccJsonify(thresholdCondition) : thresholdCondition
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills
|
||||
* the `fulfilledOutputs` of `unspentTransaction`.
|
||||
* @param {Object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill
|
||||
* its Output Condition)
|
||||
* @param {Object} metadata Metadata for the Transaction
|
||||
* @param {Object[]} outputs Array of Output objects to add to the Transaction.
|
||||
* Think of these as the recipients of the asset after the transaction.
|
||||
* For `TRANSFER` Transactions, this should usually just be a list of
|
||||
* Outputs wrapping Ed25519 Conditions generated from the public keys of
|
||||
* the recipients.
|
||||
* @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this
|
||||
* Transaction fulfills.
|
||||
* Note that listed public keys listed must be used (and in
|
||||
* the same order) to sign the Transaction
|
||||
* (`signTransaction()`).
|
||||
* @returns {Object} Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
* sending it off!
|
||||
*/
|
||||
// TODO:
|
||||
// - Make `metadata` optional argument
|
||||
static makeTransferTransaction(
|
||||
unspentOutputs,
|
||||
outputs,
|
||||
metadata
|
||||
) {
|
||||
const inputs = unspentOutputs.map((unspentOutput) => {
|
||||
const { tx, outputIndex } = { tx: unspentOutput.tx, outputIndex: unspentOutput.output_index }
|
||||
const fulfilledOutput = tx.outputs[outputIndex]
|
||||
const transactionLink = {
|
||||
output_index: outputIndex,
|
||||
transaction_id: tx.id,
|
||||
}
|
||||
|
||||
return Transaction.makeInputTemplate(fulfilledOutput.public_keys, transactionLink)
|
||||
})
|
||||
|
||||
const assetLink = {
|
||||
id: unspentOutputs[0].tx.operation === 'CREATE' ? unspentOutputs[0].tx.id
|
||||
: unspentOutputs[0].tx.asset.id
|
||||
}
|
||||
return Transaction.makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction`
|
||||
* that's been signed.
|
||||
* Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as
|
||||
* an exercise for the user.
|
||||
* @param {Object} transaction Transaction to sign. `transaction` is not modified.
|
||||
* @param {...string} privateKeys Private keys associated with the issuers of the `transaction`.
|
||||
* Looped through to iteratively sign any Input Fulfillments found in
|
||||
* the `transaction`.
|
||||
* @returns {Object} The signed version of `transaction`.
|
||||
*/
|
||||
static signTransaction(transaction, ...privateKeys) {
|
||||
const signedTx = clone(transaction)
|
||||
const serializedTransaction =
|
||||
Transaction.serializeTransactionIntoCanonicalString(transaction)
|
||||
|
||||
signedTx.inputs.forEach((input, index) => {
|
||||
const privateKey = privateKeys[index]
|
||||
const privateKeyBuffer = base58.decode(privateKey)
|
||||
|
||||
const transactionUniqueFulfillment = input.fulfills ? serializedTransaction
|
||||
.concat(input.fulfills.transaction_id)
|
||||
.concat(input.fulfills.output_index) : serializedTransaction
|
||||
const transactionHash = sha256Hash(transactionUniqueFulfillment)
|
||||
const ed25519Fulfillment = new Ed25519Sha256()
|
||||
ed25519Fulfillment.sign(Buffer.from(transactionHash, 'hex'), privateKeyBuffer)
|
||||
const fulfillmentUri = ed25519Fulfillment.serializeUri()
|
||||
|
||||
input.fulfillment = fulfillmentUri
|
||||
})
|
||||
|
||||
const serializedSignedTransaction =
|
||||
Transaction.serializeTransactionIntoCanonicalString(signedTx)
|
||||
signedTx.id = sha256Hash(serializedSignedTransaction)
|
||||
return signedTx
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate signing of the given `transaction` returning a new copy of `transaction`
|
||||
* that's been signed.
|
||||
* @param {Object} transaction Transaction to sign. `transaction` is not modified.
|
||||
* @param {Function} signFn Function signing the transaction, expected to return the fulfillment.
|
||||
* @returns {Object} The signed version of `transaction`.
|
||||
*/
|
||||
static delegateSignTransaction(transaction, signFn) {
|
||||
const signedTx = clone(transaction)
|
||||
const serializedTransaction =
|
||||
Transaction.serializeTransactionIntoCanonicalString(transaction)
|
||||
|
||||
signedTx.inputs.forEach((input, index) => {
|
||||
const fulfillmentUri = signFn(serializedTransaction, input, index)
|
||||
input.fulfillment = fulfillmentUri
|
||||
})
|
||||
|
||||
const serializedSignedTransaction = Transaction.serializeTransactionIntoCanonicalString(signedTx)
|
||||
signedTx.id = sha256Hash(serializedSignedTransaction)
|
||||
return signedTx
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate signing of the given `transaction` returning a new copy of `transaction`
|
||||
* that's been signed.
|
||||
* @param {Object} transaction Transaction to sign. `transaction` is not modified.
|
||||
* @param {Function} signFn Function signing the transaction, expected to resolve the fulfillment.
|
||||
* @returns {Promise<Object>} The signed version of `transaction`.
|
||||
*/
|
||||
static async delegateSignTransactionAsync(transaction, signFn) {
|
||||
const signedTx = clone(transaction)
|
||||
const serializedTransaction =
|
||||
Transaction.serializeTransactionIntoCanonicalString(transaction)
|
||||
|
||||
await Promise.all(signedTx.inputs.map(async (input, index) => {
|
||||
const fulfillmentUri = await signFn(serializedTransaction, input, index)
|
||||
input.fulfillment = fulfillmentUri
|
||||
}))
|
||||
|
||||
const serializedSignedTransaction = Transaction.serializeTransactionIntoCanonicalString(signedTx)
|
||||
signedTx.id = sha256Hash(serializedSignedTransaction)
|
||||
return signedTx
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'
|
||||
import sha256Hash from '../sha256Hash'
|
||||
|
||||
export default function hashTransaction(transaction) {
|
||||
// Safely remove any tx id from the given transaction for hashing
|
||||
const tx = { ...transaction }
|
||||
delete tx.id
|
||||
|
||||
return sha256Hash(serializeTransactionIntoCanonicalString(tx))
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
export makeEd25519Condition from './makeEd25519Condition'
|
||||
export makeSha256Condition from './makeSha256Condition'
|
||||
export makeThresholdCondition from './makeThresholdCondition'
|
||||
export makeCreateTransaction from './makeCreateTransaction'
|
||||
export makeOutput from './makeOutput'
|
||||
export makeTransaction from './makeTransaction'
|
||||
export makeTransferTransaction from './makeTransferTransaction'
|
||||
export serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'
|
||||
export signTransaction from './signTransaction'
|
||||
export ccJsonLoad from './utils/ccJsonLoad'
|
||||
export ccJsonify from './utils/ccJsonify'
|
|
@ -1,31 +0,0 @@
|
|||
import makeInputTemplate from './makeInputTemplate'
|
||||
import makeTransaction from './makeTransaction'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by
|
||||
* the `issuers`.
|
||||
* @param {object} asset Created asset's data
|
||||
* @param {object} metadata Metadata for the Transaction
|
||||
* @param {object[]} outputs Array of Output objects to add to the Transaction.
|
||||
* Think of these as the recipients of the asset after the transaction.
|
||||
* For `CREATE` Transactions, this should usually just be a list of
|
||||
* Outputs wrapping Ed25519 Conditions generated from the issuers' public
|
||||
* keys (so that the issuers are the recipients of the created asset).
|
||||
* @param {...string[]} issuers Public key of one or more issuers to the asset being created by this
|
||||
* Transaction.
|
||||
* Note: Each of the private keys corresponding to the given public
|
||||
* keys MUST be used later (and in the same order) when signing the
|
||||
* Transaction (`signTransaction()`).
|
||||
* @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
* sending it off!
|
||||
*/
|
||||
export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) {
|
||||
const assetDefinition = {
|
||||
'data': asset || null,
|
||||
}
|
||||
const inputs = issuers.map((issuer) => makeInputTemplate([issuer]))
|
||||
|
||||
return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs)
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import { Buffer } from 'buffer'
|
||||
|
||||
import base58 from 'bs58'
|
||||
import cc from 'five-bells-condition'
|
||||
|
||||
import ccJsonify from './utils/ccJsonify'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Create an Ed25519 Cryptocondition from an Ed25519 public key to put into an Output of a Transaction
|
||||
* @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction
|
||||
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
|
||||
* @returns {object} Ed25519 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
export default function makeEd25519Condition(publicKey, json = true) {
|
||||
const publicKeyBuffer = new Buffer(base58.decode(publicKey))
|
||||
|
||||
const ed25519Fulfillment = new cc.Ed25519Sha256()
|
||||
ed25519Fulfillment.setPublicKey(publicKeyBuffer)
|
||||
|
||||
if (json) {
|
||||
return ccJsonify(ed25519Fulfillment)
|
||||
}
|
||||
|
||||
return ed25519Fulfillment
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
export default function makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) {
|
||||
return {
|
||||
fulfillment,
|
||||
fulfills,
|
||||
'owners_before': publicKeys,
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* @public
|
||||
* Create an Output from a Condition.
|
||||
* Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition)
|
||||
* @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`)
|
||||
* @param {string} amount Amount of the output
|
||||
* @returns {object} An Output usable in a Transaction
|
||||
*/
|
||||
export default function makeOutput(condition, amount = '1') {
|
||||
if (typeof amount !== 'string') {
|
||||
throw new TypeError('`amount` must be of type string')
|
||||
}
|
||||
const publicKeys = []
|
||||
const getPublicKeys = details => {
|
||||
if (details.type === 'ed25519-sha-256') {
|
||||
if (!publicKeys.includes(details.public_key)) {
|
||||
publicKeys.push(details.public_key)
|
||||
}
|
||||
} else if (details.type === 'threshold-sha-256') {
|
||||
details.subfulfillments.map(getPublicKeys)
|
||||
}
|
||||
}
|
||||
getPublicKeys(condition.details)
|
||||
return {
|
||||
condition,
|
||||
'amount': amount,
|
||||
'public_keys': publicKeys,
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import { Buffer } from 'buffer'
|
||||
|
||||
import cc from 'five-bells-condition'
|
||||
|
||||
import ccJsonify from './utils/ccJsonify'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction
|
||||
* @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition
|
||||
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
|
||||
* @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
export default function makeSha256Condition(preimage, json = true) {
|
||||
const sha256Fulfillment = new cc.PreimageSha256()
|
||||
sha256Fulfillment.preimage = new Buffer(preimage)
|
||||
|
||||
if (json) {
|
||||
return ccJsonify(sha256Fulfillment)
|
||||
}
|
||||
return sha256Fulfillment
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
import cc from 'five-bells-condition'
|
||||
|
||||
import ccJsonify from './utils/ccJsonify'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction
|
||||
* @param {number} threshold
|
||||
* @param {Array} [subconditions=[]]
|
||||
* @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type
|
||||
* @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
export default function makeThresholdCondition(threshold, subconditions = [], json = true) {
|
||||
const thresholdCondition = new cc.ThresholdSha256()
|
||||
thresholdCondition.threshold = threshold
|
||||
|
||||
subconditions.forEach((subcondition) => {
|
||||
// TODO: add support for Condition and URIs
|
||||
thresholdCondition.addSubfulfillment(subcondition)
|
||||
})
|
||||
|
||||
if (json) {
|
||||
return ccJsonify(thresholdCondition)
|
||||
}
|
||||
|
||||
return thresholdCondition
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
import hashTransaction from './hashTransaction'
|
||||
|
||||
|
||||
function makeTransactionTemplate() {
|
||||
return {
|
||||
'id': null,
|
||||
'operation': null,
|
||||
'outputs': [],
|
||||
'inputs': [],
|
||||
'metadata': null,
|
||||
'asset': null,
|
||||
'version': '1.0',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default function makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) {
|
||||
const tx = makeTransactionTemplate()
|
||||
tx.operation = operation
|
||||
tx.asset = asset
|
||||
tx.metadata = metadata
|
||||
tx.inputs = inputs
|
||||
tx.outputs = outputs
|
||||
|
||||
// Hashing must be done after, as the hash is of the Transaction (up to now)
|
||||
tx.id = hashTransaction(tx)
|
||||
return tx
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import makeInputTemplate from './makeInputTemplate'
|
||||
import makeTransaction from './makeTransaction'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills
|
||||
* the `fulfilledOutputs` of `unspentTransaction`.
|
||||
* @param {object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill
|
||||
* its Output Condition)
|
||||
* @param {object} metadata Metadata for the Transaction
|
||||
* @param {object[]} outputs Array of Output objects to add to the Transaction.
|
||||
* Think of these as the recipients of the asset after the transaction.
|
||||
* For `TRANSFER` Transactions, this should usually just be a list of
|
||||
* Outputs wrapping Ed25519 Conditions generated from the public keys of
|
||||
* the recipients.
|
||||
* @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this
|
||||
* Transaction fulfills.
|
||||
* Note that listed public keys listed must be used (and in
|
||||
* the same order) to sign the Transaction
|
||||
* (`signTransaction()`).
|
||||
* @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before
|
||||
* sending it off!
|
||||
*/
|
||||
// TODO:
|
||||
// - Make `metadata` optional argument
|
||||
export default function makeTransferTransaction(
|
||||
unspentTransaction,
|
||||
metadata,
|
||||
outputs,
|
||||
...outputIndices
|
||||
) {
|
||||
const inputs = outputIndices.map((outputIndex) => {
|
||||
const fulfilledOutput = unspentTransaction.outputs[outputIndex]
|
||||
const transactionLink = {
|
||||
'output': outputIndex,
|
||||
'transaction_id': unspentTransaction.id,
|
||||
}
|
||||
|
||||
return makeInputTemplate(fulfilledOutput.public_keys, transactionLink)
|
||||
})
|
||||
|
||||
const assetLink = {
|
||||
'id': unspentTransaction.operation === 'CREATE' ? unspentTransaction.id
|
||||
: unspentTransaction.asset.id
|
||||
}
|
||||
|
||||
return makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs)
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import stableStringify from 'json-stable-stringify'
|
||||
import clone from 'clone'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Canonically serializes a transaction into a string by sorting the keys
|
||||
* @param {object} (transaction)
|
||||
* @return {string} a canonically serialized Transaction
|
||||
*/
|
||||
export default function serializeTransactionIntoCanonicalString(transaction) {
|
||||
// BigchainDB signs fulfillments by serializing transactions into a
|
||||
// "canonical" format where
|
||||
const tx = clone(transaction)
|
||||
// TODO: set fulfillments to null
|
||||
// Sort the keys
|
||||
return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1))
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import { Buffer } from 'buffer'
|
||||
import base58 from 'bs58'
|
||||
import cc from 'five-bells-condition'
|
||||
import clone from 'clone'
|
||||
|
||||
import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString'
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction`
|
||||
* that's been signed.
|
||||
* Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as
|
||||
* an exercise for the user.
|
||||
* @param {object} transaction Transaction to sign. `transaction` is not modified.
|
||||
* @param {...string} privateKeys Private keys associated with the issuers of the `transaction`.
|
||||
* Looped through to iteratively sign any Input Fulfillments found in
|
||||
* the `transaction`.
|
||||
* @returns {object} The signed version of `transaction`.
|
||||
*/
|
||||
export default function signTransaction(transaction, ...privateKeys) {
|
||||
const signedTx = clone(transaction)
|
||||
signedTx.inputs.forEach((input, index) => {
|
||||
const privateKey = privateKeys[index]
|
||||
const privateKeyBuffer = new Buffer(base58.decode(privateKey))
|
||||
const serializedTransaction = serializeTransactionIntoCanonicalString(transaction)
|
||||
const ed25519Fulfillment = new cc.Ed25519Sha256()
|
||||
ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer)
|
||||
const fulfillmentUri = ed25519Fulfillment.serializeUri()
|
||||
|
||||
input.fulfillment = fulfillmentUri
|
||||
})
|
||||
|
||||
return signedTx
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
import { Buffer } from 'buffer'
|
||||
import base58 from 'bs58'
|
||||
import cc from 'five-bells-condition'
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Loads a crypto-condition class (Fulfillment or Condition) from a BigchainDB JSON object
|
||||
* @param {object} conditionJson
|
||||
* @returns {cc.Condition} Ed25519 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
export default function ccJsonLoad(conditionJson) {
|
||||
if ('hash' in conditionJson) {
|
||||
const condition = new cc.Condition()
|
||||
condition.type = conditionJson.type_id
|
||||
condition.bitmask = conditionJson.bitmask
|
||||
condition.hash = new Buffer(base58.decode(conditionJson.hash))
|
||||
condition.maxFulfillmentLength = parseInt(conditionJson.max_fulfillment_length, 10)
|
||||
return condition
|
||||
} else {
|
||||
let fulfillment
|
||||
|
||||
if (conditionJson.type === 'threshold-sha-256') {
|
||||
fulfillment = new cc.ThresholdSha256()
|
||||
fulfillment.threshold = conditionJson.threshold
|
||||
conditionJson.subfulfillments.forEach((subfulfillmentJson) => {
|
||||
const subfulfillment = ccJsonLoad(subfulfillmentJson)
|
||||
if ('getConditionUri' in subfulfillment) {
|
||||
fulfillment.addSubfulfillment(subfulfillment)
|
||||
} else if ('serializeUri' in subfulfillment) {
|
||||
fulfillment.addSubcondition(subfulfillment)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (conditionJson.type === 'ed25519-sha-256') {
|
||||
fulfillment = new cc.Ed25519Sha256()
|
||||
fulfillment.publicKey = new Buffer(base58.decode(conditionJson.public_key))
|
||||
if (conditionJson.signature) {
|
||||
fulfillment.signature = new Buffer(base58.decode(conditionJson.signature))
|
||||
}
|
||||
}
|
||||
return fulfillment
|
||||
}
|
||||
}
|
64
src/transport.js
Normal file
64
src/transport.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import Request from './request'
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
* If initialized with ``>1`` nodes, the driver will send successive
|
||||
* requests to different nodes in a round-robin fashion (this will be
|
||||
* customizable in the future).
|
||||
*/
|
||||
|
||||
export default class Transport {
|
||||
constructor(nodes, timeout) {
|
||||
this.connectionPool = []
|
||||
this.timeout = timeout
|
||||
// the maximum backoff time is 10 seconds
|
||||
this.maxBackoffTime = timeout ? timeout / 2 : 10000
|
||||
nodes.forEach(node => {
|
||||
this.connectionPool.push(new Request(node))
|
||||
})
|
||||
}
|
||||
|
||||
// Select the connection with the earliest backoff time, in case of a tie,
|
||||
// prefer the one with the smaller list index
|
||||
pickConnection() {
|
||||
let connection = this.connectionPool[0]
|
||||
|
||||
this.connectionPool.forEach(conn => {
|
||||
// 0 the lowest value is the time for Thu Jan 01 1970 01:00:00 GMT+0100 (CET)
|
||||
conn.backoffTime = conn.backoffTime ? conn.backoffTime : 0
|
||||
connection = (conn.backoffTime < connection.backoffTime) ? conn : connection
|
||||
})
|
||||
return connection
|
||||
}
|
||||
|
||||
async forwardRequest(path, headers) {
|
||||
let response
|
||||
let connection
|
||||
// A new request will be executed until there is a valid response or timeout < 0
|
||||
while (this.timeout >= 0) {
|
||||
connection = this.pickConnection()
|
||||
// Date in milliseconds
|
||||
const startTime = Date.now()
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
response = await connection.request(
|
||||
path,
|
||||
headers,
|
||||
this.timeout,
|
||||
this.maxBackoffTime
|
||||
)
|
||||
const elapsed = Date.now() - startTime
|
||||
if (connection.backoffTime > 0 && this.timeout > 0) {
|
||||
this.timeout -= elapsed
|
||||
} else {
|
||||
// No connection error, the response is valid
|
||||
return response
|
||||
}
|
||||
}
|
||||
throw new Error('TimeoutError')
|
||||
}
|
||||
}
|
44
src/utils/ccJsonLoad.js
Normal file
44
src/utils/ccJsonLoad.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import base58 from 'bs58'
|
||||
import { Condition, Ed25519Sha256, ThresholdSha256 } from 'crypto-conditions'
|
||||
|
||||
/**
|
||||
* Loads a crypto-condition class (Fulfillment or Condition) from a BigchainDB JSON object
|
||||
* @param {Object} conditionJson
|
||||
* @returns {cc.Condition} Ed25519 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
export default function ccJsonLoad(conditionJson) {
|
||||
if ('hash' in conditionJson) {
|
||||
const condition = new Condition()
|
||||
condition.setTypeId(conditionJson.type_id)
|
||||
condition.setSubtypes(conditionJson.bitmask)
|
||||
condition.setHash(base58.decode(conditionJson.hash))
|
||||
// TODO: fix this, maxFulfillmentLength cannot be set in CryptoCondition lib
|
||||
condition.maxFulfillmentLength = parseInt(conditionJson.max_fulfillment_length, 10)
|
||||
return condition
|
||||
} else {
|
||||
let fulfillment
|
||||
|
||||
if (conditionJson.type === 'threshold-sha-256') {
|
||||
fulfillment = new ThresholdSha256()
|
||||
fulfillment.threshold = conditionJson.threshold
|
||||
conditionJson.subconditions.forEach((subconditionJson) => {
|
||||
const subcondition = ccJsonLoad(subconditionJson)
|
||||
if ('getConditionUri' in subcondition) {
|
||||
fulfillment.addSubfulfillment(subcondition)
|
||||
} else if ('serializeUri' in subcondition) {
|
||||
fulfillment.addSubcondition(subcondition)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (conditionJson.type === 'ed25519-sha-256') {
|
||||
fulfillment = new Ed25519Sha256()
|
||||
fulfillment.setPublicKey(base58.decode(conditionJson.public_key))
|
||||
}
|
||||
return fulfillment
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import base58 from 'bs58'
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Serializes a crypto-condition class (Condition or Fulfillment) into a BigchainDB-compatible JSON
|
||||
* @param {cc.Fulfillment} fulfillment base58 encoded Ed25519 public key for recipient of the Transaction
|
||||
* @returns {object} Ed25519 Condition (that will need to wrapped in an Output)
|
||||
* @returns {Object} Ed25519 Condition (that will need to wrapped in an Output)
|
||||
*/
|
||||
export default function ccJsonify(fulfillment) {
|
||||
let conditionUri
|
||||
|
@ -16,8 +19,8 @@ export default function ccJsonify(fulfillment) {
|
|||
}
|
||||
|
||||
const jsonBody = {
|
||||
'details': {},
|
||||
'uri': conditionUri,
|
||||
details: {},
|
||||
uri: conditionUri,
|
||||
}
|
||||
|
||||
if (fulfillment.getTypeId() === 0) {
|
||||
|
@ -32,15 +35,15 @@ export default function ccJsonify(fulfillment) {
|
|||
|
||||
if (fulfillment.getTypeId() === 2) {
|
||||
return {
|
||||
'details': {
|
||||
'type': 'threshold-sha-256',
|
||||
'threshold': fulfillment.threshold,
|
||||
'subfulfillments': fulfillment.subconditions.map((subcondition) => {
|
||||
details: {
|
||||
type: 'threshold-sha-256',
|
||||
threshold: fulfillment.threshold,
|
||||
subconditions: fulfillment.subconditions.map((subcondition) => {
|
||||
const subconditionJson = ccJsonify(subcondition.body)
|
||||
return subconditionJson.details
|
||||
})
|
||||
},
|
||||
'uri': conditionUri,
|
||||
uri: conditionUri,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +51,6 @@ export default function ccJsonify(fulfillment) {
|
|||
jsonBody.details.type = 'ed25519-sha-256'
|
||||
|
||||
if ('publicKey' in fulfillment) {
|
||||
jsonBody.details.signature = null
|
||||
jsonBody.details.public_key = base58.encode(fulfillment.publicKey)
|
||||
}
|
||||
}
|
30
test/base-request/test_baseRequest.js
Normal file
30
test/base-request/test_baseRequest.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import rewire from 'rewire'
|
||||
|
||||
const baseRequestFile = rewire('../../src/baseRequest.js')
|
||||
const baseRequest = baseRequestFile.__get__('baseRequest')
|
||||
const handleResponse = baseRequestFile.__get__('handleResponse')
|
||||
|
||||
test('HandleResponse does not throw error for response ok', t => {
|
||||
const testObj = {
|
||||
ok: true
|
||||
}
|
||||
const expected = testObj
|
||||
const actual = handleResponse(testObj)
|
||||
|
||||
t.deepEqual(actual, expected)
|
||||
})
|
||||
|
||||
test('baseRequest test query and vsprint', async t => {
|
||||
const error = await t.throwsAsync(baseRequest('https://%s.com/', {
|
||||
urlTemplateSpec: ['google'],
|
||||
query: 'teapot'
|
||||
}), { instanceOf: Error, message: 'HTTP Error: Requested page not reachable' })
|
||||
|
||||
t.is(error.requestURI, 'https://www.google.com/teapot')
|
||||
t.is(error.status, '418 I\'m a Teapot')
|
||||
})
|
|
@ -1,85 +1,130 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import * as request from '../../src/request' // eslint-disable-line
|
||||
import { Connection } from '../../src'
|
||||
import {
|
||||
Connection
|
||||
} from '../../src'
|
||||
import {
|
||||
API_PATH
|
||||
} from '../constants'
|
||||
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
test('Payload thrown at incorrect API_PATH', async t => {
|
||||
const path = 'http://localhost:9984/api/wrong/'
|
||||
const connection = new Connection(path)
|
||||
const target = {
|
||||
message: 'HTTP Error: Requested page not reachable',
|
||||
status: '404 NOT FOUND',
|
||||
requestURI: 'http://localhost:9984/api/wrong/transactions/transactionId'
|
||||
}
|
||||
const error = await t.throwsAsync(connection.getTransaction('transactionId'), {
|
||||
instanceOf: Error, message: target.message
|
||||
})
|
||||
|
||||
test('generate API URLS', t => {
|
||||
t.is('ResponseError', error.name)
|
||||
t.is(target.status, error.status)
|
||||
t.is(target.requestURI, error.requestURI)
|
||||
})
|
||||
|
||||
test('Generate API URLS', t => {
|
||||
const endpoints = {
|
||||
'blocks': 'blocks',
|
||||
'blocksDetail': 'blocks/%(blockId)s',
|
||||
'blocksDetail': 'blocks/%(blockHeight)s',
|
||||
'outputs': 'outputs',
|
||||
'statuses': 'statuses',
|
||||
'transactions': 'transactions',
|
||||
'transactionsSync': 'transactions?mode=sync',
|
||||
'transactionsAsync': 'transactions?mode=async',
|
||||
'transactionsCommit': 'transactions?mode=commit',
|
||||
'transactionsDetail': 'transactions/%(transactionId)s',
|
||||
'assets': 'assets',
|
||||
}
|
||||
Object.keys(endpoints).forEach(endpointName => {
|
||||
const url = conn.getApiUrls(endpointName)
|
||||
const expected = API_PATH + endpoints[endpointName]
|
||||
const url = Connection.getApiUrls(endpointName)
|
||||
const expected = endpoints[endpointName]
|
||||
t.is(url, expected)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test('Request with custom headers', t => {
|
||||
const testConn = new Connection(API_PATH, { hello: 'world' })
|
||||
const expectedOptions = {
|
||||
test('Normalize node from an object', t => {
|
||||
const headers = {
|
||||
custom: 'headers'
|
||||
}
|
||||
const node = {
|
||||
endpoint: API_PATH,
|
||||
headers: {
|
||||
hello: 'world'
|
||||
}
|
||||
}
|
||||
const expectedNode = {
|
||||
'endpoint': API_PATH,
|
||||
'headers': {
|
||||
hello: 'world',
|
||||
custom: 'headers'
|
||||
}
|
||||
}
|
||||
|
||||
// request is read only, cannot be mocked?
|
||||
sinon.spy(request, 'default')
|
||||
testConn._req(API_PATH, { headers: { custom: 'headers' } })
|
||||
|
||||
t.truthy(request.default.calledWith(API_PATH, expectedOptions))
|
||||
request.default.restore()
|
||||
t.deepEqual(Connection.normalizeNode(node, headers), expectedNode)
|
||||
})
|
||||
|
||||
test('Normalize node from a string', t => {
|
||||
const headers = {
|
||||
custom: 'headers'
|
||||
}
|
||||
const expectedNode = {
|
||||
'endpoint': API_PATH,
|
||||
'headers': {
|
||||
custom: 'headers'
|
||||
}
|
||||
}
|
||||
|
||||
t.deepEqual(Connection.normalizeNode(API_PATH, headers), expectedNode)
|
||||
})
|
||||
|
||||
test('Request with custom headers', t => {
|
||||
const testConn = new Connection(API_PATH, {
|
||||
hello: 'world'
|
||||
})
|
||||
const expectedOptions = {
|
||||
headers: {
|
||||
custom: 'headers'
|
||||
}
|
||||
}
|
||||
const PATH = 'blocks'
|
||||
testConn.transport.forwardRequest = sinon.spy()
|
||||
|
||||
testConn._req(PATH, {
|
||||
headers: {
|
||||
custom: 'headers'
|
||||
}
|
||||
})
|
||||
t.truthy(testConn.transport.forwardRequest.calledWith(PATH, expectedOptions))
|
||||
})
|
||||
|
||||
test('Get block for a block id', t => {
|
||||
const expectedPath = 'path'
|
||||
const blockId = 'abc'
|
||||
const blockHeight = 'abc'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.getBlock(blockId)
|
||||
conn.getBlock(blockHeight)
|
||||
t.truthy(conn._req.calledWith(
|
||||
expectedPath,
|
||||
{ urlTemplateSpec: { blockId } }
|
||||
{ urlTemplateSpec: { blockHeight } }
|
||||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get status for a transaction id', t => {
|
||||
const expectedPath = 'path'
|
||||
const transactionId = 'abc'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.getStatus(transactionId)
|
||||
t.truthy(conn._req.calledWith(
|
||||
expectedPath,
|
||||
{ query: { transaction_id: transactionId } }
|
||||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get transaction for a transaction id', t => {
|
||||
const expectedPath = 'path'
|
||||
const transactionId = 'abc'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.getTransaction(transactionId)
|
||||
t.truthy(conn._req.calledWith(
|
||||
|
@ -88,35 +133,31 @@ test('Get transaction for a transaction id', t => {
|
|||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get list of blocks for a transaction id', t => {
|
||||
const expectedPath = 'path'
|
||||
const transactionId = 'abc'
|
||||
const status = 'status'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.listBlocks(transactionId, status)
|
||||
conn.listBlocks(transactionId)
|
||||
t.truthy(conn._req.calledWith(
|
||||
expectedPath,
|
||||
{
|
||||
query: {
|
||||
transaction_id: transactionId,
|
||||
status
|
||||
}
|
||||
}
|
||||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get list of transactions for an asset id', t => {
|
||||
const expectedPath = 'path'
|
||||
const assetId = 'abc'
|
||||
const operation = 'operation'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.listTransactions(assetId, operation)
|
||||
t.truthy(conn._req.calledWith(
|
||||
|
@ -130,13 +171,12 @@ test('Get list of transactions for an asset id', t => {
|
|||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get outputs for a public key and no spent flag', t => {
|
||||
const expectedPath = 'path'
|
||||
const publicKey = 'publicKey'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.listOutputs(publicKey)
|
||||
t.truthy(conn._req.calledWith(
|
||||
|
@ -145,14 +185,13 @@ test('Get outputs for a public key and no spent flag', t => {
|
|||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get outputs for a public key and spent=false', t => {
|
||||
const expectedPath = 'path'
|
||||
const publicKey = 'publicKey'
|
||||
const spent = false
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.listOutputs(publicKey, spent)
|
||||
t.truthy(conn._req.calledWith(
|
||||
|
@ -161,14 +200,13 @@ test('Get outputs for a public key and spent=false', t => {
|
|||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get outputs for a public key and spent=true', t => {
|
||||
const expectedPath = 'path'
|
||||
const publicKey = 'publicKey'
|
||||
const spent = true
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.listOutputs(publicKey, spent)
|
||||
t.truthy(conn._req.calledWith(
|
||||
|
@ -177,32 +215,30 @@ test('Get outputs for a public key and spent=true', t => {
|
|||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get votes for a block id', t => {
|
||||
const expectedPath = 'path'
|
||||
const blockId = 'abc'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.listVotes(blockId)
|
||||
t.truthy(conn._req.calledWith(
|
||||
expectedPath,
|
||||
{ query: { block_id: blockId } }
|
||||
))
|
||||
})
|
||||
|
||||
|
||||
test('Get asset for text', t => {
|
||||
const expectedPath = 'path'
|
||||
const search = 'abc'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.searchAssets(search)
|
||||
t.truthy(conn._req.calledWith(
|
||||
expectedPath,
|
||||
{ query: { search } }
|
||||
{ query: { search, limit: 10 } }
|
||||
))
|
||||
})
|
||||
|
||||
test('Get metadata for text', t => {
|
||||
const expectedPath = 'path'
|
||||
const search = 'abc'
|
||||
|
||||
conn._req = sinon.spy()
|
||||
Connection.getApiUrls = sinon.stub().returns(expectedPath)
|
||||
|
||||
conn.searchMetadata(search)
|
||||
t.truthy(conn._req.calledWith(
|
||||
expectedPath,
|
||||
{ query: { search, limit: 10 } }
|
||||
))
|
||||
})
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import test from 'ava'
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import { createHash } from 'crypto'
|
||||
import base58 from 'bs58'
|
||||
import { Ed25519Sha256 } from 'crypto-conditions'
|
||||
import { Transaction, Ed25519Keypair } from '../src'
|
||||
// TODO: Find out if ava has something like conftest, if so put this there.
|
||||
|
||||
// NOTE: It's safer to cast `Math.random()` to a string, to avoid differences
|
||||
// in "float interpretation" between languages (e.g. JavaScript and Python)
|
||||
export const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
export function asset() { return { message: `${Math.random()}` } }
|
||||
export const metaData = { message: 'metaDataMessage' }
|
||||
|
||||
|
@ -17,16 +24,30 @@ export const createTx = Transaction.makeCreateTransaction(
|
|||
alice.publicKey
|
||||
)
|
||||
export const transferTx = Transaction.makeTransferTransaction(
|
||||
createTx,
|
||||
metaData,
|
||||
[{ tx: createTx, output_index: 0 }],
|
||||
[aliceOutput],
|
||||
0
|
||||
metaData
|
||||
)
|
||||
|
||||
export const bob = new Ed25519Keypair()
|
||||
export const bobCondition = Transaction.makeEd25519Condition(bob.publicKey)
|
||||
export const bobOutput = Transaction.makeOutput(bobCondition)
|
||||
|
||||
export function delegatedSignTransaction(...keyPairs) {
|
||||
return function sign(serializedTransaction, input) {
|
||||
const transactionUniqueFulfillment = input.fulfills ? serializedTransaction
|
||||
.concat(input.fulfills.transaction_id)
|
||||
.concat(input.fulfills.output_index) : serializedTransaction
|
||||
const transactionHash = createHash('sha3-256').update(transactionUniqueFulfillment).digest()
|
||||
const filteredKeyPairs = keyPairs.filter(
|
||||
({ publicKey }) => input.owners_before.includes(publicKey)
|
||||
)
|
||||
|
||||
// TODO: https://github.com/avajs/ava/issues/1190
|
||||
test('', () => 'dirty hack. TODO: Exclude this file from being run by ava')
|
||||
const ed25519Fulfillment = new Ed25519Sha256()
|
||||
filteredKeyPairs.forEach(keyPair => {
|
||||
const privateKey = Buffer.from(base58.decode(keyPair.privateKey))
|
||||
ed25519Fulfillment.sign(transactionHash, privateKey)
|
||||
})
|
||||
return ed25519Fulfillment.serializeUri()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import { Ed25519Keypair, Transaction, Connection } from '../../src'
|
||||
|
||||
import {
|
||||
API_PATH,
|
||||
alice,
|
||||
aliceCondition,
|
||||
aliceOutput,
|
||||
bob,
|
||||
bobOutput,
|
||||
asset,
|
||||
metaData
|
||||
metaData,
|
||||
delegatedSignTransaction
|
||||
} from '../constants'
|
||||
|
||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
||||
|
||||
|
||||
test('Keypair is created', t => {
|
||||
const keyPair = new Ed25519Keypair()
|
||||
|
||||
|
@ -21,12 +24,8 @@ test('Keypair is created', t => {
|
|||
t.truthy(keyPair.privateKey)
|
||||
})
|
||||
|
||||
|
||||
// TODO: The following tests are a bit messy currently, please do:
|
||||
//
|
||||
// - tidy up dependency on `pollStatusAndFetchTransaction`
|
||||
test('Valid CREATE transaction', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
test('Valid CREATE transaction with default node', t => {
|
||||
const conn = new Connection()
|
||||
|
||||
const tx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
|
@ -37,10 +36,40 @@ test('Valid CREATE transaction', t => {
|
|||
const txSigned = Transaction.signTransaction(tx, alice.privateKey)
|
||||
|
||||
return conn.postTransaction(txSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
.then(resTx => {
|
||||
t.truthy(resTx)
|
||||
})
|
||||
})
|
||||
|
||||
test('Valid CREATE transaction using async', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
const tx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
[aliceOutput],
|
||||
alice.publicKey
|
||||
)
|
||||
const txSigned = Transaction.signTransaction(tx, alice.privateKey)
|
||||
|
||||
return conn.postTransactionAsync(txSigned)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
})
|
||||
|
||||
test('Valid CREATE transaction using sync', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
const tx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
[aliceOutput],
|
||||
alice.publicKey
|
||||
)
|
||||
const txSigned = Transaction.signTransaction(tx, alice.privateKey)
|
||||
|
||||
return conn.postTransactionSync(txSigned)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
})
|
||||
|
||||
test('Valid TRANSFER transaction with single Ed25519 input', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
@ -55,26 +84,22 @@ test('Valid TRANSFER transaction with single Ed25519 input', t => {
|
|||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => {
|
||||
const transferTx = Transaction.makeTransferTransaction(
|
||||
createTxSigned,
|
||||
metaData,
|
||||
[{ tx: createTxSigned, output_index: 0 }],
|
||||
[aliceOutput],
|
||||
0
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned = Transaction.signTransaction(
|
||||
transferTx,
|
||||
alice.privateKey
|
||||
)
|
||||
return conn.postTransaction(transferTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(transferTxSigned)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test('Valid TRANSFER transaction with multiple Ed25519 inputs', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
const createTx = Transaction.makeCreateTransaction(
|
||||
|
@ -88,27 +113,137 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs', t => {
|
|||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ 'id': txId }) => conn.pollStatusAndFetchTransaction(txId))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => {
|
||||
const transferTx = Transaction.makeTransferTransaction(
|
||||
createTxSigned,
|
||||
metaData,
|
||||
[{ tx: createTxSigned, output_index: 0 }, { tx: createTxSigned, output_index: 1 }],
|
||||
[Transaction.makeOutput(aliceCondition, '2')],
|
||||
0,
|
||||
1
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned = Transaction.signTransaction(
|
||||
transferTx,
|
||||
alice.privateKey,
|
||||
bob.privateKey
|
||||
)
|
||||
return conn.postTransaction(transferTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(transferTxSigned)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
})
|
||||
})
|
||||
|
||||
test('Valid TRANSFER transaction with multiple Ed25519 inputs from different transactions', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
const carol = new Ed25519Keypair()
|
||||
const carolCondition = Transaction.makeEd25519Condition(carol.publicKey)
|
||||
const carolOutput = Transaction.makeOutput(carolCondition)
|
||||
const trent = new Ed25519Keypair()
|
||||
const trentCondition = Transaction.makeEd25519Condition(trent.publicKey)
|
||||
const trentOutput = Transaction.makeOutput(trentCondition)
|
||||
const eli = new Ed25519Keypair()
|
||||
const eliCondition = Transaction.makeEd25519Condition(eli.publicKey)
|
||||
|
||||
const createTx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
[aliceOutput, bobOutput],
|
||||
alice.publicKey
|
||||
)
|
||||
const createTxSigned = Transaction.signTransaction(
|
||||
createTx,
|
||||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => {
|
||||
const transferTx1 = Transaction.makeTransferTransaction(
|
||||
[{ tx: createTxSigned, output_index: 0 }],
|
||||
[carolOutput],
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned1 = Transaction.signTransaction(
|
||||
transferTx1,
|
||||
alice.privateKey
|
||||
)
|
||||
const transferTx2 = Transaction.makeTransferTransaction(
|
||||
[{ tx: createTxSigned, output_index: 1 }],
|
||||
[trentOutput],
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned2 = Transaction.signTransaction(
|
||||
transferTx2,
|
||||
bob.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransactionCommit(transferTxSigned1)
|
||||
.then(() => conn.postTransactionCommit(transferTxSigned2))
|
||||
.then(() => {
|
||||
const transferTxMultipleInputs = Transaction.makeTransferTransaction(
|
||||
[{ tx: transferTxSigned1, output_index: 0 },
|
||||
{ tx: transferTxSigned2, output_index: 0 }],
|
||||
[Transaction.makeOutput(eliCondition, '2')],
|
||||
metaData
|
||||
)
|
||||
const transferTxSignedMultipleInputs = Transaction.signTransaction(
|
||||
transferTxMultipleInputs,
|
||||
carol.privateKey,
|
||||
trent.privateKey
|
||||
)
|
||||
return conn.postTransactionCommit(transferTxSignedMultipleInputs)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Valid CREATE transaction using delegateSign with default node', t => {
|
||||
const conn = new Connection()
|
||||
|
||||
const tx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
[aliceOutput],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
const txSigned = Transaction.delegateSignTransaction(
|
||||
tx,
|
||||
delegatedSignTransaction(alice)
|
||||
)
|
||||
|
||||
return conn.postTransaction(txSigned)
|
||||
.then(resTx => {
|
||||
t.truthy(resTx)
|
||||
})
|
||||
})
|
||||
|
||||
test('Valid TRANSFER transaction with multiple Ed25519 inputs using delegateSign', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
const createTx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
[aliceOutput, bobOutput],
|
||||
alice.publicKey
|
||||
)
|
||||
const createTxSigned = Transaction.signTransaction(
|
||||
createTx,
|
||||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => {
|
||||
const transferTx = Transaction.makeTransferTransaction(
|
||||
[{ tx: createTxSigned, output_index: 0 }, { tx: createTxSigned, output_index: 1 }],
|
||||
[Transaction.makeOutput(aliceCondition, '2')],
|
||||
metaData
|
||||
)
|
||||
|
||||
const transferTxSigned = Transaction.delegateSignTransaction(
|
||||
transferTx,
|
||||
delegatedSignTransaction(alice, bob)
|
||||
)
|
||||
|
||||
return conn.postTransactionCommit(transferTxSigned)
|
||||
.then(resTx => t.truthy(resTx))
|
||||
})
|
||||
})
|
||||
|
||||
test('Search for spent and unspent outputs of a given public key', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
@ -119,7 +254,6 @@ test('Search for spent and unspent outputs of a given public key', t => {
|
|||
const trentCondition = Transaction.makeEd25519Condition(trent.publicKey)
|
||||
const trentOutput = Transaction.makeOutput(trentCondition)
|
||||
|
||||
|
||||
const createTx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
|
@ -134,26 +268,22 @@ test('Search for spent and unspent outputs of a given public key', t => {
|
|||
|
||||
// We spent output 1 (of 0, 1)
|
||||
const transferTx = Transaction.makeTransferTransaction(
|
||||
createTxSigned,
|
||||
metaData,
|
||||
[{ tx: createTxSigned, output_index: 1 }],
|
||||
[trentOutput],
|
||||
1
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned = Transaction.signTransaction(
|
||||
transferTx,
|
||||
carol.privateKey,
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
.then(() => conn.postTransaction(transferTxSigned))
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => conn.postTransactionCommit(transferTxSigned))
|
||||
.then(() => conn.listOutputs(carol.publicKey))
|
||||
// now listOutputs should return us outputs 0 and 1 (unfiltered)
|
||||
.then(outputs => t.truthy(outputs.length === 2))
|
||||
})
|
||||
|
||||
|
||||
test('Search for unspent outputs for a given public key', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
const carol = new Ed25519Keypair()
|
||||
|
@ -177,26 +307,22 @@ test('Search for unspent outputs for a given public key', t => {
|
|||
|
||||
// We spent output 1 (of 0, 1, 2)
|
||||
const transferTx = Transaction.makeTransferTransaction(
|
||||
createTxSigned,
|
||||
metaData,
|
||||
[{ tx: createTxSigned, output_index: 1 }],
|
||||
[trentOutput],
|
||||
1
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned = Transaction.signTransaction(
|
||||
transferTx,
|
||||
carol.privateKey,
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
.then(() => conn.postTransaction(transferTxSigned))
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => conn.postTransactionCommit(transferTxSigned))
|
||||
// now listOutputs should return us outputs 0 and 2 (1 is spent)
|
||||
.then(() => conn.listOutputs(carol.publicKey, 'false'))
|
||||
.then(outputs => t.truthy(outputs.length === 2))
|
||||
})
|
||||
|
||||
|
||||
test('Search for spent outputs for a given public key', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
const carol = new Ed25519Keypair()
|
||||
|
@ -220,26 +346,22 @@ test('Search for spent outputs for a given public key', t => {
|
|||
|
||||
// We spent output 1 (of 0, 1, 2)
|
||||
const transferTx = Transaction.makeTransferTransaction(
|
||||
createTxSigned,
|
||||
metaData,
|
||||
[{ tx: createTxSigned, output_index: 1 }],
|
||||
[trentOutput],
|
||||
1
|
||||
metaData
|
||||
)
|
||||
const transferTxSigned = Transaction.signTransaction(
|
||||
transferTx,
|
||||
carol.privateKey,
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
.then(() => conn.postTransaction(transferTxSigned))
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => conn.postTransactionCommit(transferTxSigned))
|
||||
// now listOutputs should only return us output 1 (0 and 2 are unspent)
|
||||
.then(() => conn.listOutputs(carol.publicKey, true))
|
||||
.then(outputs => t.truthy(outputs.length === 1))
|
||||
})
|
||||
|
||||
|
||||
test('Search for an asset', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
|
@ -254,8 +376,7 @@ test('Search for an asset', t => {
|
|||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => conn.searchAssets(createTxSigned.asset.data.message))
|
||||
.then(assets => t.truthy(
|
||||
assets.pop(),
|
||||
|
@ -263,6 +384,27 @@ test('Search for an asset', t => {
|
|||
))
|
||||
})
|
||||
|
||||
test('Search for metadata', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
const createTx = Transaction.makeCreateTransaction(
|
||||
asset(),
|
||||
metaData,
|
||||
[aliceOutput],
|
||||
alice.publicKey
|
||||
)
|
||||
const createTxSigned = Transaction.signTransaction(
|
||||
createTx,
|
||||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(() => conn.searchMetadata(createTxSigned.metadata.message))
|
||||
.then(assets => t.truthy(
|
||||
assets.pop(),
|
||||
createTxSigned.metadata.message
|
||||
))
|
||||
})
|
||||
|
||||
test('Search blocks containing a transaction', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
@ -278,17 +420,13 @@ test('Search blocks containing a transaction', t => {
|
|||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
||||
.then(({ id }) => conn.listBlocks(id, 'VALID'))
|
||||
.then(blocks => conn.getBlock(blocks.pop()))
|
||||
.then(({ block: { transactions } }) => transactions.filter(
|
||||
({ id }) => id === createTxSigned.id
|
||||
))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(({ id }) => conn.listBlocks(id))
|
||||
.then(blockHeight => conn.getBlock(blockHeight.pop()))
|
||||
.then(({ transactions }) => transactions.filter(({ id }) => id === createTxSigned.id))
|
||||
.then(transactions => t.truthy(transactions.length === 1))
|
||||
})
|
||||
|
||||
|
||||
test('Search transaction containing an asset', t => {
|
||||
const conn = new Connection(API_PATH)
|
||||
|
||||
|
@ -303,13 +441,15 @@ test('Search transaction containing an asset', t => {
|
|||
alice.privateKey
|
||||
)
|
||||
|
||||
return conn.postTransaction(createTxSigned)
|
||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id, 'CREATE'))
|
||||
return conn.postTransactionCommit(createTxSigned)
|
||||
.then(({ id }) => conn.listTransactions(id))
|
||||
.then(transactions => t.truthy(transactions.length === 1))
|
||||
.then(transactions => {
|
||||
t.truthy(transactions.length === 1)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test('Content-Type cannot be set', t => {
|
||||
t.throws(() => new Connection(API_PATH, { 'Content-Type': 'application/json' }), Error)
|
||||
t.throws(() => new Connection(API_PATH, { 'Content-Type': 'application/json' }), {
|
||||
instanceOf: Error
|
||||
})
|
||||
})
|
||||
|
|
26
test/request/test_request.js
Normal file
26
test/request/test_request.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import Connection from '../../src/connection'
|
||||
|
||||
const conn = new Connection()
|
||||
|
||||
test('Ensure that BackoffTimedelta works properly', t => {
|
||||
const req = conn.transport.pickConnection()
|
||||
req.backoffTime = Date.now() + 50
|
||||
const target = req.getBackoffTimedelta()
|
||||
// The value should be close to 50
|
||||
t.is(target > 45, true)
|
||||
})
|
||||
|
||||
test('Ensure that updateBackoffTime throws and error on TimeoutError', async t => {
|
||||
const req = conn.transport.pickConnection()
|
||||
const errorMessage = 'TimeoutError'
|
||||
req.connectionError = new Error(errorMessage)
|
||||
|
||||
t.throws(() => {
|
||||
req.updateBackoffTime()
|
||||
}, { instanceOf: Error, message: errorMessage })
|
||||
})
|
55
test/sanitize/test_sanitize.js
Normal file
55
test/sanitize/test_sanitize.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import rewire from 'rewire'
|
||||
|
||||
const sanitize = rewire('../../src/sanitize.js')
|
||||
const applyFilterOnObject = sanitize.__get__('applyFilterOnObject')
|
||||
const filterFromObject = sanitize.__get__('filterFromObject')
|
||||
|
||||
test('Ensure that null filter returns same object', t => {
|
||||
const expected = { 'testObj': 'test' }
|
||||
const actual = applyFilterOnObject({ 'testObj': 'test' }, null)
|
||||
|
||||
t.deepEqual(actual, expected)
|
||||
})
|
||||
|
||||
test('Ensure function filter with isInclusion true works properly', t => {
|
||||
const testObj = [true, false, undefined, '', 0, null]
|
||||
const expected = { 0: true }
|
||||
const actual = filterFromObject(testObj, (val) => !!val, { isInclusion: true })
|
||||
|
||||
t.deepEqual(actual, expected)
|
||||
})
|
||||
|
||||
test('Ensure function filter with isInclusion false works properly', t => {
|
||||
const testObj = [false, true, 1, 10, 'this will be removed as it is truthy']
|
||||
const expected = { 0: false }
|
||||
const actual = filterFromObject(testObj, (val) => !!val, { isInclusion: false })
|
||||
|
||||
t.deepEqual(actual, expected)
|
||||
})
|
||||
|
||||
test('Ensure array filter with isInclusion true works properly', t => {
|
||||
const testObj = [true, false, undefined, '', 0, null]
|
||||
const expected = { 0: true }
|
||||
const actual = filterFromObject(testObj, [true], { isInclusion: true })
|
||||
|
||||
t.deepEqual(actual, expected)
|
||||
})
|
||||
|
||||
test('Ensure array filter with isInclusion false works properly', t => {
|
||||
const testObj = [false, true, 1, 10]
|
||||
const expected = { 0: false }
|
||||
const actual = filterFromObject(testObj, [true, 1, 10], { isInclusion: false })
|
||||
|
||||
t.deepEqual(actual, expected)
|
||||
})
|
||||
|
||||
test('Ensure throws error when given invalid filter', t => {
|
||||
t.throws(() => {
|
||||
filterFromObject({}, 'lol')
|
||||
}, { instanceOf: Error, message: 'The given filter is not an array or function. Filter aborted' })
|
||||
})
|
50
test/text-format/test_format_text.js
Normal file
50
test/text-format/test_format_text.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import formatText from '../../src/format_text'
|
||||
|
||||
test('formatText test type 1', t => {
|
||||
const expected = 'Hi there Dimi!'
|
||||
const actual = formatText('Hi there ${dimi}!', { dimi: 'Dimi' }) // eslint-disable-line no-template-curly-in-string
|
||||
|
||||
t.is(actual, expected)
|
||||
})
|
||||
|
||||
test('formatText test type 2', t => {
|
||||
const expected = 'BigchainDB is big'
|
||||
const actual = formatText('${database} is %(status)s', { // eslint-disable-line no-template-curly-in-string
|
||||
database: 'BigchainDB',
|
||||
status: 'big'
|
||||
})
|
||||
|
||||
t.is(actual, expected)
|
||||
})
|
||||
|
||||
test('formatText test type 3', t => {
|
||||
const expected = 'Berlin is best known for its Currywurst'
|
||||
const actual = formatText(
|
||||
'Berlin is best known for its ${berlin.topKnownFor[0].name}', // eslint-disable-line no-template-curly-in-string
|
||||
{
|
||||
berlin: {
|
||||
topKnownFor: [
|
||||
{
|
||||
name: 'Currywurst'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
t.is(actual, expected)
|
||||
})
|
||||
|
||||
test('formatText test throws', t => {
|
||||
t.throws(() => {
|
||||
formatText(
|
||||
'This will give ${error.}', // eslint-disable-line no-template-curly-in-string
|
||||
{ error: [{}] }
|
||||
)
|
||||
}, { instanceOf: SyntaxError, message: '[formatText] failed to parse named argument key: error.' })
|
||||
})
|
|
@ -1,7 +1,14 @@
|
|||
import test from 'ava'
|
||||
import cc from 'five-bells-condition'
|
||||
import { Ed25519Keypair, Transaction } from '../../src'
|
||||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import { createHash } from 'crypto'
|
||||
import { validateFulfillment } from 'crypto-conditions'
|
||||
import test from 'ava'
|
||||
import base58 from 'bs58'
|
||||
import { Ed25519Keypair, Transaction, ccJsonLoad } from '../../src'
|
||||
import { delegatedSignTransaction } from '../constants'
|
||||
import sha256Hash from '../../src/sha256Hash'
|
||||
|
||||
test('Ed25519 condition encoding', t => {
|
||||
const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS'
|
||||
|
@ -9,35 +16,44 @@ test('Ed25519 condition encoding', t => {
|
|||
details: {
|
||||
type: 'ed25519-sha-256',
|
||||
public_key: publicKey,
|
||||
signature: null,
|
||||
},
|
||||
uri: 'ni:///sha-256;uLdVX7FEjLWVDkAkfMAkEqPPwFqZj7qfiGE152t_x5c?fpt=ed25519-sha-256&cost=131072'
|
||||
}
|
||||
t.deepEqual(target, Transaction.makeEd25519Condition(publicKey))
|
||||
})
|
||||
|
||||
test('Sha256Condition fulfillment', t => {
|
||||
const preimage = 'secret'
|
||||
const target = {
|
||||
details: {
|
||||
type_id: 0,
|
||||
bitmask: 3,
|
||||
preimage,
|
||||
type: 'fulfillment'
|
||||
},
|
||||
uri: 'ni:///sha-256;K7gNU3sdo-OL0wNhqoVWhr3g6s1xYv72ol_pe_Unols?fpt=preimage-sha-256&cost=6'
|
||||
}
|
||||
t.deepEqual(target, Transaction.makeSha256Condition(preimage))
|
||||
})
|
||||
|
||||
test('Threshold condition encoding', t => {
|
||||
const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS'
|
||||
const ed25519 = Transaction.makeEd25519Condition(publicKey, false)
|
||||
const condition = Transaction.makeThresholdCondition(
|
||||
1, [ed25519, ed25519])
|
||||
const condition = Transaction.makeThresholdCondition(1, [ed25519, ed25519])
|
||||
const output = Transaction.makeOutput(condition)
|
||||
const target = {
|
||||
condition: {
|
||||
details: {
|
||||
type: 'threshold-sha-256',
|
||||
threshold: 1,
|
||||
subfulfillments: [
|
||||
subconditions: [
|
||||
{
|
||||
type: 'ed25519-sha-256',
|
||||
public_key: publicKey,
|
||||
signature: null,
|
||||
},
|
||||
{
|
||||
type: 'ed25519-sha-256',
|
||||
public_key: publicKey,
|
||||
signature: null,
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -49,7 +65,6 @@ test('Threshold condition encoding', t => {
|
|||
t.deepEqual(target, output)
|
||||
})
|
||||
|
||||
|
||||
test('Fulfillment correctly formed', t => {
|
||||
const alice = new Ed25519Keypair()
|
||||
const txCreate = Transaction.makeCreateTransaction(
|
||||
|
@ -58,15 +73,79 @@ test('Fulfillment correctly formed', t => {
|
|||
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
alice.publicKey
|
||||
)
|
||||
// Sign in order to get the tx id, needed for the unique fulfillment in the transfer transaction
|
||||
const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey)
|
||||
|
||||
const txTransfer = Transaction.makeTransferTransaction(
|
||||
txCreate,
|
||||
[{ tx: signCreateTransaction, output_index: 0 }],
|
||||
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
{}
|
||||
)
|
||||
const txSigned = Transaction.signTransaction(txTransfer, alice.privateKey)
|
||||
|
||||
// Here reconstruct the fulfillment of the transfer transaction
|
||||
// The tx is serialized, and extended with tx_id and output index, and then hashed into bytes
|
||||
const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer)
|
||||
const msgUniqueFulfillment = txTransfer.inputs[0].fulfills ? msg
|
||||
.concat(txTransfer.inputs[0].fulfills.transaction_id)
|
||||
.concat(txTransfer.inputs[0].fulfills.output_index) : msg
|
||||
const msgHash = sha256Hash(msgUniqueFulfillment)
|
||||
|
||||
t.truthy(validateFulfillment(
|
||||
txSigned.inputs[0].fulfillment,
|
||||
txCreate.outputs[0].condition.uri,
|
||||
Buffer.from(msgHash, 'hex')
|
||||
))
|
||||
})
|
||||
|
||||
test('Delegated signature is correct', t => {
|
||||
const alice = new Ed25519Keypair()
|
||||
|
||||
const txCreate = Transaction.makeCreateTransaction(
|
||||
{},
|
||||
{},
|
||||
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
[0]
|
||||
alice.publicKey
|
||||
)
|
||||
const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer)
|
||||
const txSigned = Transaction.signTransaction(txTransfer, alice.privateKey)
|
||||
t.truthy(cc.validateFulfillment(txSigned.inputs[0].fulfillment,
|
||||
txCreate.outputs[0].condition.uri,
|
||||
new Buffer(msg)))
|
||||
|
||||
const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey)
|
||||
const delegatedSignCreateTransaction = Transaction.delegateSignTransaction(
|
||||
txCreate,
|
||||
delegatedSignTransaction(alice)
|
||||
)
|
||||
t.deepEqual(signCreateTransaction, delegatedSignCreateTransaction)
|
||||
})
|
||||
|
||||
test('Delegated async signature is correct', async t => {
|
||||
const alice = new Ed25519Keypair()
|
||||
|
||||
const txCreate = Transaction.makeCreateTransaction(
|
||||
{},
|
||||
{},
|
||||
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
||||
alice.publicKey
|
||||
)
|
||||
|
||||
const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey)
|
||||
const delegatedSignCreateTransaction = await Transaction.delegateSignTransactionAsync(
|
||||
txCreate,
|
||||
delegatedSignTransaction(alice)
|
||||
)
|
||||
t.deepEqual(signCreateTransaction, delegatedSignCreateTransaction)
|
||||
})
|
||||
|
||||
test('CryptoConditions JSON load', t => {
|
||||
const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS'
|
||||
const cond = ccJsonLoad({
|
||||
type: 'threshold-sha-256',
|
||||
threshold: 1,
|
||||
subconditions: [{
|
||||
type: 'ed25519-sha-256',
|
||||
public_key: publicKey
|
||||
},
|
||||
{
|
||||
hash: base58.encode(createHash('sha256').update('a').digest())
|
||||
}],
|
||||
})
|
||||
t.truthy(cond.subconditions.length === 2)
|
||||
})
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import { Transaction } from '../../src'
|
||||
import * as makeTransaction from '../../src/transaction/makeTransaction' // eslint-disable-line
|
||||
import makeInputTemplate from '../../src/transaction/makeInputTemplate'
|
||||
|
||||
import {
|
||||
alice,
|
||||
|
@ -13,7 +15,6 @@ import {
|
|||
transferTx
|
||||
} from '../constants'
|
||||
|
||||
|
||||
test('Create valid output with default amount', t => {
|
||||
const condition = {
|
||||
details: {
|
||||
|
@ -30,7 +31,6 @@ test('Create valid output with default amount', t => {
|
|||
t.deepEqual(res, expected)
|
||||
})
|
||||
|
||||
|
||||
test('Create valid output with custom amount', t => {
|
||||
const condition = {
|
||||
details: {
|
||||
|
@ -63,60 +63,53 @@ test('Pass condition not based on public_keys to makeOutput', t => {
|
|||
t.deepEqual(res, expected)
|
||||
})
|
||||
|
||||
|
||||
test('makeOutput throws TypeError with incorrect amount type', t => {
|
||||
t.throws(() => Transaction.makeOutput({}, 1337), TypeError)
|
||||
t.throws(() => Transaction.makeOutput({}, 1337), { instanceOf: TypeError })
|
||||
})
|
||||
|
||||
|
||||
test('Create TRANSFER transaction based on CREATE transaction', t => {
|
||||
sinon.spy(makeTransaction, 'default')
|
||||
|
||||
sinon.spy(Transaction, 'makeTransaction')
|
||||
Transaction.makeTransferTransaction(
|
||||
createTx,
|
||||
metaData,
|
||||
[{ tx: createTx, output_index: 0 }],
|
||||
[aliceOutput],
|
||||
0
|
||||
metaData
|
||||
)
|
||||
const expected = [
|
||||
'TRANSFER',
|
||||
{ id: createTx.id },
|
||||
metaData,
|
||||
[aliceOutput],
|
||||
[makeInputTemplate(
|
||||
[Transaction.makeInputTemplate(
|
||||
[alice.publicKey],
|
||||
{ output: 0, transaction_id: createTx.id }
|
||||
{ output_index: 0, transaction_id: createTx.id }
|
||||
)]
|
||||
]
|
||||
|
||||
// NOTE: `src/transaction/makeTransaction` is `export default`, hence we
|
||||
// can only mock `makeTransaction.default` with a hack:
|
||||
// See: https://stackoverflow.com/a/33676328/1263876
|
||||
t.truthy(makeTransaction.default.calledWith(...expected))
|
||||
makeTransaction.default.restore()
|
||||
t.truthy(Transaction.makeTransaction.calledWith(...expected))
|
||||
Transaction.makeTransaction.restore()
|
||||
})
|
||||
|
||||
|
||||
test('Create TRANSFER transaction based on TRANSFER transaction', t => {
|
||||
sinon.spy(makeTransaction, 'default')
|
||||
sinon.spy(Transaction, 'makeTransaction')
|
||||
|
||||
Transaction.makeTransferTransaction(
|
||||
transferTx,
|
||||
metaData,
|
||||
[{ tx: transferTx, output_index: 0 }],
|
||||
[aliceOutput],
|
||||
0
|
||||
metaData
|
||||
)
|
||||
const expected = [
|
||||
'TRANSFER',
|
||||
{ id: transferTx.asset.id },
|
||||
metaData,
|
||||
[aliceOutput],
|
||||
[makeInputTemplate(
|
||||
[Transaction.makeInputTemplate(
|
||||
[alice.publicKey],
|
||||
{ output: 0, transaction_id: transferTx.id }
|
||||
{ output_index: 0, transaction_id: transferTx.id }
|
||||
)]
|
||||
]
|
||||
|
||||
t.truthy(makeTransaction.default.calledWith(...expected))
|
||||
makeTransaction.default.restore()
|
||||
t.truthy(Transaction.makeTransaction.calledWith(...expected))
|
||||
Transaction.makeTransaction.restore()
|
||||
})
|
||||
|
|
23
test/transport/test_transport.js
Normal file
23
test/transport/test_transport.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import test from 'ava'
|
||||
|
||||
import {
|
||||
Connection
|
||||
} from '../../src'
|
||||
|
||||
test('Pick connection with earliest backoff time', async t => {
|
||||
const path1 = 'http://localhost:9984/api/v1/'
|
||||
const path2 = 'http://localhostwrong:9984/api/v1/'
|
||||
|
||||
// Reverse order
|
||||
const conn = new Connection([path2, path1])
|
||||
// This will trigger the 'forwardRequest' so the correct connection will be taken
|
||||
await conn.searchAssets('example')
|
||||
|
||||
const connection1 = conn.transport.connectionPool[1]
|
||||
|
||||
t.deepEqual(conn.transport.pickConnection(), connection1)
|
||||
})
|
10
types/Ed25519Keypair.d.ts
vendored
Normal file
10
types/Ed25519Keypair.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
export default class Ed25519Keypair {
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
|
||||
constructor(seed?: Buffer);
|
||||
}
|
31
types/baseRequest.d.ts
vendored
Normal file
31
types/baseRequest.d.ts
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
export interface RequestConfig {
|
||||
headers?: Record<string, string | string[]>;
|
||||
jsonBody?: Record<string, any>;
|
||||
query?: Record<string, any>;
|
||||
method?: 'GET' | ' POST' | 'PUT';
|
||||
urlTemplateSpec?: any[] | Record<string, any>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export function ResponseError(
|
||||
message: string,
|
||||
status?: number,
|
||||
requestURI?: string
|
||||
): void;
|
||||
|
||||
declare function timeout<T = Response>(
|
||||
ms: number,
|
||||
promise: Promise<T>
|
||||
): Promise<T>;
|
||||
|
||||
declare function handleResponse(res: Response): Response;
|
||||
|
||||
export default function baseRequest(
|
||||
url: string,
|
||||
config: RequestConfig,
|
||||
requestTimeout?: number
|
||||
): Promise<Response>;
|
179
types/connection.d.ts
vendored
Normal file
179
types/connection.d.ts
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import type { RequestConfig } from './baseRequest';
|
||||
import type { Node } from './request';
|
||||
import type Transport from './transport';
|
||||
import type {
|
||||
CreateTransaction,
|
||||
TransactionOperations,
|
||||
TransferTransaction,
|
||||
TransactionCommon,
|
||||
} from './transaction';
|
||||
|
||||
declare const DEFAULT_NODE = 'http://localhost:9984/api/v1/';
|
||||
declare const DEFAULT_TIMEOUT = 20000; // The default value is 20 seconds
|
||||
|
||||
export interface InputNode {
|
||||
endpoint: string;
|
||||
}
|
||||
|
||||
export type AssetResult = {
|
||||
id: string;
|
||||
data: Record<string, any>;
|
||||
};
|
||||
|
||||
export type MetadataResult = {
|
||||
id: string;
|
||||
metadata: Record<string, any>;
|
||||
};
|
||||
|
||||
export enum Endpoints {
|
||||
blocks = 'blocks',
|
||||
blocksDetail = 'blocksDetail',
|
||||
outputs = 'outputs',
|
||||
transactions = 'transactions',
|
||||
transactionsSync = 'transactionsSync',
|
||||
transactionsAsync = 'transactionsAsync',
|
||||
transactionsCommit = 'transactionsCommit',
|
||||
transactionsDetail = 'transactionsDetail',
|
||||
assets = 'assets',
|
||||
metadata = 'metadata',
|
||||
}
|
||||
|
||||
export interface EndpointsUrl {
|
||||
[Endpoints.blocks]: 'blocks';
|
||||
[Endpoints.blocksDetail]: 'blocks/%(blockHeight)s';
|
||||
[Endpoints.outputs]: 'outputs';
|
||||
[Endpoints.transactions]: 'transactions';
|
||||
[Endpoints.transactionsSync]: 'transactions?mode=sync';
|
||||
[Endpoints.transactionsAsync]: 'transactions?mode=async';
|
||||
[Endpoints.transactionsCommit]: 'transactions?mode=commit';
|
||||
[Endpoints.transactionsDetail]: 'transactions/%(transactionId)s';
|
||||
[Endpoints.assets]: 'assets';
|
||||
[Endpoints.metadata]: 'metadata';
|
||||
}
|
||||
|
||||
export interface EndpointsResponse<
|
||||
O = TransactionOperations.CREATE,
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
> {
|
||||
[Endpoints.blocks]: number[];
|
||||
[Endpoints.blocksDetail]: {
|
||||
height: number;
|
||||
transactions: (CreateTransaction | TransferTransaction)[];
|
||||
};
|
||||
[Endpoints.outputs]: {
|
||||
transaction_id: string;
|
||||
output_index: number;
|
||||
}[];
|
||||
[Endpoints.transactions]: O extends TransactionOperations.CREATE
|
||||
? CreateTransaction[]
|
||||
: O extends TransactionOperations.TRANSFER
|
||||
? TransferTransaction[]
|
||||
: (CreateTransaction | TransferTransaction)[];
|
||||
[Endpoints.transactionsSync]: O extends TransactionOperations.CREATE
|
||||
? CreateTransaction<A, M>
|
||||
: TransferTransaction<M>;
|
||||
[Endpoints.transactionsAsync]: O extends TransactionOperations.CREATE
|
||||
? CreateTransaction<A, M>
|
||||
: TransferTransaction<M>;
|
||||
[Endpoints.transactionsCommit]: O extends TransactionOperations.CREATE
|
||||
? CreateTransaction<A, M>
|
||||
: TransferTransaction<M>;
|
||||
[Endpoints.transactionsDetail]: O extends TransactionOperations.CREATE
|
||||
? CreateTransaction<A, M>
|
||||
: TransferTransaction<M>;
|
||||
[Endpoints.assets]: AssetResult[];
|
||||
[Endpoints.metadata]: MetadataResult[];
|
||||
}
|
||||
|
||||
export default class Connection {
|
||||
private transport: Transport;
|
||||
private normalizedNodes: Node[];
|
||||
private headers: Record<string, string | string[]>;
|
||||
|
||||
constructor(
|
||||
nodes: string | InputNode | (string | InputNode)[],
|
||||
headers?: Record<string, string | string[]>,
|
||||
timeout?: number
|
||||
);
|
||||
|
||||
static normalizeNode(
|
||||
node: string | InputNode,
|
||||
headers: Record<string, string | string[]>
|
||||
): Node;
|
||||
|
||||
static getApiUrls<E extends keyof EndpointsUrl>(endpoint: E): EndpointsUrl[E];
|
||||
|
||||
private _req<E extends keyof EndpointsUrl, O = Record<string, any>>(
|
||||
path: EndpointsUrl[E],
|
||||
options: RequestConfig
|
||||
): Promise<O>;
|
||||
|
||||
getBlock(
|
||||
blockHeight: number | string
|
||||
): Promise<EndpointsResponse[Endpoints.blocksDetail]>;
|
||||
|
||||
getTransaction<O = TransactionOperations.CREATE>(
|
||||
transactionId: string
|
||||
): Promise<EndpointsResponse<O>[Endpoints.transactionsDetail]>;
|
||||
|
||||
listBlocks(
|
||||
transactionId: string
|
||||
): Promise<EndpointsResponse[Endpoints.blocks]>;
|
||||
|
||||
listOutputs(
|
||||
publicKey: string,
|
||||
spent?: boolean
|
||||
): Promise<EndpointsResponse[Endpoints.outputs]>;
|
||||
|
||||
listTransactions(
|
||||
assetId: string,
|
||||
operation?: TransactionOperations
|
||||
): Promise<EndpointsResponse<typeof operation>[Endpoints.transactions]>;
|
||||
|
||||
postTransaction<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE,
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
>(
|
||||
transaction: TransactionCommon<O>
|
||||
): Promise<EndpointsResponse<O, A, M>[Endpoints.transactionsCommit]>;
|
||||
|
||||
postTransactionSync<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE,
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
>(
|
||||
transaction: TransactionCommon<O>
|
||||
): Promise<EndpointsResponse<O, A, M>[Endpoints.transactionsSync]>;
|
||||
|
||||
postTransactionAsync<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE,
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
>(
|
||||
transaction: TransactionCommon<O>
|
||||
): Promise<EndpointsResponse<O, A, M>[Endpoints.transactionsAsync]>;
|
||||
|
||||
postTransactionCommit<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE,
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
>(
|
||||
transaction: TransactionCommon<O>
|
||||
): Promise<EndpointsResponse<O, A, M>[Endpoints.transactionsCommit]>;
|
||||
|
||||
searchAssets(
|
||||
search: string,
|
||||
limit?: number
|
||||
): Promise<EndpointsResponse[Endpoints.assets]>;
|
||||
|
||||
searchMetadata(
|
||||
search: string,
|
||||
limit?: number
|
||||
): Promise<EndpointsResponse[Endpoints.metadata]>;
|
||||
}
|
39
types/index.d.ts
vendored
Normal file
39
types/index.d.ts
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import Ed25519Keypair from './Ed25519Keypair';
|
||||
import Connection, {
|
||||
Endpoints,
|
||||
EndpointsResponse,
|
||||
EndpointsUrl,
|
||||
} from './connection';
|
||||
import Transaction, {
|
||||
CreateTransaction,
|
||||
TransactionCommon,
|
||||
TransactionCommonSigned,
|
||||
TransactionInput,
|
||||
TransactionOutput,
|
||||
TransferTransaction,
|
||||
TransactionUnspentOutput,
|
||||
TransactionOperations,
|
||||
} from './transaction';
|
||||
import ccJsonLoad from './utils/ccJsonLoad';
|
||||
import ccJsonify from './utils/ccJsonify';
|
||||
|
||||
export { ccJsonLoad, ccJsonify, Connection, Ed25519Keypair, Transaction };
|
||||
|
||||
// Extras
|
||||
export {
|
||||
Endpoints,
|
||||
EndpointsResponse,
|
||||
EndpointsUrl,
|
||||
CreateTransaction,
|
||||
TransactionCommon,
|
||||
TransactionCommonSigned,
|
||||
TransactionInput,
|
||||
TransactionOutput,
|
||||
TransferTransaction,
|
||||
TransactionUnspentOutput,
|
||||
TransactionOperations,
|
||||
};
|
32
types/request.d.ts
vendored
Normal file
32
types/request.d.ts
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import type { RequestConfig } from './baseRequest';
|
||||
|
||||
export interface Node {
|
||||
endpoint: string;
|
||||
headers: Record<string, string | string[]>;
|
||||
}
|
||||
|
||||
export default class Request {
|
||||
private node: Node;
|
||||
private backoffTime: number;
|
||||
private retries: number;
|
||||
private connectionError?: Error;
|
||||
|
||||
constructor(node: Node);
|
||||
|
||||
request<O = Record<string, any>>(
|
||||
urlPath: string,
|
||||
config?: RequestConfig,
|
||||
timeout?: number,
|
||||
maxBackoffTime?: number
|
||||
): Promise<O>;
|
||||
|
||||
updateBackoffTime(maxBackoffTime: number): void;
|
||||
|
||||
getBackoffTimedelta(): number;
|
||||
|
||||
static sleep(ms: number): void;
|
||||
}
|
25
types/sanitize.d.ts
vendored
Normal file
25
types/sanitize.d.ts
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
declare type FilterFn = (val: any, key?: string) => void;
|
||||
|
||||
declare function filterFromObject<I = Record<string, any>>(
|
||||
obj: I,
|
||||
filter: Array<any> | FilterFn,
|
||||
conf: { isInclusion?: boolean }
|
||||
): Partial<I>;
|
||||
|
||||
declare function applyFilterOnObject<I = Record<string, any>>(
|
||||
obj: I,
|
||||
filterFn?: FilterFn
|
||||
): Partial<I>;
|
||||
|
||||
declare function selectFromObject<I = Record<string, any>>(
|
||||
obj: I,
|
||||
filter: Array<any> | FilterFn
|
||||
): Partial<I>;
|
||||
|
||||
export default function sanitize<I = Record<string, any>>(
|
||||
obj: I
|
||||
): Partial<I> | I;
|
236
types/transaction.d.ts
vendored
Normal file
236
types/transaction.d.ts
vendored
Normal file
|
@ -0,0 +1,236 @@
|
|||
import type {
|
||||
Ed25519Sha256,
|
||||
Fulfillment,
|
||||
PreimageSha256,
|
||||
ThresholdSha256,
|
||||
} from 'crypto-conditions';
|
||||
import {
|
||||
Ed25519Sha256JSONCondition,
|
||||
PreimageSha256JSONCondition,
|
||||
ThresholdSha256JSONCondition,
|
||||
} from './utils/ccJsonify';
|
||||
|
||||
export interface TransactionInput {
|
||||
fulfillment: string;
|
||||
fulfills: {
|
||||
output_index: number;
|
||||
transaction_id: string;
|
||||
} | null;
|
||||
owners_before: string[];
|
||||
}
|
||||
export interface TransactionOutput {
|
||||
amount: string;
|
||||
condition:
|
||||
| PreimageSha256JSONCondition
|
||||
| ThresholdSha256JSONCondition
|
||||
| Ed25519Sha256JSONCondition;
|
||||
public_keys: string[];
|
||||
}
|
||||
|
||||
export enum TransactionOperations {
|
||||
CREATE = 'CREATE',
|
||||
TRANSFER = 'TRANSFER',
|
||||
}
|
||||
|
||||
export interface TransactionCommon<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE,
|
||||
A extends Record<string, any> = Record<string, unknown>,
|
||||
M extends Record<string, any> = Record<string, unknown>
|
||||
> {
|
||||
id?: string;
|
||||
inputs: TransactionInput[];
|
||||
outputs: TransactionOutput[];
|
||||
version: string;
|
||||
metadata: M;
|
||||
operation: O;
|
||||
asset: TransactionAssetMap<O, A>;
|
||||
}
|
||||
|
||||
export interface TransactionCommonSigned<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE,
|
||||
A extends Record<string, any> = Record<string, unknown>,
|
||||
M extends Record<string, any> = Record<string, unknown>
|
||||
> extends Omit<TransactionCommon<O, A, M>, 'id'> {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export type TransactionAssetMap<
|
||||
Operation,
|
||||
A extends Record<string, any>
|
||||
> = Operation extends TransactionOperations.CREATE
|
||||
? {
|
||||
data: A;
|
||||
}
|
||||
: {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export interface CreateTransaction<
|
||||
A extends Record<string, any> = Record<string, unknown>,
|
||||
M extends Record<string, any> = Record<string, unknown>
|
||||
> extends TransactionCommon<TransactionOperations.CREATE, A, M> {
|
||||
id: string;
|
||||
asset: TransactionAssetMap<TransactionOperations.CREATE, A>;
|
||||
operation: TransactionOperations.CREATE;
|
||||
}
|
||||
|
||||
export interface TransferTransaction<
|
||||
M extends Record<string, any> = Record<string, unknown>
|
||||
> extends TransactionCommon<TransactionOperations.TRANSFER, any, M> {
|
||||
id: string;
|
||||
asset: TransactionAssetMap<TransactionOperations.TRANSFER, { id: string }>;
|
||||
operation: TransactionOperations.TRANSFER;
|
||||
}
|
||||
|
||||
export interface TransactionUnspentOutput {
|
||||
tx: TransactionCommon;
|
||||
output_index: number;
|
||||
}
|
||||
|
||||
interface TxTemplate {
|
||||
id: null;
|
||||
operation: null;
|
||||
outputs: [];
|
||||
inputs: [];
|
||||
metadata: null;
|
||||
asset: null;
|
||||
version: '2.0';
|
||||
}
|
||||
|
||||
export type DelegateSignFunction = (
|
||||
serializedTransaction: string,
|
||||
input: TransactionInput,
|
||||
index?: number
|
||||
) => string;
|
||||
|
||||
export type DelegateSignFunctionAsync = (
|
||||
serializedTransaction: string,
|
||||
input: TransactionInput,
|
||||
index?: number
|
||||
) => Promise<string>;
|
||||
|
||||
export default class Transaction {
|
||||
static serializeTransactionIntoCanonicalString<
|
||||
O extends TransactionOperations = TransactionOperations
|
||||
>(transaction: TransactionCommon<O>): string;
|
||||
|
||||
static serializeTransactionIntoCanonicalString(
|
||||
transaction: CreateTransaction | TransferTransaction
|
||||
): string;
|
||||
|
||||
static makeEd25519Condition(publicKey: string): Ed25519Sha256JSONCondition;
|
||||
|
||||
static makeEd25519Condition(
|
||||
publicKey: string,
|
||||
json: true
|
||||
): Ed25519Sha256JSONCondition;
|
||||
|
||||
static makeEd25519Condition(publicKey: string, json: false): Ed25519Sha256;
|
||||
|
||||
static makeEd25519Condition(
|
||||
publicKey: string,
|
||||
json?: boolean
|
||||
): Ed25519Sha256 | Ed25519Sha256JSONCondition;
|
||||
|
||||
static makeSha256Condition(preimage: string): PreimageSha256JSONCondition;
|
||||
|
||||
static makeSha256Condition(
|
||||
preimage: string,
|
||||
json: true
|
||||
): PreimageSha256JSONCondition;
|
||||
|
||||
static makeSha256Condition(preimage: string, json: false): PreimageSha256;
|
||||
|
||||
static makeSha256Condition(
|
||||
preimage: string,
|
||||
json?: boolean
|
||||
): PreimageSha256 | PreimageSha256JSONCondition;
|
||||
|
||||
static makeThresholdCondition(
|
||||
threshold: number,
|
||||
subconditions: (string | Fulfillment)[]
|
||||
): ThresholdSha256JSONCondition;
|
||||
|
||||
static makeThresholdCondition(
|
||||
threshold: number,
|
||||
subconditions: (string | Fulfillment)[],
|
||||
json: true
|
||||
): ThresholdSha256JSONCondition;
|
||||
|
||||
static makeThresholdCondition(
|
||||
threshold: number,
|
||||
subconditions: (string | Fulfillment)[],
|
||||
json: false
|
||||
): ThresholdSha256;
|
||||
|
||||
static makeThresholdCondition(
|
||||
threshold: number,
|
||||
subconditions: (string | Fulfillment)[],
|
||||
json?: boolean
|
||||
): ThresholdSha256 | ThresholdSha256JSONCondition;
|
||||
|
||||
static makeInputTemplate(
|
||||
publicKeys: string[],
|
||||
fulfills?: TransactionInput['fulfills'],
|
||||
fulfillment?: TransactionInput['fulfillment']
|
||||
): TransactionInput;
|
||||
|
||||
static makeOutput(
|
||||
condition:
|
||||
| PreimageSha256JSONCondition
|
||||
| ThresholdSha256JSONCondition
|
||||
| Ed25519Sha256JSONCondition,
|
||||
amount?: string
|
||||
): TransactionOutput;
|
||||
|
||||
static makeTransactionTemplate(): TxTemplate;
|
||||
|
||||
static makeTransaction<
|
||||
O extends TransactionOperations,
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
>(
|
||||
operation: O,
|
||||
asset: A,
|
||||
metadata: M,
|
||||
outputs: TransactionOutput[],
|
||||
inputs: TransactionInput[]
|
||||
): TransactionCommon<O, A, M>;
|
||||
|
||||
static makeCreateTransaction<
|
||||
A = Record<string, any>,
|
||||
M = Record<string, any>
|
||||
>(
|
||||
asset: A,
|
||||
metadata: M,
|
||||
outputs: TransactionOutput[],
|
||||
...issuers: string[]
|
||||
): CreateTransaction<A, M>;
|
||||
|
||||
static makeTransferTransaction<M = Record<string, any>>(
|
||||
unspentOutputs: TransactionUnspentOutput[],
|
||||
outputs: TransactionOutput[],
|
||||
metadata: M
|
||||
): TransferTransaction<M>;
|
||||
|
||||
static signTransaction<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE
|
||||
>(
|
||||
transaction: TransactionCommon<O>,
|
||||
...privateKeys: string[]
|
||||
): TransactionCommonSigned<O>;
|
||||
|
||||
static delegateSignTransaction<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE
|
||||
>(
|
||||
transaction: TransactionCommon<O>,
|
||||
signFn: DelegateSignFunction
|
||||
): TransactionCommonSigned<O>;
|
||||
|
||||
static delegateSignTransactionAsync<
|
||||
O extends TransactionOperations = TransactionOperations.CREATE
|
||||
>(
|
||||
transaction: TransactionCommon<O>,
|
||||
signFn: DelegateSignFunctionAsync
|
||||
): Promise<TransactionCommonSigned<O>>;
|
||||
}
|
21
types/transport.d.ts
vendored
Normal file
21
types/transport.d.ts
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import Request, { Node } from './request';
|
||||
import type { RequestConfig } from './baseRequest';
|
||||
|
||||
export default class Transport {
|
||||
private connectionPool: Request[];
|
||||
private timeout: number;
|
||||
private maxBackoffTime: number;
|
||||
|
||||
constructor(nodes: Node[], timeout: number);
|
||||
|
||||
pickConnection(): Request;
|
||||
|
||||
forwardRequest<O = Record<string, any>>(
|
||||
path: string,
|
||||
config: RequestConfig
|
||||
): Promise<O>;
|
||||
}
|
32
types/utils/ccJsonLoad.d.ts
vendored
Normal file
32
types/utils/ccJsonLoad.d.ts
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import type {
|
||||
Condition,
|
||||
Ed25519Sha256,
|
||||
PreimageSha256,
|
||||
ThresholdSha256,
|
||||
} from 'crypto-conditions';
|
||||
import type {
|
||||
Ed25519Sha256JSONCondition,
|
||||
JSONCondition,
|
||||
PreimageSha256JSONCondition,
|
||||
ThresholdSha256JSONCondition,
|
||||
} from './ccJsonify';
|
||||
|
||||
declare function ccJsonLoad(
|
||||
conditionJson: PreimageSha256JSONCondition
|
||||
): PreimageSha256;
|
||||
|
||||
declare function ccJsonLoad(
|
||||
conditionJson: ThresholdSha256JSONCondition
|
||||
): ThresholdSha256;
|
||||
|
||||
declare function ccJsonLoad(
|
||||
conditionJson: Ed25519Sha256JSONCondition
|
||||
): Ed25519Sha256;
|
||||
|
||||
declare function ccJsonLoad(conditionJson: JSONCondition): Condition;
|
||||
|
||||
export default ccJsonLoad;
|
70
types/utils/ccJsonify.d.ts
vendored
Normal file
70
types/utils/ccJsonify.d.ts
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
import type {
|
||||
Condition,
|
||||
Ed25519Sha256,
|
||||
PreimageSha256,
|
||||
ThresholdSha256,
|
||||
} from 'crypto-conditions';
|
||||
import type { TypeId, TypeName } from 'crypto-conditions/types/types';
|
||||
|
||||
interface BaseJSONCondition {
|
||||
details: {
|
||||
[key: string]: any;
|
||||
};
|
||||
uri: string;
|
||||
}
|
||||
|
||||
export interface JSONCondition extends BaseJSONCondition {
|
||||
details: {
|
||||
type_id: TypeId;
|
||||
bitmask: number;
|
||||
type: 'condition';
|
||||
hash: string;
|
||||
max_fulfillment_length: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PreimageSha256JSONCondition extends BaseJSONCondition {
|
||||
details: {
|
||||
type_id: TypeId.PreimageSha256;
|
||||
bitmask: 3;
|
||||
preimage?: string;
|
||||
type?: 'fulfillement';
|
||||
};
|
||||
}
|
||||
|
||||
export interface ThresholdSha256JSONCondition extends BaseJSONCondition {
|
||||
details: {
|
||||
type: TypeName.ThresholdSha256;
|
||||
subConditions: (Ed25519Sha256JSONCondition | PreimageSha256JSONCondition)[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface Ed25519Sha256JSONCondition extends BaseJSONCondition {
|
||||
details: { type: TypeName.Ed25519Sha256; publicKey?: string };
|
||||
}
|
||||
|
||||
export type JSONConditionUnion =
|
||||
| JSONCondition
|
||||
| PreimageSha256JSONCondition
|
||||
| ThresholdSha256JSONCondition
|
||||
| Ed25519Sha256JSONCondition;
|
||||
|
||||
declare function ccJsonify(
|
||||
fulfillment: PreimageSha256
|
||||
): PreimageSha256JSONCondition;
|
||||
|
||||
declare function ccJsonify(
|
||||
fulfillment: ThresholdSha256
|
||||
): ThresholdSha256JSONCondition;
|
||||
|
||||
declare function ccJsonify(
|
||||
fulfillment: Ed25519Sha256
|
||||
): Ed25519Sha256JSONCondition;
|
||||
|
||||
declare function ccJsonify(fulfillment: Condition): JSONCondition;
|
||||
|
||||
export default ccJsonify;
|
42
webpack.common.js
Normal file
42
webpack.common.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable strict, no-console, object-shorthand */
|
||||
|
||||
'use strict'
|
||||
|
||||
const { ProvidePlugin } = require('webpack')
|
||||
const { paths } = require('./webpack.parts')
|
||||
|
||||
module.exports = {
|
||||
entry: paths.entry,
|
||||
mode: 'none',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
emitOnErrors: false
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js'],
|
||||
modules: ['node_modules'],
|
||||
fallback: {
|
||||
buffer: require.resolve('buffer/'),
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer']
|
||||
})
|
||||
]
|
||||
}
|
|
@ -1,111 +1,34 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable strict, no-console, object-shorthand */
|
||||
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const webpack = require('webpack')
|
||||
|
||||
const PRODUCTION = process.env.NODE_ENV === 'production'
|
||||
|
||||
const PATHS = {
|
||||
ENTRY: path.resolve(__dirname, './src/index.js'),
|
||||
BUNDLE: path.resolve(__dirname, 'dist/browser'),
|
||||
NODE_MODULES: path.resolve(__dirname, 'node_modules'),
|
||||
const common = require('./webpack.common')
|
||||
|
||||
const { outputs } = require('./webpack.parts')
|
||||
|
||||
// '[libraryTarget]': [file extension]
|
||||
const OUTPUT_MAPPING = {
|
||||
'amd': 'amd',
|
||||
'commonjs': 'cjs',
|
||||
'commonjs2': 'cjs2',
|
||||
'umd': 'umd',
|
||||
'window': 'window',
|
||||
}
|
||||
|
||||
const OUTPUTS = [
|
||||
{
|
||||
filename: PRODUCTION ? 'bigchaindb-driver.window.min.js' : 'bigchaindb-driver.window.js',
|
||||
library: 'BigchainDB',
|
||||
libraryTarget: 'window',
|
||||
path: PATHS.BUNDLE,
|
||||
},
|
||||
{
|
||||
filename: PRODUCTION ? 'bigchaindb-driver.umd.min.js' : 'bigchaindb-driver.umd.js',
|
||||
library: 'bigchaindb-driver',
|
||||
libraryTarget: 'umd',
|
||||
path: PATHS.BUNDLE,
|
||||
},
|
||||
{
|
||||
filename: PRODUCTION ? 'bigchaindb-driver.cjs.min.js' : 'bigchaindb-driver.cjs.js',
|
||||
library: 'bigchaindb-driver',
|
||||
libraryTarget: 'commonjs',
|
||||
path: PATHS.BUNDLE,
|
||||
},
|
||||
{
|
||||
filename: PRODUCTION ? 'bigchaindb-driver.cjs2.min.js' : 'bigchaindb-driver.cjs2.js',
|
||||
library: 'bigchaindb-driver',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: PATHS.BUNDLE,
|
||||
},
|
||||
{
|
||||
filename: PRODUCTION ? 'bigchaindb-driver.amd.min.js' : 'bigchaindb-driver.amd.js',
|
||||
library: 'bigchaindb-driver',
|
||||
libraryTarget: 'amd',
|
||||
path: PATHS.BUNDLE,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
/** PLUGINS **/
|
||||
const PLUGINS = [
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
]
|
||||
|
||||
const PROD_PLUGINS = [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false,
|
||||
},
|
||||
output: {
|
||||
comments: false,
|
||||
},
|
||||
sourceMap: true,
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
debug: false,
|
||||
minimize: true,
|
||||
}),
|
||||
]
|
||||
const OVERRIDES = {
|
||||
// optimization: {
|
||||
// minimize: false
|
||||
// }
|
||||
}
|
||||
|
||||
if (PRODUCTION) {
|
||||
PLUGINS.push(...PROD_PLUGINS)
|
||||
module.exports = outputs(common, 'production', OUTPUT_MAPPING, OVERRIDES)
|
||||
} else {
|
||||
module.exports = outputs(common, 'development', OUTPUT_MAPPING, OVERRIDES)
|
||||
}
|
||||
|
||||
const configBoilerplate = {
|
||||
entry: [PATHS.ENTRY],
|
||||
|
||||
devtool: PRODUCTION ? '#source-map' : '#inline-source-map',
|
||||
|
||||
resolve: {
|
||||
extensions: ['.js'],
|
||||
modules: ['node_modules'], // Don't use absolute path here to allow recursive matching
|
||||
},
|
||||
|
||||
plugins: PLUGINS,
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: [PATHS.NODE_MODULES],
|
||||
use: [{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
},
|
||||
}],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
/** EXPORTED WEBPACK CONFIG **/
|
||||
const config = OUTPUTS.map(output => {
|
||||
const configCopy = Object.assign({}, configBoilerplate)
|
||||
configCopy.output = output
|
||||
return configCopy
|
||||
})
|
||||
|
||||
module.exports = config
|
||||
|
|
32
webpack.development.js
Normal file
32
webpack.development.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable strict, no-console, object-shorthand, import/no-extraneous-dependencies */
|
||||
|
||||
'use strict'
|
||||
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
|
||||
module.exports = {
|
||||
devtool: 'inline-source-map',
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
test: /vendor/,
|
||||
}),
|
||||
new TerserPlugin({
|
||||
test: /^((?!(vendor)).)*.js$/,
|
||||
})
|
||||
],
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
commons: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'vendors',
|
||||
chunks: 'all'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
59
webpack.parts.js
Normal file
59
webpack.parts.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable strict, no-console, object-shorthand, import/no-extraneous-dependencies */
|
||||
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
const development = require('./webpack.development')
|
||||
const production = require('./webpack.production')
|
||||
|
||||
const AddVendorsPlugin = require('./plugins/add-vendors-plugin')
|
||||
|
||||
const paths = {
|
||||
entry: path.resolve(__dirname, './src/index.js'),
|
||||
bundle: path.resolve(__dirname, 'dist/browser'),
|
||||
}
|
||||
|
||||
const outputs = (base, env, mapping, overrides) => {
|
||||
const collection = []
|
||||
const library = 'bigchaindb-driver'
|
||||
const windowLibrary = 'BigchainDB'
|
||||
|
||||
let environment = development
|
||||
let ext = 'js'
|
||||
|
||||
if (env === 'production') {
|
||||
environment = production
|
||||
ext = `min.${ext}`
|
||||
}
|
||||
|
||||
Object.entries(mapping).forEach(([target, extension]) => {
|
||||
const filename = `[name].${library}.${extension}.${ext}`
|
||||
|
||||
const compiled = {
|
||||
output: {
|
||||
filename: filename,
|
||||
library: target === 'window' ? windowLibrary : library,
|
||||
libraryTarget: target,
|
||||
path: paths.bundle
|
||||
},
|
||||
plugins: [
|
||||
new AddVendorsPlugin(`${library}.${extension}.${ext}`)
|
||||
]
|
||||
}
|
||||
|
||||
collection.push(merge(base, environment, compiled, overrides))
|
||||
})
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
outputs,
|
||||
paths
|
||||
}
|
11
webpack.production.js
Normal file
11
webpack.production.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright BigchainDB GmbH and BigchainDB contributors
|
||||
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||
// Code is Apache-2.0 and docs are CC-BY-4.0
|
||||
|
||||
/* eslint-disable strict, no-console, object-shorthand */
|
||||
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
devtool: 'source-map',
|
||||
}
|
Loading…
Reference in New Issue
Block a user