├── .babelrc ├── .ci ├── travis-before-install.sh ├── travis-before-script.sh └── travis-install.sh ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .husky └── .gitignore ├── .npmignore ├── .travis.yml ├── API.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.rst ├── LICENSE ├── LICENSE-docs ├── README.md ├── RELEASE_PROCESS.md ├── compose ├── Dockerfile └── tendermint │ └── tmdata │ └── config.toml ├── docker-compose.yml ├── docs ├── Makefile ├── README.md ├── make.bat ├── requirements.txt ├── source │ ├── .conf.py.swp │ ├── advanced.rst │ ├── conf.py │ ├── index.rst │ ├── quickstart.rst │ ├── readme.rst │ └── usage.rst └── upgrade-guides │ └── 0.3.0.md ├── examples ├── .babelrc ├── .gitignore ├── README.md ├── package.json └── src │ ├── basic-usage-async-await.js │ ├── basic-usage.js │ ├── query-assets.js │ └── seed-func.js ├── media ├── repo-banner.sketch └── repo-banner@2x.png ├── package.json ├── plugins └── add-vendors-plugin.js ├── src ├── Ed25519Keypair.js ├── baseRequest.js ├── connection.js ├── format_text.js ├── index.js ├── request.js ├── sanitize.js ├── sha256Hash.js ├── stringify_as_query_param.js ├── transaction.js ├── transport.js └── utils │ ├── ccJsonLoad.js │ └── ccJsonify.js ├── test ├── base-request │ └── test_baseRequest.js ├── connection │ └── test_connection.js ├── constants.js ├── integration │ └── test_integration.js ├── request │ └── test_request.js ├── sanitize │ └── test_sanitize.js ├── text-format │ └── test_format_text.js ├── transaction │ ├── test_cryptoconditions.js │ └── test_transaction.js └── transport │ └── test_transport.js ├── types ├── Ed25519Keypair.d.ts ├── baseRequest.d.ts ├── connection.d.ts ├── index.d.ts ├── request.d.ts ├── sanitize.d.ts ├── transaction.d.ts ├── transport.d.ts └── utils │ ├── ccJsonLoad.d.ts │ └── ccJsonify.d.ts ├── webpack.common.js ├── webpack.config.js ├── webpack.development.js ├── webpack.parts.js └── webpack.production.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": [ 7 | "> 0.25%, not dead", 8 | "not IE 11", 9 | "maintained node versions" 10 | ] 11 | } 12 | ] 13 | ], 14 | "plugins": [ 15 | "@babel/plugin-proposal-export-default-from", 16 | "@babel/plugin-transform-object-assign", 17 | "@babel/plugin-proposal-object-rest-spread", 18 | [ 19 | "@babel/plugin-transform-runtime", 20 | { 21 | "absoluteRuntime": false, 22 | "corejs": 3, 23 | "helpers": true, 24 | "regenerator": true 25 | } 26 | ] 27 | ], 28 | "sourceMaps": true 29 | } 30 | -------------------------------------------------------------------------------- /.ci/travis-before-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright BigchainDB GmbH and BigchainDB contributors 3 | # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | # Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | 7 | sudo apt-get update 8 | sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce 9 | 10 | sudo rm /usr/local/bin/docker-compose 11 | curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose 12 | chmod +x docker-compose 13 | sudo mv docker-compose /usr/local/bin 14 | -------------------------------------------------------------------------------- /.ci/travis-before-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright BigchainDB GmbH and BigchainDB contributors 3 | # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | # Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | 7 | set -e -x 8 | 9 | docker-compose up -d bigchaindb 10 | 11 | npm install 12 | gem install cowsay 13 | npm install -g codecov -------------------------------------------------------------------------------- /.ci/travis-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright BigchainDB GmbH and BigchainDB contributors 3 | # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | # Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | 7 | set -e -x 8 | 9 | docker-compose build --no-cache bigchaindb 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | coverage 4 | media 5 | docs 6 | compose -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['eslint:recommended', 'airbnb-base', 'plugin:import/recommended'], 3 | parser: '@babel/eslint-parser', 4 | parserOptions: { requireConfigFile: false }, 5 | env: { 6 | browser: true, 7 | node: true, 8 | }, 9 | settings: { 10 | 'import/ignore': ['node_modules', '.(scss|css)$', '.(jpe?g|png|gif|svg)'], 11 | }, 12 | rules: { 13 | /** 14 | * Possible Errors 15 | * http://eslint.org/docs/rus/#possible-errors 16 | */ 17 | 18 | // Allow dangling commas for multiline arrays and objects 19 | // http://eslint.org/docs/rules/comma-dangle 20 | 'comma-dangle': [1, 'only-multiline'], 21 | 22 | // Warn against use of console for non-error logging 23 | // http://eslint.org/docs/rules/no-console 24 | 'no-console': [1, { allow: ['error'] }], 25 | 26 | // Allow use of Object.prototypes builtins directly 27 | // http://eslint.org/docs/rules/no-prototype-builtins 28 | 'no-prototype-builtins': [0], 29 | 30 | /** 31 | * Best Practices 32 | * http://eslint.org/docs/rules/#best-practices 33 | */ 34 | 35 | // Allow else clauses after an if with a return 36 | // http://eslint.org/docs/rules/no-else-return 37 | 'no-else-return': [0], 38 | 39 | // Disallow reassignment of function parameters (but allow assigning to parameter's properties) 40 | // http://eslint.org/docs/rules/no-param-reassign.html 41 | 'no-param-reassign': [2, { props: false }], 42 | 43 | /** 44 | * Variables 45 | * http://eslint.org/docs/rules/#variables 46 | */ 47 | 48 | // Disallow use of variables and classes before they are defined 49 | // http://eslint.org/docs/rules/no-use-before-define 50 | 'no-use-before-define': [2, { functions: false, classes: true }], 51 | 52 | // Disallow declaration of variables that are not used in the code, unless they are prefixed by 53 | // `ignored` (useful for creating subset objects through destructuring and rest objects) 54 | // http://eslint.org/docs/rules/no-unused-vars 55 | 'no-unused-vars': [ 56 | 2, 57 | { 58 | vars: 'local', 59 | args: 'after-used', 60 | varsIgnorePattern: 'ignored.+', 61 | }, 62 | ], 63 | 64 | /** 65 | * Stylelistic Issues 66 | * (http://eslint.org/docs/rules/#stylistic-issues) 67 | */ 68 | 69 | // Enforce 4-space indents, except for switch cases 70 | // http://eslint.org/docs/rules/indent 71 | 'indent': [2, 4, { SwitchCase: 1, VariableDeclarator: 1 }], 72 | 73 | // Specify the maximum length of a code line to be 100 74 | // http://eslint.org/docs/rules/max-len 75 | 'max-len': [ 76 | 2, 77 | { 78 | code: 105, // Use 105 to give some leeway for *just* slightly longer lines when convienient 79 | ignorePattern: '^(import|export) .* from .*$', 80 | ignoreComments: false, 81 | ignoreTrailingComments: true, 82 | ignoreUrls: true, 83 | }, 84 | ], 85 | 86 | // Require capitalization when using `new`, but don't require capitalized functions to be called 87 | // with new 88 | // http://eslint.org/docs/rules/new-cap 89 | 'new-cap': [2, { newIsCap: true, capIsNew: false }], 90 | 91 | // Allow the continue statement 92 | // http://eslint.org/docs/rules/no-continue 93 | 'no-continue': [0], 94 | 95 | // Disallow un-paren'd mixes of different operators if they're not of the same precendence 96 | // http://eslint.org/docs/rules/no-mixed-operators 97 | 'no-mixed-operators': [ 98 | 2, 99 | { 100 | groups: [ 101 | ['+', '-', '*', '/', '%', '**'], 102 | ['&', '|', '^', '~', '<<', '>>', '>>>'], 103 | ['==', '!=', '===', '!==', '>', '>=', '<', '<='], 104 | ['&&', '||'], 105 | ['in', 'instanceof'], 106 | ], 107 | allowSamePrecedence: true, 108 | }, 109 | ], 110 | 111 | // Allow use of unary increment/decrement operators 112 | // http://eslint.org/docs/rules/no-plusplus 113 | 'no-plusplus': [0], 114 | 115 | // Always allow dangling underscores 116 | // http://eslint.org/docs/rules/no-underscore-dangle 117 | 'no-underscore-dangle': [0], 118 | 119 | // Require unix-style line breaks 120 | // http://eslint.org/docs/rules/linebreak-style 121 | 'linebreak-style': [2, 'unix'], 122 | 123 | // Require operators to always be at the end of a line, except for the ternary operator 124 | // http://eslint.org/docs/rules/operator-linebreak 125 | 'operator-linebreak': [ 126 | 2, 127 | 'after', 128 | { overrides: { '?': 'ignore', ':': 'ignore' } }, 129 | ], 130 | 131 | // Require properties to be consistently quoted. Force numbers to be quoted, as they can have 132 | // weird behaviour during the coercion into a string) 133 | // http://eslint.org/docs/rules/quote-props 134 | 'quote-props': [ 135 | 2, 136 | 'consistent', 137 | { keywords: false, unnecessary: true, numbers: true }, 138 | ], 139 | 140 | // Require spaces before parens for anonymous function declarations 141 | // http://eslint.org/docs/rules/space-before-function-paren 142 | 'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }], 143 | 144 | // Require a space immediately following the // or /* in a comment for most comments 145 | // http://eslint.org/docs/rules/spaced-comment 146 | 'spaced-comment': [ 147 | 2, 148 | 'always', 149 | { 150 | line: { 151 | exceptions: ['-', '+'], 152 | }, 153 | block: { 154 | exceptions: ['*'], 155 | }, 156 | }, 157 | ], 158 | 159 | // We don't like semicolons so kill them 160 | // http://eslint.org/docs/rules/semi 161 | 'semi': [2, 'never'], 162 | 163 | /** 164 | * Import rules 165 | * https://github.com/benmosher/eslint-plugin-import#rules 166 | */ 167 | 168 | // Ensure named imports coupled with named exports 169 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#when-not-to-use-it 170 | 'import/named': 2, 171 | 172 | // Ensure default import coupled with default export 173 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it 174 | 'import/default': 2, 175 | 176 | // Disallow namespace (wildcard) imports 177 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md 178 | 'import/no-namespace': 2, 179 | 180 | // Enforce imports to not specify a trailing .js extension 181 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md 182 | 'import/extensions': [2, { js: 'never' }], 183 | 184 | // Enforce module import order: builtin -> external -> internal 185 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md 186 | 'import/order': [ 187 | 2, 188 | { 189 | groups: [ 190 | 'builtin', 191 | 'external', 192 | ['internal', 'parent', 'sibling', 'index'], 193 | ], 194 | }, 195 | ], 196 | 'import/no-extraneous-dependencies': ['error', { 'devDependencies': true }], 197 | /** 198 | * ES6-specific Issues 199 | * (http://eslint.org/docs/rules/#ecmascript-6) 200 | */ 201 | 'arrow-body-style': [0], 202 | 'arrow-parens': [0], 203 | 'arrow-spacing': [0], 204 | 'constructor-super': [0], 205 | 'generator-star-spacing': [0], 206 | 'no-class-assign': [0], 207 | 'no-confusing-arrow': [0], 208 | 'no-const-assign': [0], 209 | 'no-dupe-class-members': [0], 210 | 'no-duplicate-imports': [0], 211 | 'no-new-symbol': [0], 212 | 'no-restricted-imports': [0], 213 | 'no-this-before-super': [0], 214 | 'no-useless-computed-key': [0], 215 | 'no-useless-constructor': [0], 216 | 'no-useless-rename': [0], 217 | 'no-var': [0], 218 | 'object-shorthand': [0], 219 | 'prefer-arrow-callback': [0], 220 | 'prefer-const': [0], 221 | 'prefer-reflect': [0], 222 | 'prefer-rest-params': [0], 223 | 'prefer-spread': [0], 224 | 'prefer-template': [0], 225 | 'require-yield': [0], 226 | 'rest-spread-spacing': [0], 227 | 'sort-imports': [0], 228 | 'template-curly-spacing': [0], 229 | 'yield-star-spacing': [0], 230 | }, 231 | } 232 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - README.md 9 | - API.md 10 | - docs/*.rst 11 | pull_request: 12 | branches: 13 | - master 14 | types: 15 | - ready_for_review 16 | - opened 17 | - reopened 18 | - synchronize 19 | paths-ignore: 20 | - README.md 21 | - API.md 22 | - docs/*.rst 23 | 24 | jobs: 25 | test: 26 | runs-on: ubuntu-latest 27 | if: github.event_name == 'release' || github.event_name == 'push' || !github.event.pull_request.draft 28 | timeout-minutes: 10 29 | 30 | steps: 31 | - name: Checkout the commit 32 | uses: actions/checkout@v2 33 | 34 | - name: Set up Node 35 | uses: actions/setup-node@v2 36 | with: 37 | node-version: 14 38 | 39 | - name: Cache dependencies 40 | id: cache 41 | uses: actions/cache@v2 42 | with: 43 | path: ~/.npm 44 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 45 | restore-keys: | 46 | ${{ runner.os }}-node- 47 | 48 | - name: Run BigChainDB node 49 | run: | 50 | echo Building and starting up docker containers 51 | docker-compose -f ./docker-compose.yml up -d 52 | 53 | - name: Install dependencies 54 | env: 55 | HUSKY_SKIP_INSTALL: 'true' 56 | run: npm install 57 | 58 | - name: Lint 59 | run: npm run lint 60 | 61 | - name: Build 62 | run: npm run build 63 | 64 | # ensure BCDB node is up and running 65 | - run: sleep 20 66 | 67 | - name: Test 68 | run: npm run test 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.seed 2 | *.log 3 | *.dat 4 | *.out 5 | *.pid 6 | *.gz 7 | .idea 8 | *.sublime-project 9 | *.sublime-workspace 10 | *.sublime-workspace 11 | .DS_Store 12 | .vscode 13 | 14 | .env 15 | .genv 16 | 17 | node_modules 18 | dist 19 | package-lock.json 20 | coverage 21 | coverage.lcov 22 | .nyc_output 23 | yarn.lock 24 | docs/build/ 25 | docs/_build/ 26 | docs/build/ 27 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.seed 2 | *.log 3 | *.dat 4 | *.out 5 | *.pid 6 | *.gz 7 | .idea 8 | *.sublime-project 9 | *.sublime-workspace 10 | *.sublime-workspace 11 | .DS_Store 12 | .vscode 13 | 14 | .env 15 | .genv 16 | 17 | node_modules 18 | package-lock.json 19 | coverage 20 | coverage.lcov 21 | .nyc_output 22 | yarn.lock 23 | 24 | docs/build/ 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Copyright BigchainDB GmbH and BigchainDB contributors 2 | # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | # Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | sudo: required 6 | 7 | services: 8 | - docker 9 | 10 | language: node_js 11 | 12 | node_js: 13 | - 10 14 | - 12 15 | - 14 16 | 17 | cache: 18 | directories: 19 | - node_modules 20 | 21 | env: 22 | global: 23 | - DOCKER_COMPOSE_VERSION=1.28.5 24 | 25 | before_install: 26 | - .ci/travis-before-install.sh 27 | 28 | install: 29 | - .ci/travis-install.sh 30 | 31 | before_script: 32 | - .ci/travis-before-script.sh 33 | 34 | script: npm test 35 | 36 | notifications: 37 | email: false 38 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | - [Ed25519Keypair][1] 6 | - [Parameters][2] 7 | - [Properties][3] 8 | - [Connection][4] 9 | - [Parameters][5] 10 | - [getBlock][6] 11 | - [Parameters][7] 12 | - [getTransaction][8] 13 | - [Parameters][9] 14 | - [listBlocks][10] 15 | - [Parameters][11] 16 | - [listOutputs][12] 17 | - [Parameters][13] 18 | - [listTransactions][14] 19 | - [Parameters][15] 20 | - [postTransaction][16] 21 | - [Parameters][17] 22 | - [postTransactionSync][18] 23 | - [Parameters][19] 24 | - [postTransactionAsync][20] 25 | - [Parameters][21] 26 | - [postTransactionCommit][22] 27 | - [Parameters][23] 28 | - [searchAssets][24] 29 | - [Parameters][25] 30 | - [searchMetadata][26] 31 | - [Parameters][27] 32 | - [Transaction][28] 33 | - [serializeTransactionIntoCanonicalString][29] 34 | - [Parameters][30] 35 | - [makeCreateTransaction][31] 36 | - [Parameters][32] 37 | - [makeEd25519Condition][33] 38 | - [Parameters][34] 39 | - [makeOutput][35] 40 | - [Parameters][36] 41 | - [makeSha256Condition][37] 42 | - [Parameters][38] 43 | - [makeThresholdCondition][39] 44 | - [Parameters][40] 45 | - [makeTransferTransaction][41] 46 | - [Parameters][42] 47 | - [signTransaction][43] 48 | - [Parameters][44] 49 | - [delegateSignTransaction][45] 50 | - [Parameters][46] 51 | - [delegateSignTransactionAsync][47] 52 | - [Parameters][48] 53 | - [ccJsonLoad][49] 54 | - [Parameters][50] 55 | - [ccJsonify][51] 56 | - [Parameters][52] 57 | 58 | ## Ed25519Keypair 59 | 60 | [src/Ed25519Keypair.js:16-21][53] 61 | 62 | Type: [Object][54] 63 | 64 | ### Parameters 65 | 66 | - `seed` **[Buffer][55]?** A seed that will be used as a key derivation function 67 | 68 | ### Properties 69 | 70 | - `publicKey` **[string][56]** 71 | - `privateKey` **[string][56]** 72 | 73 | ## Connection 74 | 75 | [src/connection.js:21-199][57] 76 | 77 | ### Parameters 78 | 79 | - `nodes` 80 | - `headers` **[Object][54]** Common headers for every request (optional, default `{}`) 81 | - `timeout` **float** Optional timeout in secs (optional, default `DEFAULT_TIMEOUT`) 82 | 83 | ### getBlock 84 | 85 | [src/connection.js:79-85][58] 86 | 87 | #### Parameters 88 | 89 | - `blockHeight` 90 | 91 | ### getTransaction 92 | 93 | [src/connection.js:90-96][59] 94 | 95 | #### Parameters 96 | 97 | - `transactionId` 98 | 99 | ### listBlocks 100 | 101 | [src/connection.js:102-108][60] 102 | 103 | #### Parameters 104 | 105 | - `transactionId` 106 | - `status` 107 | 108 | ### listOutputs 109 | 110 | [src/connection.js:114-126][61] 111 | 112 | #### Parameters 113 | 114 | - `publicKey` 115 | - `spent` 116 | 117 | ### listTransactions 118 | 119 | [src/connection.js:132-139][62] 120 | 121 | #### Parameters 122 | 123 | - `assetId` 124 | - `operation` 125 | 126 | ### postTransaction 127 | 128 | [src/connection.js:144-146][63] 129 | 130 | #### Parameters 131 | 132 | - `transaction` 133 | 134 | ### postTransactionSync 135 | 136 | [src/connection.js:151-156][64] 137 | 138 | #### Parameters 139 | 140 | - `transaction` 141 | 142 | ### postTransactionAsync 143 | 144 | [src/connection.js:161-166][65] 145 | 146 | #### Parameters 147 | 148 | - `transaction` 149 | 150 | ### postTransactionCommit 151 | 152 | [src/connection.js:171-176][66] 153 | 154 | #### Parameters 155 | 156 | - `transaction` 157 | 158 | ### searchAssets 159 | 160 | [src/connection.js:181-187][67] 161 | 162 | #### Parameters 163 | 164 | - `search` 165 | 166 | ### searchMetadata 167 | 168 | [src/connection.js:192-198][68] 169 | 170 | #### Parameters 171 | 172 | - `search` 173 | 174 | ## Transaction 175 | 176 | [src/transaction.js:16-288][69] 177 | 178 | Construct Transactions 179 | 180 | ### serializeTransactionIntoCanonicalString 181 | 182 | [src/transaction.js:22-29][70] 183 | 184 | Canonically serializes a transaction into a string by sorting the keys 185 | 186 | #### Parameters 187 | 188 | - `transaction` 189 | - `null` **[Object][54]** (transaction) 190 | 191 | Returns **[string][56]** a canonically serialized Transaction 192 | 193 | ### makeCreateTransaction 194 | 195 | [src/transaction.js:80-87][71] 196 | 197 | Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by 198 | the `issuers`. 199 | 200 | #### Parameters 201 | 202 | - `asset` **[Object][54]** Created asset's data 203 | - `metadata` **[Object][54]** Metadata for the Transaction 204 | - `outputs` **[Array][72]<[Object][54]>** Array of Output objects to add to the Transaction. 205 | Think of these as the recipients of the asset after the transaction. 206 | For `CREATE` Transactions, this should usually just be a list of 207 | Outputs wrapping Ed25519 Conditions generated from the issuers' public 208 | keys (so that the issuers are the recipients of the created asset). 209 | - `issuers` **...[Array][72]<[string][56]>** Public key of one or more issuers to the asset being created by this 210 | Transaction. 211 | Note: Each of the private keys corresponding to the given public 212 | keys MUST be used later (and in the same order) when signing the 213 | Transaction (`signTransaction()`). 214 | 215 | Returns **[Object][54]** Unsigned transaction -- make sure to call signTransaction() on it before 216 | sending it off! 217 | 218 | ### makeEd25519Condition 219 | 220 | [src/transaction.js:96-101][73] 221 | 222 | Create an Ed25519 Cryptocondition from an Ed25519 public key 223 | to put into an Output of a Transaction 224 | 225 | #### Parameters 226 | 227 | - `publicKey` **[string][56]** base58 encoded Ed25519 public key for the recipient of the Transaction 228 | - `json` **[boolean][74]** If true returns a json object otherwise a crypto-condition type (optional, default `true`) 229 | 230 | Returns **[Object][54]** Ed25519 Condition (that will need to wrapped in an Output) 231 | 232 | ### makeOutput 233 | 234 | [src/transaction.js:111-131][75] 235 | 236 | Create an Output from a Condition. 237 | Note: Assumes the given Condition was generated from a 238 | single public key (e.g. a Ed25519 Condition) 239 | 240 | #### Parameters 241 | 242 | - `condition` **[Object][54]** Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) 243 | - `amount` **[string][56]** Amount of the output (optional, default `'1'`) 244 | 245 | Returns **[Object][54]** An Output usable in a Transaction 246 | 247 | ### makeSha256Condition 248 | 249 | [src/transaction.js:139-143][76] 250 | 251 | Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction 252 | 253 | #### Parameters 254 | 255 | - `preimage` **[string][56]** Preimage to be hashed and wrapped in a crypto-condition 256 | - `json` **[boolean][74]** If true returns a json object otherwise a crypto-condition type (optional, default `true`) 257 | 258 | Returns **[Object][54]** Preimage-Sha256 Condition (that will need to wrapped in an Output) 259 | 260 | ### makeThresholdCondition 261 | 262 | [src/transaction.js:152-162][77] 263 | 264 | Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction 265 | 266 | #### Parameters 267 | 268 | - `threshold` **[number][78]** 269 | - `subconditions` **[Array][72]** (optional, default `[]`) 270 | - `json` **[boolean][74]** If true returns a json object otherwise a crypto-condition type (optional, default `true`) 271 | 272 | Returns **[Object][54]** Sha256 Threshold Condition (that will need to wrapped in an Output) 273 | 274 | ### makeTransferTransaction 275 | 276 | [src/transaction.js:185-206][79] 277 | 278 | Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills 279 | the `fulfilledOutputs` of `unspentTransaction`. 280 | 281 | #### Parameters 282 | 283 | - `unspentOutputs` 284 | - `outputs` **[Array][72]<[Object][54]>** Array of Output objects to add to the Transaction. 285 | Think of these as the recipients of the asset after the transaction. 286 | For `TRANSFER` Transactions, this should usually just be a list of 287 | Outputs wrapping Ed25519 Conditions generated from the public keys of 288 | the recipients. 289 | - `metadata` **[Object][54]** Metadata for the Transaction 290 | - `unspentTransaction` **[Object][54]** Previous Transaction you have control over (i.e. can fulfill 291 | its Output Condition) 292 | - `OutputIndices` **...[number][78]** Indices of the Outputs in `unspentTransaction` that this 293 | Transaction fulfills. 294 | Note that listed public keys listed must be used (and in 295 | the same order) to sign the Transaction 296 | (`signTransaction()`). 297 | 298 | Returns **[Object][54]** Unsigned transaction -- make sure to call signTransaction() on it before 299 | sending it off! 300 | 301 | ### signTransaction 302 | 303 | [src/transaction.js:219-243][80] 304 | 305 | Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction` 306 | that's been signed. 307 | Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as 308 | an exercise for the user. 309 | 310 | #### Parameters 311 | 312 | - `transaction` **[Object][54]** Transaction to sign. `transaction` is not modified. 313 | - `privateKeys` **...[string][56]** Private keys associated with the issuers of the `transaction`. 314 | Looped through to iteratively sign any Input Fulfillments found in 315 | the `transaction`. 316 | 317 | Returns **[Object][54]** The signed version of `transaction`. 318 | 319 | ### delegateSignTransaction 320 | 321 | [src/transaction.js:252-265][81] 322 | 323 | Delegate signing of the given `transaction` returning a new copy of `transaction` 324 | that's been signed. 325 | 326 | #### Parameters 327 | 328 | - `transaction` **[Object][54]** Transaction to sign. `transaction` is not modified. 329 | - `signFn` **[Function][82]** Function signing the transaction, expected to return the fulfillment. 330 | 331 | Returns **[Object][54]** The signed version of `transaction`. 332 | 333 | ### delegateSignTransactionAsync 334 | 335 | [src/transaction.js:274-287][83] 336 | 337 | Delegate signing of the given `transaction` returning a new copy of `transaction` 338 | that's been signed. 339 | 340 | #### Parameters 341 | 342 | - `transaction` **[Object][54]** Transaction to sign. `transaction` is not modified. 343 | - `signFn` **[Function][82]** Function signing the transaction, expected to resolve the fulfillment. 344 | 345 | Returns **[Promise][84]<[Object][54]>** The signed version of `transaction`. 346 | 347 | ## ccJsonLoad 348 | 349 | [src/utils/ccJsonLoad.js:13-44][85] 350 | 351 | Loads a crypto-condition class (Fulfillment or Condition) from a BigchainDB JSON object 352 | 353 | ### Parameters 354 | 355 | - `conditionJson` **[Object][54]** 356 | 357 | Returns **cc.Condition** Ed25519 Condition (that will need to wrapped in an Output) 358 | 359 | ## ccJsonify 360 | 361 | [src/utils/ccJsonify.js:12-65][86] 362 | 363 | Serializes a crypto-condition class (Condition or Fulfillment) into a BigchainDB-compatible JSON 364 | 365 | ### Parameters 366 | 367 | - `fulfillment` **cc.Fulfillment** base58 encoded Ed25519 public key for recipient of the Transaction 368 | 369 | Returns **[Object][54]** Ed25519 Condition (that will need to wrapped in an Output) 370 | 371 | [1]: #ed25519keypair 372 | 373 | [2]: #parameters 374 | 375 | [3]: #properties 376 | 377 | [4]: #connection 378 | 379 | [5]: #parameters-1 380 | 381 | [6]: #getblock 382 | 383 | [7]: #parameters-2 384 | 385 | [8]: #gettransaction 386 | 387 | [9]: #parameters-3 388 | 389 | [10]: #listblocks 390 | 391 | [11]: #parameters-4 392 | 393 | [12]: #listoutputs 394 | 395 | [13]: #parameters-5 396 | 397 | [14]: #listtransactions 398 | 399 | [15]: #parameters-6 400 | 401 | [16]: #posttransaction 402 | 403 | [17]: #parameters-7 404 | 405 | [18]: #posttransactionsync 406 | 407 | [19]: #parameters-8 408 | 409 | [20]: #posttransactionasync 410 | 411 | [21]: #parameters-9 412 | 413 | [22]: #posttransactioncommit 414 | 415 | [23]: #parameters-10 416 | 417 | [24]: #searchassets 418 | 419 | [25]: #parameters-11 420 | 421 | [26]: #searchmetadata 422 | 423 | [27]: #parameters-12 424 | 425 | [28]: #transaction 426 | 427 | [29]: #serializetransactionintocanonicalstring 428 | 429 | [30]: #parameters-13 430 | 431 | [31]: #makecreatetransaction 432 | 433 | [32]: #parameters-14 434 | 435 | [33]: #makeed25519condition 436 | 437 | [34]: #parameters-15 438 | 439 | [35]: #makeoutput 440 | 441 | [36]: #parameters-16 442 | 443 | [37]: #makesha256condition 444 | 445 | [38]: #parameters-17 446 | 447 | [39]: #makethresholdcondition 448 | 449 | [40]: #parameters-18 450 | 451 | [41]: #maketransfertransaction 452 | 453 | [42]: #parameters-19 454 | 455 | [43]: #signtransaction 456 | 457 | [44]: #parameters-20 458 | 459 | [45]: #delegatesigntransaction 460 | 461 | [46]: #parameters-21 462 | 463 | [47]: #delegatesigntransactionasync 464 | 465 | [48]: #parameters-22 466 | 467 | [49]: #ccjsonload 468 | 469 | [50]: #parameters-23 470 | 471 | [51]: #ccjsonify 472 | 473 | [52]: #parameters-24 474 | 475 | [53]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/Ed25519Keypair.js#L16-L21 "Source code on GitHub" 476 | 477 | [54]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 478 | 479 | [55]: https://nodejs.org/api/buffer.html 480 | 481 | [56]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 482 | 483 | [57]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L21-L199 "Source code on GitHub" 484 | 485 | [58]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L79-L85 "Source code on GitHub" 486 | 487 | [59]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L90-L96 "Source code on GitHub" 488 | 489 | [60]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L102-L108 "Source code on GitHub" 490 | 491 | [61]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L114-L126 "Source code on GitHub" 492 | 493 | [62]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L132-L139 "Source code on GitHub" 494 | 495 | [63]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L144-L146 "Source code on GitHub" 496 | 497 | [64]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L151-L156 "Source code on GitHub" 498 | 499 | [65]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L161-L166 "Source code on GitHub" 500 | 501 | [66]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L171-L176 "Source code on GitHub" 502 | 503 | [67]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L181-L187 "Source code on GitHub" 504 | 505 | [68]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/connection.js#L192-L198 "Source code on GitHub" 506 | 507 | [69]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L16-L288 "Source code on GitHub" 508 | 509 | [70]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L22-L29 "Source code on GitHub" 510 | 511 | [71]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L80-L87 "Source code on GitHub" 512 | 513 | [72]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 514 | 515 | [73]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L96-L101 "Source code on GitHub" 516 | 517 | [74]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean 518 | 519 | [75]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L111-L131 "Source code on GitHub" 520 | 521 | [76]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L139-L143 "Source code on GitHub" 522 | 523 | [77]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L152-L162 "Source code on GitHub" 524 | 525 | [78]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number 526 | 527 | [79]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L185-L206 "Source code on GitHub" 528 | 529 | [80]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L219-L243 "Source code on GitHub" 530 | 531 | [81]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L252-L265 "Source code on GitHub" 532 | 533 | [82]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function 534 | 535 | [83]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/transaction.js#L274-L287 "Source code on GitHub" 536 | 537 | [84]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise 538 | 539 | [85]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/utils/ccJsonLoad.js#L13-L44 "Source code on GitHub" 540 | 541 | [86]: https://github.com/bigchaindb/js-bigchaindb-driver/blob/76c877c649801f0a26351d03237e0b59c18bd3ef/src/utils/ccJsonify.js#L12-L65 "Source code on GitHub" 542 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | See [https://github.com/bigchaindb/bigchaindb/blob/master/CODE_OF_CONDUCT.md](https://github.com/bigchaindb/bigchaindb/blob/master/CODE_OF_CONDUCT.md) 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | 2 | .. Copyright BigchainDB GmbH and BigchainDB contributors 3 | SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | .. highlight:: shell 7 | 8 | ============ 9 | Contributing 10 | ============ 11 | 12 | Contributions are welcome, and they are greatly appreciated! Every 13 | little bit helps, and credit will always be given. 14 | 15 | You can contribute in many ways: 16 | 17 | Types of Contributions 18 | ---------------------- 19 | 20 | Report Bugs 21 | ~~~~~~~~~~~ 22 | 23 | Report bugs at https://github.com/bigchaindb/js-bigchaindb-driver/issues. 24 | 25 | If you are reporting a bug, please include: 26 | 27 | * Your operating system name and version. 28 | * Any details about your local setup that might be helpful in troubleshooting. 29 | * Detailed steps to reproduce the bug. 30 | 31 | Fix Bugs 32 | ~~~~~~~~ 33 | 34 | Look through the GitHub issues for bugs. Anything tagged with "bug" 35 | and "help wanted" is open to whoever wants to implement it. 36 | 37 | Implement Features 38 | ~~~~~~~~~~~~~~~~~~ 39 | 40 | Look through the GitHub issues for features. Anything tagged with "enhancement" 41 | and "help wanted" is open to whoever wants to implement it. 42 | 43 | Write Documentation 44 | ~~~~~~~~~~~~~~~~~~~ 45 | 46 | bigchaindb-driver could always use more documentation, whether as part of the 47 | official bigchaindb-driver docs, in docstrings, or even on the web in blog posts, 48 | articles, and such. 49 | 50 | Submit Feedback 51 | ~~~~~~~~~~~~~~~ 52 | 53 | The best way to send feedback is to file an issue at https://github.com/bigchaindb/js-bigchaindb-driver/issues. 54 | 55 | If you are proposing a feature: 56 | 57 | * Explain in detail how it would work. 58 | * Keep the scope as narrow as possible, to make it easier to implement. 59 | * Remember that this is a volunteer-driven project, and that contributions 60 | are welcome :) 61 | 62 | Get Started! 63 | ------------ 64 | 65 | Ready to contribute? Here's how to set up `js-bigchaindb-driver`_ for local 66 | development. 67 | 68 | 1. Fork the `js-bigchaindb-driver`_ repo on GitHub. 69 | 2. Clone your fork locally and enter into the project:: 70 | 71 | $ git clone git@github.com:your_name_here/js-bigchaindb-driver.git 72 | $ cd js-bigchaindb-driver/ 73 | 74 | 3. Create a branch for local development:: 75 | 76 | $ git checkout -b name-of-your-bugfix-or-feature 77 | 78 | Now you can make your changes locally. 79 | 80 | 4. Write tests ;-) 81 | 82 | 5. Test! 83 | 84 | 6. Commit your changes and push your branch to GitHub:: 85 | 86 | $ git add . 87 | $ git commit -m "Your detailed description of your changes." 88 | $ git push origin name-of-your-bugfix-or-feature 89 | 90 | 7. Submit a pull request through the GitHub website. 91 | 92 | 93 | Pull Request Guidelines 94 | ----------------------- 95 | 96 | Before you submit a pull request, check that it meets these guidelines: 97 | 98 | 1. The pull request should include tests. 99 | 2. If the pull request adds functionality, the docs should be updated. Put 100 | your new functionality into a function with a docstring, and add the 101 | feature to the list in README.rst. 102 | 3. The pull request should work for JS and node. Travis or others would be an interesting 103 | way for automate the tests... 104 | 105 | 106 | Dependency on Bigchaindb 107 | ~~~~~~~~~~~~~~~~~~~~~~~~ 108 | 109 | This version is compatible from BigchainDB server v0.10.1 110 | 111 | .. _bigchaindb-driver: https://github.com/bigchaindb/js-bigchaindb-driver 112 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. -------------------------------------------------------------------------------- /LICENSE-docs: -------------------------------------------------------------------------------- 1 | The official BigchainDB documentation, _except for the short code snippets 2 | embedded within it_, is licensed under a Creative Commons Attribution- 3 | ShareAlike 4.0 International license, the full text of which can be found 4 | at http://creativecommons.org/licenses/by-sa/4.0/legalcode 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # [![js-bigchaindb-driver](media/repo-banner@2x.png)](https://www.bigchaindb.com) 8 | 9 | > Official JavaScript driver for [BigchainDB](https://github.com/bigchaindb/bigchaindb) to create transactions in Node.js and the browser. 10 | 11 | [![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) 12 | [![npm](https://img.shields.io/npm/v/bigchaindb-driver.svg)](https://www.npmjs.com/package/bigchaindb-driver) 13 | [![codecov](https://codecov.io/gh/bigchaindb/js-bigchaindb-driver/branch/master/graph/badge.svg)](https://codecov.io/gh/bigchaindb/js-bigchaindb-driver) 14 | [![js ascribe](https://img.shields.io/badge/js-ascribe-39BA91.svg)](https://github.com/ascribe/javascript) 15 | [![Build Status](https://travis-ci.com/bigchaindb/js-bigchaindb-driver.svg?branch=master)](https://travis-ci.com/bigchaindb/js-bigchaindb-driver) 16 | [![Greenkeeper badge](https://badges.greenkeeper.io/bigchaindb/js-bigchaindb-driver.svg)](https://greenkeeper.io/) 17 | 18 | - [Main Documentation](https://docs.bigchaindb.com/projects/js-driver/en/latest/usage.html) 19 | - [Driver API reference](API.md) 20 | 21 | ## Compatibility 22 | 23 | | BigchainDB Server | BigchainDB JavaScript Driver | 24 | | ----------------- |------------------------------| 25 | | `0.10` | `0.1.x` | 26 | | `1.0.0` | `0.3.x` | 27 | | `1.3.x` | `3.x.x` | 28 | | `>= 2.0.0` | `4.x.x` | 29 | 30 | ## Breaking changes 31 | 32 | - **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) 33 | - **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) 34 | 35 | ## Table of Contents 36 | 37 | - [Installation and Usage](#installation-and-usage) 38 | - [Example: Create a transaction](#example-create-a-transaction) 39 | - [Browser usage](#browser-usage) 40 | - [BigchainDB Documentation](#bigchaindb-documentation) 41 | - [Speed Optimizations](#speed-optimizations) 42 | - [Development](#development) 43 | - [Release Process](#release-process) 44 | - [Authors](#authors) 45 | - [Licenses](#licenses) 46 | 47 | --- 48 | 49 | ## Installation and Usage 50 | 51 | ```bash 52 | npm install bigchaindb-driver 53 | ``` 54 | 55 | ```js 56 | const driver = require('bigchaindb-driver') 57 | // or ES6+ 58 | import driver from 'bigchaindb-driver' 59 | ``` 60 | 61 | ### Example: Create a transaction 62 | 63 | ```js 64 | const driver = require('bigchaindb-driver') 65 | const base58 = require('bs58'); 66 | const crypto = require('crypto'); 67 | const { Ed25519Sha256 } = require('crypto-conditions'); 68 | 69 | // BigchainDB server instance (e.g. https://example.com/api/v1/) 70 | const API_PATH = 'http://localhost:9984/api/v1/' 71 | 72 | // Create a new keypair. 73 | const alice = new driver.Ed25519Keypair() 74 | 75 | // Construct a transaction payload 76 | const tx = driver.Transaction.makeCreateTransaction( 77 | // Define the asset to store, in this example it is the current temperature 78 | // (in Celsius) for the city of Berlin. 79 | { city: 'Berlin, DE', temperature: 22, datetime: new Date().toString() }, 80 | 81 | // Metadata contains information about the transaction itself 82 | // (can be `null` if not needed) 83 | { what: 'My first BigchainDB transaction' }, 84 | 85 | // A transaction needs an output 86 | [ driver.Transaction.makeOutput( 87 | driver.Transaction.makeEd25519Condition(alice.publicKey)) 88 | ], 89 | alice.publicKey 90 | ) 91 | 92 | // Sign the transaction with private keys 93 | const txSigned = driver.Transaction.signTransaction(tx, alice.privateKey) 94 | 95 | // Or use delegateSignTransaction to provide your own signature function 96 | function signTransaction() { 97 | // get privateKey from somewhere 98 | const privateKeyBuffer = Buffer.from(base58.decode(alice.privateKey)) 99 | return function sign(serializedTransaction, input, index) { 100 | const transactionUniqueFulfillment = input.fulfills ? serializedTransaction 101 | .concat(input.fulfills.transaction_id) 102 | .concat(input.fulfills.output_index) : serializedTransaction 103 | const transactionHash = crypto.createHash('sha3-256').update(transactionUniqueFulfillment).digest() 104 | const ed25519Fulfillment = new Ed25519Sha256(); 105 | ed25519Fulfillment.sign(transactionHash, privateKeyBuffer); 106 | return ed25519Fulfillment.serializeUri(); 107 | }; 108 | } 109 | const txSigned = driver.Transaction.delegateSignTransaction(tx, signTransaction()) 110 | 111 | // Send the transaction off to BigchainDB 112 | const conn = new driver.Connection(API_PATH) 113 | 114 | conn.postTransactionCommit(txSigned) 115 | .then(retrievedTx => console.log('Transaction', retrievedTx.id, 'successfully posted.')) 116 | ``` 117 | 118 | ### Browser usage 119 | 120 | ```html 121 | 122 | 123 | 124 | 125 | BigchainDB boilerplate 126 | 127 | 128 | 129 | 168 | 169 | 170 |

