mirror of
https://github.com/bigchaindb/js-bigchaindb-driver.git
synced 2024-11-22 01:36:56 +01:00
Merge pull request #159 from bigchaindb/tendermint-tx-fixed
Update driver in order to be compatible with BigchainDB2.0
This commit is contained in:
commit
618c2526f8
23
.babelrc
23
.babelrc
@ -1,9 +1,5 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": ["env"],
|
||||||
"@ava/stage-4",
|
|
||||||
"@ava/transform-test-files",
|
|
||||||
"es2015-no-commonjs"
|
|
||||||
],
|
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"transform-export-extensions",
|
"transform-export-extensions",
|
||||||
@ -11,21 +7,4 @@
|
|||||||
"transform-object-rest-spread"
|
"transform-object-rest-spread"
|
||||||
],
|
],
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
|
|
||||||
"env": {
|
|
||||||
"bundle": {
|
|
||||||
"plugins": [
|
|
||||||
["transform-runtime", {
|
|
||||||
"polyfill": true,
|
|
||||||
"regenerator": false
|
|
||||||
}]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"cjs": {
|
|
||||||
"plugins": [
|
|
||||||
"add-module-exports",
|
|
||||||
"transform-es2015-modules-commonjs"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
9
.ci/travis-before-install.sh
Executable file
9
.ci/travis-before-install.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||||
|
|
||||||
|
sudo rm /usr/local/bin/docker-compose
|
||||||
|
curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||||
|
chmod +x docker-compose
|
||||||
|
sudo mv docker-compose /usr/local/bin
|
5
.ci/travis-before-script.sh
Executable file
5
.ci/travis-before-script.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e -x
|
||||||
|
|
||||||
|
docker-compose up -d bigchaindb
|
5
.ci/travis-install.sh
Executable file
5
.ci/travis-install.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e -x
|
||||||
|
|
||||||
|
docker-compose build --no-cache bigchaindb
|
5
.ci/travis_script.sh
Executable file
5
.ci/travis_script.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e -x
|
||||||
|
|
||||||
|
docker-compose run --rm js-bigchaindb-driver yarn test
|
23
.travis.yml
23
.travis.yml
@ -11,17 +11,20 @@ cache:
|
|||||||
directories:
|
directories:
|
||||||
- node_modules
|
- node_modules
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- DOCKER_COMPOSE_VERSION=1.19.0
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- docker run -d -p 27017:27017 mongo:3.4 --replSet=bigchain-rs
|
- .ci/travis-before-install.sh
|
||||||
- docker run -d -p 9984:9984
|
|
||||||
-e BIGCHAINDB_KEYPAIR_PUBLIC=8wHUvvraRo5yEoJAt66UTZaFq9YZ9tFFwcauKPDtjkGw
|
install:
|
||||||
-e BIGCHAINDB_KEYPAIR_PRIVATE=5C5Cknco7YxBRP9AgB1cbUVTL4FAcooxErLygw1DeG2D
|
- .ci/travis-install.sh
|
||||||
-e BIGCHAINDB_DATABASE_BACKEND=mongodb
|
|
||||||
-e BIGCHAINDB_DATABASE_HOST=172.17.0.1
|
before_script:
|
||||||
bigchaindb/bigchaindb:1.3.0
|
- .ci/travis-before-script.sh
|
||||||
start
|
- gem install cowsay
|
||||||
- gem install cowsay
|
- npm install -g codecov
|
||||||
- npm install -g codecov
|
|
||||||
|
|
||||||
script: yarn test
|
script: yarn test
|
||||||
|
|
||||||
|
12
compose/Dockerfile
Normal file
12
compose/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
FROM python:3.6
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y vim
|
||||||
|
|
||||||
|
RUN mkdir -p /usr/src/app
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN pip install --upgrade pip ipdb ipython
|
||||||
|
|
||||||
|
COPY . /usr/src/app/
|
||||||
|
|
||||||
|
RUN pip install git+https://github.com/bigchaindb/bigchaindb.git
|
17
compose/tendermint/tmdata/config.toml
Normal file
17
compose/tendermint/tmdata/config.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# This is a TOML config file.
|
||||||
|
# For more information, see https://github.com/toml-lang/toml
|
||||||
|
|
||||||
|
proxy_app = "tcp://bigchaindb:46658"
|
||||||
|
moniker = "anonymous"
|
||||||
|
fast_sync = true
|
||||||
|
db_backend = "leveldb"
|
||||||
|
log_level = "state:debug,*:error"
|
||||||
|
|
||||||
|
[consensus]
|
||||||
|
create_empty_blocks = false
|
||||||
|
|
||||||
|
[rpc]
|
||||||
|
laddr = "tcp://0.0.0.0:46657"
|
||||||
|
|
||||||
|
[p2p]
|
||||||
|
laddr = "tcp://0.0.0.0:46656"
|
39
docker-compose.yml
Normal file
39
docker-compose.yml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
version: '2.1'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo:3.4.13
|
||||||
|
ports:
|
||||||
|
- "27017"
|
||||||
|
command: mongod
|
||||||
|
bigchaindb:
|
||||||
|
depends_on:
|
||||||
|
- mongodb
|
||||||
|
- tendermint
|
||||||
|
image: bigchaindb/bigchaindb:master
|
||||||
|
environment:
|
||||||
|
BIGCHAINDB_DATABASE_HOST: mongodb
|
||||||
|
BIGCHAINDB_DATABASE_PORT: 27017
|
||||||
|
BIGCHAINDB_SERVER_BIND: 0.0.0.0:9984
|
||||||
|
BIGCHAINDB_WSSERVER_HOST: 0.0.0.0
|
||||||
|
BIGCHAINDB_TENDERMINT_HOST: tendermint
|
||||||
|
BIGCHAINDB_TENDERMINT_PORT: 46657
|
||||||
|
ports:
|
||||||
|
- "9984:9984"
|
||||||
|
- "9985:9985"
|
||||||
|
- "46658"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "bash", "-c", "curl http://bigchaindb:9984 && curl http://tendermint:46657/abci_query"]
|
||||||
|
interval: 3s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
command: -l DEBUG start
|
||||||
|
tendermint:
|
||||||
|
image: tendermint/tendermint:0.12
|
||||||
|
volumes:
|
||||||
|
- ./compose/tendermint/tmdata/config.toml:/tendermint/config.toml
|
||||||
|
entrypoint: ''
|
||||||
|
ports:
|
||||||
|
- "46656"
|
||||||
|
- "46657"
|
||||||
|
command: bash -c "tendermint init && tendermint node"
|
@ -36,10 +36,33 @@ Compatibility Matrix
|
|||||||
+-----------------------+----------------------------------+
|
+-----------------------+----------------------------------+
|
||||||
| ``1.3`` | ``3.x.x`` |
|
| ``1.3`` | ``3.x.x`` |
|
||||||
+-----------------------+----------------------------------+
|
+-----------------------+----------------------------------+
|
||||||
|
| ``2.0`` | ``4.x.x`` |
|
||||||
|
+-----------------------+----------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Older versions
|
Older versions
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
#### Versions 4.x.x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
As part of the changes in the BigchainDB 2.0 server, some endpoint were
|
||||||
|
modified. In order to be consistent with them, the JS driver does not have
|
||||||
|
anymore the `pollStatusAndFetchTransaction()` method as there are three
|
||||||
|
different ways of posting a transaction.
|
||||||
|
- `async` using the `postTransaction`: the response will return immediately and not wait to see if the transaction is valid.
|
||||||
|
- `sync` using the `postTransactionSync`: the response will return after the transaction is validated.
|
||||||
|
- `commit` using the `postTransactionCommit`: the response will return after the transaction is committed to a block.
|
||||||
|
|
||||||
|
By default in the docs we will use the `postTransactionCommit` as is way of
|
||||||
|
being sure that the transaction is validated and commited to a block, so
|
||||||
|
there will not be any issue if you try to transfer the asset immediately.
|
||||||
|
|
||||||
|
|
||||||
|
#### Versions 3.2.x
|
||||||
|
|
||||||
For versions below 3.2, a transfer transaction looked like:
|
For versions below 3.2, a transfer transaction looked like:
|
||||||
|
|
||||||
.. code-block:: js
|
.. code-block:: js
|
||||||
@ -72,7 +95,7 @@ transaction should be now:
|
|||||||
|
|
||||||
|
|
||||||
The upgrade allows to create transfer transaction spending outputs that belong
|
The upgrade allows to create transfer transaction spending outputs that belong
|
||||||
to different transactions. So for instance is now possible to create a transfer
|
to different transactions. So for instance is now possible to create a transfer
|
||||||
transaction spending two outputs from two different create transactions:
|
transaction spending two outputs from two different create transactions:
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ And sent over to a BigchainDB node:
|
|||||||
|
|
||||||
.. code-block:: js
|
.. code-block:: js
|
||||||
|
|
||||||
conn.postTransaction(txCreateAliceSimpleSigned)
|
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||||
|
|
||||||
Notice the transaction ``id``:
|
Notice the transaction ``id``:
|
||||||
|
|
||||||
@ -136,22 +136,6 @@ Notice the transaction ``id``:
|
|||||||
|
|
||||||
txid = txCreateAliceSimpleSigned.id
|
txid = txCreateAliceSimpleSigned.id
|
||||||
|
|
||||||
To check the status of the transaction:
|
|
||||||
|
|
||||||
.. code-block:: js
|
|
||||||
|
|
||||||
conn.getStatus(txCreateAliceSimpleSigned.id)
|
|
||||||
|
|
||||||
It is also possible to check the status every 0.5 seconds
|
|
||||||
with use of the transaction ``id``:
|
|
||||||
|
|
||||||
.. code-block:: js
|
|
||||||
|
|
||||||
conn.pollStatusAndFetchTransaction(txCreateAliceSimpleSigned.id)
|
|
||||||
|
|
||||||
.. note:: It may take a small amount of time before a BigchainDB cluster
|
|
||||||
confirms a transaction as being valid.
|
|
||||||
|
|
||||||
Asset Transfer
|
Asset Transfer
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
@ -198,13 +182,10 @@ And sent over to a BigchainDB node:
|
|||||||
|
|
||||||
.. code-block:: js
|
.. code-block:: js
|
||||||
|
|
||||||
conn.postTransaction(txTransferBobSigned)
|
conn.postTransactionCommit(txTransferBobSigned)
|
||||||
|
|
||||||
Check the status again:
|
Check the status again:
|
||||||
|
|
||||||
.. code-block:: js
|
|
||||||
|
|
||||||
conn.pollStatusAndFetchTransaction(txTransferBobSigned.id)
|
|
||||||
|
|
||||||
Bob is the new owner:
|
Bob is the new owner:
|
||||||
|
|
||||||
@ -362,15 +343,10 @@ Recap: Asset Creation & Transfer
|
|||||||
// Send the transaction off to BigchainDB
|
// Send the transaction off to BigchainDB
|
||||||
const conn = new driver.Connection(API_PATH)
|
const conn = new driver.Connection(API_PATH)
|
||||||
|
|
||||||
conn.postTransaction(txCreateAliceSimpleSigned)
|
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||||
// Check status of transaction every 0.5 seconds until fulfilled
|
|
||||||
.then(() => conn.pollStatusAndFetchTransaction(txCreateAliceSimpleSigned.id))
|
|
||||||
.then(retrievedTx => console.log('Transaction', retrievedTx.id, 'successfully posted.'))
|
.then(retrievedTx => console.log('Transaction', retrievedTx.id, 'successfully posted.'))
|
||||||
// Check status after transaction has completed (result: { 'status': 'valid' })
|
// With the postTransactionCommit if the response is correct, then the transaction
|
||||||
// If you check the status of a transaction to fast without polling,
|
// is valid and commited to a block
|
||||||
// It returns that the transaction is waiting in the 'backlog'
|
|
||||||
.then(() => conn.getStatus(txCreateAliceSimpleSigned.id))
|
|
||||||
.then(status => console.log('Retrieved status method 2: ', status))
|
|
||||||
|
|
||||||
// Transfer bicycle to Bob
|
// Transfer bicycle to Bob
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -386,12 +362,12 @@ Recap: Asset Creation & Transfer
|
|||||||
let txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
let txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
||||||
console.log('Posting signed transaction: ', txTransferBobSigned)
|
console.log('Posting signed transaction: ', txTransferBobSigned)
|
||||||
|
|
||||||
// Post and poll status
|
// Post with commit so transaction is validated and included in a block
|
||||||
return conn.postTransaction(txTransferBobSigned)
|
return conn.postTransactionCommit(txTransferBobSigned)
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
console.log('Response from BDB server:', res)
|
console.log('Response from BDB server:', res)
|
||||||
return conn.pollStatusAndFetchTransaction(res.id)
|
return res.id
|
||||||
})
|
})
|
||||||
.then(tx => {
|
.then(tx => {
|
||||||
console.log('Is Bob the owner?', tx['outputs'][0]['public_keys'][0] == bob.publicKey)
|
console.log('Is Bob the owner?', tx['outputs'][0]['public_keys'][0] == bob.publicKey)
|
||||||
@ -608,9 +584,7 @@ and further we transfer it from Bob to Chris. Expectations:
|
|||||||
const txCreateAliceSimpleSigned = driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
const txCreateAliceSimpleSigned = driver.Transaction.signTransaction(txCreateAliceSimple, alice.privateKey)
|
||||||
console.log('\n\nPosting signed create transaction for Alice:\n', txCreateAliceSimpleSigned)
|
console.log('\n\nPosting signed create transaction for Alice:\n', txCreateAliceSimpleSigned)
|
||||||
|
|
||||||
conn.postTransaction(txCreateAliceSimpleSigned)
|
conn.postTransactionCommit(txCreateAliceSimpleSigned)
|
||||||
// Check status of transaction every 0.5 seconds until fulfilled
|
|
||||||
.then(() => conn.pollStatusAndFetchTransaction(txCreateAliceSimpleSigned.id))
|
|
||||||
|
|
||||||
// Transfer bicycle from Alice to Bob
|
// Transfer bicycle from Alice to Bob
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -624,10 +598,9 @@ and further we transfer it from Bob to Chris. Expectations:
|
|||||||
txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
txTransferBobSigned = driver.Transaction.signTransaction(txTransferBob, alice.privateKey)
|
||||||
console.log('\n\nPosting signed transaction to Bob:\n', txTransferBobSigned)
|
console.log('\n\nPosting signed transaction to Bob:\n', txTransferBobSigned)
|
||||||
|
|
||||||
// Post and poll status
|
// Post with commit so transaction is validated and included in a block
|
||||||
return conn.postTransaction(txTransferBobSigned)
|
return conn.postTransactionCommit(txTransferBobSigned)
|
||||||
})
|
})
|
||||||
.then(res => conn.pollStatusAndFetchTransaction(res.id))
|
|
||||||
|
|
||||||
// Second transfer of bicycle from Bob to Chris
|
// Second transfer of bicycle from Bob to Chris
|
||||||
.then(tx => {
|
.then(tx => {
|
||||||
@ -641,10 +614,9 @@ and further we transfer it from Bob to Chris. Expectations:
|
|||||||
let txTransferChrisSigned = driver.Transaction.signTransaction(txTransferChris, bob.privateKey)
|
let txTransferChrisSigned = driver.Transaction.signTransaction(txTransferChris, bob.privateKey)
|
||||||
console.log('\n\nPosting signed transaction to Chris:\n', txTransferChrisSigned)
|
console.log('\n\nPosting signed transaction to Chris:\n', txTransferChrisSigned)
|
||||||
|
|
||||||
// Post and poll status
|
// Post with commit so transaction is validated and included in a block
|
||||||
return conn.postTransaction(txTransferChrisSigned)
|
return conn.postTransactionCommit(txTransferChrisSigned)
|
||||||
})
|
})
|
||||||
.then(res => conn.pollStatusAndFetchTransaction(res.id))
|
|
||||||
.then(() => conn.listOutputs(alice.publicKey, true))
|
.then(() => conn.listOutputs(alice.publicKey, true))
|
||||||
.then(listSpentOutputs => {
|
.then(listSpentOutputs => {
|
||||||
console.log("\nSpent outputs for Alice: ", listSpentOutputs.length) // Spent outputs: 1
|
console.log("\nSpent outputs for Alice: ", listSpentOutputs.length) // Spent outputs: 1
|
||||||
|
56
package.json
56
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bigchaindb-driver",
|
"name": "bigchaindb-driver",
|
||||||
"version": "3.2.0",
|
"version": "4.0.0",
|
||||||
"description": "Node.js driver for BigchainDB",
|
"description": "Node.js driver for BigchainDB",
|
||||||
"homepage": "https://www.bigchaindb.com/",
|
"homepage": "https://www.bigchaindb.com/",
|
||||||
"bugs": "https://github.com/bigchaindb/js-bigchaindb-driver/issues",
|
"bugs": "https://github.com/bigchaindb/js-bigchaindb-driver/issues",
|
||||||
@ -20,6 +20,7 @@
|
|||||||
"build:dist": "cross-env NODE_ENV=production webpack -p",
|
"build:dist": "cross-env NODE_ENV=production webpack -p",
|
||||||
"clean": "rimraf dist/bundle dist/node",
|
"clean": "rimraf dist/bundle dist/node",
|
||||||
"test": "npm run lint && nyc ava test/ && npm run thanks && npm run report-coverage",
|
"test": "npm run lint && nyc ava test/ && npm run thanks && npm run report-coverage",
|
||||||
|
"testmine": "npm run lint && nyc ava test/integration/test_min*",
|
||||||
"thanks": "cowsay Hi, thanks for your interest in BigchainDB. We appreciate your contribution!",
|
"thanks": "cowsay Hi, thanks for your interest in BigchainDB. We appreciate your contribution!",
|
||||||
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||||
"release-minor": "./node_modules/release-it/bin/release-it.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
"release-minor": "./node_modules/release-it/bin/release-it.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
|
||||||
@ -35,46 +36,47 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ava": "^0.25.0",
|
"ava": "^0.25.0",
|
||||||
"babel-cli": "^6.22.2",
|
"babel-cli": "^6.26.0",
|
||||||
"babel-eslint": "^8.0.0",
|
"babel-eslint": "^8.2.2",
|
||||||
"babel-loader": "^7.0.0",
|
"babel-loader": "^7.1.4",
|
||||||
"babel-plugin-add-module-exports": "^0.2.1",
|
"babel-plugin-add-module-exports": "^0.2.1",
|
||||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.23.0",
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
|
||||||
"babel-plugin-transform-export-extensions": "^6.22.0",
|
"babel-plugin-transform-export-extensions": "^6.22.0",
|
||||||
"babel-plugin-transform-object-assign": "^6.22.0",
|
"babel-plugin-transform-object-assign": "^6.22.0",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.22.0",
|
||||||
|
"babel-preset-env": "^1.6.1",
|
||||||
"babel-preset-es2015-no-commonjs": "0.0.2",
|
"babel-preset-es2015-no-commonjs": "0.0.2",
|
||||||
"babel-preset-latest": "^6.22.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"babel-runtime": "^6.22.0",
|
"cross-env": "^5.1.4",
|
||||||
"cross-env": "^5.0.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint": "^4.1.1",
|
"eslint-config-ascribe": "^3.0.5",
|
||||||
"eslint-config-ascribe": "^3.0.4",
|
"eslint-plugin-import": "^2.9.0",
|
||||||
"eslint-plugin-import": "^2.2.0",
|
"husky": "^0.14.3",
|
||||||
"husky": "^0.14.0",
|
|
||||||
"lint-staged": "^7.0.0",
|
"lint-staged": "^7.0.0",
|
||||||
"nyc": "^11.0.2",
|
"nyc": "^11.6.0",
|
||||||
"release-it": "^7.0.0",
|
"release-it": "^7.2.1",
|
||||||
"rimraf": "^2.5.4",
|
"rimraf": "^2.6.2",
|
||||||
"sinon": "^4.0.0",
|
"sinon": "^4.4.9",
|
||||||
"webpack": "^4.0.0"
|
"webpack": "^4.4.1",
|
||||||
|
"webpack-cli": "^2.0.13"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browser-resolve": "^1.11.2",
|
"browser-resolve": "^1.11.2",
|
||||||
"bs58": "^4.0.0",
|
"bs58": "^4.0.1",
|
||||||
"buffer": "^5.0.2",
|
"buffer": "^5.1.0",
|
||||||
"clone": "^2.1.0",
|
"clone": "^2.1.1",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.5.4",
|
||||||
"decamelize": "^2.0.0",
|
"decamelize": "^2.0.0",
|
||||||
"es6-promise": "^4.0.5",
|
"es6-promise": "^4.2.4",
|
||||||
"fetch-ponyfill": "^6.0.0",
|
"fetch-ponyfill": "^6.0.1",
|
||||||
"crypto-conditions": "^2.0.1",
|
"crypto-conditions": "^2.0.1",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"js-sha3": "^0.7.0",
|
"js-sha3": "^0.7.0",
|
||||||
"js-utility-belt": "^1.5.0",
|
"js-utility-belt": "^1.5.0",
|
||||||
"json-stable-stringify": "^1.0.1",
|
"json-stable-stringify": "^1.0.1",
|
||||||
"query-string": "^5.0.0",
|
"query-string": "^6.0.0",
|
||||||
"sprintf-js": "^1.0.3",
|
"sprintf-js": "^1.1.1",
|
||||||
"tweetnacl": "^1.0.0"
|
"tweetnacl": "^1.0.0"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -19,10 +19,11 @@ export default class Connection {
|
|||||||
getApiUrls(endpoint) {
|
getApiUrls(endpoint) {
|
||||||
return this.path + {
|
return this.path + {
|
||||||
'blocks': 'blocks',
|
'blocks': 'blocks',
|
||||||
'blocksDetail': 'blocks/%(blockId)s',
|
'blocksDetail': 'blocks/%(blockHeight)s',
|
||||||
'outputs': 'outputs',
|
'outputs': 'outputs',
|
||||||
'statuses': 'statuses',
|
|
||||||
'transactions': 'transactions',
|
'transactions': 'transactions',
|
||||||
|
'transactionsSync': 'transactions?mode=sync',
|
||||||
|
'transactionsCommit': 'transactions?mode=commit',
|
||||||
'transactionsDetail': 'transactions/%(transactionId)s',
|
'transactionsDetail': 'transactions/%(transactionId)s',
|
||||||
'assets': 'assets',
|
'assets': 'assets',
|
||||||
'metadata': 'metadata',
|
'metadata': 'metadata',
|
||||||
@ -38,24 +39,12 @@ export default class Connection {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
* @param blockId
|
* @param blockHeight
|
||||||
*/
|
*/
|
||||||
getBlock(blockId) {
|
getBlock(blockHeight) {
|
||||||
return this._req(this.getApiUrls('blocksDetail'), {
|
return this._req(this.getApiUrls('blocksDetail'), {
|
||||||
urlTemplateSpec: {
|
urlTemplateSpec: {
|
||||||
blockId
|
blockHeight
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
* @param transactionId
|
|
||||||
*/
|
|
||||||
getStatus(transactionId) {
|
|
||||||
return this._req(this.getApiUrls('statuses'), {
|
|
||||||
query: {
|
|
||||||
transaction_id: transactionId
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -77,11 +66,10 @@ export default class Connection {
|
|||||||
* @param transactionId
|
* @param transactionId
|
||||||
* @param status
|
* @param status
|
||||||
*/
|
*/
|
||||||
listBlocks(transactionId, status) {
|
listBlocks(transactionId) {
|
||||||
return this._req(this.getApiUrls('blocks'), {
|
return this._req(this.getApiUrls('blocks'), {
|
||||||
query: {
|
query: {
|
||||||
transaction_id: transactionId,
|
transaction_id: transactionId,
|
||||||
status
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -133,27 +121,12 @@ export default class Connection {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
* @param txId
|
* @param transaction
|
||||||
* @return {Promise}
|
|
||||||
*/
|
*/
|
||||||
pollStatusAndFetchTransaction(txId) {
|
postTransaction(transaction) {
|
||||||
return new Promise((resolve, reject) => {
|
return this._req(this.getApiUrls('transactions'), {
|
||||||
const timer = setInterval(() => {
|
method: 'POST',
|
||||||
this.getStatus(txId)
|
jsonBody: transaction
|
||||||
.then((res) => {
|
|
||||||
if (res.status === 'valid') {
|
|
||||||
clearInterval(timer)
|
|
||||||
this.getTransaction(txId)
|
|
||||||
.then((res_) => {
|
|
||||||
resolve(res_)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
clearInterval(timer)
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
}, 500)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +134,20 @@ export default class Connection {
|
|||||||
* @public
|
* @public
|
||||||
* @param transaction
|
* @param transaction
|
||||||
*/
|
*/
|
||||||
postTransaction(transaction) {
|
postTransactionSync(transaction) {
|
||||||
return this._req(this.getApiUrls('transactions'), {
|
return this._req(this.getApiUrls('transactionsSync'), {
|
||||||
|
method: 'POST',
|
||||||
|
jsonBody: transaction
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @param transaction
|
||||||
|
*/
|
||||||
|
postTransactionCommit(transaction) {
|
||||||
|
return this._req(this.getApiUrls('transactionsCommit'), {
|
||||||
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
jsonBody: transaction
|
jsonBody: transaction
|
||||||
})
|
})
|
||||||
|
@ -30,14 +30,6 @@ export default class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static hashTransaction(transaction) {
|
|
||||||
// Safely remove any tx id from the given transaction for hashing
|
|
||||||
const tx = { ...transaction }
|
|
||||||
delete tx.id
|
|
||||||
|
|
||||||
return sha256Hash(Transaction.serializeTransactionIntoCanonicalString(tx))
|
|
||||||
}
|
|
||||||
|
|
||||||
static makeTransactionTemplate() {
|
static makeTransactionTemplate() {
|
||||||
const txTemplate = {
|
const txTemplate = {
|
||||||
'id': null,
|
'id': null,
|
||||||
@ -46,7 +38,7 @@ export default class Transaction {
|
|||||||
'inputs': [],
|
'inputs': [],
|
||||||
'metadata': null,
|
'metadata': null,
|
||||||
'asset': null,
|
'asset': null,
|
||||||
'version': '1.0',
|
'version': '2.0',
|
||||||
}
|
}
|
||||||
return txTemplate
|
return txTemplate
|
||||||
}
|
}
|
||||||
@ -58,8 +50,6 @@ export default class Transaction {
|
|||||||
tx.metadata = metadata
|
tx.metadata = metadata
|
||||||
tx.inputs = inputs
|
tx.inputs = inputs
|
||||||
tx.outputs = outputs
|
tx.outputs = outputs
|
||||||
|
|
||||||
tx.id = Transaction.hashTransaction(tx)
|
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,15 +236,23 @@ export default class Transaction {
|
|||||||
signedTx.inputs.forEach((input, index) => {
|
signedTx.inputs.forEach((input, index) => {
|
||||||
const privateKey = privateKeys[index]
|
const privateKey = privateKeys[index]
|
||||||
const privateKeyBuffer = Buffer.from(base58.decode(privateKey))
|
const privateKeyBuffer = Buffer.from(base58.decode(privateKey))
|
||||||
const serializedTransaction = Transaction
|
const serializedTransaction =
|
||||||
.serializeTransactionIntoCanonicalString(transaction)
|
Transaction.serializeTransactionIntoCanonicalString(transaction)
|
||||||
|
|
||||||
|
const transactionUniqueFulfillment = input.fulfills ? serializedTransaction
|
||||||
|
.concat(input.fulfills.transaction_id)
|
||||||
|
.concat(input.fulfills.output_index) : serializedTransaction
|
||||||
|
const transactionHash = sha256Hash(transactionUniqueFulfillment)
|
||||||
const ed25519Fulfillment = new cc.Ed25519Sha256()
|
const ed25519Fulfillment = new cc.Ed25519Sha256()
|
||||||
ed25519Fulfillment.sign(Buffer.from(serializedTransaction), privateKeyBuffer)
|
ed25519Fulfillment.sign(Buffer.from(transactionHash, 'hex'), privateKeyBuffer)
|
||||||
const fulfillmentUri = ed25519Fulfillment.serializeUri()
|
const fulfillmentUri = ed25519Fulfillment.serializeUri()
|
||||||
|
|
||||||
input.fulfillment = fulfillmentUri
|
input.fulfillment = fulfillmentUri
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const serializedTransaction =
|
||||||
|
Transaction.serializeTransactionIntoCanonicalString(signedTx)
|
||||||
|
signedTx.id = sha256Hash(serializedTransaction)
|
||||||
return signedTx
|
return signedTx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ import sinon from 'sinon'
|
|||||||
|
|
||||||
import * as request from '../../src/request' // eslint-disable-line
|
import * as request from '../../src/request' // eslint-disable-line
|
||||||
import { Connection } from '../../src'
|
import { Connection } from '../../src'
|
||||||
|
import { API_PATH } from '../constants'
|
||||||
|
|
||||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
|
||||||
const conn = new Connection(API_PATH)
|
const conn = new Connection(API_PATH)
|
||||||
|
|
||||||
test('Payload thrown at incorrect API_PATH', t => {
|
test('Payload thrown at incorrect API_PATH', t => {
|
||||||
@ -24,9 +24,8 @@ test('Payload thrown at incorrect API_PATH', t => {
|
|||||||
test('Generate API URLS', t => {
|
test('Generate API URLS', t => {
|
||||||
const endpoints = {
|
const endpoints = {
|
||||||
'blocks': 'blocks',
|
'blocks': 'blocks',
|
||||||
'blocksDetail': 'blocks/%(blockId)s',
|
'blocksDetail': 'blocks/%(blockHeight)s',
|
||||||
'outputs': 'outputs',
|
'outputs': 'outputs',
|
||||||
'statuses': 'statuses',
|
|
||||||
'transactions': 'transactions',
|
'transactions': 'transactions',
|
||||||
'transactionsDetail': 'transactions/%(transactionId)s',
|
'transactionsDetail': 'transactions/%(transactionId)s',
|
||||||
'assets': 'assets',
|
'assets': 'assets',
|
||||||
@ -59,30 +58,15 @@ test('Request with custom headers', t => {
|
|||||||
|
|
||||||
test('Get block for a block id', t => {
|
test('Get block for a block id', t => {
|
||||||
const expectedPath = 'path'
|
const expectedPath = 'path'
|
||||||
const blockId = 'abc'
|
const blockHeight = 'abc'
|
||||||
|
|
||||||
conn._req = sinon.spy()
|
conn._req = sinon.spy()
|
||||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||||
|
|
||||||
conn.getBlock(blockId)
|
conn.getBlock(blockHeight)
|
||||||
t.truthy(conn._req.calledWith(
|
t.truthy(conn._req.calledWith(
|
||||||
expectedPath,
|
expectedPath,
|
||||||
{ urlTemplateSpec: { blockId } }
|
{ urlTemplateSpec: { blockHeight } }
|
||||||
))
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
test('Get status for a transaction id', t => {
|
|
||||||
const expectedPath = 'path'
|
|
||||||
const transactionId = 'abc'
|
|
||||||
|
|
||||||
conn._req = sinon.spy()
|
|
||||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
|
||||||
|
|
||||||
conn.getStatus(transactionId)
|
|
||||||
t.truthy(conn._req.calledWith(
|
|
||||||
expectedPath,
|
|
||||||
{ query: { transaction_id: transactionId } }
|
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -105,18 +89,16 @@ test('Get transaction for a transaction id', t => {
|
|||||||
test('Get list of blocks for a transaction id', t => {
|
test('Get list of blocks for a transaction id', t => {
|
||||||
const expectedPath = 'path'
|
const expectedPath = 'path'
|
||||||
const transactionId = 'abc'
|
const transactionId = 'abc'
|
||||||
const status = 'status'
|
|
||||||
|
|
||||||
conn._req = sinon.spy()
|
conn._req = sinon.spy()
|
||||||
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
conn.getApiUrls = sinon.stub().returns(expectedPath)
|
||||||
|
|
||||||
conn.listBlocks(transactionId, status)
|
conn.listBlocks(transactionId)
|
||||||
t.truthy(conn._req.calledWith(
|
t.truthy(conn._req.calledWith(
|
||||||
expectedPath,
|
expectedPath,
|
||||||
{
|
{
|
||||||
query: {
|
query: {
|
||||||
transaction_id: transactionId,
|
transaction_id: transactionId,
|
||||||
status
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
@ -4,6 +4,7 @@ import { Transaction, Ed25519Keypair } from '../src'
|
|||||||
|
|
||||||
// NOTE: It's safer to cast `Math.random()` to a string, to avoid differences
|
// NOTE: It's safer to cast `Math.random()` to a string, to avoid differences
|
||||||
// in "float interpretation" between languages (e.g. JavaScript and Python)
|
// in "float interpretation" between languages (e.g. JavaScript and Python)
|
||||||
|
export const API_PATH = 'http://localhost:9984/api/v1/'
|
||||||
export function asset() { return { message: `${Math.random()}` } }
|
export function asset() { return { message: `${Math.random()}` } }
|
||||||
export const metaData = { message: 'metaDataMessage' }
|
export const metaData = { message: 'metaDataMessage' }
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import test from 'ava'
|
|||||||
import { Ed25519Keypair, Transaction, Connection } from '../../src'
|
import { Ed25519Keypair, Transaction, Connection } from '../../src'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
API_PATH,
|
||||||
alice,
|
alice,
|
||||||
aliceCondition,
|
aliceCondition,
|
||||||
aliceOutput,
|
aliceOutput,
|
||||||
@ -11,8 +12,6 @@ import {
|
|||||||
metaData
|
metaData
|
||||||
} from '../constants'
|
} from '../constants'
|
||||||
|
|
||||||
const API_PATH = 'http://localhost:9984/api/v1/'
|
|
||||||
|
|
||||||
|
|
||||||
test('Keypair is created', t => {
|
test('Keypair is created', t => {
|
||||||
const keyPair = new Ed25519Keypair()
|
const keyPair = new Ed25519Keypair()
|
||||||
@ -36,8 +35,7 @@ test('Valid CREATE transaction', t => {
|
|||||||
)
|
)
|
||||||
const txSigned = Transaction.signTransaction(tx, alice.privateKey)
|
const txSigned = Transaction.signTransaction(tx, alice.privateKey)
|
||||||
|
|
||||||
return conn.postTransaction(txSigned)
|
return conn.postTransactionCommit(txSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(resTx => t.truthy(resTx))
|
.then(resTx => t.truthy(resTx))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -55,8 +53,7 @@ test('Valid TRANSFER transaction with single Ed25519 input', t => {
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const transferTx = Transaction.makeTransferTransaction(
|
const transferTx = Transaction.makeTransferTransaction(
|
||||||
[{ tx: createTxSigned, output_index: 0 }],
|
[{ tx: createTxSigned, output_index: 0 }],
|
||||||
@ -67,8 +64,7 @@ test('Valid TRANSFER transaction with single Ed25519 input', t => {
|
|||||||
transferTx,
|
transferTx,
|
||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
return conn.postTransaction(transferTxSigned)
|
return conn.postTransactionCommit(transferTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(resTx => t.truthy(resTx))
|
.then(resTx => t.truthy(resTx))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -87,8 +83,7 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs', t => {
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ 'id': txId }) => conn.pollStatusAndFetchTransaction(txId))
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const transferTx = Transaction.makeTransferTransaction(
|
const transferTx = Transaction.makeTransferTransaction(
|
||||||
[{ tx: createTxSigned, output_index: 0 }, { tx: createTxSigned, output_index: 1 }],
|
[{ tx: createTxSigned, output_index: 0 }, { tx: createTxSigned, output_index: 1 }],
|
||||||
@ -100,8 +95,7 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs', t => {
|
|||||||
alice.privateKey,
|
alice.privateKey,
|
||||||
bob.privateKey
|
bob.privateKey
|
||||||
)
|
)
|
||||||
return conn.postTransaction(transferTxSigned)
|
return conn.postTransactionCommit(transferTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(resTx => t.truthy(resTx))
|
.then(resTx => t.truthy(resTx))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -129,8 +123,7 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs from different tra
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ 'id': txId }) => conn.pollStatusAndFetchTransaction(txId))
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const transferTx1 = Transaction.makeTransferTransaction(
|
const transferTx1 = Transaction.makeTransferTransaction(
|
||||||
[{ tx: createTxSigned, output_index: 0 }],
|
[{ tx: createTxSigned, output_index: 0 }],
|
||||||
@ -151,10 +144,8 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs from different tra
|
|||||||
bob.privateKey
|
bob.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(transferTxSigned1)
|
return conn.postTransactionCommit(transferTxSigned1)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
.then(conn.postTransactionCommit(transferTxSigned2))
|
||||||
.then(conn.postTransaction(transferTxSigned2))
|
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const transferTxMultipleInputs = Transaction.makeTransferTransaction(
|
const transferTxMultipleInputs = Transaction.makeTransferTransaction(
|
||||||
[{ tx: transferTxSigned1, output_index: 0 },
|
[{ tx: transferTxSigned1, output_index: 0 },
|
||||||
@ -167,14 +158,12 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs from different tra
|
|||||||
carol.privateKey,
|
carol.privateKey,
|
||||||
trent.privateKey
|
trent.privateKey
|
||||||
)
|
)
|
||||||
return conn.postTransaction(transferTxSignedMultipleInputs)
|
return conn.postTransactionCommit(transferTxSignedMultipleInputs)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(resTx => t.truthy(resTx))
|
.then(resTx => t.truthy(resTx))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
test('Search for spent and unspent outputs of a given public key', t => {
|
test('Search for spent and unspent outputs of a given public key', t => {
|
||||||
const conn = new Connection(API_PATH)
|
const conn = new Connection(API_PATH)
|
||||||
const carol = new Ed25519Keypair()
|
const carol = new Ed25519Keypair()
|
||||||
@ -208,10 +197,8 @@ test('Search for spent and unspent outputs of a given public key', t => {
|
|||||||
carol.privateKey,
|
carol.privateKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
.then(() => conn.postTransactionCommit(transferTxSigned))
|
||||||
.then(() => conn.postTransaction(transferTxSigned))
|
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(() => conn.listOutputs(carol.publicKey))
|
.then(() => conn.listOutputs(carol.publicKey))
|
||||||
// now listOutputs should return us outputs 0 and 1 (unfiltered)
|
// now listOutputs should return us outputs 0 and 1 (unfiltered)
|
||||||
.then(outputs => t.truthy(outputs.length === 2))
|
.then(outputs => t.truthy(outputs.length === 2))
|
||||||
@ -250,10 +237,8 @@ test('Search for unspent outputs for a given public key', t => {
|
|||||||
carol.privateKey,
|
carol.privateKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
.then(() => conn.postTransactionCommit(transferTxSigned))
|
||||||
.then(() => conn.postTransaction(transferTxSigned))
|
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
// now listOutputs should return us outputs 0 and 2 (1 is spent)
|
// now listOutputs should return us outputs 0 and 2 (1 is spent)
|
||||||
.then(() => conn.listOutputs(carol.publicKey, 'false'))
|
.then(() => conn.listOutputs(carol.publicKey, 'false'))
|
||||||
.then(outputs => t.truthy(outputs.length === 2))
|
.then(outputs => t.truthy(outputs.length === 2))
|
||||||
@ -292,10 +277,8 @@ test('Search for spent outputs for a given public key', t => {
|
|||||||
carol.privateKey,
|
carol.privateKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
.then(() => conn.postTransactionCommit(transferTxSigned))
|
||||||
.then(() => conn.postTransaction(transferTxSigned))
|
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
// now listOutputs should only return us output 1 (0 and 2 are unspent)
|
// now listOutputs should only return us output 1 (0 and 2 are unspent)
|
||||||
.then(() => conn.listOutputs(carol.publicKey, true))
|
.then(() => conn.listOutputs(carol.publicKey, true))
|
||||||
.then(outputs => t.truthy(outputs.length === 1))
|
.then(outputs => t.truthy(outputs.length === 1))
|
||||||
@ -316,8 +299,7 @@ test('Search for an asset', t => {
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(() => conn.searchAssets(createTxSigned.asset.data.message))
|
.then(() => conn.searchAssets(createTxSigned.asset.data.message))
|
||||||
.then(assets => t.truthy(
|
.then(assets => t.truthy(
|
||||||
assets.pop(),
|
assets.pop(),
|
||||||
@ -340,8 +322,7 @@ test('Search for metadata', t => {
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
|
||||||
.then(() => conn.searchMetadata(createTxSigned.metadata.message))
|
.then(() => conn.searchMetadata(createTxSigned.metadata.message))
|
||||||
.then(assets => t.truthy(
|
.then(assets => t.truthy(
|
||||||
assets.pop(),
|
assets.pop(),
|
||||||
@ -349,6 +330,7 @@ test('Search for metadata', t => {
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
test('Search blocks containing a transaction', t => {
|
test('Search blocks containing a transaction', t => {
|
||||||
const conn = new Connection(API_PATH)
|
const conn = new Connection(API_PATH)
|
||||||
|
|
||||||
@ -363,11 +345,10 @@ test('Search blocks containing a transaction', t => {
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id))
|
.then(({ id }) => conn.listBlocks(id))
|
||||||
.then(({ id }) => conn.listBlocks(id, 'VALID'))
|
.then(blockHeight => conn.getBlock(blockHeight.pop()))
|
||||||
.then(blocks => conn.getBlock(blocks.pop()))
|
.then(({ transactions }) => transactions.filter(({ id }) => id === createTxSigned.id))
|
||||||
.then(({ block: { transactions } }) => transactions.filter(({ id }) => id === createTxSigned.id))
|
|
||||||
.then(transactions => t.truthy(transactions.length === 1))
|
.then(transactions => t.truthy(transactions.length === 1))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -386,10 +367,11 @@ test('Search transaction containing an asset', t => {
|
|||||||
alice.privateKey
|
alice.privateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
return conn.postTransaction(createTxSigned)
|
return conn.postTransactionCommit(createTxSigned)
|
||||||
.then(({ id }) => conn.pollStatusAndFetchTransaction(id, 'CREATE'))
|
|
||||||
.then(({ id }) => conn.listTransactions(id))
|
.then(({ id }) => conn.listTransactions(id))
|
||||||
.then(transactions => t.truthy(transactions.length === 1))
|
.then(transactions => {
|
||||||
|
t.truthy(transactions.length === 1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import test from 'ava'
|
import test from 'ava'
|
||||||
import cc from 'crypto-conditions'
|
import cc from 'crypto-conditions'
|
||||||
import { Ed25519Keypair, Transaction, ccJsonLoad } from '../../src'
|
import { Ed25519Keypair, Transaction, ccJsonLoad } from '../../src'
|
||||||
|
import sha256Hash from '../../src/sha256Hash'
|
||||||
|
|
||||||
test('Ed25519 condition encoding', t => {
|
test('Ed25519 condition encoding', t => {
|
||||||
const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS'
|
const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS'
|
||||||
@ -53,16 +54,27 @@ test('Fulfillment correctly formed', t => {
|
|||||||
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
||||||
alice.publicKey
|
alice.publicKey
|
||||||
)
|
)
|
||||||
|
// Sign in order to get the tx id, needed for the unique fulfillment in the transfer transaction
|
||||||
|
const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey)
|
||||||
|
|
||||||
const txTransfer = Transaction.makeTransferTransaction(
|
const txTransfer = Transaction.makeTransferTransaction(
|
||||||
[{ tx: txCreate, output_index: 0 }],
|
[{ tx: signCreateTransaction, output_index: 0 }],
|
||||||
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
[Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))],
|
||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer)
|
|
||||||
const txSigned = Transaction.signTransaction(txTransfer, alice.privateKey)
|
const txSigned = Transaction.signTransaction(txTransfer, alice.privateKey)
|
||||||
|
|
||||||
|
// Here reconstruct the fulfillment of the transfer transaction
|
||||||
|
// The tx is serialized, and extended with tx_id and output index, and then hashed into bytes
|
||||||
|
const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer)
|
||||||
|
const msgUniqueFulfillment = txTransfer.inputs[0].fulfills ? msg
|
||||||
|
.concat(txTransfer.inputs[0].fulfills.transaction_id)
|
||||||
|
.concat(txTransfer.inputs[0].fulfills.output_index) : msg
|
||||||
|
const msgHash = sha256Hash(msgUniqueFulfillment)
|
||||||
|
|
||||||
t.truthy(cc.validateFulfillment(
|
t.truthy(cc.validateFulfillment(
|
||||||
txSigned.inputs[0].fulfillment, txCreate.outputs[0].condition.uri,
|
txSigned.inputs[0].fulfillment, txCreate.outputs[0].condition.uri,
|
||||||
Buffer.from(msg)
|
Buffer.from(msgHash, 'hex')
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ const PLUGINS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const PROD_PLUGINS = [
|
const PROD_PLUGINS = [
|
||||||
|
/*
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
compress: {
|
compress: {
|
||||||
warnings: false,
|
warnings: false,
|
||||||
@ -67,6 +68,7 @@ const PROD_PLUGINS = [
|
|||||||
debug: false,
|
debug: false,
|
||||||
minimize: true,
|
minimize: true,
|
||||||
}),
|
}),
|
||||||
|
*/
|
||||||
]
|
]
|
||||||
|
|
||||||
if (PRODUCTION) {
|
if (PRODUCTION) {
|
||||||
|
Loading…
Reference in New Issue
Block a user