From 0ed3aa39b41f146861559c8df05b4d3f806ac384 Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 16 Jun 2017 11:42:23 +0200 Subject: [PATCH 01/10] fulfills.txid ==> fulfills.transaction_id --- src/transaction/makeTransferTransaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/makeTransferTransaction.js b/src/transaction/makeTransferTransaction.js index d28dae8..5fbf228 100644 --- a/src/transaction/makeTransferTransaction.js +++ b/src/transaction/makeTransferTransaction.js @@ -32,7 +32,7 @@ export default function makeTransferTransaction( const fulfilledOutput = unspentTransaction.outputs[outputIndex] const transactionLink = { 'output': outputIndex, - 'txid': unspentTransaction.id, + 'transaction_id': unspentTransaction.id, } return makeInputTemplate(fulfilledOutput.public_keys, transactionLink) From 27d8dabd7a5d94c0dabfadaa1da082691a498f86 Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 16 Jun 2017 11:43:09 +0200 Subject: [PATCH 02/10] Stringify output.amount --- src/transaction/makeOutput.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/transaction/makeOutput.js b/src/transaction/makeOutput.js index d8eb1f3..820f3c3 100644 --- a/src/transaction/makeOutput.js +++ b/src/transaction/makeOutput.js @@ -3,10 +3,13 @@ * Create an Output from a Condition. * Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition) * @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) - * @param {number} amount Amount of the output + * @param {string} amount Amount of the output * @returns {object} An Output usable in a Transaction */ -export default function makeOutput(condition, amount = 1) { +export default function makeOutput(condition, amount = '1') { + if (typeof amount !== 'string') { + throw new TypeError('`amount` must be of type string') + } return { 'amount': amount, condition, From a14dbbaebdd33883de5640fa5090886a8d799304 Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 16 Jun 2017 14:12:02 +0200 Subject: [PATCH 03/10] Add tests for makeOutput --- test/transaction/test_transaction.js | 55 ++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/transaction/test_transaction.js diff --git a/test/transaction/test_transaction.js b/test/transaction/test_transaction.js new file mode 100644 index 0000000..f23d110 --- /dev/null +++ b/test/transaction/test_transaction.js @@ -0,0 +1,55 @@ +import test from 'ava' +import { Transaction } from '../../src' + + +test('Create valid output with default amount', t => { + const condition = { + details: { + public_key: 'abc' + } + } + const expected = { + amount: '1', + condition, + public_keys: ['abc'] + } + const res = Transaction.makeOutput(condition) + return t.deepEqual(res, expected) +}) + + +test('Create valid output with custom amount', t => { + const condition = { + details: { + public_key: 'abc' + } + } + const customAmount = '1337' + const expected = { + amount: customAmount, + condition, + public_keys: ['abc'] + } + const res = Transaction.makeOutput(condition, customAmount) + return t.deepEqual(res, expected) +}) + +test('Pass condition not based on public_keys to makeOutput', t => { + const condition = { + details: { + idea: 'just pretend this is e.g. a hashlock' + } + } + const expected = { + amount: '1', + condition, + public_keys: [] + } + const res = Transaction.makeOutput(condition) + return t.deepEqual(res, expected) +}) + + +test('makeOutput throws TypeError with incorrect amount type', t => { + t.throws(() => Transaction.makeOutput({}, 1337), TypeError) +}) From b8241589dff79198edbf4662c12577df5b16076e Mon Sep 17 00:00:00 2001 From: tim Date: Mon, 19 Jun 2017 13:27:39 +0200 Subject: [PATCH 04/10] fulfills.txid => fulfills.transaction_id + tests --- src/transaction/makeCreateTransaction.js | 2 + src/transaction/makeTransferTransaction.js | 49 +++++++++++----- test/transaction/test_transaction.js | 68 +++++++++++++++++++++- 3 files changed, 102 insertions(+), 17 deletions(-) diff --git a/src/transaction/makeCreateTransaction.js b/src/transaction/makeCreateTransaction.js index 8b259de..cc2d6d8 100644 --- a/src/transaction/makeCreateTransaction.js +++ b/src/transaction/makeCreateTransaction.js @@ -21,6 +21,8 @@ import makeTransaction from './makeTransaction' * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before * sending it off! */ +// TODO: `outputs` should throw or include output in array if no array was +// passed export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) { const assetDefinition = { 'data': asset || null, diff --git a/src/transaction/makeTransferTransaction.js b/src/transaction/makeTransferTransaction.js index 5fbf228..b1a217f 100644 --- a/src/transaction/makeTransferTransaction.js +++ b/src/transaction/makeTransferTransaction.js @@ -2,6 +2,32 @@ import makeInputTemplate from './makeInputTemplate' import makeTransaction from './makeTransaction' +// TODO: Can we remove `export` here somehow, but still be able to import the +// function for tests? +export function _makeTransferTransaction( + unspentTransaction, + metadata, + outputs, + ...fulfilledOutputs + ) { + const inputs = fulfilledOutputs.map((outputIndex) => { + const fulfilledOutput = unspentTransaction.outputs[outputIndex] + const transactionLink = { + 'output': outputIndex, + 'transaction_id': unspentTransaction.id, + } + + return makeInputTemplate(fulfilledOutput.public_keys, transactionLink) + }) + + const assetLink = { + 'id': unspentTransaction.operation === 'CREATE' ? unspentTransaction.id + : unspentTransaction.asset.id + } + + return ['TRANSFER', assetLink, metadata, outputs, inputs] +} + /** * @public * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills @@ -22,26 +48,17 @@ import makeTransaction from './makeTransaction' * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before * sending it off! */ + +// TODO: +// - Make `metadata` optional argument +// - Rename `fulfilledOutputs`, e.g. inputs +// TODO: `outputs` should throw or include output in array if no array was +// passed export default function makeTransferTransaction( unspentTransaction, metadata, outputs, ...fulfilledOutputs ) { - const inputs = fulfilledOutputs.map((outputIndex) => { - const fulfilledOutput = unspentTransaction.outputs[outputIndex] - const transactionLink = { - 'output': outputIndex, - 'transaction_id': unspentTransaction.id, - } - - return makeInputTemplate(fulfilledOutput.public_keys, transactionLink) - }) - - const assetLink = { - 'id': unspentTransaction.operation === 'CREATE' ? unspentTransaction.id - : unspentTransaction.asset.id - } - - return makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs) + return makeTransaction(..._makeTransferTransaction(...arguments)) } diff --git a/test/transaction/test_transaction.js b/test/transaction/test_transaction.js index f23d110..0999005 100644 --- a/test/transaction/test_transaction.js +++ b/test/transaction/test_transaction.js @@ -1,5 +1,27 @@ import test from 'ava' -import { Transaction } from '../../src' +import { Transaction, Ed25519Keypair } from '../../src' +import { _makeTransferTransaction } from '../../src/transaction/makeTransferTransaction' +import makeInputTemplate from '../../src/transaction/makeInputTemplate' + + +// TODO: Find out if ava has something like conftest, if so put this there. +const alice = new Ed25519Keypair() +const aliceCondition = Transaction.makeEd25519Condition(alice.publicKey) +const aliceOutput = Transaction.makeOutput(aliceCondition) +const assetMessage = { assetMessage: 'assetMessage' } +const metaDataMessage = { metaDataMessage: 'metaDataMessage' } +const createTx = Transaction.makeCreateTransaction( + assetMessage, + metaDataMessage, + [aliceOutput], + alice.publicKey +) +const transferTx = Transaction.makeTransferTransaction( + createTx, + metaDataMessage, + [aliceOutput], + 0 +) test('Create valid output with default amount', t => { @@ -53,3 +75,47 @@ test('Pass condition not based on public_keys to makeOutput', t => { test('makeOutput throws TypeError with incorrect amount type', t => { t.throws(() => Transaction.makeOutput({}, 1337), TypeError) }) + + +test('Create TRANSFER transaction based on CREATE transaction', t => { + const testTx = _makeTransferTransaction( + createTx, + metaDataMessage, + [aliceOutput], + 0 + ) + const expected = [ + 'TRANSFER', + {id: createTx.id }, + metaDataMessage, + [aliceOutput], + [makeInputTemplate( + [alice.publicKey], + { output: 0, transaction_id: createTx.id } + )] + ] + + t.deepEqual(testTx, expected) +}) + + +test('Create TRANSFER transaction based on TRANSFER transaction', t => { + const testTx = _makeTransferTransaction( + transferTx, + metaDataMessage, + [aliceOutput], + 0 + ) + const expected = [ + 'TRANSFER', + { id: transferTx.asset.id }, + metaDataMessage, + [aliceOutput], + [makeInputTemplate( + [alice.publicKey], + { output: 0, transaction_id: transferTx.id } + )] + ] + + t.deepEqual(testTx, expected) +}) From ed18384b82e91661faf26b00f13b112d5b4c9d54 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 20 Jun 2017 10:59:25 +0200 Subject: [PATCH 05/10] Bump ascribe-eslint-config --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d533b1..1f2bac7 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "babel-runtime": "^6.22.0", "cross-env": "^5.0.1", "eslint": "^3.14.1", - "eslint-config-ascribe": "^3.0.1", + "eslint-config-ascribe": "^3.0.4", "eslint-plugin-import": "^2.2.0", "husky": "^0.13.4", "release-it": "^2.7.3", From 9183205f042f55f5fa874d0afa1c048b49d8a81f Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 20 Jun 2017 11:03:01 +0200 Subject: [PATCH 06/10] Use rest params in fn definition --- src/transaction/makeTransferTransaction.js | 9 ++------- test/transaction/test_transaction.js | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/transaction/makeTransferTransaction.js b/src/transaction/makeTransferTransaction.js index b1a217f..5e5f62f 100644 --- a/src/transaction/makeTransferTransaction.js +++ b/src/transaction/makeTransferTransaction.js @@ -54,11 +54,6 @@ export function _makeTransferTransaction( // - Rename `fulfilledOutputs`, e.g. inputs // TODO: `outputs` should throw or include output in array if no array was // passed -export default function makeTransferTransaction( - unspentTransaction, - metadata, - outputs, - ...fulfilledOutputs - ) { - return makeTransaction(..._makeTransferTransaction(...arguments)) +export default function makeTransferTransaction(...args) { + return makeTransaction(..._makeTransferTransaction(...args)) } diff --git a/test/transaction/test_transaction.js b/test/transaction/test_transaction.js index 0999005..407c524 100644 --- a/test/transaction/test_transaction.js +++ b/test/transaction/test_transaction.js @@ -86,7 +86,7 @@ test('Create TRANSFER transaction based on CREATE transaction', t => { ) const expected = [ 'TRANSFER', - {id: createTx.id }, + { id: createTx.id }, metaDataMessage, [aliceOutput], [makeInputTemplate( From 3389726cb27d44acc543941ef8344432985ed7b5 Mon Sep 17 00:00:00 2001 From: tim Date: Mon, 19 Jun 2017 18:50:10 +0200 Subject: [PATCH 07/10] Test against BDB:master --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ec208c6..1a817bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ before_install: -e BIGCHAINDB_KEYPAIR_PRIVATE=5C5Cknco7YxBRP9AgB1cbUVTL4FAcooxErLygw1DeG2D -e BIGCHAINDB_DATABASE_BACKEND=mongodb -e BIGCHAINDB_DATABASE_HOST=172.17.0.1 - bigchaindb/bigchaindb:0.10.2 + bigchaindb/bigchaindb:master start script: yarn test From ac0a1240541a8b7ca4f75c9c8bdd8f8718483460 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 20 Jun 2017 13:34:14 +0200 Subject: [PATCH 08/10] Remove unnecessary returns --- test/transaction/test_transaction.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/transaction/test_transaction.js b/test/transaction/test_transaction.js index 407c524..bb7213f 100644 --- a/test/transaction/test_transaction.js +++ b/test/transaction/test_transaction.js @@ -36,7 +36,7 @@ test('Create valid output with default amount', t => { public_keys: ['abc'] } const res = Transaction.makeOutput(condition) - return t.deepEqual(res, expected) + t.deepEqual(res, expected) }) @@ -53,7 +53,7 @@ test('Create valid output with custom amount', t => { public_keys: ['abc'] } const res = Transaction.makeOutput(condition, customAmount) - return t.deepEqual(res, expected) + t.deepEqual(res, expected) }) test('Pass condition not based on public_keys to makeOutput', t => { @@ -68,7 +68,7 @@ test('Pass condition not based on public_keys to makeOutput', t => { public_keys: [] } const res = Transaction.makeOutput(condition) - return t.deepEqual(res, expected) + t.deepEqual(res, expected) }) From 42b400253b2332ca6d0b79c15951df02347c45f4 Mon Sep 17 00:00:00 2001 From: tim Date: Mon, 19 Jun 2017 14:44:51 +0200 Subject: [PATCH 09/10] Add sinon.js (mocks) to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 1f2bac7..43ca2c6 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "husky": "^0.13.4", "release-it": "^2.7.3", "rimraf": "^2.5.4", + "sinon": "^2.3.4", "webpack": "^2.2.1" }, "dependencies": { From ede11da4c70f3b871b05fa30219444abd39729fa Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 20 Jun 2017 14:55:58 +0200 Subject: [PATCH 10/10] Correct mocking of export default --- src/transaction/makeCreateTransaction.js | 2 - src/transaction/makeTransferTransaction.js | 62 +++++++++------------- test/transaction/test_transaction.js | 21 ++++++-- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/transaction/makeCreateTransaction.js b/src/transaction/makeCreateTransaction.js index cc2d6d8..8b259de 100644 --- a/src/transaction/makeCreateTransaction.js +++ b/src/transaction/makeCreateTransaction.js @@ -21,8 +21,6 @@ import makeTransaction from './makeTransaction' * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before * sending it off! */ -// TODO: `outputs` should throw or include output in array if no array was -// passed export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) { const assetDefinition = { 'data': asset || null, diff --git a/src/transaction/makeTransferTransaction.js b/src/transaction/makeTransferTransaction.js index 5e5f62f..6e9207f 100644 --- a/src/transaction/makeTransferTransaction.js +++ b/src/transaction/makeTransferTransaction.js @@ -2,15 +2,35 @@ import makeInputTemplate from './makeInputTemplate' import makeTransaction from './makeTransaction' -// TODO: Can we remove `export` here somehow, but still be able to import the -// function for tests? -export function _makeTransferTransaction( +/** + * @public + * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills + * the `fulfilledOutputs` of `unspentTransaction`. + * @param {object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill + * its Output Condition) + * @param {object} metadata Metadata for the Transaction + * @param {object[]} outputs Array of Output objects to add to the Transaction. + * Think of these as the recipients of the asset after the transaction. + * For `TRANSFER` Transactions, this should usually just be a list of + * Outputs wrapping Ed25519 Conditions generated from the public keys of + * the recipients. + * @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this + * Transaction fulfills. + * Note that listed public keys listed must be used (and in + * the same order) to sign the Transaction + * (`signTransaction()`). + * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before + * sending it off! + */ +// TODO: +// - Make `metadata` optional argument +export default function makeTransferTransaction( unspentTransaction, metadata, outputs, - ...fulfilledOutputs + ...outputIndices ) { - const inputs = fulfilledOutputs.map((outputIndex) => { + const inputs = outputIndices.map((outputIndex) => { const fulfilledOutput = unspentTransaction.outputs[outputIndex] const transactionLink = { 'output': outputIndex, @@ -25,35 +45,5 @@ export function _makeTransferTransaction( : unspentTransaction.asset.id } - return ['TRANSFER', assetLink, metadata, outputs, inputs] -} - -/** - * @public - * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills - * the `fulfilledOutputs` of `unspentTransaction`. - * @param {object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill - * its Output Condition) - * @param {object} metadata Metadata for the Transaction - * @param {object[]} outputs Array of Output objects to add to the Transaction. - * Think of these as the recipients of the asset after the transaction. - * For `TRANSFER` Transactions, this should usually just be a list of - * Outputs wrapping Ed25519 Conditions generated from the public keys of - * the recipients. - * @param {...number} fulfilledOutputs Indices of the Outputs in `unspentTransaction` that this - * Transaction fulfills. - * Note that the public keys listed in the fulfilled Outputs - * must be used (and in the same order) to sign the Transaction - * (`signTransaction()`). - * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before - * sending it off! - */ - -// TODO: -// - Make `metadata` optional argument -// - Rename `fulfilledOutputs`, e.g. inputs -// TODO: `outputs` should throw or include output in array if no array was -// passed -export default function makeTransferTransaction(...args) { - return makeTransaction(..._makeTransferTransaction(...args)) + return makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs) } diff --git a/test/transaction/test_transaction.js b/test/transaction/test_transaction.js index bb7213f..6ef3f6d 100644 --- a/test/transaction/test_transaction.js +++ b/test/transaction/test_transaction.js @@ -1,6 +1,8 @@ import test from 'ava' +import sinon from 'sinon' + import { Transaction, Ed25519Keypair } from '../../src' -import { _makeTransferTransaction } from '../../src/transaction/makeTransferTransaction' +import * as makeTransaction from '../../src/transaction/makeTransaction' // eslint-disable-line import makeInputTemplate from '../../src/transaction/makeInputTemplate' @@ -78,7 +80,9 @@ test('makeOutput throws TypeError with incorrect amount type', t => { test('Create TRANSFER transaction based on CREATE transaction', t => { - const testTx = _makeTransferTransaction( + sinon.spy(makeTransaction, 'default') + + Transaction.makeTransferTransaction( createTx, metaDataMessage, [aliceOutput], @@ -95,12 +99,18 @@ test('Create TRANSFER transaction based on CREATE transaction', t => { )] ] - t.deepEqual(testTx, expected) + // NOTE: `src/transaction/makeTransaction` is `export default`, hence we + // can only mock `makeTransaction.default` with a hack: + // See: https://stackoverflow.com/a/33676328/1263876 + t.truthy(makeTransaction.default.calledWith(...expected)) + makeTransaction.default.restore() }) test('Create TRANSFER transaction based on TRANSFER transaction', t => { - const testTx = _makeTransferTransaction( + sinon.spy(makeTransaction, 'default') + + Transaction.makeTransferTransaction( transferTx, metaDataMessage, [aliceOutput], @@ -117,5 +127,6 @@ test('Create TRANSFER transaction based on TRANSFER transaction', t => { )] ] - t.deepEqual(testTx, expected) + t.truthy(makeTransaction.default.calledWith(...expected)) + makeTransaction.default.restore() })