Hello BigchainDB

171 |

Your transaction id is: processing

172 | 173 | 174 | ``` 175 | 176 | ## BigchainDB Documentation 177 | 178 | - [The Hitchhiker's Guide to BigchainDB](https://www.bigchaindb.com/developers/guide/) 179 | - [HTTP API Reference](https://docs.bigchaindb.com/projects/server/en/latest/http-client-server-api.html) 180 | - [The Transaction Model](https://docs.bigchaindb.com/projects/server/en/latest/data-models/transaction-model.html?highlight=crypto%20conditions) 181 | - [Inputs and Outputs](https://docs.bigchaindb.com/projects/server/en/latest/data-models/inputs-outputs.html) 182 | - [Asset Transfer](https://docs.bigchaindb.com/projects/py-driver/en/latest/usage.html#asset-transfer) 183 | - [All BigchainDB Documentation](https://docs.bigchaindb.com/) 184 | 185 | ## Speed Optimizations 186 | 187 | This implementation plays "safe" by using JS-native (or downgradable) libraries for its crypto-related functions to keep compatibilities with the browser. If you do want some more speed, feel free to explore the following: 188 | 189 | * [chloride](https://github.com/dominictarr/chloride), or its underlying [sodium](https://github.com/paixaop/node-sodium) library 190 | * [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) 191 | 192 | ## Development 193 | 194 | ```js 195 | git clone git@github.com:bigchaindb/js-bigchaindb-driver.git 196 | cd js-bigchaindb-driver/ 197 | 198 | npm i 199 | npm run dev 200 | ``` 201 | 202 | 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`: 203 | 204 | ```bash 205 | npm run doc 206 | ``` 207 | 208 | ## Release Process 209 | 210 | See the file named [RELEASE_PROCESS.md](RELEASE_PROCESS.md). 211 | 212 | ## Authors 213 | 214 | * inspired by [`js-bigchaindb-quickstart`](https://github.com/sohkai/js-bigchaindb-quickstart) of @sohkhai [thanks] 215 | * BigchainDB 216 | * BigchainDB contributors 217 | 218 | ## Licenses 219 | 220 | See [LICENSE](LICENSE) and [LICENSE-docs](LICENSE-docs). 221 | -------------------------------------------------------------------------------- /RELEASE_PROCESS.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Our Release Process 8 | 9 | ## Notes 10 | 11 | BigchainDB follows 12 | [the Python form of Semantic Versioning](https://packaging.python.org/tutorials/distributing-packages/#choosing-a-versioning-scheme) 13 | (i.e. MAJOR.MINOR.PATCH), 14 | which is almost identical 15 | to [regular semantic versioning](http://semver.org/), but there's no hyphen, e.g. 16 | 17 | - `0.9.0` for a typical final release 18 | - `4.5.2a1` not `4.5.2-a1` for the first Alpha release 19 | - `3.4.5rc2` not `3.4.5-rc2` for Release Candidate 2 20 | 21 | **Note:** For Git tags (which are used to identify releases on GitHub), we append a `v` in front. 22 | 23 | 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. 24 | 25 | ## Steps 26 | 27 | 1. Make sure you have a recent version of node and npm. 28 | 1. `npm install` 29 | 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. 30 | 1. Make sure your local `master` branch is in sync with GitHub: `git checkout master` and `git pull` 31 | 1. Do a test build: 32 | 33 | `npm run build` 34 | 35 | If that fails, then get it working. 36 | 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. 37 | 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). 38 | 39 | `npm login` 40 | 41 | 1. release-it needs a Github personal access token so it can interact with GitHub on your behalf. To get one, go to: 42 | 43 | [https://github.com/settings/tokens](https://github.com/settings/tokens) 44 | 45 | and then make that token available as an environment variable, e.g. 46 | 47 | `export GITHUB_TOKEN="f941e0..."` 48 | 49 | 1. Do the release: 50 | 51 | - For a patch release, do `npm run release` 52 | - For a minor release, do `npm run release-minor` 53 | - For a major release, do `npm run release-major` 54 | 55 | If your npm account is using two-factor authentication, 56 | you will have to append a one-time password (OTP) like `--npm.otp=123456`. 57 | The above command will automatically do a bunch of things: 58 | 59 | - bump the project version in `package.json`, then git commit and git push it. 60 | - create a new Git tag of the form `v{verson}`, e.g. `v1.2.3` 61 | - create a new [GitHub release](https://github.com/bigchaindb/js-bigchaindb-driver/releases). 62 | - publish a new npm release 63 | 64 | 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). 65 | 66 | 1. Make sure everything worked as expected. 67 | 68 | - Was the version number bumped properly in [package.json](package.json)? 69 | - Was a new Git tag created? See the [list of tags](https://github.com/bigchaindb/js-bigchaindb-driver/tags). 70 | - Was a new GitHub release created? See the [list of releases](https://github.com/bigchaindb/js-bigchaindb-driver/releases). 71 | - Was a new npm package published on npm? [Check on npmjs.com](https://www.npmjs.com/package/bigchaindb-driver). 72 | 73 | 1. You can edit the description of the GitHub release to add or remove details. 74 | 75 | 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: 76 | 77 | 1. Click on "Builds", select "latest" from the drop-down menu, then click the "Build Version:" button. 78 | 1. Wait for the build of "latest" to finish. This can take a few minutes. 79 | 1. Go to Admin --> Advanced Settings 80 | and make sure that "Default branch:" (i.e. what "latest" points to) 81 | is set to the new release's tag, e.g. `v0.9.1`. 82 | (It won't be an option if you didn't wait for the build of "latest" to finish.) 83 | Then scroll to the bottom and click "Save". 84 | 1. Go to Admin --> Versions 85 | and under **Choose Active Versions**, do these things: 86 | 87 | 1. Make sure that the new version's tag is "Active" and "Public" 88 | 1. Make sure the **stable** branch is _not_ active. 89 | 1. Scroll to the bottom of the page and click "Save". 90 | 91 | Congratulations, you have released a new version of the BigchainDB JavaScript Driver! 92 | -------------------------------------------------------------------------------- /compose/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | 3 | RUN apt-get update && apt-get install -y vim 4 | 5 | RUN mkdir -p /usr/src/app 6 | WORKDIR /usr/src/app 7 | 8 | RUN pip install --upgrade pip ipdb ipython 9 | 10 | COPY . /usr/src/app/ 11 | 12 | RUN pip install git+https://github.com/bigchaindb/bigchaindb.git 13 | -------------------------------------------------------------------------------- /compose/tendermint/tmdata/config.toml: -------------------------------------------------------------------------------- 1 | # This is a TOML config file. 2 | # For more information, see https://github.com/toml-lang/toml 3 | 4 | proxy_app = "tcp://bigchaindb:46658" 5 | moniker = "anonymous" 6 | fast_sync = true 7 | db_backend = "leveldb" 8 | log_level = "state:debug,*:error" 9 | 10 | [consensus] 11 | create_empty_blocks = false 12 | 13 | [rpc] 14 | laddr = "tcp://0.0.0.0:46657" 15 | 16 | [p2p] 17 | laddr = "tcp://0.0.0.0:46656" 18 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Copyright BigchainDB GmbH and BigchainDB contributors 2 | # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | # Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | version: '2.1' 6 | 7 | services: 8 | mongodb: 9 | image: mongo:3.6 10 | ports: 11 | - "27017" 12 | command: mongod 13 | bigchaindb: 14 | depends_on: 15 | - mongodb 16 | - tendermint 17 | image: bigchaindb/bigchaindb:master 18 | environment: 19 | BIGCHAINDB_DATABASE_HOST: mongodb 20 | BIGCHAINDB_DATABASE_PORT: 27017 21 | BIGCHAINDB_SERVER_BIND: 0.0.0.0:9984 22 | BIGCHAINDB_WSSERVER_HOST: 0.0.0.0 23 | BIGCHAINDB_TENDERMINT_HOST: tendermint 24 | BIGCHAINDB_TENDERMINT_PORT: 26657 25 | ports: 26 | - "9984:9984" 27 | - "9985:9985" 28 | - "26658" 29 | healthcheck: 30 | test: ["CMD", "bash", "-c", "curl http://bigchaindb:9984 && curl http://tendermint:26657/abci_query"] 31 | interval: 3s 32 | timeout: 5s 33 | retries: 3 34 | command: -l DEBUG start 35 | tendermint: 36 | image: tendermint/tendermint:v0.31.5 37 | # volumes: 38 | # - ./tmdata:/tendermint 39 | entrypoint: '' 40 | ports: 41 | - "26656" 42 | - "26657" 43 | command: sh -c "tendermint init && tendermint node --consensus.create_empty_blocks=false --proxy_app=tcp://bigchaindb:26658" 44 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = BigchainDBJavascriptDriver 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | .PHONY: clean 18 | clean: 19 | rm -rf $(BUILDDIR)/* 20 | @echo 21 | @echo "Removed $(BUILDDIR)/html." 22 | 23 | .PHONY: html 24 | html: 25 | $(SPHINXBUILD) -b html $(SOURCEDIR) $(BUILDDIR)/html 26 | @echo 27 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 28 | 29 | # Catch-all target: route all unknown targets to Sphinx using the new 30 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 31 | %: Makefile 32 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 33 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # BigchainDBJavaScriptDriverDocs 8 | BigchainDB JavaScript Driver Documentation with Sphinx 9 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=BigchainDBJavascriptDriver 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx~=1.0 2 | recommonmark>=0.4.0 3 | sphinx-rtd-theme>=0.2.4 4 | -------------------------------------------------------------------------------- /docs/source/.conf.py.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigchaindb/js-bigchaindb-driver/17d3a02cb31749aa008061f6f49042059b775512/docs/source/.conf.py.swp -------------------------------------------------------------------------------- /docs/source/advanced.rst: -------------------------------------------------------------------------------- 1 | 2 | .. Copyright BigchainDB GmbH and BigchainDB contributors 3 | SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | ================= 7 | Advanced Examples 8 | ================= 9 | 10 | Crypto Conditions 11 | ----------------- 12 | 13 | Let's start with a basic use case example. Alice bought a bicycle for €240. 14 | She will use the bike for a year and will give it to her daughter afterwards. 15 | First, we create an asset registering the bicycle: 16 | 17 | .. code-block:: js 18 | 19 | const txCreateAliceSimple = driver.Transaction.makeCreateTransaction( 20 | {'asset': 'bicycle'}, 21 | {'purchase_price': '€240'}, 22 | [ 23 | driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) 24 | ], 25 | alice.publicKey 26 | ) 27 | 28 | const txCreateAliceSimpleSigned = driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey) 29 | 30 | After a year, she decides it's time to transfer the bicycle to her daughter Carly. 31 | 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. 32 | So, Alice needs a crypto conditions that defines that she or her daughter can sign the ``TRANSFER`` transaction to a possible buyer. 33 | 34 | We need to define a threshold as well. This defines how many persons have to sign the transaction to ``TRANSFER`` it. 35 | In this case, we define two subconditions with the public keys from Alice and Carly. Next, we set the threshold to **one**. 36 | This means that just one of the subconditions has to sign the transaction to transfer it. 37 | This can be the mother Alice, or Carly herself. 38 | 39 | .. code-block:: js 40 | 41 | // Create condition for Alice and Carly 42 | let subConditionFrom = driver.Transaction.makeEd25519Condition(alice.publicKey, false) 43 | let subConditionTo = driver.Transaction.makeEd25519Condition(carly.publicKey, false) 44 | 45 | // Create condition object with threshold and subconditions 46 | let condition = driver.Transaction.makeThresholdCondition(1, [subConditionFrom, subConditionTo]) 47 | 48 | // Generate output with condition added 49 | let output = driver.Transaction.makeOutput(condition) 50 | 51 | // Add Carly to the output.public_keys field so she is the owner 52 | output.public_keys = [carly.publicKey] 53 | 54 | let transaction = driver.Transaction.makeTransferTransaction( 55 | [{ tx: txCreateAliceSimpleSigned, output_index: 0 }], 56 | [output], 57 | {'meta': 'Transfer to new user with conditions'} 58 | ); 59 | 60 | // Add alice as previous owner 61 | transaction.inputs[0].owners_before = [alice.publicKey] 62 | 63 | // Because the addition of crypto conditions, the id for the transaction has to be regenerated 64 | delete transaction.id 65 | transaction.id = sha3.sha3_256 66 | .create() 67 | .update(driver.Transaction.serializeTransactionIntoCanonicalString(transaction)) 68 | .hex() 69 | 70 | // Alice has to sign this transfer because she is still the owner of the created asset 71 | let signedCryptoConditionTx = driver.Transaction.signTransaction(transaction, alice.privateKey) 72 | 73 | As you can see, we need to generate a new transactionId because we have added crypto conditions. 74 | We do this with the js-sha3 package, you need to install this package through ``npm``: 75 | 76 | ``npm install --save js-sha3`` 77 | 78 | Don't forget to import the package in your code: 79 | 80 | .. code-block:: js 81 | 82 | import * as sha3 from 'js-sha3' 83 | 84 | 85 | 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) 86 | 87 | .. TODO: Document Utils when finished 88 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright BigchainDB GmbH and BigchainDB contributors 3 | # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | # Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | # 7 | # BigchainDB Javascript Driver documentation build configuration file, created by 8 | # sphinx-quickstart on Wed Aug 2 15:39:03 2017. 9 | # 10 | # This file is execfile()d with the current directory set to its 11 | # containing dir. 12 | # 13 | # Note that not all possible configuration values are present in this 14 | # autogenerated file. 15 | # 16 | # All configuration values have a default; values that are commented out 17 | # serve to show the default. 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | # 23 | # import os 24 | # import sys 25 | # sys.path.insert(0, os.path.abspath('.')) 26 | 27 | 28 | 29 | # -- General configuration ------------------------------------------------ 30 | 31 | # If your documentation needs a minimal Sphinx version, state it here. 32 | # 33 | # needs_sphinx = '1.0' 34 | 35 | import datetime 36 | import sphinx_rtd_theme 37 | 38 | from recommonmark.parser import CommonMarkParser 39 | 40 | # Add any Sphinx extension module names here, as strings. They can be 41 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 42 | # ones. 43 | extensions = [ 44 | 'sphinx.ext.autodoc', 45 | ] 46 | 47 | # Add any paths that contain templates here, relative to this directory. 48 | templates_path = ['ntemplates'] 49 | 50 | source_parsers = { 51 | '.md': CommonMarkParser, 52 | } 53 | 54 | # The suffix(es) of source filenames. 55 | # You can specify multiple suffix as a list of string: 56 | # 57 | # source_suffix = ['.rst', '.md'] 58 | source_suffix = ['.rst', '.md'] 59 | 60 | # The master toctree document. 61 | master_doc = 'index' 62 | 63 | # General information about the project. 64 | project = 'BigchainDB Javascript Driver' 65 | now = datetime.datetime.now() 66 | copyright = str(now.year) + ', BigchainDB Contributors' 67 | author = 'BigchainDB Contributors' 68 | 69 | # The version info for the project you're documenting, acts as replacement for 70 | # |version| and |release|, also used in various other places throughout the 71 | # built documents. 72 | # 73 | # The short X.Y version. 74 | version = '0.0.1' 75 | # The full version, including alpha/beta/rc tags. 76 | release = '0.0.1' 77 | 78 | # The language for content autogenerated by Sphinx. Refer to documentation 79 | # for a list of supported languages. 80 | # 81 | # This is also used if you do content translation via gettext catalogs. 82 | # Usually you set "language" from the command line for these cases. 83 | language = None 84 | 85 | # List of patterns, relative to source directory, that match files and 86 | # directories to ignore when looking for source files. 87 | # This patterns also effect to html_static_path and html_extra_path 88 | exclude_patterns = [] 89 | 90 | # The name of the Pygments (syntax highlighting) style to use. 91 | pygments_style = 'sphinx' 92 | 93 | # If true, `todo` and `todoList` produce output, else they produce nothing. 94 | todo_include_todos = False 95 | 96 | 97 | # -- Options for HTML output ---------------------------------------------- 98 | 99 | # The theme to use for HTML and HTML Help pages. See the documentation for 100 | # a list of builtin themes. 101 | # 102 | html_theme = 'sphinx_rtd_theme' 103 | 104 | # Theme options are theme-specific and customize the look and feel of a theme 105 | # further. For a list of options available for each theme, see the 106 | # documentation. 107 | # 108 | # html_theme_options = {} 109 | 110 | # Add any paths that contain custom static files (such as style sheets) here, 111 | # relative to this directory. They are copied after the builtin static files, 112 | # so a file named "default.css" will overwrite the builtin "default.css". 113 | # html_static_path = ['nstatic'] 114 | # Commented out this option because Sphinx can not find the path 115 | 116 | # Custom sidebar templates, must be a dictionary that maps document names 117 | # to template names. 118 | # 119 | # This is required for the alabaster theme 120 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 121 | html_sidebars = { 122 | '**': [ 123 | 'about.html', 124 | 'navigation.html', 125 | 'relations.html', # needs 'show_related': True theme option to display 126 | 'searchbox.html', 127 | 'donate.html', 128 | ] 129 | } 130 | 131 | 132 | # -- Options for HTMLHelp output ------------------------------------------ 133 | 134 | # Output file base name for HTML help builder. 135 | htmlhelp_basename = 'BigchainDBJavascriptDriverdoc' 136 | 137 | 138 | # -- Options for LaTeX output --------------------------------------------- 139 | 140 | latex_elements = { 141 | # The paper size ('letterpaper' or 'a4paper'). 142 | # 143 | # 'papersize': 'letterpaper', 144 | 145 | # The font size ('10pt', '11pt' or '12pt'). 146 | # 147 | # 'pointsize': '10pt', 148 | 149 | # Additional stuff for the LaTeX preamble. 150 | # 151 | # 'preamble': '', 152 | 153 | # Latex figure (float) alignment 154 | # 155 | # 'figure_align': 'htbp', 156 | } 157 | 158 | # Grouping the document tree into LaTeX files. List of tuples 159 | # (source start file, target name, title, 160 | # author, documentclass [howto, manual, or own class]). 161 | latex_documents = [ 162 | (master_doc, 'BigchainDBJavascriptDriver.tex', 'BigchainDB Javascript Driver Documentation', 163 | 'BigchainDB', 'manual'), 164 | ] 165 | 166 | 167 | # -- Options for manual page output --------------------------------------- 168 | 169 | # One entry per manual page. List of tuples 170 | # (source start file, name, description, authors, manual section). 171 | man_pages = [ 172 | (master_doc, 'bigchaindbjavascriptdriver', 'BigchainDB Javascript Driver Documentation', 173 | [author], 1) 174 | ] 175 | 176 | 177 | # -- Options for Texinfo output ------------------------------------------- 178 | 179 | # Grouping the document tree into Texinfo files. List of tuples 180 | # (source start file, target name, title, author, 181 | # dir menu entry, description, category) 182 | texinfo_documents = [ 183 | (master_doc, 'BigchainDBJavascriptDriver', 'BigchainDB Javascript Driver Documentation', 184 | author, 'BigchainDBJavascriptDriver', 'One line description of project.', 185 | 'Miscellaneous'), 186 | ] 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | 2 | .. Copyright BigchainDB GmbH and BigchainDB contributors 3 | SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | BigchainDB Javascript Driver Documentation 7 | ========================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | ← Back to All BigchainDB Docs 13 | readme 14 | quickstart 15 | usage 16 | advanced 17 | 18 | Indices and tables 19 | ================== 20 | 21 | * :ref:`genindex` 22 | * :ref:`modindex` 23 | * :ref:`search` 24 | -------------------------------------------------------------------------------- /docs/source/quickstart.rst: -------------------------------------------------------------------------------- 1 | 2 | .. Copyright BigchainDB GmbH and BigchainDB contributors 3 | SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | ========================= 7 | Quickstart / Installation 8 | ========================= 9 | 10 | Installation with package manager npm: 11 | 12 | .. code-block:: bash 13 | 14 | $ npm install bigchaindb-driver 15 | -------------------------------------------------------------------------------- /docs/source/readme.rst: -------------------------------------------------------------------------------- 1 | 2 | .. Copyright BigchainDB GmbH and BigchainDB contributors 3 | SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 4 | Code is Apache-2.0 and docs are CC-BY-4.0 5 | 6 | BigchainDB JavaScript Driver 7 | ============================ 8 | 9 | .. image:: https://img.shields.io/npm/v/bigchaindb-driver.svg 10 | :target: https://www.npmjs.com/package/bigchaindb-driver 11 | 12 | .. image:: https://codecov.io/gh/bigchaindb/js-bigchaindb-driver/branch/master/graph/badge.svg 13 | :target: https://codecov.io/gh/bigchaindb/js-bigchaindb-driver 14 | 15 | .. image:: https://img.shields.io/badge/js-ascribe-39BA91.svg 16 | :target: https://github.com/ascribe/javascript 17 | 18 | .. image:: https://travis-ci.com/bigchaindb/js-bigchaindb-driver.svg?branch=master 19 | :target: https://travis-ci.com/bigchaindb/js-bigchaindb-driver 20 | 21 | .. image:: https://badges.greenkeeper.io/bigchaindb/js-bigchaindb-driver.svg 22 | :target: https://greenkeeper.io/ 23 | 24 | Features 25 | -------- 26 | 27 | * Support for preparing, fulfilling, and sending transactions to a BigchainDB 28 | node. 29 | * Retrieval of transactions by id. 30 | * Getting status of a transaction by id. 31 | 32 | Compatibility Matrix 33 | -------------------- 34 | 35 | +-----------------------+----------------------------------+ 36 | | **BigchainDB Server** | **BigchainDB Javascript Driver** | 37 | +=======================+==================================+ 38 | | ``0.10`` | ``0.1.x`` | 39 | +-----------------------+----------------------------------+ 40 | | ``1.0`` | ``0.3.x`` | 41 | +-----------------------+----------------------------------+ 42 | | ``1.3`` | ``3.x.x`` | 43 | +-----------------------+----------------------------------+ 44 | | ``2.0`` | ``4.x.x`` | 45 | +-----------------------+----------------------------------+ 46 | 47 | 48 | 49 | Older versions 50 | -------------------- 51 | 52 | **Version 4.x.x** 53 | 54 | As part of the changes in the BigchainDB 2.0 server, some endpoints were 55 | modified. In order to be consistent with them, the JS driver does not have 56 | anymore the `pollStatusAndFetchTransaction()` method as there are three 57 | different ways of posting a transaction: 58 | 59 | - `commit` using the `postTransaction` or the `postTransactionCommit`: the response will return after the transaction is committed to a block. 60 | - `sync` using the `postTransactionSync`: the response will return after the transaction is validated. 61 | - `async` using the `postTransactionAsync`: the response will return immediately and not wait to see if the transaction is valid. 62 | 63 | By default in the docs we will use the `postTransactionCommit` as is way of 64 | being sure that the transaction is validated and commited to a block, so 65 | there will not be any issue if you try to do any other action with the asset immediately. 66 | 67 | Note: In order to not create breaking changes, both methods `postTransaction` and `postTransactionCommit` are kept although 68 | they do exactly the same 69 | 70 | 71 | **Version 3.2.x** 72 | 73 | For versions below 3.2, a transfer transaction looked like: 74 | 75 | .. code-block:: js 76 | 77 | const createTranfer = BigchainDB.Transaction.makeTransferTransaction( 78 | txCreated, 79 | metadata, [BigchainDB.Transaction.makeOutput( 80 | BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))], 81 | 0 82 | ) 83 | 84 | const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer, 85 | keypair.privateKey) 86 | 87 | 88 | In order to upgrade and do it compatible with the new driver version, this 89 | transaction should be now: 90 | 91 | .. code-block:: js 92 | 93 | const createTranfer = BigchainDB.Transaction.makeTransferTransaction( 94 | [{ tx: txCreated, output_index: 0 }], 95 | [BigchainDB.Transaction.makeOutput( 96 | BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))], 97 | metaData 98 | ) 99 | 100 | const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer, 101 | keypair.privateKey) 102 | 103 | 104 | The upgrade allows to create transfer transaction spending outputs that belong 105 | to different transactions. So for instance is now possible to create a transfer 106 | transaction spending two outputs from two different create transactions: 107 | 108 | 109 | .. code-block:: js 110 | 111 | const createTranfer = BigchainDB.Transaction.makeTransferTransaction( 112 | [{ tx: txCreated1, output_index: 0 }, 113 | { tx: txCreated2, output_index: 0}], 114 | [BigchainDB.Transaction.makeOutput( 115 | BigchainDB.Transaction.makeEd25519Condition(alice.publicKey))], 116 | metaData 117 | ) 118 | 119 | const signedTransfer = BigchainDB.Transaction.signTransaction(createTranfer, 120 | keypair.privateKey) 121 | -------------------------------------------------------------------------------- /docs/upgrade-guides/0.3.0.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Updating js-bigchaindb-driver from v0.1.x to v0.3.0 8 | 9 | The latest version of js-bigchaindb-driver contains breaking changes to its 10 | external API. In this document, we enumerate all changes to allow you to make 11 | upgrades efficiently. 12 | 13 | Note that upgrading the js-bigchaindb-driver to v0.3.0 was done to enable 14 | functionality included in the latest (v1.0) BigchainDB release. A full list of 15 | BigchainDB v1.0's breaking changes can be found 16 | [here](https://github.com/bigchaindb/bigchaindb/blob/17913dca682ff105540c0ea73365f1763efc2083/docs/upgrade-guides/v0.10--%3Ev1.0.md). 17 | Note that v1.0 [contains breaking changes to its core data 18 | models](https://github.com/bigchaindb/bigchaindb/blob/17913dca682ff105540c0ea73365f1763efc2083/docs/upgrade-guides/v0.10--%3Ev1.0.md#breaking-changes-to-the-data-model). 19 | 20 | This document will just go into the very specific breaking changes affecting 21 | the JavaScript driver. 22 | 23 | 24 | ### Breaking changes to js-bigchaindb-driver's APIs 25 | 26 | #### Output amount is now a string 27 | 28 | ```js 29 | // old 30 | export default function makeOutput(condition, amount = 1) {} 31 | 32 | // new 33 | export default function makeOutput(condition, amount = '1') {} 34 | ``` 35 | 36 | 37 | #### Update to Crypto-Conditions version 2 38 | 39 | All conditions or fulfillments passed manually to the driver now need to comply 40 | with ILP's Crypto-Condition version 2 specification. For more information, 41 | [see the updated 42 | specification](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02) 43 | or checkout the [latest reference implementation of Crypto-Conditions in 44 | JavaScript](https://github.com/interledgerjs/five-bells-condition). 45 | 46 | 47 | #### Several `Connection` methods now require positional arguments 48 | 49 | ##### `Connection.listBlocks` 50 | 51 | ```js 52 | // old 53 | new Connection(PATH).listBlocks({ tx_id, status }) 54 | 55 | // new 56 | new Connection(PATH).listBlocks(transactionId, status) 57 | ``` 58 | 59 | 60 | ##### `Connection.listOutputs` 61 | 62 | ```js 63 | // old 64 | new Connection(PATH).listOutputs({ public_key, unspent }) 65 | 66 | // new 67 | new Connection(PATH).listOutputs(publicKey, spent) 68 | ``` 69 | 70 | **NOTE:** The `unspent` flag has been inversed. This is inline [with breaking 71 | changes to BigchainDB 72 | v1.0](https://github.com/bigchaindb/bigchaindb/blob/17913dca682ff105540c0ea73365f1763efc2083/docs/upgrade-guides/v0.10--%3Ev1.0.md#get-apiv1outputs). 73 | 74 | 75 | ##### `Connection.listTransactions` 76 | 77 | ```js 78 | // old 79 | new Connection(PATH).listTransactions({ asset_id, operation }) 80 | 81 | // new 82 | new Connection(PATH).listTransactions(assetId, operation) 83 | ``` 84 | 85 | 86 | ### Newly added endpoints 87 | 88 | ##### `Connection.searchAsset` 89 | 90 | ```js 91 | // new 92 | new Connection(PATH).searchAssets(search) 93 | ``` 94 | 95 | A querying interface to text-search all assets in BigchainDB. For more 96 | documentation, [see BigchainDB's HTTP 97 | API](https://docs.bigchaindb.com/projects/server/en/latest/http-client-server-api.html#assets). 98 | 99 | 100 | ### Newly available bundles and CDN hosting 101 | 102 | The driver is now bundled automatically each time we publish it to npm.com. We 103 | now ship packages for `commonjs`, `commonjs2`, `amd`, `umd`, `window` and 104 | node.js. Thanks to unpkg.com, we're also able to provide all these packages on 105 | a CDN. A link to all the bundles can be found 106 | [here](https://unpkg.com/bigchaindb-driver@0.3.0/dist/browser/). 107 | 108 | 109 | A few notes: 110 | 111 | - Adjust version number in link as appropriate 112 | - only include `bigchaindb-driver.*.min.js`, but now everything `bundle.*`. 113 | This is [a known 114 | issue](https://github.com/bigchaindb/js-bigchaindb-driver/issues/66). 115 | -------------------------------------------------------------------------------- /examples/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env"]], 3 | "plugins": [ 4 | "@babel/plugin-syntax-async-generators", 5 | [ 6 | "@babel/plugin-transform-runtime", 7 | { 8 | "absoluteRuntime": false, 9 | "helpers": true, 10 | "regenerator": true 11 | } 12 | ], 13 | "@babel/plugin-transform-regenerator", 14 | "@babel/plugin-transform-async-to-generator" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Quick Notes 8 | `dotenv` is listed as a dependencies in `package.json`. 9 | If you want to use this, add a `.env` file to the root of this project (same level as this `README.md` file) 10 | and replace the variables to fit your specific config. 11 | 12 | ``` 13 | BIGCHAINDB_API_PATH=https://test.bigchaindb.com/api/v1/ 14 | BIGCHAINDB_APP_ID= 15 | BIGCHAINDB_APP_KEY= 16 | ``` 17 | 18 | # Usage 19 | `npm install` -> Installs all required dependencies to run these examples. 20 | 21 | ## Different Examples 22 | **Basic Usage**: Create asset and transfer it to new owner. 23 | -> `npm start` 24 | 25 | **Async/Await Basic Usage**: Basic usage example rewritten with async/await. 26 | -> `npm run basic-async` 27 | 28 | **Querying for Assets**: Query for assetdata or metadata. 29 | -> `npm run query-assets` 30 | 31 | **Seed/Keypair Functionality**: Create keypair with bip39 library. 32 | -> `npm run seed-func` 33 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-driver-bigchaindb-examples", 3 | "version": "1.0.0", 4 | "main": "src/basic-usage.js", 5 | "scripts": { 6 | "build": "npm run clean && babel src -d dist", 7 | "serve": "node dist/basic-usage.js", 8 | "clean": "rimraf ./dist", 9 | "start": "nodemon src/basic-usage.js --exec babel-node", 10 | "query-assets": "nodemon src/query-assets.js --exec babel-node", 11 | "seed-func": "nodemon src/seed-func.js --exec babel-node", 12 | "basic-async": "nodemon src/basic-usage-async-await.js --exec babel-node" 13 | }, 14 | "author": "BigchainDB", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "@babel/cli": "^7.13.0", 18 | "@babel/core": "^7.13.8", 19 | "@babel/eslint-parser": "^7.13.8", 20 | "@babel/node": "7.13.0", 21 | "@babel/plugin-syntax-async-generators": "^7.8.4", 22 | "@babel/plugin-transform-async-to-generator": "^7.13.0", 23 | "@babel/plugin-transform-regenerator": "^7.12.13", 24 | "@babel/plugin-transform-runtime": "^7.13.9", 25 | "@babel/preset-env": "^7.13.9", 26 | "@babel/register": "^7.13.8", 27 | "babel-loader": "^8.2.2", 28 | "nodemon": "^2.0.7", 29 | "rimraf": "^3.0.2" 30 | }, 31 | "repository": "/", 32 | "private": true, 33 | "dependencies": { 34 | "bigchaindb-driver": "^4.1.2", 35 | "bip39": "^3.0.3", 36 | "dotenv": "^8.2.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/src/basic-usage-async-await.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable import/no-unresolved */ 6 | 7 | const driver = require('bigchaindb-driver') 8 | require('dotenv').config() 9 | 10 | // ======== Preparation ======== // 11 | const conn = new driver.Connection('https://test.ipdb.io/api/v1/', { 12 | header1: 'header1_value', 13 | header2: 'header2_value' 14 | }) 15 | 16 | const alice = new driver.Ed25519Keypair() 17 | const bob = new driver.Ed25519Keypair() 18 | 19 | const assetdata = { 20 | 'bicycle': { 21 | 'serial_number': 'abcd1234', 22 | 'manufacturer': 'Bicycle Inc.', 23 | } 24 | } 25 | 26 | const metadata = { 'planet': 'earth' } 27 | 28 | // Call async basic usage function 29 | basicUsage() 30 | 31 | async function basicUsage() { 32 | // ======== Create Transaction Bicycle ======== // 33 | const txCreateAliceSimple = driver.Transaction.makeCreateTransaction( 34 | assetdata, 35 | metadata, 36 | [ 37 | driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) 38 | ], 39 | alice.publicKey 40 | ) 41 | 42 | const txCreateAliceSimpleSigned = 43 | driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey) 44 | 45 | // ======== POST CREATE Transaction ======== // 46 | const createdTx = await conn.postTransactionCommit(txCreateAliceSimpleSigned) 47 | 48 | // ======== POST TRANSFER Transaction ======== // 49 | const txTransferBob = driver.Transaction.makeTransferTransaction( 50 | [{ tx: createdTx, output_index: 0 }], 51 | [driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))], 52 | { price: '100 euro' } 53 | ) 54 | 55 | const txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey) 56 | 57 | await conn.postTransactionCommit(txTransferBobSigned) 58 | 59 | // ======== Querying Assets ======== // 60 | const assets = await conn.searchAssets('Bicycle Inc.') 61 | console.log(assets) // eslint-disable-line no-console 62 | } 63 | -------------------------------------------------------------------------------- /examples/src/basic-usage.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable import/no-unresolved */ 6 | 7 | const driver = require('bigchaindb-driver') 8 | require('dotenv').config() 9 | 10 | // ======== Preparation ======== // 11 | const conn = new driver.Connection('https://test.ipdb.io/api/v1/', { 12 | header1: 'header1_value', 13 | header2: 'header2_value' 14 | }) 15 | 16 | const alice = new driver.Ed25519Keypair() 17 | const bob = new driver.Ed25519Keypair() 18 | 19 | const assetdata = { 20 | 'bicycle': { 21 | 'serial_number': 'abcd1234', 22 | 'manufacturer': 'Bicycle Inc.', 23 | } 24 | } 25 | 26 | const metadata = { 'planet': 'earth' } 27 | 28 | // ======== Create Transaction Bicycle ======== // 29 | const txCreateAliceSimple = driver.Transaction.makeCreateTransaction( 30 | assetdata, 31 | metadata, 32 | [ 33 | driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) 34 | ], 35 | alice.publicKey 36 | ) 37 | 38 | const txCreateAliceSimpleSigned = 39 | driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey) 40 | 41 | // ======== Post Transaction and Fetch Result ======== // 42 | conn.postTransactionCommit(txCreateAliceSimpleSigned) 43 | // ======== Transfer Bicycle to Bob ======== // 44 | .then((fetchedTx) => { 45 | const txTransferBob = driver.Transaction.makeTransferTransaction( 46 | [{ tx: fetchedTx, output_index: 0 }], 47 | [driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(bob.publicKey))], 48 | { price: '100 euro' } 49 | ) 50 | 51 | // Sign transfer transaction with Alice's private key 52 | const txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey) 53 | 54 | return conn.postTransactionCommit(txTransferBobSigned) 55 | }) 56 | .then(tx => { 57 | console.log('Is Bob the owner?', tx.outputs[0].public_keys[0] === bob.publicKey) // eslint-disable-line no-console 58 | console.log('Was Alice the previous owner?', tx.inputs[0].owners_before[0] === alice.publicKey) // eslint-disable-line no-console 59 | }) 60 | 61 | // ======== Search Asset by Serial Number ======== // 62 | .then(() => conn.searchAssets('Bicycle Inc.')) 63 | .then(assets => console.log('Found assets with serial number Bicycle Inc.:', assets)) // eslint-disable-line no-console 64 | -------------------------------------------------------------------------------- /examples/src/query-assets.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable import/no-unresolved */ 6 | 7 | const driver = require('bigchaindb-driver') 8 | require('dotenv').config() 9 | 10 | // ======== Preparation ======== // 11 | const conn = new driver.Connection('https://example.com/api/v1/', { 12 | header1: 'header1_value', 13 | header2: 'header2_value' 14 | }) 15 | 16 | const alice = new driver.Ed25519Keypair() 17 | 18 | // ======== Asset Array ======== // 19 | const assetArray = [] 20 | assetArray.push({ 'bicycle': { 'serial_number': 'abc', 'manufacturer': 'BicyclesInc' } }) 21 | assetArray.push({ 'bicycle': { 'serial_number': 'cde', 'manufacturer': 'BicyclesInc' } }) 22 | assetArray.push({ 'bicycle': { 'serial_number': 'fgh', 'manufacturer': 'BicyclesInc' } }) 23 | 24 | const metadata = { 'planet': 'Pluto' } 25 | 26 | // ======== Create Transactions for bicycles ======== // 27 | function createTx(assetdata) { 28 | const txCreate = driver.Transaction.makeCreateTransaction( 29 | assetdata, 30 | metadata, 31 | [ 32 | driver.Transaction.makeOutput(driver.Transaction.makeEd25519Condition(alice.publicKey)) 33 | ], 34 | alice.publicKey 35 | ) 36 | 37 | const txCreateSigned = driver.Transaction.signTransaction(txCreate, alice.privateKey) 38 | return conn.postTransactionCommit(txCreateSigned) 39 | } 40 | 41 | // ======== Execute all promises in order to post transactions and fetch them ======== // 42 | Promise.all(assetArray.map(createTx)) 43 | 44 | // ======== Querying Assets for Assetdata ======== // 45 | .then(() => conn.searchAssets('BicyclesInc')) 46 | .then(assets => console.log('Found assets with serial number "BicyclesInc":', assets)) // eslint-disable-line no-console 47 | 48 | // ======== Querying Assets for Metadata ======== // 49 | .then(() => conn.searchMetadata('Pluto')) 50 | .then(assets => console.log('Found assets with metadata "Pluto":', assets)) // eslint-disable-line no-console 51 | -------------------------------------------------------------------------------- /examples/src/seed-func.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable import/no-unresolved */ 6 | 7 | import bip39 from 'bip39' 8 | 9 | const driver = require('bigchaindb-driver') 10 | 11 | // ======== Create Keypair ======== // 12 | /** 13 | * Use a passphrase to derive a keypair 14 | * If you use the same seed -> you will derive the same keypair 15 | * 16 | * mnemnoicToSeed() transforms the passphrase you gave as an input 17 | * to a byteArray 18 | * 19 | * BigchainDB however only accepts an input length of 32 characters 20 | * so we have to slice this to give it as input for driver.Ed25519Keypair() 21 | * 22 | * Is it safe to slice? Yes, a seed of length 32 is very safe according 23 | * to related papers discussing this. 24 | */ 25 | const passphrase = 'This is a random passphrase' 26 | const seed = bip39.mnemonicToSeed(passphrase).slice(0, 32) 27 | 28 | const keypair = new driver.Ed25519Keypair(seed) 29 | 30 | console.log(`Public Key: ${keypair.publicKey} - Private Key: ${keypair.privateKey}`) // eslint-disable-line no-console 31 | 32 | // ======== Other Bip39 Functionality not related to BigchainDB ======== // 33 | 34 | /* Create Random passphrase */ 35 | const mnemonic = bip39.generateMnemonic() 36 | console.log('Random passphrase: ', mnemonic) // eslint-disable-line no-console 37 | 38 | /* Validate mnemnoic */ 39 | console.log(bip39.validateMnemonic(mnemonic)) // eslint-disable-line no-console 40 | console.log(bip39.validateMnemonic('some random strings together but to short')) // eslint-disable-line no-console 41 | -------------------------------------------------------------------------------- /media/repo-banner.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigchaindb/js-bigchaindb-driver/17d3a02cb31749aa008061f6f49042059b775512/media/repo-banner.sketch -------------------------------------------------------------------------------- /media/repo-banner@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bigchaindb/js-bigchaindb-driver/17d3a02cb31749aa008061f6f49042059b775512/media/repo-banner@2x.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bigchaindb-driver", 3 | "version": "4.3.0", 4 | "description": "Node.js driver for BigchainDB", 5 | "homepage": "https://www.bigchaindb.com/", 6 | "bugs": "https://github.com/bigchaindb/js-bigchaindb-driver/issues", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/bigchaindb/js-bigchaindb-driver.git" 10 | }, 11 | "license": "Apache-2.0", 12 | "author": "BigchainDB", 13 | "files": [ 14 | "dist", 15 | "types" 16 | ], 17 | "main": "./dist/node/index.js", 18 | "browser": "./dist/browser/bigchaindb-driver.cjs2.min.js", 19 | "types": "./types/index.d.ts", 20 | "sideEffects": false, 21 | "scripts": { 22 | "lint": "eslint .", 23 | "lint:fix": "eslint . --fix", 24 | "build": "npm run clean && npm run build:cjs && npm run build:dist", 25 | "build:bundle": "webpack", 26 | "build:cjs": "cross-env BABEL_ENV=cjs babel ./src -d dist/node", 27 | "build:dist": "cross-env NODE_ENV=production webpack", 28 | "dev": "webpack -w", 29 | "clean": "rimraf dist/bundle dist/browser dist/node", 30 | "test": "npm run lint && nyc ava && npm run report-coverage", 31 | "thanks": "cowsay Hi, thanks for your interest in BigchainDB. We appreciate your contribution!", 32 | "release": "read -p 'GITHUB_TOKEN: ' GITHUB_TOKEN && export GITHUB_TOKEN=$GITHUB_TOKEN && release-it --src.tagName='v%s'", 33 | "release-minor": "release-it minor --non-interactive", 34 | "release-major": "release-it major --non-interactive", 35 | "prepublishOnly": "npm run build", 36 | "report-coverage": "nyc report --reporter=lcov > coverage.lcov && codecov", 37 | "doc": "documentation build src/index.js -f md -o API.md -g --markdown-toc" 38 | }, 39 | "devDependencies": { 40 | "@ava/babel": "^2.0.0", 41 | "@babel/cli": "^7.17.0", 42 | "@babel/core": "^7.17.2", 43 | "@babel/eslint-parser": "^7.17.0", 44 | "@babel/plugin-proposal-export-default-from": "^7.16.7", 45 | "@babel/plugin-proposal-object-rest-spread": "^7.16.7", 46 | "@babel/plugin-syntax-async-generators": "^7.8.4", 47 | "@babel/plugin-transform-async-to-generator": "^7.16.8", 48 | "@babel/plugin-transform-object-assign": "^7.16.7", 49 | "@babel/plugin-transform-regenerator": "^7.16.7", 50 | "@babel/plugin-transform-runtime": "^7.17.0", 51 | "@babel/preset-env": "^7.16.11", 52 | "@babel/register": "^7.17.0", 53 | "ava": "^3.15.0", 54 | "babel-loader": "^8.2.2", 55 | "buffer": "^6.0.3", 56 | "codecov": "^3.8.1", 57 | "cross-env": "^7.0.3", 58 | "documentation": "^13.2.5", 59 | "eslint": "^8.9.0", 60 | "eslint-config-airbnb-base": "^15.0.0", 61 | "eslint-plugin-import": "^2.25.4", 62 | "husky": "^7.0.4", 63 | "lint-staged": "^12.3.4", 64 | "nyc": "^15.1.0", 65 | "release-it": "^14.12.4", 66 | "rewire": "^6.0.0", 67 | "rimraf": "^3.0.2", 68 | "sinon": "^13.0.1", 69 | "terser-webpack-plugin": "^5.3.1", 70 | "webpack": "^5.68.0", 71 | "webpack-cli": "^4.9.2", 72 | "webpack-merge": "^5.8.0", 73 | "webpack-sources": "^3.2.3" 74 | }, 75 | "dependencies": { 76 | "@babel/runtime-corejs3": "^7.17.2", 77 | "abort-controller": "^3.0.0", 78 | "bs58": "^4.0.1", 79 | "clone": "^2.1.2", 80 | "core-js": "^3.21.0", 81 | "crypto-conditions": "2.2.1", 82 | "decamelize": "^5.0.0", 83 | "es6-promise": "^4.2.8", 84 | "fetch-ponyfill": "^7.1.0", 85 | "js-sha3": "^0.8.0", 86 | "json-stable-stringify": "^1.0.1", 87 | "query-string": "^7.1.1", 88 | "sprintf-js": "^1.1.2", 89 | "tweetnacl": "^1.0.3" 90 | }, 91 | "keywords": [ 92 | "bigchaindb", 93 | "driver", 94 | "blockchain", 95 | "decentralized", 96 | "dapp" 97 | ], 98 | "lint-staged": { 99 | "*.js": [ 100 | "eslint" 101 | ] 102 | }, 103 | "ava": { 104 | "files": [ 105 | "test/**/*.js", 106 | "!test/constants.js" 107 | ], 108 | "source": [ 109 | "**/*.{js,jsx}", 110 | "!node_modules/**/*", 111 | "!dist/**/*" 112 | ], 113 | "failFast": true, 114 | "failWithoutAssertions": false, 115 | "tap": true, 116 | "powerAssert": false, 117 | "require": [ 118 | "@babel/register" 119 | ], 120 | "babel": true 121 | }, 122 | "husky": { 123 | "hooks": { 124 | "pre-commit": "lint-staged" 125 | } 126 | }, 127 | "release-it": { 128 | "github": { 129 | "release": true 130 | }, 131 | "git": { 132 | "tagName": "v${version}" 133 | }, 134 | "hooks": { 135 | "before:init": [ 136 | "npm run test" 137 | ] 138 | }, 139 | "npm": { 140 | "publish": true 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /plugins/add-vendors-plugin.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable strict, no-console, object-shorthand, import/no-extraneous-dependencies */ 6 | 7 | const { ConcatSource } = require('webpack-sources') 8 | 9 | module.exports = class AddVendorsPlugin { 10 | constructor(base) { 11 | this.base = base 12 | } 13 | 14 | apply(compiler) { 15 | compiler.hooks.emit.tapAsync( 16 | `AddVendorsPlugin ${this.base}`, 17 | (compilation, callback) => { 18 | const main = compilation.assets[`main.${this.base}`] 19 | const mainMap = compilation.assets[`main.${this.base}.map`] 20 | const vendor = compilation.assets[`vendors.${this.base}`] 21 | 22 | if (main && vendor) { 23 | const compiledAsset = new ConcatSource(main._value[0]) 24 | compiledAsset.add(vendor) 25 | compiledAsset.add(main._value[1]) 26 | compilation.assets = {} 27 | compilation.assets[this.base] = compiledAsset 28 | } else if (main && mainMap) { 29 | compilation.assets = {} 30 | compilation.assets[this.base] = main 31 | compilation.assets[`${this.base}.map`] = mainMap 32 | } 33 | 34 | callback() 35 | } 36 | ) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Ed25519Keypair.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import base58 from 'bs58' 6 | import { sign } from 'tweetnacl' 7 | 8 | /** 9 | * @public 10 | * Ed25519 keypair in base58 (as BigchainDB expects base58 keys) 11 | * @type {Object} 12 | * @param {Buffer} [seed] A seed that will be used as a key derivation function 13 | * @property {string} publicKey 14 | * @property {string} privateKey 15 | */ 16 | export default function Ed25519Keypair(seed) { 17 | const keyPair = seed ? sign.keyPair.fromSeed(seed) : sign.keyPair() 18 | this.publicKey = base58.encode(Buffer.from(keyPair.publicKey)) 19 | // tweetnacl's generated secret key is the secret key + public key (resulting in a 64-byte buffer) 20 | this.privateKey = base58.encode(Buffer.from(keyPair.secretKey.slice(0, 32))) 21 | } 22 | -------------------------------------------------------------------------------- /src/baseRequest.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | // TODO: remove abort-controller when using Node >=15 6 | import AbortController from 'abort-controller' 7 | import { Promise } from 'es6-promise' 8 | import fetchPonyfill from 'fetch-ponyfill' 9 | import { vsprintf } from 'sprintf-js' 10 | 11 | import formatText from './format_text' 12 | import stringifyAsQueryParam from './stringify_as_query_param' 13 | 14 | const fetch = fetchPonyfill({ Promise }) 15 | 16 | export function ResponseError(message, status, requestURI) { 17 | this.name = 'ResponseError' 18 | this.message = message 19 | this.status = status 20 | this.requestURI = requestURI 21 | this.stack = new Error().stack 22 | } 23 | 24 | ResponseError.prototype = new Error() 25 | 26 | /** 27 | * @private 28 | * Timeout function following https://github.com/github/fetch/issues/175#issuecomment-284787564 29 | * @param {integer} obj Source object 30 | * @param {Promise} filter Array of key names to select or function to invoke per iteration 31 | * @param {AbortController} controller AbortController instance bound to fetch 32 | * @return {Object} TimeoutError if the time was consumed, otherwise the Promise will be resolved 33 | */ 34 | function timeout(ms, promise, controller) { 35 | return new Promise((resolve, reject) => { 36 | const nodeTimeout = setTimeout(() => { 37 | controller.abort() 38 | const errorObject = { 39 | message: 'TimeoutError', 40 | } 41 | reject(new Error(errorObject)) 42 | }, ms) 43 | promise 44 | .then((res) => { 45 | clearTimeout(nodeTimeout) 46 | resolve(res) 47 | }) 48 | .catch((err) => { 49 | clearTimeout(nodeTimeout) 50 | reject(err) 51 | }) 52 | }) 53 | } 54 | 55 | /** 56 | * @private 57 | * @param {Promise} res Source object 58 | * @return {Promise} Promise that will resolve with the response if its status was 2xx; 59 | * otherwise rejects with the response 60 | */ 61 | function handleResponse(res) { 62 | // If status is not a 2xx (based on Response.ok), assume it's an error 63 | // See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch 64 | if (!(res && res.ok)) { 65 | throw new ResponseError( 66 | 'HTTP Error: Requested page not reachable', 67 | `${res.status} ${res.statusText}`, 68 | res.url 69 | ) 70 | } 71 | return res 72 | } 73 | 74 | /** 75 | * @private 76 | * imported from https://github.com/bigchaindb/js-utility-belt/ 77 | * 78 | * Global fetch wrapper that adds some basic error handling and ease of use enhancements. 79 | * Considers any non-2xx response as an error. 80 | * 81 | * For more information on fetch, see https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch. 82 | * 83 | * Expects fetch to already be available (either in a ES6 environment, bundled through webpack, or 84 | * injected through a polyfill). 85 | * 86 | * @param {string} url Url to request. Can be specified as a sprintf format string (see 87 | * https://github.com/alexei/sprintf.js) that will be resolved using 88 | * `config.urlTemplateSpec`. 89 | * @param {Object} config Additional configuration, mostly passed to fetch as its 'init' config 90 | * (see https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch#Parameters). 91 | * @param {*} config.jsonBody Json payload to the request. Will automatically be 92 | * JSON.stringify()-ed and override `config.body`. 93 | * @param {string|Object} config.query Query parameter to append to the end of the url. 94 | * If specified as an object, keys will be 95 | * decamelized into snake case first. 96 | * @param {*[]|Object} config.urlTemplateSpec Format spec to use to expand the url (see sprintf). 97 | * @param {*} config.* All other options are passed through to fetch. 98 | * @param {integer} requestTimeout Timeout for a single request 99 | * 100 | * @return {Promise} If requestTimeout the timeout function will be called. Otherwise resolve the 101 | * Promise with the handleResponse function 102 | */ 103 | export default function baseRequest( 104 | url, 105 | { 106 | jsonBody, query, urlTemplateSpec, ...fetchConfig 107 | } = {}, 108 | requestTimeout = 0 109 | ) { 110 | let expandedUrl = url 111 | 112 | if (urlTemplateSpec != null) { 113 | if (Array.isArray(urlTemplateSpec) && urlTemplateSpec.length) { 114 | // Use vsprintf for the array call signature 115 | expandedUrl = vsprintf(url, urlTemplateSpec) 116 | } else if ( 117 | urlTemplateSpec && 118 | typeof urlTemplateSpec === 'object' && 119 | Object.keys(urlTemplateSpec).length 120 | ) { 121 | expandedUrl = formatText(url, urlTemplateSpec) 122 | } else if (process.env.NODE_ENV !== 'production') { 123 | // eslint-disable-next-line no-console 124 | console.warn( 125 | 'Supplied urlTemplateSpec was not an array or object. Ignoring...' 126 | ) 127 | } 128 | } 129 | 130 | if (query != null) { 131 | if (typeof query === 'string') { 132 | expandedUrl += query 133 | } else if (query && typeof query === 'object') { 134 | expandedUrl += stringifyAsQueryParam(query) 135 | } else if (process.env.NODE_ENV !== 'production') { 136 | // eslint-disable-next-line no-console 137 | console.warn('Supplied query was not a string or object. Ignoring...') 138 | } 139 | } 140 | 141 | if (jsonBody != null) { 142 | fetchConfig.body = JSON.stringify(jsonBody) 143 | } 144 | 145 | if (requestTimeout) { 146 | const controller = new AbortController() 147 | const { signal } = controller 148 | return timeout( 149 | requestTimeout, 150 | fetch.fetch(expandedUrl, { ...fetchConfig, signal }), 151 | controller 152 | ) 153 | .then(handleResponse) 154 | } else { 155 | return fetch.fetch(expandedUrl, fetchConfig).then(handleResponse) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/connection.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import Transport from './transport' 6 | 7 | const HEADER_BLACKLIST = ['content-type'] 8 | const DEFAULT_NODE = 'http://localhost:9984/api/v1/' 9 | const DEFAULT_TIMEOUT = 20000 // The default value is 20 seconds 10 | 11 | /** 12 | * 13 | * @param {String, Array} nodes Nodes for the connection. String possible to be backwards compatible 14 | * with version before 4.1.0 version 15 | * @param {Object} headers Common headers for every request 16 | * @param {float} timeout Optional timeout in secs 17 | * 18 | * 19 | */ 20 | 21 | export default class Connection { 22 | // This driver implements the BEP-14 https://github.com/bigchaindb/BEPs/tree/master/14 23 | constructor(nodes, headers = {}, timeout = DEFAULT_TIMEOUT) { 24 | // Copy object 25 | this.headers = { ...headers } 26 | 27 | // Validate headers 28 | Object.keys(headers).forEach(header => { 29 | if (HEADER_BLACKLIST.includes(header.toLowerCase())) { 30 | throw new Error(`Header ${header} is reserved and cannot be set.`) 31 | } 32 | }) 33 | 34 | this.normalizedNodes = [] 35 | if (!nodes) { 36 | this.normalizedNodes.push(Connection.normalizeNode(DEFAULT_NODE, this.headers)) 37 | } else if (Array.isArray(nodes)) { 38 | nodes.forEach(node => { 39 | this.normalizedNodes.push(Connection.normalizeNode(node, this.headers)) 40 | }) 41 | } else { 42 | this.normalizedNodes.push(Connection.normalizeNode(nodes, this.headers)) 43 | } 44 | 45 | this.transport = new Transport(this.normalizedNodes, timeout) 46 | } 47 | 48 | static normalizeNode(node, headers) { 49 | if (typeof node === 'string') { 50 | return { 'endpoint': node, 'headers': headers } 51 | } else { 52 | const allHeaders = { ...headers, ...node.headers } 53 | return { 'endpoint': node.endpoint, 'headers': allHeaders } 54 | } 55 | } 56 | 57 | static getApiUrls(endpoint) { 58 | return { 59 | 'blocks': 'blocks', 60 | 'blocksDetail': 'blocks/%(blockHeight)s', 61 | 'outputs': 'outputs', 62 | 'transactions': 'transactions', 63 | 'transactionsSync': 'transactions?mode=sync', 64 | 'transactionsAsync': 'transactions?mode=async', 65 | 'transactionsCommit': 'transactions?mode=commit', 66 | 'transactionsDetail': 'transactions/%(transactionId)s', 67 | 'assets': 'assets', 68 | 'metadata': 'metadata' 69 | }[endpoint] 70 | } 71 | 72 | _req(path, options = {}) { 73 | return this.transport.forwardRequest(path, options) 74 | } 75 | 76 | /** 77 | * @param blockHeight 78 | */ 79 | getBlock(blockHeight) { 80 | return this._req(Connection.getApiUrls('blocksDetail'), { 81 | urlTemplateSpec: { 82 | blockHeight 83 | } 84 | }) 85 | } 86 | 87 | /** 88 | * @param transactionId 89 | */ 90 | getTransaction(transactionId) { 91 | return this._req(Connection.getApiUrls('transactionsDetail'), { 92 | urlTemplateSpec: { 93 | transactionId 94 | } 95 | }) 96 | } 97 | 98 | /** 99 | * @param transactionId 100 | * @param status 101 | */ 102 | listBlocks(transactionId) { 103 | return this._req(Connection.getApiUrls('blocks'), { 104 | query: { 105 | transaction_id: transactionId, 106 | } 107 | }) 108 | } 109 | 110 | /** 111 | * @param publicKey 112 | * @param spent 113 | */ 114 | listOutputs(publicKey, spent) { 115 | const query = { 116 | public_key: publicKey 117 | } 118 | // NOTE: If `spent` is not defined, it must not be included in the 119 | // query parameters. 120 | if (spent !== undefined) { 121 | query.spent = spent.toString() 122 | } 123 | return this._req(Connection.getApiUrls('outputs'), { 124 | query 125 | }) 126 | } 127 | 128 | /** 129 | * @param assetId 130 | * @param operation 131 | */ 132 | listTransactions(assetId, operation) { 133 | return this._req(Connection.getApiUrls('transactions'), { 134 | query: { 135 | asset_id: assetId, 136 | operation 137 | } 138 | }) 139 | } 140 | 141 | /** 142 | * @param transaction 143 | */ 144 | postTransaction(transaction) { 145 | return this.postTransactionCommit(transaction) 146 | } 147 | 148 | /** 149 | * @param transaction 150 | */ 151 | postTransactionSync(transaction) { 152 | return this._req(Connection.getApiUrls('transactionsSync'), { 153 | method: 'POST', 154 | jsonBody: transaction 155 | }) 156 | } 157 | 158 | /** 159 | * @param transaction 160 | */ 161 | postTransactionAsync(transaction) { 162 | return this._req(Connection.getApiUrls('transactionsAsync'), { 163 | method: 'POST', 164 | jsonBody: transaction 165 | }) 166 | } 167 | 168 | /** 169 | * @param transaction 170 | */ 171 | postTransactionCommit(transaction) { 172 | return this._req(Connection.getApiUrls('transactionsCommit'), { 173 | method: 'POST', 174 | jsonBody: transaction 175 | }) 176 | } 177 | 178 | /** 179 | * @param search 180 | */ 181 | searchAssets(search, limit = 10) { 182 | return this._req(Connection.getApiUrls('assets'), { 183 | query: { 184 | search, 185 | limit 186 | } 187 | }) 188 | } 189 | 190 | /** 191 | * @param search 192 | */ 193 | searchMetadata(search, limit = 10) { 194 | return this._req(Connection.getApiUrls('metadata'), { 195 | query: { 196 | search, 197 | limit 198 | } 199 | }) 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/format_text.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import { sprintf } from 'sprintf-js' 6 | 7 | // Regexes taken from or inspired by sprintf-js 8 | const Regex = { 9 | TEMPLATE_LITERAL: /\${([^)]+?)}/g, 10 | KEY: /^([a-z_][a-z_\d]*)/i, 11 | KEY_ACCESS: /^\.([a-z_][a-z_\d]*)/i, 12 | INDEX_ACCESS: /^\[(\d+)\]/ 13 | } 14 | 15 | /** 16 | * imported from https://github.com/bigchaindb/js-utility-belt/ 17 | * @private 18 | * Formats strings similarly to C's sprintf, with the addition of '${...}' formats. 19 | * 20 | * Makes a first pass replacing '${...}' formats before passing the expanded string and other 21 | * arguments to sprintf-js. For more information on what sprintf can do, see 22 | * https://github.com/alexei/sprintf.js. 23 | * 24 | * Examples: 25 | * formatText('Hi there ${dimi}!', { dimi: 'Dimi' }) 26 | * => 'Hi there Dimi!' 27 | * 28 | * formatText('${database} is %(status)s', { database: 'BigchainDB', status: 'big' }) 29 | * => 'BigchainDB is big' 30 | * 31 | * Like sprintf-js, string interpolation for keywords and indexes is supported too: 32 | * formatText('Berlin is best known for its ${berlin.topKnownFor[0].name}', { 33 | * berlin: { 34 | * topKnownFor: [{ 35 | * name: 'Currywurst' 36 | * }, ... 37 | * ] 38 | * } 39 | * }) 40 | * => 'Berlin is best known for its Currywurst' 41 | */ 42 | export default function formatText(s, ...argv) { 43 | let expandedFormatStr = s 44 | 45 | // Try to replace formats of the form '${...}' if named replacement fields are used 46 | if (s && argv.length === 1 && typeof argv[0] === 'object') { 47 | const templateSpecObj = argv[0] 48 | 49 | expandedFormatStr = s.replace(Regex.TEMPLATE_LITERAL, (match, replacement) => { 50 | let interpolationLeft = replacement 51 | 52 | /** 53 | * @private 54 | * Interpolation algorithm inspired by sprintf-js. 55 | * 56 | * Goes through the replacement string getting the left-most key or index to interpolate 57 | * on each pass. `value` at each step holds the last interpolation result, `curMatch` is 58 | * the current property match, and `interpolationLeft` is the portion of the replacement 59 | * string still to be interpolated. 60 | * 61 | * It's useful to note that RegExp.exec() returns with an array holding: 62 | * [0]: Full string matched 63 | * [1+]: Matching groups 64 | * 65 | * And that in the regexes defined, the first matching group always corresponds to the 66 | * property matched. 67 | */ 68 | let value 69 | let curMatch = Regex.KEY.exec(interpolationLeft) 70 | if (curMatch !== null) { 71 | value = templateSpecObj[curMatch[1]] 72 | 73 | // Assigning in the conditionals here makes the code less bloated 74 | /* eslint-disable no-cond-assign */ 75 | while ((interpolationLeft = interpolationLeft.substring(curMatch[0].length)) && 76 | value != null) { 77 | if ((curMatch = Regex.KEY_ACCESS.exec(interpolationLeft))) { 78 | value = value[curMatch[1]] 79 | } else if ((curMatch = Regex.INDEX_ACCESS.exec(interpolationLeft))) { 80 | value = value[curMatch[1]] 81 | } else { 82 | break 83 | } 84 | } 85 | /* eslint-enable no-cond-assign */ 86 | } 87 | 88 | // If there's anything left to interpolate by the end then we've failed to interpolate 89 | // the entire replacement string. 90 | if (interpolationLeft.length) { 91 | throw new SyntaxError(`[formatText] failed to parse named argument key: ${replacement}`) 92 | } 93 | 94 | return value 95 | }) 96 | } 97 | 98 | return sprintf(expandedFormatStr, ...argv) 99 | } 100 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import Ed25519Keypair from './Ed25519Keypair' 6 | import Connection from './connection' 7 | import Transaction from './transaction' 8 | import ccJsonLoad from './utils/ccJsonLoad' 9 | import ccJsonify from './utils/ccJsonify' 10 | 11 | export { 12 | ccJsonLoad, ccJsonify, Connection, Ed25519Keypair, Transaction 13 | } 14 | -------------------------------------------------------------------------------- /src/request.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import baseRequest from './baseRequest' 6 | import sanitize from './sanitize' 7 | 8 | const DEFAULT_REQUEST_CONFIG = { 9 | headers: { 10 | 'Accept': 'application/json' 11 | } 12 | } 13 | 14 | const BACKOFF_DELAY = 500 // 0.5 seconds 15 | const ERROR_FROM_SERVER = 'HTTP Error: Requested page not reachable' 16 | /** 17 | * @private 18 | * Small wrapper around js-utility-belt's request that provides url resolving, 19 | * default settings, and response handling. 20 | */ 21 | 22 | export default class Request { 23 | constructor(node) { 24 | this.node = node 25 | this.backoffTime = null 26 | this.retries = 0 27 | this.connectionError = null 28 | } 29 | 30 | async request(urlPath, config, timeout, maxBackoffTime) { 31 | if (!urlPath) { 32 | return Promise.reject(new Error('Request was not given a url.')) 33 | } 34 | // Load default fetch configuration and remove any falsy query parameters 35 | const requestConfig = { 36 | ...this.node.headers, 37 | ...DEFAULT_REQUEST_CONFIG, 38 | ...config, 39 | query: config.query && sanitize(config.query) 40 | } 41 | const apiUrl = this.node.endpoint + urlPath 42 | if (requestConfig.jsonBody) { 43 | requestConfig.headers = { ...requestConfig.headers, 'Content-Type': 'application/json' } 44 | } 45 | 46 | // If connectionError occurs, a timestamp equal to now + 47 | // `backoffTimedelta` is assigned to the object. 48 | // Next time the function is called, it either 49 | // waits till the timestamp is passed or raises `TimeoutError`. 50 | // If `ConnectionError` occurs two or more times in a row, 51 | // the retry count is incremented and the new timestamp is calculated 52 | // as now + the `backoffTimedelta` 53 | // The `backoffTimedelta` is the minimum between the default delay 54 | // multiplied by two to the power of the 55 | // number of retries or timeout/2 or 10. See Transport class for that 56 | // If a request is successful, the backoff timestamp is removed, 57 | // the retry count is back to zero. 58 | 59 | const backoffTimedelta = this.getBackoffTimedelta() 60 | 61 | if (timeout != null && timeout < backoffTimedelta) { 62 | const errorObject = { 63 | message: 'TimeoutError' 64 | } 65 | throw errorObject 66 | } 67 | if (backoffTimedelta > 0) { 68 | await Request.sleep(backoffTimedelta) 69 | } 70 | 71 | const requestTimeout = timeout ? timeout - backoffTimedelta : timeout 72 | return baseRequest(apiUrl, requestConfig, requestTimeout) 73 | .then((res) => { 74 | this.connectionError = null 75 | return res.json() 76 | }) 77 | .catch(err => { 78 | // ConnectionError 79 | this.connectionError = err 80 | }) 81 | .finally(() => { 82 | this.updateBackoffTime(maxBackoffTime) 83 | }) 84 | } 85 | 86 | updateBackoffTime(maxBackoffTime) { 87 | if (!this.connectionError) { 88 | this.retries = 0 89 | this.backoffTime = null 90 | } else if (this.connectionError.message === ERROR_FROM_SERVER) { 91 | // If status is not a 2xx (based on Response.ok), throw error 92 | this.retries = 0 93 | this.backoffTime = null 94 | throw this.connectionError 95 | } else { 96 | // Timeout or no connection could be stablished 97 | const backoffTimedelta = Math.min(BACKOFF_DELAY * (2 ** this.retries), maxBackoffTime) 98 | this.backoffTime = Date.now() + backoffTimedelta 99 | this.retries += 1 100 | if (this.connectionError.message === 'TimeoutError') { 101 | throw this.connectionError 102 | } 103 | } 104 | } 105 | 106 | getBackoffTimedelta() { 107 | if (!this.backoffTime) { 108 | return 0 109 | } 110 | return (this.backoffTime - Date.now()) 111 | } 112 | 113 | static sleep(ms) { 114 | return new Promise(resolve => { 115 | setTimeout(resolve, ms) 116 | }) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/sanitize.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import 'core-js/features/array/includes' 6 | import 'core-js/features/object/entries' 7 | 8 | /** 9 | * @private 10 | * Abstraction for selectFromObject and omitFromObject for DRYness. 11 | * Set isInclusion to true if the filter should be for including the filtered items (ie. selecting 12 | * only them vs omitting only them). 13 | */ 14 | function filterFromObject(obj, filter, { isInclusion = true } = {}) { 15 | if (filter && Array.isArray(filter)) { 16 | return applyFilterOnObject(obj, isInclusion ? (val => filter.includes(val)) 17 | : (val => !filter.includes(val))) 18 | } else if (filter && typeof filter === 'function') { 19 | // Flip the filter fn's return if it's for inclusion 20 | return applyFilterOnObject(obj, isInclusion ? filter 21 | : (...args) => !filter(...args)) 22 | } else { 23 | throw new Error('The given filter is not an array or function. Filter aborted') 24 | } 25 | } 26 | 27 | /** 28 | * @private 29 | * Returns a filtered copy of the given object's own enumerable properties (no inherited 30 | * properties), keeping any keys that pass the given filter function. 31 | */ 32 | function applyFilterOnObject(obj, filterFn) { 33 | if (filterFn == null) { 34 | return { ...obj } 35 | } 36 | 37 | const filteredObj = {} 38 | Object.entries(obj).forEach(([key, val]) => { 39 | if (filterFn(val, key)) { 40 | filteredObj[key] = val 41 | } 42 | }) 43 | 44 | return filteredObj 45 | } 46 | 47 | /** 48 | * @private 49 | * Similar to lodash's _.pick(), this returns a copy of the given object's 50 | * own and inherited enumerable properties, selecting only the keys in 51 | * the given array or whose value pass the given filter function. 52 | * @param {Object} obj Source object 53 | * @param {Array|function} filter Array of key names to select or function to invoke per iteration 54 | * @return {Object} The new object 55 | */ 56 | function selectFromObject(obj, filter) { 57 | return filterFromObject(obj, filter) 58 | } 59 | 60 | /** 61 | * @private 62 | * Glorified selectFromObject. Takes an object and returns a filtered shallow copy that strips out 63 | * any properties that are falsy (including coercions, ie. undefined, null, '', 0, ...). 64 | * Does not modify the passed in object. 65 | * 66 | * @param {Object} obj Javascript object 67 | * @return {Object} Sanitized Javascript object 68 | */ 69 | export default function sanitize(obj) { 70 | return selectFromObject(obj, (val) => !!val) 71 | } 72 | -------------------------------------------------------------------------------- /src/sha256Hash.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable camelcase */ 6 | import { sha3_256 } from 'js-sha3' 7 | 8 | export default function sha256Hash(data) { 9 | return sha3_256 10 | .create() 11 | .update(data) 12 | .hex() 13 | } 14 | /* eslint-enable camelcase */ 15 | -------------------------------------------------------------------------------- /src/stringify_as_query_param.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import 'core-js/features/object/entries' 6 | import decamelize from 'decamelize' 7 | import queryString from 'query-string' 8 | 9 | /** 10 | * @private 11 | * imported from https://github.com/bigchaindb/js-utility-belt/ 12 | * 13 | * Takes a key-value dictionary (ie. object) and converts it to a query-parameter string that you 14 | * can directly append into a URL. 15 | * 16 | * Extends queryString.stringify by allowing you to specify a `transform` function that will be 17 | * invoked on each of the dictionary's keys before being stringified into the query-parameter 18 | * string. 19 | * 20 | * By default `transform` is `decamelize`, so a dictionary of the form: 21 | * 22 | * { 23 | * page: 1, 24 | * pageSize: 10 25 | * } 26 | * 27 | * will be converted to a string like: 28 | * 29 | * ?page=1&page_size=10 30 | * 31 | * @param {Object} obj Query params dictionary 32 | * @param {function} [transform=decamelize] Transform function for each of the param keys 33 | * @return {string} Query param string 34 | */ 35 | export default function stringifyAsQueryParam(obj, transform = decamelize) { 36 | if (!obj || typeof obj !== 'object' || !Object.keys(obj).length) { 37 | return '' 38 | } 39 | 40 | const transformedKeysObj = Object.entries(obj).reduce((paramsObj, [key, value]) => { 41 | paramsObj[transform(key)] = value 42 | return paramsObj 43 | }, {}) 44 | 45 | return `?${queryString.stringify(transformedKeysObj)}` 46 | } 47 | -------------------------------------------------------------------------------- /src/transaction.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import stableStringify from 'json-stable-stringify' 6 | import clone from 'clone' 7 | import base58 from 'bs58' 8 | import { Ed25519Sha256, PreimageSha256, ThresholdSha256 } from 'crypto-conditions' 9 | import ccJsonify from './utils/ccJsonify' 10 | import sha256Hash from './sha256Hash' 11 | 12 | /** 13 | * Construct Transactions 14 | */ 15 | export default class Transaction { 16 | /** 17 | * Canonically serializes a transaction into a string by sorting the keys 18 | * @param {Object} (transaction) 19 | * @return {string} a canonically serialized Transaction 20 | */ 21 | static serializeTransactionIntoCanonicalString(transaction) { 22 | // BigchainDB signs fulfillments by serializing transactions into a 23 | // "canonical" format where 24 | const tx = clone(transaction) 25 | // TODO: set fulfillments to null 26 | // Sort the keys 27 | return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) 28 | } 29 | 30 | static makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { 31 | return { 32 | fulfillment, 33 | fulfills, 34 | 'owners_before': publicKeys, 35 | } 36 | } 37 | 38 | static makeTransactionTemplate() { 39 | const txTemplate = { 40 | id: null, 41 | operation: null, 42 | outputs: [], 43 | inputs: [], 44 | metadata: null, 45 | asset: null, 46 | version: '2.0', 47 | } 48 | return txTemplate 49 | } 50 | 51 | static makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { 52 | const tx = Transaction.makeTransactionTemplate() 53 | tx.operation = operation 54 | tx.asset = asset 55 | tx.metadata = metadata 56 | tx.inputs = inputs 57 | tx.outputs = outputs 58 | return tx 59 | } 60 | 61 | /** 62 | * Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by 63 | * the `issuers`. 64 | * @param {Object} asset Created asset's data 65 | * @param {Object} metadata Metadata for the Transaction 66 | * @param {Object[]} outputs Array of Output objects to add to the Transaction. 67 | * Think of these as the recipients of the asset after the transaction. 68 | * For `CREATE` Transactions, this should usually just be a list of 69 | * Outputs wrapping Ed25519 Conditions generated from the issuers' public 70 | * keys (so that the issuers are the recipients of the created asset). 71 | * @param {...string[]} issuers Public key of one or more issuers to the asset being created by this 72 | * Transaction. 73 | * Note: Each of the private keys corresponding to the given public 74 | * keys MUST be used later (and in the same order) when signing the 75 | * Transaction (`signTransaction()`). 76 | * @returns {Object} Unsigned transaction -- make sure to call signTransaction() on it before 77 | * sending it off! 78 | */ 79 | static makeCreateTransaction(asset, metadata, outputs, ...issuers) { 80 | const assetDefinition = { 81 | data: asset || null, 82 | } 83 | const inputs = issuers.map((issuer) => Transaction.makeInputTemplate([issuer])) 84 | 85 | return Transaction.makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) 86 | } 87 | 88 | /** 89 | * Create an Ed25519 Cryptocondition from an Ed25519 public key 90 | * to put into an Output of a Transaction 91 | * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction 92 | * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type 93 | * @returns {Object} Ed25519 Condition (that will need to wrapped in an Output) 94 | */ 95 | static makeEd25519Condition(publicKey, json = true) { 96 | const publicKeyBuffer = base58.decode(publicKey) 97 | const ed25519Fulfillment = new Ed25519Sha256() 98 | ed25519Fulfillment.setPublicKey(publicKeyBuffer) 99 | return json ? ccJsonify(ed25519Fulfillment) : ed25519Fulfillment 100 | } 101 | 102 | /** 103 | * Create an Output from a Condition. 104 | * Note: Assumes the given Condition was generated from a 105 | * single public key (e.g. a Ed25519 Condition) 106 | * @param {Object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) 107 | * @param {string} amount Amount of the output 108 | * @returns {Object} An Output usable in a Transaction 109 | */ 110 | static makeOutput(condition, amount = '1') { 111 | if (typeof amount !== 'string') { 112 | throw new TypeError('`amount` must be of type string') 113 | } 114 | const publicKeys = [] 115 | const getPublicKeys = details => { 116 | if (details.type === 'ed25519-sha-256') { 117 | if (!publicKeys.includes(details.public_key)) { 118 | publicKeys.push(details.public_key) 119 | } 120 | } else if (details.type === 'threshold-sha-256') { 121 | details.subconditions.map(getPublicKeys) 122 | } 123 | } 124 | getPublicKeys(condition.details) 125 | return { 126 | condition, 127 | amount, 128 | public_keys: publicKeys, 129 | } 130 | } 131 | 132 | /** 133 | * Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction 134 | * @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition 135 | * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type 136 | * @returns {Object} Preimage-Sha256 Condition (that will need to wrapped in an Output) 137 | */ 138 | static makeSha256Condition(preimage, json = true) { 139 | const sha256Fulfillment = new PreimageSha256() 140 | sha256Fulfillment.setPreimage(Buffer.from(preimage)) 141 | return json ? ccJsonify(sha256Fulfillment) : sha256Fulfillment 142 | } 143 | 144 | /** 145 | * Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction 146 | * @param {number} threshold 147 | * @param {Array} [subconditions=[]] 148 | * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type 149 | * @returns {Object} Sha256 Threshold Condition (that will need to wrapped in an Output) 150 | */ 151 | static makeThresholdCondition(threshold, subconditions = [], json = true) { 152 | const thresholdCondition = new ThresholdSha256() 153 | thresholdCondition.setThreshold(threshold) 154 | subconditions.forEach((subcondition) => { 155 | // TODO: add support for Condition 156 | thresholdCondition.addSubfulfillment(subcondition) 157 | // ? Should be thresholdCondition.addSubcondition(subcondition) 158 | }) 159 | 160 | return json ? ccJsonify(thresholdCondition) : thresholdCondition 161 | } 162 | 163 | /** 164 | * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills 165 | * the `fulfilledOutputs` of `unspentTransaction`. 166 | * @param {Object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill 167 | * its Output Condition) 168 | * @param {Object} metadata Metadata for the Transaction 169 | * @param {Object[]} outputs Array of Output objects to add to the Transaction. 170 | * Think of these as the recipients of the asset after the transaction. 171 | * For `TRANSFER` Transactions, this should usually just be a list of 172 | * Outputs wrapping Ed25519 Conditions generated from the public keys of 173 | * the recipients. 174 | * @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this 175 | * Transaction fulfills. 176 | * Note that listed public keys listed must be used (and in 177 | * the same order) to sign the Transaction 178 | * (`signTransaction()`). 179 | * @returns {Object} Unsigned transaction -- make sure to call signTransaction() on it before 180 | * sending it off! 181 | */ 182 | // TODO: 183 | // - Make `metadata` optional argument 184 | static makeTransferTransaction( 185 | unspentOutputs, 186 | outputs, 187 | metadata 188 | ) { 189 | const inputs = unspentOutputs.map((unspentOutput) => { 190 | const { tx, outputIndex } = { tx: unspentOutput.tx, outputIndex: unspentOutput.output_index } 191 | const fulfilledOutput = tx.outputs[outputIndex] 192 | const transactionLink = { 193 | output_index: outputIndex, 194 | transaction_id: tx.id, 195 | } 196 | 197 | return Transaction.makeInputTemplate(fulfilledOutput.public_keys, transactionLink) 198 | }) 199 | 200 | const assetLink = { 201 | id: unspentOutputs[0].tx.operation === 'CREATE' ? unspentOutputs[0].tx.id 202 | : unspentOutputs[0].tx.asset.id 203 | } 204 | return Transaction.makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs) 205 | } 206 | 207 | /** 208 | * Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction` 209 | * that's been signed. 210 | * Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as 211 | * an exercise for the user. 212 | * @param {Object} transaction Transaction to sign. `transaction` is not modified. 213 | * @param {...string} privateKeys Private keys associated with the issuers of the `transaction`. 214 | * Looped through to iteratively sign any Input Fulfillments found in 215 | * the `transaction`. 216 | * @returns {Object} The signed version of `transaction`. 217 | */ 218 | static signTransaction(transaction, ...privateKeys) { 219 | const signedTx = clone(transaction) 220 | const serializedTransaction = 221 | Transaction.serializeTransactionIntoCanonicalString(transaction) 222 | 223 | signedTx.inputs.forEach((input, index) => { 224 | const privateKey = privateKeys[index] 225 | const privateKeyBuffer = base58.decode(privateKey) 226 | 227 | const transactionUniqueFulfillment = input.fulfills ? serializedTransaction 228 | .concat(input.fulfills.transaction_id) 229 | .concat(input.fulfills.output_index) : serializedTransaction 230 | const transactionHash = sha256Hash(transactionUniqueFulfillment) 231 | const ed25519Fulfillment = new Ed25519Sha256() 232 | ed25519Fulfillment.sign(Buffer.from(transactionHash, 'hex'), privateKeyBuffer) 233 | const fulfillmentUri = ed25519Fulfillment.serializeUri() 234 | 235 | input.fulfillment = fulfillmentUri 236 | }) 237 | 238 | const serializedSignedTransaction = 239 | Transaction.serializeTransactionIntoCanonicalString(signedTx) 240 | signedTx.id = sha256Hash(serializedSignedTransaction) 241 | return signedTx 242 | } 243 | 244 | /** 245 | * Delegate signing of the given `transaction` returning a new copy of `transaction` 246 | * that's been signed. 247 | * @param {Object} transaction Transaction to sign. `transaction` is not modified. 248 | * @param {Function} signFn Function signing the transaction, expected to return the fulfillment. 249 | * @returns {Object} The signed version of `transaction`. 250 | */ 251 | static delegateSignTransaction(transaction, signFn) { 252 | const signedTx = clone(transaction) 253 | const serializedTransaction = 254 | Transaction.serializeTransactionIntoCanonicalString(transaction) 255 | 256 | signedTx.inputs.forEach((input, index) => { 257 | const fulfillmentUri = signFn(serializedTransaction, input, index) 258 | input.fulfillment = fulfillmentUri 259 | }) 260 | 261 | const serializedSignedTransaction = Transaction.serializeTransactionIntoCanonicalString(signedTx) 262 | signedTx.id = sha256Hash(serializedSignedTransaction) 263 | return signedTx 264 | } 265 | 266 | /** 267 | * Delegate signing of the given `transaction` returning a new copy of `transaction` 268 | * that's been signed. 269 | * @param {Object} transaction Transaction to sign. `transaction` is not modified. 270 | * @param {Function} signFn Function signing the transaction, expected to resolve the fulfillment. 271 | * @returns {Promise} The signed version of `transaction`. 272 | */ 273 | static async delegateSignTransactionAsync(transaction, signFn) { 274 | const signedTx = clone(transaction) 275 | const serializedTransaction = 276 | Transaction.serializeTransactionIntoCanonicalString(transaction) 277 | 278 | await Promise.all(signedTx.inputs.map(async (input, index) => { 279 | const fulfillmentUri = await signFn(serializedTransaction, input, index) 280 | input.fulfillment = fulfillmentUri 281 | })) 282 | 283 | const serializedSignedTransaction = Transaction.serializeTransactionIntoCanonicalString(signedTx) 284 | signedTx.id = sha256Hash(serializedSignedTransaction) 285 | return signedTx 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /src/transport.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import Request from './request' 6 | 7 | /** 8 | * 9 | * @private 10 | * If initialized with ``>1`` nodes, the driver will send successive 11 | * requests to different nodes in a round-robin fashion (this will be 12 | * customizable in the future). 13 | */ 14 | 15 | export default class Transport { 16 | constructor(nodes, timeout) { 17 | this.connectionPool = [] 18 | this.timeout = timeout 19 | // the maximum backoff time is 10 seconds 20 | this.maxBackoffTime = timeout ? timeout / 2 : 10000 21 | nodes.forEach(node => { 22 | this.connectionPool.push(new Request(node)) 23 | }) 24 | } 25 | 26 | // Select the connection with the earliest backoff time, in case of a tie, 27 | // prefer the one with the smaller list index 28 | pickConnection() { 29 | let connection = this.connectionPool[0] 30 | 31 | this.connectionPool.forEach(conn => { 32 | // 0 the lowest value is the time for Thu Jan 01 1970 01:00:00 GMT+0100 (CET) 33 | conn.backoffTime = conn.backoffTime ? conn.backoffTime : 0 34 | connection = (conn.backoffTime < connection.backoffTime) ? conn : connection 35 | }) 36 | return connection 37 | } 38 | 39 | async forwardRequest(path, headers) { 40 | let response 41 | let connection 42 | // A new request will be executed until there is a valid response or timeout < 0 43 | while (this.timeout >= 0) { 44 | connection = this.pickConnection() 45 | // Date in milliseconds 46 | const startTime = Date.now() 47 | // eslint-disable-next-line no-await-in-loop 48 | response = await connection.request( 49 | path, 50 | headers, 51 | this.timeout, 52 | this.maxBackoffTime 53 | ) 54 | const elapsed = Date.now() - startTime 55 | if (connection.backoffTime > 0 && this.timeout > 0) { 56 | this.timeout -= elapsed 57 | } else { 58 | // No connection error, the response is valid 59 | return response 60 | } 61 | } 62 | throw new Error('TimeoutError') 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/utils/ccJsonLoad.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import base58 from 'bs58' 6 | import { Condition, Ed25519Sha256, ThresholdSha256 } from 'crypto-conditions' 7 | 8 | /** 9 | * Loads a crypto-condition class (Fulfillment or Condition) from a BigchainDB JSON object 10 | * @param {Object} conditionJson 11 | * @returns {cc.Condition} Ed25519 Condition (that will need to wrapped in an Output) 12 | */ 13 | export default function ccJsonLoad(conditionJson) { 14 | if ('hash' in conditionJson) { 15 | const condition = new Condition() 16 | condition.setTypeId(conditionJson.type_id) 17 | condition.setSubtypes(conditionJson.bitmask) 18 | condition.setHash(base58.decode(conditionJson.hash)) 19 | // TODO: fix this, maxFulfillmentLength cannot be set in CryptoCondition lib 20 | condition.maxFulfillmentLength = parseInt(conditionJson.max_fulfillment_length, 10) 21 | return condition 22 | } else { 23 | let fulfillment 24 | 25 | if (conditionJson.type === 'threshold-sha-256') { 26 | fulfillment = new ThresholdSha256() 27 | fulfillment.threshold = conditionJson.threshold 28 | conditionJson.subconditions.forEach((subconditionJson) => { 29 | const subcondition = ccJsonLoad(subconditionJson) 30 | if ('getConditionUri' in subcondition) { 31 | fulfillment.addSubfulfillment(subcondition) 32 | } else if ('serializeUri' in subcondition) { 33 | fulfillment.addSubcondition(subcondition) 34 | } 35 | }) 36 | } 37 | 38 | if (conditionJson.type === 'ed25519-sha-256') { 39 | fulfillment = new Ed25519Sha256() 40 | fulfillment.setPublicKey(base58.decode(conditionJson.public_key)) 41 | } 42 | return fulfillment 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/utils/ccJsonify.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import base58 from 'bs58' 6 | 7 | /** 8 | * Serializes a crypto-condition class (Condition or Fulfillment) into a BigchainDB-compatible JSON 9 | * @param {cc.Fulfillment} fulfillment base58 encoded Ed25519 public key for recipient of the Transaction 10 | * @returns {Object} Ed25519 Condition (that will need to wrapped in an Output) 11 | */ 12 | export default function ccJsonify(fulfillment) { 13 | let conditionUri 14 | 15 | if ('getConditionUri' in fulfillment) { 16 | conditionUri = fulfillment.getConditionUri() 17 | } else if ('serializeUri' in fulfillment) { 18 | conditionUri = fulfillment.serializeUri() 19 | } 20 | 21 | const jsonBody = { 22 | details: {}, 23 | uri: conditionUri, 24 | } 25 | 26 | if (fulfillment.getTypeId() === 0) { 27 | jsonBody.details.type_id = 0 28 | jsonBody.details.bitmask = 3 29 | 30 | if ('preimage' in fulfillment) { 31 | jsonBody.details.preimage = fulfillment.preimage.toString() 32 | jsonBody.details.type = 'fulfillment' 33 | } 34 | } 35 | 36 | if (fulfillment.getTypeId() === 2) { 37 | return { 38 | details: { 39 | type: 'threshold-sha-256', 40 | threshold: fulfillment.threshold, 41 | subconditions: fulfillment.subconditions.map((subcondition) => { 42 | const subconditionJson = ccJsonify(subcondition.body) 43 | return subconditionJson.details 44 | }) 45 | }, 46 | uri: conditionUri, 47 | } 48 | } 49 | 50 | if (fulfillment.getTypeId() === 4) { 51 | jsonBody.details.type = 'ed25519-sha-256' 52 | 53 | if ('publicKey' in fulfillment) { 54 | jsonBody.details.public_key = base58.encode(fulfillment.publicKey) 55 | } 56 | } 57 | 58 | if ('hash' in fulfillment) { 59 | jsonBody.details.hash = base58.encode(fulfillment.hash) 60 | jsonBody.details.max_fulfillment_length = fulfillment.maxFulfillmentLength 61 | jsonBody.details.type = 'condition' 62 | } 63 | 64 | return jsonBody 65 | } 66 | -------------------------------------------------------------------------------- /test/base-request/test_baseRequest.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import rewire from 'rewire' 7 | 8 | const baseRequestFile = rewire('../../src/baseRequest.js') 9 | const baseRequest = baseRequestFile.__get__('baseRequest') 10 | const handleResponse = baseRequestFile.__get__('handleResponse') 11 | 12 | test('HandleResponse does not throw error for response ok', t => { 13 | const testObj = { 14 | ok: true 15 | } 16 | const expected = testObj 17 | const actual = handleResponse(testObj) 18 | 19 | t.deepEqual(actual, expected) 20 | }) 21 | 22 | test('baseRequest test query and vsprint', async t => { 23 | const error = await t.throwsAsync(baseRequest('https://%s.com/', { 24 | urlTemplateSpec: ['google'], 25 | query: 'teapot' 26 | }), { instanceOf: Error, message: 'HTTP Error: Requested page not reachable' }) 27 | 28 | t.is(error.requestURI, 'https://www.google.com/teapot') 29 | t.is(error.status, '418 I\'m a Teapot') 30 | }) 31 | -------------------------------------------------------------------------------- /test/connection/test_connection.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import sinon from 'sinon' 7 | 8 | import { 9 | Connection 10 | } from '../../src' 11 | import { 12 | API_PATH 13 | } from '../constants' 14 | 15 | const conn = new Connection(API_PATH) 16 | 17 | test('Payload thrown at incorrect API_PATH', async t => { 18 | const path = 'http://localhost:9984/api/wrong/' 19 | const connection = new Connection(path) 20 | const target = { 21 | message: 'HTTP Error: Requested page not reachable', 22 | status: '404 NOT FOUND', 23 | requestURI: 'http://localhost:9984/api/wrong/transactions/transactionId' 24 | } 25 | const error = await t.throwsAsync(connection.getTransaction('transactionId'), { 26 | instanceOf: Error, message: target.message 27 | }) 28 | 29 | t.is('ResponseError', error.name) 30 | t.is(target.status, error.status) 31 | t.is(target.requestURI, error.requestURI) 32 | }) 33 | 34 | test('Generate API URLS', t => { 35 | const endpoints = { 36 | 'blocks': 'blocks', 37 | 'blocksDetail': 'blocks/%(blockHeight)s', 38 | 'outputs': 'outputs', 39 | 'transactions': 'transactions', 40 | 'transactionsSync': 'transactions?mode=sync', 41 | 'transactionsAsync': 'transactions?mode=async', 42 | 'transactionsCommit': 'transactions?mode=commit', 43 | 'transactionsDetail': 'transactions/%(transactionId)s', 44 | 'assets': 'assets', 45 | } 46 | Object.keys(endpoints).forEach(endpointName => { 47 | const url = Connection.getApiUrls(endpointName) 48 | const expected = endpoints[endpointName] 49 | t.is(url, expected) 50 | }) 51 | }) 52 | 53 | test('Normalize node from an object', t => { 54 | const headers = { 55 | custom: 'headers' 56 | } 57 | const node = { 58 | endpoint: API_PATH, 59 | headers: { 60 | hello: 'world' 61 | } 62 | } 63 | const expectedNode = { 64 | 'endpoint': API_PATH, 65 | 'headers': { 66 | hello: 'world', 67 | custom: 'headers' 68 | } 69 | } 70 | 71 | t.deepEqual(Connection.normalizeNode(node, headers), expectedNode) 72 | }) 73 | 74 | test('Normalize node from a string', t => { 75 | const headers = { 76 | custom: 'headers' 77 | } 78 | const expectedNode = { 79 | 'endpoint': API_PATH, 80 | 'headers': { 81 | custom: 'headers' 82 | } 83 | } 84 | 85 | t.deepEqual(Connection.normalizeNode(API_PATH, headers), expectedNode) 86 | }) 87 | 88 | test('Request with custom headers', t => { 89 | const testConn = new Connection(API_PATH, { 90 | hello: 'world' 91 | }) 92 | const expectedOptions = { 93 | headers: { 94 | custom: 'headers' 95 | } 96 | } 97 | const PATH = 'blocks' 98 | testConn.transport.forwardRequest = sinon.spy() 99 | 100 | testConn._req(PATH, { 101 | headers: { 102 | custom: 'headers' 103 | } 104 | }) 105 | t.truthy(testConn.transport.forwardRequest.calledWith(PATH, expectedOptions)) 106 | }) 107 | 108 | test('Get block for a block id', t => { 109 | const expectedPath = 'path' 110 | const blockHeight = 'abc' 111 | 112 | conn._req = sinon.spy() 113 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 114 | 115 | conn.getBlock(blockHeight) 116 | t.truthy(conn._req.calledWith( 117 | expectedPath, 118 | { urlTemplateSpec: { blockHeight } } 119 | )) 120 | }) 121 | 122 | test('Get transaction for a transaction id', t => { 123 | const expectedPath = 'path' 124 | const transactionId = 'abc' 125 | 126 | conn._req = sinon.spy() 127 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 128 | 129 | conn.getTransaction(transactionId) 130 | t.truthy(conn._req.calledWith( 131 | expectedPath, 132 | { urlTemplateSpec: { transactionId } } 133 | )) 134 | }) 135 | 136 | test('Get list of blocks for a transaction id', t => { 137 | const expectedPath = 'path' 138 | const transactionId = 'abc' 139 | 140 | conn._req = sinon.spy() 141 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 142 | 143 | conn.listBlocks(transactionId) 144 | t.truthy(conn._req.calledWith( 145 | expectedPath, 146 | { 147 | query: { 148 | transaction_id: transactionId, 149 | } 150 | } 151 | )) 152 | }) 153 | 154 | test('Get list of transactions for an asset id', t => { 155 | const expectedPath = 'path' 156 | const assetId = 'abc' 157 | const operation = 'operation' 158 | 159 | conn._req = sinon.spy() 160 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 161 | 162 | conn.listTransactions(assetId, operation) 163 | t.truthy(conn._req.calledWith( 164 | expectedPath, 165 | { 166 | query: { 167 | asset_id: assetId, 168 | operation 169 | } 170 | } 171 | )) 172 | }) 173 | 174 | test('Get outputs for a public key and no spent flag', t => { 175 | const expectedPath = 'path' 176 | const publicKey = 'publicKey' 177 | 178 | conn._req = sinon.spy() 179 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 180 | 181 | conn.listOutputs(publicKey) 182 | t.truthy(conn._req.calledWith( 183 | expectedPath, 184 | { query: { public_key: publicKey } } 185 | )) 186 | }) 187 | 188 | test('Get outputs for a public key and spent=false', t => { 189 | const expectedPath = 'path' 190 | const publicKey = 'publicKey' 191 | const spent = false 192 | 193 | conn._req = sinon.spy() 194 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 195 | 196 | conn.listOutputs(publicKey, spent) 197 | t.truthy(conn._req.calledWith( 198 | expectedPath, 199 | { query: { public_key: publicKey, spent: 'false' } } 200 | )) 201 | }) 202 | 203 | test('Get outputs for a public key and spent=true', t => { 204 | const expectedPath = 'path' 205 | const publicKey = 'publicKey' 206 | const spent = true 207 | 208 | conn._req = sinon.spy() 209 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 210 | 211 | conn.listOutputs(publicKey, spent) 212 | t.truthy(conn._req.calledWith( 213 | expectedPath, 214 | { query: { public_key: publicKey, spent: 'true' } } 215 | )) 216 | }) 217 | 218 | test('Get asset for text', t => { 219 | const expectedPath = 'path' 220 | const search = 'abc' 221 | 222 | conn._req = sinon.spy() 223 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 224 | 225 | conn.searchAssets(search) 226 | t.truthy(conn._req.calledWith( 227 | expectedPath, 228 | { query: { search, limit: 10 } } 229 | )) 230 | }) 231 | 232 | test('Get metadata for text', t => { 233 | const expectedPath = 'path' 234 | const search = 'abc' 235 | 236 | conn._req = sinon.spy() 237 | Connection.getApiUrls = sinon.stub().returns(expectedPath) 238 | 239 | conn.searchMetadata(search) 240 | t.truthy(conn._req.calledWith( 241 | expectedPath, 242 | { query: { search, limit: 10 } } 243 | )) 244 | }) 245 | -------------------------------------------------------------------------------- /test/constants.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import { createHash } from 'crypto' 6 | import base58 from 'bs58' 7 | import { Ed25519Sha256 } from 'crypto-conditions' 8 | import { Transaction, Ed25519Keypair } from '../src' 9 | // TODO: Find out if ava has something like conftest, if so put this there. 10 | 11 | // NOTE: It's safer to cast `Math.random()` to a string, to avoid differences 12 | // in "float interpretation" between languages (e.g. JavaScript and Python) 13 | export const API_PATH = 'http://localhost:9984/api/v1/' 14 | export function asset() { return { message: `${Math.random()}` } } 15 | export const metaData = { message: 'metaDataMessage' } 16 | 17 | export const alice = new Ed25519Keypair() 18 | export const aliceCondition = Transaction.makeEd25519Condition(alice.publicKey) 19 | export const aliceOutput = Transaction.makeOutput(aliceCondition) 20 | export const createTx = Transaction.makeCreateTransaction( 21 | asset, 22 | metaData, 23 | [aliceOutput], 24 | alice.publicKey 25 | ) 26 | export const transferTx = Transaction.makeTransferTransaction( 27 | [{ tx: createTx, output_index: 0 }], 28 | [aliceOutput], 29 | metaData 30 | ) 31 | 32 | export const bob = new Ed25519Keypair() 33 | export const bobCondition = Transaction.makeEd25519Condition(bob.publicKey) 34 | export const bobOutput = Transaction.makeOutput(bobCondition) 35 | 36 | export function delegatedSignTransaction(...keyPairs) { 37 | return function sign(serializedTransaction, input) { 38 | const transactionUniqueFulfillment = input.fulfills ? serializedTransaction 39 | .concat(input.fulfills.transaction_id) 40 | .concat(input.fulfills.output_index) : serializedTransaction 41 | const transactionHash = createHash('sha3-256').update(transactionUniqueFulfillment).digest() 42 | const filteredKeyPairs = keyPairs.filter( 43 | ({ publicKey }) => input.owners_before.includes(publicKey) 44 | ) 45 | 46 | const ed25519Fulfillment = new Ed25519Sha256() 47 | filteredKeyPairs.forEach(keyPair => { 48 | const privateKey = Buffer.from(base58.decode(keyPair.privateKey)) 49 | ed25519Fulfillment.sign(transactionHash, privateKey) 50 | }) 51 | return ed25519Fulfillment.serializeUri() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/integration/test_integration.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import { Ed25519Keypair, Transaction, Connection } from '../../src' 7 | 8 | import { 9 | API_PATH, 10 | alice, 11 | aliceCondition, 12 | aliceOutput, 13 | bob, 14 | bobOutput, 15 | asset, 16 | metaData, 17 | delegatedSignTransaction 18 | } from '../constants' 19 | 20 | test('Keypair is created', t => { 21 | const keyPair = new Ed25519Keypair() 22 | 23 | t.truthy(keyPair.publicKey) 24 | t.truthy(keyPair.privateKey) 25 | }) 26 | 27 | test('Valid CREATE transaction with default node', t => { 28 | const conn = new Connection() 29 | 30 | const tx = Transaction.makeCreateTransaction( 31 | asset(), 32 | metaData, 33 | [aliceOutput], 34 | alice.publicKey 35 | ) 36 | const txSigned = Transaction.signTransaction(tx, alice.privateKey) 37 | 38 | return conn.postTransaction(txSigned) 39 | .then(resTx => { 40 | t.truthy(resTx) 41 | }) 42 | }) 43 | 44 | test('Valid CREATE transaction using async', t => { 45 | const conn = new Connection(API_PATH) 46 | 47 | const tx = Transaction.makeCreateTransaction( 48 | asset(), 49 | metaData, 50 | [aliceOutput], 51 | alice.publicKey 52 | ) 53 | const txSigned = Transaction.signTransaction(tx, alice.privateKey) 54 | 55 | return conn.postTransactionAsync(txSigned) 56 | .then(resTx => t.truthy(resTx)) 57 | }) 58 | 59 | test('Valid CREATE transaction using sync', t => { 60 | const conn = new Connection(API_PATH) 61 | 62 | const tx = Transaction.makeCreateTransaction( 63 | asset(), 64 | metaData, 65 | [aliceOutput], 66 | alice.publicKey 67 | ) 68 | const txSigned = Transaction.signTransaction(tx, alice.privateKey) 69 | 70 | return conn.postTransactionSync(txSigned) 71 | .then(resTx => t.truthy(resTx)) 72 | }) 73 | 74 | test('Valid TRANSFER transaction with single Ed25519 input', t => { 75 | const conn = new Connection(API_PATH) 76 | const createTx = Transaction.makeCreateTransaction( 77 | asset(), 78 | metaData, 79 | [aliceOutput], 80 | alice.publicKey 81 | ) 82 | const createTxSigned = Transaction.signTransaction( 83 | createTx, 84 | alice.privateKey 85 | ) 86 | 87 | return conn.postTransactionCommit(createTxSigned) 88 | .then(() => { 89 | const transferTx = Transaction.makeTransferTransaction( 90 | [{ tx: createTxSigned, output_index: 0 }], 91 | [aliceOutput], 92 | metaData 93 | ) 94 | const transferTxSigned = Transaction.signTransaction( 95 | transferTx, 96 | alice.privateKey 97 | ) 98 | return conn.postTransactionCommit(transferTxSigned) 99 | .then(resTx => t.truthy(resTx)) 100 | }) 101 | }) 102 | 103 | test('Valid TRANSFER transaction with multiple Ed25519 inputs', t => { 104 | const conn = new Connection(API_PATH) 105 | const createTx = Transaction.makeCreateTransaction( 106 | asset(), 107 | metaData, 108 | [aliceOutput, bobOutput], 109 | alice.publicKey 110 | ) 111 | const createTxSigned = Transaction.signTransaction( 112 | createTx, 113 | alice.privateKey 114 | ) 115 | 116 | return conn.postTransactionCommit(createTxSigned) 117 | .then(() => { 118 | const transferTx = Transaction.makeTransferTransaction( 119 | [{ tx: createTxSigned, output_index: 0 }, { tx: createTxSigned, output_index: 1 }], 120 | [Transaction.makeOutput(aliceCondition, '2')], 121 | metaData 122 | ) 123 | const transferTxSigned = Transaction.signTransaction( 124 | transferTx, 125 | alice.privateKey, 126 | bob.privateKey 127 | ) 128 | return conn.postTransactionCommit(transferTxSigned) 129 | .then(resTx => t.truthy(resTx)) 130 | }) 131 | }) 132 | 133 | test('Valid TRANSFER transaction with multiple Ed25519 inputs from different transactions', t => { 134 | const conn = new Connection(API_PATH) 135 | const carol = new Ed25519Keypair() 136 | const carolCondition = Transaction.makeEd25519Condition(carol.publicKey) 137 | const carolOutput = Transaction.makeOutput(carolCondition) 138 | const trent = new Ed25519Keypair() 139 | const trentCondition = Transaction.makeEd25519Condition(trent.publicKey) 140 | const trentOutput = Transaction.makeOutput(trentCondition) 141 | const eli = new Ed25519Keypair() 142 | const eliCondition = Transaction.makeEd25519Condition(eli.publicKey) 143 | 144 | const createTx = Transaction.makeCreateTransaction( 145 | asset(), 146 | metaData, 147 | [aliceOutput, bobOutput], 148 | alice.publicKey 149 | ) 150 | const createTxSigned = Transaction.signTransaction( 151 | createTx, 152 | alice.privateKey 153 | ) 154 | 155 | return conn.postTransactionCommit(createTxSigned) 156 | .then(() => { 157 | const transferTx1 = Transaction.makeTransferTransaction( 158 | [{ tx: createTxSigned, output_index: 0 }], 159 | [carolOutput], 160 | metaData 161 | ) 162 | const transferTxSigned1 = Transaction.signTransaction( 163 | transferTx1, 164 | alice.privateKey 165 | ) 166 | const transferTx2 = Transaction.makeTransferTransaction( 167 | [{ tx: createTxSigned, output_index: 1 }], 168 | [trentOutput], 169 | metaData 170 | ) 171 | const transferTxSigned2 = Transaction.signTransaction( 172 | transferTx2, 173 | bob.privateKey 174 | ) 175 | 176 | return conn.postTransactionCommit(transferTxSigned1) 177 | .then(() => conn.postTransactionCommit(transferTxSigned2)) 178 | .then(() => { 179 | const transferTxMultipleInputs = Transaction.makeTransferTransaction( 180 | [{ tx: transferTxSigned1, output_index: 0 }, 181 | { tx: transferTxSigned2, output_index: 0 }], 182 | [Transaction.makeOutput(eliCondition, '2')], 183 | metaData 184 | ) 185 | const transferTxSignedMultipleInputs = Transaction.signTransaction( 186 | transferTxMultipleInputs, 187 | carol.privateKey, 188 | trent.privateKey 189 | ) 190 | return conn.postTransactionCommit(transferTxSignedMultipleInputs) 191 | .then(resTx => t.truthy(resTx)) 192 | }) 193 | }) 194 | }) 195 | 196 | test('Valid CREATE transaction using delegateSign with default node', t => { 197 | const conn = new Connection() 198 | 199 | const tx = Transaction.makeCreateTransaction( 200 | asset(), 201 | metaData, 202 | [aliceOutput], 203 | alice.publicKey 204 | ) 205 | 206 | const txSigned = Transaction.delegateSignTransaction( 207 | tx, 208 | delegatedSignTransaction(alice) 209 | ) 210 | 211 | return conn.postTransaction(txSigned) 212 | .then(resTx => { 213 | t.truthy(resTx) 214 | }) 215 | }) 216 | 217 | test('Valid TRANSFER transaction with multiple Ed25519 inputs using delegateSign', t => { 218 | const conn = new Connection(API_PATH) 219 | const createTx = Transaction.makeCreateTransaction( 220 | asset(), 221 | metaData, 222 | [aliceOutput, bobOutput], 223 | alice.publicKey 224 | ) 225 | const createTxSigned = Transaction.signTransaction( 226 | createTx, 227 | alice.privateKey 228 | ) 229 | 230 | return conn.postTransactionCommit(createTxSigned) 231 | .then(() => { 232 | const transferTx = Transaction.makeTransferTransaction( 233 | [{ tx: createTxSigned, output_index: 0 }, { tx: createTxSigned, output_index: 1 }], 234 | [Transaction.makeOutput(aliceCondition, '2')], 235 | metaData 236 | ) 237 | 238 | const transferTxSigned = Transaction.delegateSignTransaction( 239 | transferTx, 240 | delegatedSignTransaction(alice, bob) 241 | ) 242 | 243 | return conn.postTransactionCommit(transferTxSigned) 244 | .then(resTx => t.truthy(resTx)) 245 | }) 246 | }) 247 | 248 | test('Search for spent and unspent outputs of a given public key', t => { 249 | const conn = new Connection(API_PATH) 250 | const carol = new Ed25519Keypair() 251 | const carolCondition = Transaction.makeEd25519Condition(carol.publicKey) 252 | const carolOutput = Transaction.makeOutput(carolCondition) 253 | const trent = new Ed25519Keypair() 254 | const trentCondition = Transaction.makeEd25519Condition(trent.publicKey) 255 | const trentOutput = Transaction.makeOutput(trentCondition) 256 | 257 | const createTx = Transaction.makeCreateTransaction( 258 | asset(), 259 | metaData, 260 | [carolOutput, carolOutput], 261 | carol.publicKey 262 | ) 263 | const createTxSigned = Transaction.signTransaction( 264 | createTx, 265 | carol.privateKey, 266 | carol.privateKey 267 | ) 268 | 269 | // We spent output 1 (of 0, 1) 270 | const transferTx = Transaction.makeTransferTransaction( 271 | [{ tx: createTxSigned, output_index: 1 }], 272 | [trentOutput], 273 | metaData 274 | ) 275 | const transferTxSigned = Transaction.signTransaction( 276 | transferTx, 277 | carol.privateKey, 278 | ) 279 | 280 | return conn.postTransactionCommit(createTxSigned) 281 | .then(() => conn.postTransactionCommit(transferTxSigned)) 282 | .then(() => conn.listOutputs(carol.publicKey)) 283 | // now listOutputs should return us outputs 0 and 1 (unfiltered) 284 | .then(outputs => t.truthy(outputs.length === 2)) 285 | }) 286 | 287 | test('Search for unspent outputs for a given public key', t => { 288 | const conn = new Connection(API_PATH) 289 | const carol = new Ed25519Keypair() 290 | const carolCondition = Transaction.makeEd25519Condition(carol.publicKey) 291 | const carolOutput = Transaction.makeOutput(carolCondition) 292 | const trent = new Ed25519Keypair() 293 | const trentCondition = Transaction.makeEd25519Condition(trent.publicKey) 294 | const trentOutput = Transaction.makeOutput(trentCondition) 295 | 296 | const createTx = Transaction.makeCreateTransaction( 297 | asset(), 298 | metaData, 299 | [carolOutput, carolOutput, carolOutput], 300 | carol.publicKey 301 | ) 302 | const createTxSigned = Transaction.signTransaction( 303 | createTx, 304 | carol.privateKey, 305 | carol.privateKey 306 | ) 307 | 308 | // We spent output 1 (of 0, 1, 2) 309 | const transferTx = Transaction.makeTransferTransaction( 310 | [{ tx: createTxSigned, output_index: 1 }], 311 | [trentOutput], 312 | metaData 313 | ) 314 | const transferTxSigned = Transaction.signTransaction( 315 | transferTx, 316 | carol.privateKey, 317 | ) 318 | 319 | return conn.postTransactionCommit(createTxSigned) 320 | .then(() => conn.postTransactionCommit(transferTxSigned)) 321 | // now listOutputs should return us outputs 0 and 2 (1 is spent) 322 | .then(() => conn.listOutputs(carol.publicKey, 'false')) 323 | .then(outputs => t.truthy(outputs.length === 2)) 324 | }) 325 | 326 | test('Search for spent outputs for a given public key', t => { 327 | const conn = new Connection(API_PATH) 328 | const carol = new Ed25519Keypair() 329 | const carolCondition = Transaction.makeEd25519Condition(carol.publicKey) 330 | const carolOutput = Transaction.makeOutput(carolCondition) 331 | const trent = new Ed25519Keypair() 332 | const trentCondition = Transaction.makeEd25519Condition(trent.publicKey) 333 | const trentOutput = Transaction.makeOutput(trentCondition) 334 | 335 | const createTx = Transaction.makeCreateTransaction( 336 | asset(), 337 | metaData, 338 | [carolOutput, carolOutput, carolOutput], 339 | carol.publicKey 340 | ) 341 | const createTxSigned = Transaction.signTransaction( 342 | createTx, 343 | carol.privateKey, 344 | carol.privateKey 345 | ) 346 | 347 | // We spent output 1 (of 0, 1, 2) 348 | const transferTx = Transaction.makeTransferTransaction( 349 | [{ tx: createTxSigned, output_index: 1 }], 350 | [trentOutput], 351 | metaData 352 | ) 353 | const transferTxSigned = Transaction.signTransaction( 354 | transferTx, 355 | carol.privateKey, 356 | ) 357 | 358 | return conn.postTransactionCommit(createTxSigned) 359 | .then(() => conn.postTransactionCommit(transferTxSigned)) 360 | // now listOutputs should only return us output 1 (0 and 2 are unspent) 361 | .then(() => conn.listOutputs(carol.publicKey, true)) 362 | .then(outputs => t.truthy(outputs.length === 1)) 363 | }) 364 | 365 | test('Search for an asset', t => { 366 | const conn = new Connection(API_PATH) 367 | 368 | const createTx = Transaction.makeCreateTransaction( 369 | asset(), 370 | metaData, 371 | [aliceOutput], 372 | alice.publicKey 373 | ) 374 | const createTxSigned = Transaction.signTransaction( 375 | createTx, 376 | alice.privateKey 377 | ) 378 | 379 | return conn.postTransactionCommit(createTxSigned) 380 | .then(() => conn.searchAssets(createTxSigned.asset.data.message)) 381 | .then(assets => t.truthy( 382 | assets.pop(), 383 | createTxSigned.asset.data.message 384 | )) 385 | }) 386 | 387 | test('Search for metadata', t => { 388 | const conn = new Connection(API_PATH) 389 | 390 | const createTx = Transaction.makeCreateTransaction( 391 | asset(), 392 | metaData, 393 | [aliceOutput], 394 | alice.publicKey 395 | ) 396 | const createTxSigned = Transaction.signTransaction( 397 | createTx, 398 | alice.privateKey 399 | ) 400 | 401 | return conn.postTransactionCommit(createTxSigned) 402 | .then(() => conn.searchMetadata(createTxSigned.metadata.message)) 403 | .then(assets => t.truthy( 404 | assets.pop(), 405 | createTxSigned.metadata.message 406 | )) 407 | }) 408 | 409 | test('Search blocks containing a transaction', t => { 410 | const conn = new Connection(API_PATH) 411 | 412 | const createTx = Transaction.makeCreateTransaction( 413 | asset(), 414 | metaData, 415 | [aliceOutput], 416 | alice.publicKey 417 | ) 418 | const createTxSigned = Transaction.signTransaction( 419 | createTx, 420 | alice.privateKey 421 | ) 422 | 423 | return conn.postTransactionCommit(createTxSigned) 424 | .then(({ id }) => conn.listBlocks(id)) 425 | .then(blockHeight => conn.getBlock(blockHeight.pop())) 426 | .then(({ transactions }) => transactions.filter(({ id }) => id === createTxSigned.id)) 427 | .then(transactions => t.truthy(transactions.length === 1)) 428 | }) 429 | 430 | test('Search transaction containing an asset', t => { 431 | const conn = new Connection(API_PATH) 432 | 433 | const createTx = Transaction.makeCreateTransaction( 434 | asset(), 435 | metaData, 436 | [aliceOutput], 437 | alice.publicKey 438 | ) 439 | const createTxSigned = Transaction.signTransaction( 440 | createTx, 441 | alice.privateKey 442 | ) 443 | 444 | return conn.postTransactionCommit(createTxSigned) 445 | .then(({ id }) => conn.listTransactions(id)) 446 | .then(transactions => { 447 | t.truthy(transactions.length === 1) 448 | }) 449 | }) 450 | 451 | test('Content-Type cannot be set', t => { 452 | t.throws(() => new Connection(API_PATH, { 'Content-Type': 'application/json' }), { 453 | instanceOf: Error 454 | }) 455 | }) 456 | -------------------------------------------------------------------------------- /test/request/test_request.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import Connection from '../../src/connection' 7 | 8 | const conn = new Connection() 9 | 10 | test('Ensure that BackoffTimedelta works properly', t => { 11 | const req = conn.transport.pickConnection() 12 | req.backoffTime = Date.now() + 50 13 | const target = req.getBackoffTimedelta() 14 | // The value should be close to 50 15 | t.is(target > 45, true) 16 | }) 17 | 18 | test('Ensure that updateBackoffTime throws and error on TimeoutError', async t => { 19 | const req = conn.transport.pickConnection() 20 | const errorMessage = 'TimeoutError' 21 | req.connectionError = new Error(errorMessage) 22 | 23 | t.throws(() => { 24 | req.updateBackoffTime() 25 | }, { instanceOf: Error, message: errorMessage }) 26 | }) 27 | -------------------------------------------------------------------------------- /test/sanitize/test_sanitize.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import rewire from 'rewire' 7 | 8 | const sanitize = rewire('../../src/sanitize.js') 9 | const applyFilterOnObject = sanitize.__get__('applyFilterOnObject') 10 | const filterFromObject = sanitize.__get__('filterFromObject') 11 | 12 | test('Ensure that null filter returns same object', t => { 13 | const expected = { 'testObj': 'test' } 14 | const actual = applyFilterOnObject({ 'testObj': 'test' }, null) 15 | 16 | t.deepEqual(actual, expected) 17 | }) 18 | 19 | test('Ensure function filter with isInclusion true works properly', t => { 20 | const testObj = [true, false, undefined, '', 0, null] 21 | const expected = { 0: true } 22 | const actual = filterFromObject(testObj, (val) => !!val, { isInclusion: true }) 23 | 24 | t.deepEqual(actual, expected) 25 | }) 26 | 27 | test('Ensure function filter with isInclusion false works properly', t => { 28 | const testObj = [false, true, 1, 10, 'this will be removed as it is truthy'] 29 | const expected = { 0: false } 30 | const actual = filterFromObject(testObj, (val) => !!val, { isInclusion: false }) 31 | 32 | t.deepEqual(actual, expected) 33 | }) 34 | 35 | test('Ensure array filter with isInclusion true works properly', t => { 36 | const testObj = [true, false, undefined, '', 0, null] 37 | const expected = { 0: true } 38 | const actual = filterFromObject(testObj, [true], { isInclusion: true }) 39 | 40 | t.deepEqual(actual, expected) 41 | }) 42 | 43 | test('Ensure array filter with isInclusion false works properly', t => { 44 | const testObj = [false, true, 1, 10] 45 | const expected = { 0: false } 46 | const actual = filterFromObject(testObj, [true, 1, 10], { isInclusion: false }) 47 | 48 | t.deepEqual(actual, expected) 49 | }) 50 | 51 | test('Ensure throws error when given invalid filter', t => { 52 | t.throws(() => { 53 | filterFromObject({}, 'lol') 54 | }, { instanceOf: Error, message: 'The given filter is not an array or function. Filter aborted' }) 55 | }) 56 | -------------------------------------------------------------------------------- /test/text-format/test_format_text.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import formatText from '../../src/format_text' 7 | 8 | test('formatText test type 1', t => { 9 | const expected = 'Hi there Dimi!' 10 | const actual = formatText('Hi there ${dimi}!', { dimi: 'Dimi' }) // eslint-disable-line no-template-curly-in-string 11 | 12 | t.is(actual, expected) 13 | }) 14 | 15 | test('formatText test type 2', t => { 16 | const expected = 'BigchainDB is big' 17 | const actual = formatText('${database} is %(status)s', { // eslint-disable-line no-template-curly-in-string 18 | database: 'BigchainDB', 19 | status: 'big' 20 | }) 21 | 22 | t.is(actual, expected) 23 | }) 24 | 25 | test('formatText test type 3', t => { 26 | const expected = 'Berlin is best known for its Currywurst' 27 | const actual = formatText( 28 | 'Berlin is best known for its ${berlin.topKnownFor[0].name}', // eslint-disable-line no-template-curly-in-string 29 | { 30 | berlin: { 31 | topKnownFor: [ 32 | { 33 | name: 'Currywurst' 34 | } 35 | ] 36 | } 37 | } 38 | ) 39 | 40 | t.is(actual, expected) 41 | }) 42 | 43 | test('formatText test throws', t => { 44 | t.throws(() => { 45 | formatText( 46 | 'This will give ${error.}', // eslint-disable-line no-template-curly-in-string 47 | { error: [{}] } 48 | ) 49 | }, { instanceOf: SyntaxError, message: '[formatText] failed to parse named argument key: error.' }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/transaction/test_cryptoconditions.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import { createHash } from 'crypto' 6 | import { validateFulfillment } from 'crypto-conditions' 7 | import test from 'ava' 8 | import base58 from 'bs58' 9 | import { Ed25519Keypair, Transaction, ccJsonLoad } from '../../src' 10 | import { delegatedSignTransaction } from '../constants' 11 | import sha256Hash from '../../src/sha256Hash' 12 | 13 | test('Ed25519 condition encoding', t => { 14 | const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS' 15 | const target = { 16 | details: { 17 | type: 'ed25519-sha-256', 18 | public_key: publicKey, 19 | }, 20 | uri: 'ni:///sha-256;uLdVX7FEjLWVDkAkfMAkEqPPwFqZj7qfiGE152t_x5c?fpt=ed25519-sha-256&cost=131072' 21 | } 22 | t.deepEqual(target, Transaction.makeEd25519Condition(publicKey)) 23 | }) 24 | 25 | test('Sha256Condition fulfillment', t => { 26 | const preimage = 'secret' 27 | const target = { 28 | details: { 29 | type_id: 0, 30 | bitmask: 3, 31 | preimage, 32 | type: 'fulfillment' 33 | }, 34 | uri: 'ni:///sha-256;K7gNU3sdo-OL0wNhqoVWhr3g6s1xYv72ol_pe_Unols?fpt=preimage-sha-256&cost=6' 35 | } 36 | t.deepEqual(target, Transaction.makeSha256Condition(preimage)) 37 | }) 38 | 39 | test('Threshold condition encoding', t => { 40 | const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS' 41 | const ed25519 = Transaction.makeEd25519Condition(publicKey, false) 42 | const condition = Transaction.makeThresholdCondition(1, [ed25519, ed25519]) 43 | const output = Transaction.makeOutput(condition) 44 | const target = { 45 | condition: { 46 | details: { 47 | type: 'threshold-sha-256', 48 | threshold: 1, 49 | subconditions: [ 50 | { 51 | type: 'ed25519-sha-256', 52 | public_key: publicKey, 53 | }, 54 | { 55 | type: 'ed25519-sha-256', 56 | public_key: publicKey, 57 | } 58 | ] 59 | }, 60 | uri: 'ni:///sha-256;xTeBhQj7ae5Tym7cp83fwtkesQnhdwNwDEMIYwnf2g0?fpt=threshold-sha-256&cost=133120&subtypes=ed25519-sha-256', 61 | }, 62 | amount: '1', 63 | public_keys: [publicKey] 64 | } 65 | t.deepEqual(target, output) 66 | }) 67 | 68 | test('Fulfillment correctly formed', t => { 69 | const alice = new Ed25519Keypair() 70 | const txCreate = Transaction.makeCreateTransaction( 71 | {}, 72 | {}, 73 | [Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))], 74 | alice.publicKey 75 | ) 76 | // Sign in order to get the tx id, needed for the unique fulfillment in the transfer transaction 77 | const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey) 78 | 79 | const txTransfer = Transaction.makeTransferTransaction( 80 | [{ tx: signCreateTransaction, output_index: 0 }], 81 | [Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))], 82 | {} 83 | ) 84 | const txSigned = Transaction.signTransaction(txTransfer, alice.privateKey) 85 | 86 | // Here reconstruct the fulfillment of the transfer transaction 87 | // The tx is serialized, and extended with tx_id and output index, and then hashed into bytes 88 | const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer) 89 | const msgUniqueFulfillment = txTransfer.inputs[0].fulfills ? msg 90 | .concat(txTransfer.inputs[0].fulfills.transaction_id) 91 | .concat(txTransfer.inputs[0].fulfills.output_index) : msg 92 | const msgHash = sha256Hash(msgUniqueFulfillment) 93 | 94 | t.truthy(validateFulfillment( 95 | txSigned.inputs[0].fulfillment, 96 | txCreate.outputs[0].condition.uri, 97 | Buffer.from(msgHash, 'hex') 98 | )) 99 | }) 100 | 101 | test('Delegated signature is correct', t => { 102 | const alice = new Ed25519Keypair() 103 | 104 | const txCreate = Transaction.makeCreateTransaction( 105 | {}, 106 | {}, 107 | [Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))], 108 | alice.publicKey 109 | ) 110 | 111 | const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey) 112 | const delegatedSignCreateTransaction = Transaction.delegateSignTransaction( 113 | txCreate, 114 | delegatedSignTransaction(alice) 115 | ) 116 | t.deepEqual(signCreateTransaction, delegatedSignCreateTransaction) 117 | }) 118 | 119 | test('Delegated async signature is correct', async t => { 120 | const alice = new Ed25519Keypair() 121 | 122 | const txCreate = Transaction.makeCreateTransaction( 123 | {}, 124 | {}, 125 | [Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))], 126 | alice.publicKey 127 | ) 128 | 129 | const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey) 130 | const delegatedSignCreateTransaction = await Transaction.delegateSignTransactionAsync( 131 | txCreate, 132 | delegatedSignTransaction(alice) 133 | ) 134 | t.deepEqual(signCreateTransaction, delegatedSignCreateTransaction) 135 | }) 136 | 137 | test('CryptoConditions JSON load', t => { 138 | const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS' 139 | const cond = ccJsonLoad({ 140 | type: 'threshold-sha-256', 141 | threshold: 1, 142 | subconditions: [{ 143 | type: 'ed25519-sha-256', 144 | public_key: publicKey 145 | }, 146 | { 147 | hash: base58.encode(createHash('sha256').update('a').digest()) 148 | }], 149 | }) 150 | t.truthy(cond.subconditions.length === 2) 151 | }) 152 | -------------------------------------------------------------------------------- /test/transaction/test_transaction.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | import sinon from 'sinon' 7 | 8 | import { Transaction } from '../../src' 9 | 10 | import { 11 | alice, 12 | aliceOutput, 13 | metaData, 14 | createTx, 15 | transferTx 16 | } from '../constants' 17 | 18 | test('Create valid output with default amount', t => { 19 | const condition = { 20 | details: { 21 | type: 'ed25519-sha-256', 22 | public_key: 'abc' 23 | } 24 | } 25 | const expected = { 26 | amount: '1', 27 | condition, 28 | public_keys: ['abc'] 29 | } 30 | const res = Transaction.makeOutput(condition) 31 | t.deepEqual(res, expected) 32 | }) 33 | 34 | test('Create valid output with custom amount', t => { 35 | const condition = { 36 | details: { 37 | type: 'ed25519-sha-256', 38 | public_key: 'abc' 39 | } 40 | } 41 | const customAmount = '1337' 42 | const expected = { 43 | amount: customAmount, 44 | condition, 45 | public_keys: ['abc'] 46 | } 47 | const res = Transaction.makeOutput(condition, customAmount) 48 | t.deepEqual(res, expected) 49 | }) 50 | 51 | test('Pass condition not based on public_keys to makeOutput', t => { 52 | const condition = { 53 | details: { 54 | idea: 'just pretend this is e.g. a hashlock' 55 | } 56 | } 57 | const expected = { 58 | amount: '1', 59 | condition, 60 | public_keys: [] 61 | } 62 | const res = Transaction.makeOutput(condition) 63 | t.deepEqual(res, expected) 64 | }) 65 | 66 | test('makeOutput throws TypeError with incorrect amount type', t => { 67 | t.throws(() => Transaction.makeOutput({}, 1337), { instanceOf: TypeError }) 68 | }) 69 | 70 | test('Create TRANSFER transaction based on CREATE transaction', t => { 71 | sinon.spy(Transaction, 'makeTransaction') 72 | Transaction.makeTransferTransaction( 73 | [{ tx: createTx, output_index: 0 }], 74 | [aliceOutput], 75 | metaData 76 | ) 77 | const expected = [ 78 | 'TRANSFER', 79 | { id: createTx.id }, 80 | metaData, 81 | [aliceOutput], 82 | [Transaction.makeInputTemplate( 83 | [alice.publicKey], 84 | { output_index: 0, transaction_id: createTx.id } 85 | )] 86 | ] 87 | // NOTE: `src/transaction/makeTransaction` is `export default`, hence we 88 | // can only mock `makeTransaction.default` with a hack: 89 | // See: https://stackoverflow.com/a/33676328/1263876 90 | t.truthy(Transaction.makeTransaction.calledWith(...expected)) 91 | Transaction.makeTransaction.restore() 92 | }) 93 | 94 | test('Create TRANSFER transaction based on TRANSFER transaction', t => { 95 | sinon.spy(Transaction, 'makeTransaction') 96 | 97 | Transaction.makeTransferTransaction( 98 | [{ tx: transferTx, output_index: 0 }], 99 | [aliceOutput], 100 | metaData 101 | ) 102 | const expected = [ 103 | 'TRANSFER', 104 | { id: transferTx.asset.id }, 105 | metaData, 106 | [aliceOutput], 107 | [Transaction.makeInputTemplate( 108 | [alice.publicKey], 109 | { output_index: 0, transaction_id: transferTx.id } 110 | )] 111 | ] 112 | 113 | t.truthy(Transaction.makeTransaction.calledWith(...expected)) 114 | Transaction.makeTransaction.restore() 115 | }) 116 | -------------------------------------------------------------------------------- /test/transport/test_transport.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import test from 'ava' 6 | 7 | import { 8 | Connection 9 | } from '../../src' 10 | 11 | test('Pick connection with earliest backoff time', async t => { 12 | const path1 = 'http://localhost:9984/api/v1/' 13 | const path2 = 'http://localhostwrong:9984/api/v1/' 14 | 15 | // Reverse order 16 | const conn = new Connection([path2, path1]) 17 | // This will trigger the 'forwardRequest' so the correct connection will be taken 18 | await conn.searchAssets('example') 19 | 20 | const connection1 = conn.transport.connectionPool[1] 21 | 22 | t.deepEqual(conn.transport.pickConnection(), connection1) 23 | }) 24 | -------------------------------------------------------------------------------- /types/Ed25519Keypair.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | export default class Ed25519Keypair { 6 | publicKey: string; 7 | privateKey: string; 8 | 9 | constructor(seed?: Buffer); 10 | } 11 | -------------------------------------------------------------------------------- /types/baseRequest.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | export interface RequestConfig { 6 | headers?: Record; 7 | jsonBody?: Record; 8 | query?: Record; 9 | method?: 'GET' | ' POST' | 'PUT'; 10 | urlTemplateSpec?: any[] | Record; 11 | [key: string]: any; 12 | } 13 | 14 | export function ResponseError( 15 | message: string, 16 | status?: number, 17 | requestURI?: string 18 | ): void; 19 | 20 | declare function timeout( 21 | ms: number, 22 | promise: Promise 23 | ): Promise; 24 | 25 | declare function handleResponse(res: Response): Response; 26 | 27 | export default function baseRequest( 28 | url: string, 29 | config: RequestConfig, 30 | requestTimeout?: number 31 | ): Promise; 32 | -------------------------------------------------------------------------------- /types/connection.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import type { RequestConfig } from './baseRequest'; 6 | import type { Node } from './request'; 7 | import type Transport from './transport'; 8 | import type { 9 | CreateTransaction, 10 | TransactionOperations, 11 | TransferTransaction, 12 | TransactionCommon, 13 | } from './transaction'; 14 | 15 | declare const DEFAULT_NODE = 'http://localhost:9984/api/v1/'; 16 | declare const DEFAULT_TIMEOUT = 20000; // The default value is 20 seconds 17 | 18 | export interface InputNode { 19 | endpoint: string; 20 | } 21 | 22 | export type AssetResult = { 23 | id: string; 24 | data: Record; 25 | }; 26 | 27 | export type MetadataResult = { 28 | id: string; 29 | metadata: Record; 30 | }; 31 | 32 | export enum Endpoints { 33 | blocks = 'blocks', 34 | blocksDetail = 'blocksDetail', 35 | outputs = 'outputs', 36 | transactions = 'transactions', 37 | transactionsSync = 'transactionsSync', 38 | transactionsAsync = 'transactionsAsync', 39 | transactionsCommit = 'transactionsCommit', 40 | transactionsDetail = 'transactionsDetail', 41 | assets = 'assets', 42 | metadata = 'metadata', 43 | } 44 | 45 | export interface EndpointsUrl { 46 | [Endpoints.blocks]: 'blocks'; 47 | [Endpoints.blocksDetail]: 'blocks/%(blockHeight)s'; 48 | [Endpoints.outputs]: 'outputs'; 49 | [Endpoints.transactions]: 'transactions'; 50 | [Endpoints.transactionsSync]: 'transactions?mode=sync'; 51 | [Endpoints.transactionsAsync]: 'transactions?mode=async'; 52 | [Endpoints.transactionsCommit]: 'transactions?mode=commit'; 53 | [Endpoints.transactionsDetail]: 'transactions/%(transactionId)s'; 54 | [Endpoints.assets]: 'assets'; 55 | [Endpoints.metadata]: 'metadata'; 56 | } 57 | 58 | export interface EndpointsResponse< 59 | O = TransactionOperations.CREATE, 60 | A = Record, 61 | M = Record 62 | > { 63 | [Endpoints.blocks]: number[]; 64 | [Endpoints.blocksDetail]: { 65 | height: number; 66 | transactions: (CreateTransaction | TransferTransaction)[]; 67 | }; 68 | [Endpoints.outputs]: { 69 | transaction_id: string; 70 | output_index: number; 71 | }[]; 72 | [Endpoints.transactions]: O extends TransactionOperations.CREATE 73 | ? CreateTransaction[] 74 | : O extends TransactionOperations.TRANSFER 75 | ? TransferTransaction[] 76 | : (CreateTransaction | TransferTransaction)[]; 77 | [Endpoints.transactionsSync]: O extends TransactionOperations.CREATE 78 | ? CreateTransaction 79 | : TransferTransaction; 80 | [Endpoints.transactionsAsync]: O extends TransactionOperations.CREATE 81 | ? CreateTransaction 82 | : TransferTransaction; 83 | [Endpoints.transactionsCommit]: O extends TransactionOperations.CREATE 84 | ? CreateTransaction 85 | : TransferTransaction; 86 | [Endpoints.transactionsDetail]: O extends TransactionOperations.CREATE 87 | ? CreateTransaction 88 | : TransferTransaction; 89 | [Endpoints.assets]: AssetResult[]; 90 | [Endpoints.metadata]: MetadataResult[]; 91 | } 92 | 93 | export default class Connection { 94 | private transport: Transport; 95 | private normalizedNodes: Node[]; 96 | private headers: Record; 97 | 98 | constructor( 99 | nodes: string | InputNode | (string | InputNode)[], 100 | headers?: Record, 101 | timeout?: number 102 | ); 103 | 104 | static normalizeNode( 105 | node: string | InputNode, 106 | headers: Record 107 | ): Node; 108 | 109 | static getApiUrls(endpoint: E): EndpointsUrl[E]; 110 | 111 | private _req>( 112 | path: EndpointsUrl[E], 113 | options: RequestConfig 114 | ): Promise; 115 | 116 | getBlock( 117 | blockHeight: number | string 118 | ): Promise; 119 | 120 | getTransaction( 121 | transactionId: string 122 | ): Promise[Endpoints.transactionsDetail]>; 123 | 124 | listBlocks( 125 | transactionId: string 126 | ): Promise; 127 | 128 | listOutputs( 129 | publicKey: string, 130 | spent?: boolean 131 | ): Promise; 132 | 133 | listTransactions( 134 | assetId: string, 135 | operation?: TransactionOperations 136 | ): Promise[Endpoints.transactions]>; 137 | 138 | postTransaction< 139 | O extends TransactionOperations = TransactionOperations.CREATE, 140 | A = Record, 141 | M = Record 142 | >( 143 | transaction: TransactionCommon 144 | ): Promise[Endpoints.transactionsCommit]>; 145 | 146 | postTransactionSync< 147 | O extends TransactionOperations = TransactionOperations.CREATE, 148 | A = Record, 149 | M = Record 150 | >( 151 | transaction: TransactionCommon 152 | ): Promise[Endpoints.transactionsSync]>; 153 | 154 | postTransactionAsync< 155 | O extends TransactionOperations = TransactionOperations.CREATE, 156 | A = Record, 157 | M = Record 158 | >( 159 | transaction: TransactionCommon 160 | ): Promise[Endpoints.transactionsAsync]>; 161 | 162 | postTransactionCommit< 163 | O extends TransactionOperations = TransactionOperations.CREATE, 164 | A = Record, 165 | M = Record 166 | >( 167 | transaction: TransactionCommon 168 | ): Promise[Endpoints.transactionsCommit]>; 169 | 170 | searchAssets( 171 | search: string, 172 | limit?: number 173 | ): Promise; 174 | 175 | searchMetadata( 176 | search: string, 177 | limit?: number 178 | ): Promise; 179 | } 180 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import Ed25519Keypair from './Ed25519Keypair'; 6 | import Connection, { 7 | Endpoints, 8 | EndpointsResponse, 9 | EndpointsUrl, 10 | } from './connection'; 11 | import Transaction, { 12 | CreateTransaction, 13 | TransactionCommon, 14 | TransactionCommonSigned, 15 | TransactionInput, 16 | TransactionOutput, 17 | TransferTransaction, 18 | TransactionUnspentOutput, 19 | TransactionOperations, 20 | } from './transaction'; 21 | import ccJsonLoad from './utils/ccJsonLoad'; 22 | import ccJsonify from './utils/ccJsonify'; 23 | 24 | export { ccJsonLoad, ccJsonify, Connection, Ed25519Keypair, Transaction }; 25 | 26 | // Extras 27 | export { 28 | Endpoints, 29 | EndpointsResponse, 30 | EndpointsUrl, 31 | CreateTransaction, 32 | TransactionCommon, 33 | TransactionCommonSigned, 34 | TransactionInput, 35 | TransactionOutput, 36 | TransferTransaction, 37 | TransactionUnspentOutput, 38 | TransactionOperations, 39 | }; 40 | -------------------------------------------------------------------------------- /types/request.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import type { RequestConfig } from './baseRequest'; 6 | 7 | export interface Node { 8 | endpoint: string; 9 | headers: Record; 10 | } 11 | 12 | export default class Request { 13 | private node: Node; 14 | private backoffTime: number; 15 | private retries: number; 16 | private connectionError?: Error; 17 | 18 | constructor(node: Node); 19 | 20 | request>( 21 | urlPath: string, 22 | config?: RequestConfig, 23 | timeout?: number, 24 | maxBackoffTime?: number 25 | ): Promise; 26 | 27 | updateBackoffTime(maxBackoffTime: number): void; 28 | 29 | getBackoffTimedelta(): number; 30 | 31 | static sleep(ms: number): void; 32 | } 33 | -------------------------------------------------------------------------------- /types/sanitize.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | declare type FilterFn = (val: any, key?: string) => void; 6 | 7 | declare function filterFromObject>( 8 | obj: I, 9 | filter: Array | FilterFn, 10 | conf: { isInclusion?: boolean } 11 | ): Partial; 12 | 13 | declare function applyFilterOnObject>( 14 | obj: I, 15 | filterFn?: FilterFn 16 | ): Partial; 17 | 18 | declare function selectFromObject>( 19 | obj: I, 20 | filter: Array | FilterFn 21 | ): Partial; 22 | 23 | export default function sanitize>( 24 | obj: I 25 | ): Partial | I; 26 | -------------------------------------------------------------------------------- /types/transaction.d.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Ed25519Sha256, 3 | Fulfillment, 4 | PreimageSha256, 5 | ThresholdSha256, 6 | } from 'crypto-conditions'; 7 | import { 8 | Ed25519Sha256JSONCondition, 9 | PreimageSha256JSONCondition, 10 | ThresholdSha256JSONCondition, 11 | } from './utils/ccJsonify'; 12 | 13 | export interface TransactionInput { 14 | fulfillment: string; 15 | fulfills: { 16 | output_index: number; 17 | transaction_id: string; 18 | } | null; 19 | owners_before: string[]; 20 | } 21 | export interface TransactionOutput { 22 | amount: string; 23 | condition: 24 | | PreimageSha256JSONCondition 25 | | ThresholdSha256JSONCondition 26 | | Ed25519Sha256JSONCondition; 27 | public_keys: string[]; 28 | } 29 | 30 | export enum TransactionOperations { 31 | CREATE = 'CREATE', 32 | TRANSFER = 'TRANSFER', 33 | } 34 | 35 | export interface TransactionCommon< 36 | O extends TransactionOperations = TransactionOperations.CREATE, 37 | A extends Record = Record, 38 | M extends Record = Record 39 | > { 40 | id?: string; 41 | inputs: TransactionInput[]; 42 | outputs: TransactionOutput[]; 43 | version: string; 44 | metadata: M; 45 | operation: O; 46 | asset: TransactionAssetMap; 47 | } 48 | 49 | export interface TransactionCommonSigned< 50 | O extends TransactionOperations = TransactionOperations.CREATE, 51 | A extends Record = Record, 52 | M extends Record = Record 53 | > extends Omit, 'id'> { 54 | id: string; 55 | } 56 | 57 | export type TransactionAssetMap< 58 | Operation, 59 | A extends Record 60 | > = Operation extends TransactionOperations.CREATE 61 | ? { 62 | data: A; 63 | } 64 | : { 65 | id: string; 66 | }; 67 | 68 | export interface CreateTransaction< 69 | A extends Record = Record, 70 | M extends Record = Record 71 | > extends TransactionCommon { 72 | id: string; 73 | asset: TransactionAssetMap; 74 | operation: TransactionOperations.CREATE; 75 | } 76 | 77 | export interface TransferTransaction< 78 | M extends Record = Record 79 | > extends TransactionCommon { 80 | id: string; 81 | asset: TransactionAssetMap; 82 | operation: TransactionOperations.TRANSFER; 83 | } 84 | 85 | export interface TransactionUnspentOutput { 86 | tx: TransactionCommon; 87 | output_index: number; 88 | } 89 | 90 | interface TxTemplate { 91 | id: null; 92 | operation: null; 93 | outputs: []; 94 | inputs: []; 95 | metadata: null; 96 | asset: null; 97 | version: '2.0'; 98 | } 99 | 100 | export type DelegateSignFunction = ( 101 | serializedTransaction: string, 102 | input: TransactionInput, 103 | index?: number 104 | ) => string; 105 | 106 | export type DelegateSignFunctionAsync = ( 107 | serializedTransaction: string, 108 | input: TransactionInput, 109 | index?: number 110 | ) => Promise; 111 | 112 | export default class Transaction { 113 | static serializeTransactionIntoCanonicalString< 114 | O extends TransactionOperations = TransactionOperations 115 | >(transaction: TransactionCommon): string; 116 | 117 | static serializeTransactionIntoCanonicalString( 118 | transaction: CreateTransaction | TransferTransaction 119 | ): string; 120 | 121 | static makeEd25519Condition(publicKey: string): Ed25519Sha256JSONCondition; 122 | 123 | static makeEd25519Condition( 124 | publicKey: string, 125 | json: true 126 | ): Ed25519Sha256JSONCondition; 127 | 128 | static makeEd25519Condition(publicKey: string, json: false): Ed25519Sha256; 129 | 130 | static makeEd25519Condition( 131 | publicKey: string, 132 | json?: boolean 133 | ): Ed25519Sha256 | Ed25519Sha256JSONCondition; 134 | 135 | static makeSha256Condition(preimage: string): PreimageSha256JSONCondition; 136 | 137 | static makeSha256Condition( 138 | preimage: string, 139 | json: true 140 | ): PreimageSha256JSONCondition; 141 | 142 | static makeSha256Condition(preimage: string, json: false): PreimageSha256; 143 | 144 | static makeSha256Condition( 145 | preimage: string, 146 | json?: boolean 147 | ): PreimageSha256 | PreimageSha256JSONCondition; 148 | 149 | static makeThresholdCondition( 150 | threshold: number, 151 | subconditions: (string | Fulfillment)[] 152 | ): ThresholdSha256JSONCondition; 153 | 154 | static makeThresholdCondition( 155 | threshold: number, 156 | subconditions: (string | Fulfillment)[], 157 | json: true 158 | ): ThresholdSha256JSONCondition; 159 | 160 | static makeThresholdCondition( 161 | threshold: number, 162 | subconditions: (string | Fulfillment)[], 163 | json: false 164 | ): ThresholdSha256; 165 | 166 | static makeThresholdCondition( 167 | threshold: number, 168 | subconditions: (string | Fulfillment)[], 169 | json?: boolean 170 | ): ThresholdSha256 | ThresholdSha256JSONCondition; 171 | 172 | static makeInputTemplate( 173 | publicKeys: string[], 174 | fulfills?: TransactionInput['fulfills'], 175 | fulfillment?: TransactionInput['fulfillment'] 176 | ): TransactionInput; 177 | 178 | static makeOutput( 179 | condition: 180 | | PreimageSha256JSONCondition 181 | | ThresholdSha256JSONCondition 182 | | Ed25519Sha256JSONCondition, 183 | amount?: string 184 | ): TransactionOutput; 185 | 186 | static makeTransactionTemplate(): TxTemplate; 187 | 188 | static makeTransaction< 189 | O extends TransactionOperations, 190 | A = Record, 191 | M = Record 192 | >( 193 | operation: O, 194 | asset: A, 195 | metadata: M, 196 | outputs: TransactionOutput[], 197 | inputs: TransactionInput[] 198 | ): TransactionCommon; 199 | 200 | static makeCreateTransaction< 201 | A = Record, 202 | M = Record 203 | >( 204 | asset: A, 205 | metadata: M, 206 | outputs: TransactionOutput[], 207 | ...issuers: string[] 208 | ): CreateTransaction; 209 | 210 | static makeTransferTransaction>( 211 | unspentOutputs: TransactionUnspentOutput[], 212 | outputs: TransactionOutput[], 213 | metadata: M 214 | ): TransferTransaction; 215 | 216 | static signTransaction< 217 | O extends TransactionOperations = TransactionOperations.CREATE 218 | >( 219 | transaction: TransactionCommon, 220 | ...privateKeys: string[] 221 | ): TransactionCommonSigned; 222 | 223 | static delegateSignTransaction< 224 | O extends TransactionOperations = TransactionOperations.CREATE 225 | >( 226 | transaction: TransactionCommon, 227 | signFn: DelegateSignFunction 228 | ): TransactionCommonSigned; 229 | 230 | static delegateSignTransactionAsync< 231 | O extends TransactionOperations = TransactionOperations.CREATE 232 | >( 233 | transaction: TransactionCommon, 234 | signFn: DelegateSignFunctionAsync 235 | ): Promise>; 236 | } 237 | -------------------------------------------------------------------------------- /types/transport.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import Request, { Node } from './request'; 6 | import type { RequestConfig } from './baseRequest'; 7 | 8 | export default class Transport { 9 | private connectionPool: Request[]; 10 | private timeout: number; 11 | private maxBackoffTime: number; 12 | 13 | constructor(nodes: Node[], timeout: number); 14 | 15 | pickConnection(): Request; 16 | 17 | forwardRequest>( 18 | path: string, 19 | config: RequestConfig 20 | ): Promise; 21 | } 22 | -------------------------------------------------------------------------------- /types/utils/ccJsonLoad.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import type { 6 | Condition, 7 | Ed25519Sha256, 8 | PreimageSha256, 9 | ThresholdSha256, 10 | } from 'crypto-conditions'; 11 | import type { 12 | Ed25519Sha256JSONCondition, 13 | JSONCondition, 14 | PreimageSha256JSONCondition, 15 | ThresholdSha256JSONCondition, 16 | } from './ccJsonify'; 17 | 18 | declare function ccJsonLoad( 19 | conditionJson: PreimageSha256JSONCondition 20 | ): PreimageSha256; 21 | 22 | declare function ccJsonLoad( 23 | conditionJson: ThresholdSha256JSONCondition 24 | ): ThresholdSha256; 25 | 26 | declare function ccJsonLoad( 27 | conditionJson: Ed25519Sha256JSONCondition 28 | ): Ed25519Sha256; 29 | 30 | declare function ccJsonLoad(conditionJson: JSONCondition): Condition; 31 | 32 | export default ccJsonLoad; 33 | -------------------------------------------------------------------------------- /types/utils/ccJsonify.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | import type { 6 | Condition, 7 | Ed25519Sha256, 8 | PreimageSha256, 9 | ThresholdSha256, 10 | } from 'crypto-conditions'; 11 | import type { TypeId, TypeName } from 'crypto-conditions/types/types'; 12 | 13 | interface BaseJSONCondition { 14 | details: { 15 | [key: string]: any; 16 | }; 17 | uri: string; 18 | } 19 | 20 | export interface JSONCondition extends BaseJSONCondition { 21 | details: { 22 | type_id: TypeId; 23 | bitmask: number; 24 | type: 'condition'; 25 | hash: string; 26 | max_fulfillment_length: number; 27 | }; 28 | } 29 | 30 | export interface PreimageSha256JSONCondition extends BaseJSONCondition { 31 | details: { 32 | type_id: TypeId.PreimageSha256; 33 | bitmask: 3; 34 | preimage?: string; 35 | type?: 'fulfillement'; 36 | }; 37 | } 38 | 39 | export interface ThresholdSha256JSONCondition extends BaseJSONCondition { 40 | details: { 41 | type: TypeName.ThresholdSha256; 42 | subConditions: (Ed25519Sha256JSONCondition | PreimageSha256JSONCondition)[]; 43 | }; 44 | } 45 | 46 | export interface Ed25519Sha256JSONCondition extends BaseJSONCondition { 47 | details: { type: TypeName.Ed25519Sha256; publicKey?: string }; 48 | } 49 | 50 | export type JSONConditionUnion = 51 | | JSONCondition 52 | | PreimageSha256JSONCondition 53 | | ThresholdSha256JSONCondition 54 | | Ed25519Sha256JSONCondition; 55 | 56 | declare function ccJsonify( 57 | fulfillment: PreimageSha256 58 | ): PreimageSha256JSONCondition; 59 | 60 | declare function ccJsonify( 61 | fulfillment: ThresholdSha256 62 | ): ThresholdSha256JSONCondition; 63 | 64 | declare function ccJsonify( 65 | fulfillment: Ed25519Sha256 66 | ): Ed25519Sha256JSONCondition; 67 | 68 | declare function ccJsonify(fulfillment: Condition): JSONCondition; 69 | 70 | export default ccJsonify; 71 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable strict, no-console, object-shorthand */ 6 | 7 | 'use strict' 8 | 9 | const { ProvidePlugin } = require('webpack') 10 | const { paths } = require('./webpack.parts') 11 | 12 | module.exports = { 13 | entry: paths.entry, 14 | mode: 'none', 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.js$/, 19 | exclude: /node_modules/, 20 | use: { 21 | loader: 'babel-loader', 22 | }, 23 | } 24 | ] 25 | }, 26 | optimization: { 27 | minimize: true, 28 | emitOnErrors: false 29 | }, 30 | resolve: { 31 | extensions: ['.js'], 32 | modules: ['node_modules'], 33 | fallback: { 34 | buffer: require.resolve('buffer/'), 35 | } 36 | }, 37 | plugins: [ 38 | new ProvidePlugin({ 39 | Buffer: ['buffer', 'Buffer'] 40 | }) 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable strict, no-console, object-shorthand */ 6 | 7 | 'use strict' 8 | 9 | const PRODUCTION = process.env.NODE_ENV === 'production' 10 | 11 | const common = require('./webpack.common') 12 | 13 | const { outputs } = require('./webpack.parts') 14 | 15 | // '[libraryTarget]': [file extension] 16 | const OUTPUT_MAPPING = { 17 | 'amd': 'amd', 18 | 'commonjs': 'cjs', 19 | 'commonjs2': 'cjs2', 20 | 'umd': 'umd', 21 | 'window': 'window', 22 | } 23 | 24 | const OVERRIDES = { 25 | // optimization: { 26 | // minimize: false 27 | // } 28 | } 29 | 30 | if (PRODUCTION) { 31 | module.exports = outputs(common, 'production', OUTPUT_MAPPING, OVERRIDES) 32 | } else { 33 | module.exports = outputs(common, 'development', OUTPUT_MAPPING, OVERRIDES) 34 | } 35 | -------------------------------------------------------------------------------- /webpack.development.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable strict, no-console, object-shorthand, import/no-extraneous-dependencies */ 6 | 7 | 'use strict' 8 | 9 | const TerserPlugin = require('terser-webpack-plugin') 10 | 11 | module.exports = { 12 | devtool: 'inline-source-map', 13 | optimization: { 14 | minimizer: [ 15 | new TerserPlugin({ 16 | test: /vendor/, 17 | }), 18 | new TerserPlugin({ 19 | test: /^((?!(vendor)).)*.js$/, 20 | }) 21 | ], 22 | splitChunks: { 23 | cacheGroups: { 24 | commons: { 25 | test: /[\\/]node_modules[\\/]/, 26 | name: 'vendors', 27 | chunks: 'all' 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /webpack.parts.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable strict, no-console, object-shorthand, import/no-extraneous-dependencies */ 6 | 7 | 'use strict' 8 | 9 | const path = require('path') 10 | const { merge } = require('webpack-merge') 11 | 12 | const development = require('./webpack.development') 13 | const production = require('./webpack.production') 14 | 15 | const AddVendorsPlugin = require('./plugins/add-vendors-plugin') 16 | 17 | const paths = { 18 | entry: path.resolve(__dirname, './src/index.js'), 19 | bundle: path.resolve(__dirname, 'dist/browser'), 20 | } 21 | 22 | const outputs = (base, env, mapping, overrides) => { 23 | const collection = [] 24 | const library = 'bigchaindb-driver' 25 | const windowLibrary = 'BigchainDB' 26 | 27 | let environment = development 28 | let ext = 'js' 29 | 30 | if (env === 'production') { 31 | environment = production 32 | ext = `min.${ext}` 33 | } 34 | 35 | Object.entries(mapping).forEach(([target, extension]) => { 36 | const filename = `[name].${library}.${extension}.${ext}` 37 | 38 | const compiled = { 39 | output: { 40 | filename: filename, 41 | library: target === 'window' ? windowLibrary : library, 42 | libraryTarget: target, 43 | path: paths.bundle 44 | }, 45 | plugins: [ 46 | new AddVendorsPlugin(`${library}.${extension}.${ext}`) 47 | ] 48 | } 49 | 50 | collection.push(merge(base, environment, compiled, overrides)) 51 | }) 52 | 53 | return collection 54 | } 55 | 56 | module.exports = { 57 | outputs, 58 | paths 59 | } 60 | -------------------------------------------------------------------------------- /webpack.production.js: -------------------------------------------------------------------------------- 1 | // Copyright BigchainDB GmbH and BigchainDB contributors 2 | // SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) 3 | // Code is Apache-2.0 and docs are CC-BY-4.0 4 | 5 | /* eslint-disable strict, no-console, object-shorthand */ 6 | 7 | 'use strict' 8 | 9 | module.exports = { 10 | devtool: 'source-map', 11 | } 12 | --------------------------------------------------------------------------------