From aba3c7d4bcf80dc73269fe516a17adf25ba1166d Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 20:51:24 +0100 Subject: [PATCH 01/11] Everything in one file --- src/transaction.js | 256 ++++++++++++++++++ src/transaction/hashTransaction.js | 10 - src/transaction/index.js | 11 - src/transaction/makeCreateTransaction.js | 31 --- src/transaction/makeEd25519Condition.js | 27 -- src/transaction/makeInputTemplate.js | 7 - src/transaction/makeOutput.js | 29 -- src/transaction/makeSha256Condition.js | 23 -- src/transaction/makeThresholdCondition.js | 28 -- src/transaction/makeTransaction.js | 28 -- src/transaction/makeTransferTransaction.js | 49 ---- ...serializeTransactionIntoCanonicalString.js | 18 -- src/transaction/signTransaction.js | 35 --- src/{transaction => }/utils/ccJsonLoad.js | 0 src/{transaction => }/utils/ccJsonify.js | 0 15 files changed, 256 insertions(+), 296 deletions(-) create mode 100644 src/transaction.js delete mode 100644 src/transaction/hashTransaction.js delete mode 100644 src/transaction/index.js delete mode 100644 src/transaction/makeCreateTransaction.js delete mode 100644 src/transaction/makeEd25519Condition.js delete mode 100644 src/transaction/makeInputTemplate.js delete mode 100644 src/transaction/makeOutput.js delete mode 100644 src/transaction/makeSha256Condition.js delete mode 100644 src/transaction/makeThresholdCondition.js delete mode 100644 src/transaction/makeTransaction.js delete mode 100644 src/transaction/makeTransferTransaction.js delete mode 100644 src/transaction/serializeTransactionIntoCanonicalString.js delete mode 100644 src/transaction/signTransaction.js rename src/{transaction => }/utils/ccJsonLoad.js (100%) rename src/{transaction => }/utils/ccJsonify.js (100%) diff --git a/src/transaction.js b/src/transaction.js new file mode 100644 index 0000000..7af085b --- /dev/null +++ b/src/transaction.js @@ -0,0 +1,256 @@ +import { Buffer } from 'buffer' +import stableStringify from 'json-stable-stringify' +import clone from 'clone' +import base58 from 'bs58' +import cc from 'five-bells-condition' +import ccJsonify from './utils/ccJsonify' +import sha256Hash from './sha256Hash' + +/** + * @public + * Canonically serializes a transaction into a string by sorting the keys + * @param {object} (transaction) + * @return {string} a canonically serialized Transaction + */ +export default function serializeTransactionIntoCanonicalString(transaction) { + // BigchainDB signs fulfillments by serializing transactions into a + // "canonical" format where + const tx = clone(transaction) + // TODO: set fulfillments to null + // Sort the keys + return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) +} + +export default function makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { + return { + fulfillment, + fulfills, + 'owners_before': publicKeys, + } +} + +export default function hashTransaction(transaction) { + // Safely remove any tx id from the given transaction for hashing + const tx = { ...transaction } + delete tx.id + + return sha256Hash(serializeTransactionIntoCanonicalString(tx)) +} + +function makeTransactionTemplate() { + return { + 'id': null, + 'operation': null, + 'outputs': [], + 'inputs': [], + 'metadata': null, + 'asset': null, + 'version': '1.0', + } +} + +export default function makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { + const tx = makeTransactionTemplate() + tx.operation = operation + tx.asset = asset + tx.metadata = metadata + tx.inputs = inputs + tx.outputs = outputs + + // Hashing must be done after, as the hash is of the Transaction (up to now) + tx.id = hashTransaction(tx) + return tx +} + +/** + * @public + * Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by + * the `issuers`. + * @param {object} asset Created asset's data + * @param {object} metadata Metadata for the Transaction + * @param {object[]} outputs Array of Output objects to add to the Transaction. + * Think of these as the recipients of the asset after the transaction. + * For `CREATE` Transactions, this should usually just be a list of + * Outputs wrapping Ed25519 Conditions generated from the issuers' public + * keys (so that the issuers are the recipients of the created asset). + * @param {...string[]} issuers Public key of one or more issuers to the asset being created by this + * Transaction. + * Note: Each of the private keys corresponding to the given public + * keys MUST be used later (and in the same order) when signing the + * Transaction (`signTransaction()`). + * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before + * sending it off! + */ +export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) { + const assetDefinition = { + 'data': asset || null, + } + const inputs = issuers.map((issuer) => makeInputTemplate([issuer])) + + return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) +} + +/** + * @public + * Create an Ed25519 Cryptocondition from an Ed25519 public key to put into an Output of a Transaction + * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction + * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type + * @returns {object} Ed25519 Condition (that will need to wrapped in an Output) + */ +export default function makeEd25519Condition(publicKey, json = true) { + const publicKeyBuffer = new Buffer(base58.decode(publicKey)) + + const ed25519Fulfillment = new cc.Ed25519Sha256() + ed25519Fulfillment.setPublicKey(publicKeyBuffer) + + if (json) { + return ccJsonify(ed25519Fulfillment) + } + + return ed25519Fulfillment +} + +/** + * @public + * Create an Output from a Condition. + * Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition) + * @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) + * @param {string} amount Amount of the output + * @returns {object} An Output usable in a Transaction + */ +export default function makeOutput(condition, amount = '1') { + if (typeof amount !== 'string') { + throw new TypeError('`amount` must be of type string') + } + const publicKeys = [] + const getPublicKeys = details => { + if (details.type === 'ed25519-sha-256') { + if (!publicKeys.includes(details.public_key)) { + publicKeys.push(details.public_key) + } + } else if (details.type === 'threshold-sha-256') { + details.subconditions.map(getPublicKeys) + } + } + getPublicKeys(condition.details) + return { + condition, + 'amount': amount, + 'public_keys': publicKeys, + } +} + +/** + * @public + * Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction + * @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition + * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type + * @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output) + */ +export default function makeSha256Condition(preimage, json = true) { + const sha256Fulfillment = new cc.PreimageSha256() + sha256Fulfillment.preimage = new Buffer(preimage) + + if (json) { + return ccJsonify(sha256Fulfillment) + } + return sha256Fulfillment +} + +/** + * @public + * Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction + * @param {number} threshold + * @param {Array} [subconditions=[]] + * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type + * @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output) + */ +export default function makeThresholdCondition(threshold, subconditions = [], json = true) { + const thresholdCondition = new cc.ThresholdSha256() + thresholdCondition.threshold = threshold + + subconditions.forEach((subcondition) => { + // TODO: add support for Condition and URIs + thresholdCondition.addSubfulfillment(subcondition) + }) + + if (json) { + return ccJsonify(thresholdCondition) + } + + return thresholdCondition +} + +/** + * @public + * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills + * the `fulfilledOutputs` of `unspentTransaction`. + * @param {object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill + * its Output Condition) + * @param {object} metadata Metadata for the Transaction + * @param {object[]} outputs Array of Output objects to add to the Transaction. + * Think of these as the recipients of the asset after the transaction. + * For `TRANSFER` Transactions, this should usually just be a list of + * Outputs wrapping Ed25519 Conditions generated from the public keys of + * the recipients. + * @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this + * Transaction fulfills. + * Note that listed public keys listed must be used (and in + * the same order) to sign the Transaction + * (`signTransaction()`). + * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before + * sending it off! + */ +// TODO: +// - Make `metadata` optional argument +export default function makeTransferTransaction( + unspentTransaction, + metadata, + outputs, + ...outputIndices +) { + const inputs = outputIndices.map((outputIndex) => { + const fulfilledOutput = unspentTransaction.outputs[outputIndex] + const transactionLink = { + 'output_index': 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) +} + +/** + * @public + * Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction` + * that's been signed. + * Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as + * an exercise for the user. + * @param {object} transaction Transaction to sign. `transaction` is not modified. + * @param {...string} privateKeys Private keys associated with the issuers of the `transaction`. + * Looped through to iteratively sign any Input Fulfillments found in + * the `transaction`. + * @returns {object} The signed version of `transaction`. + */ +export default function signTransaction(transaction, ...privateKeys) { + const signedTx = clone(transaction) + signedTx.inputs.forEach((input, index) => { + const privateKey = privateKeys[index] + const privateKeyBuffer = new Buffer(base58.decode(privateKey)) + const serializedTransaction = serializeTransactionIntoCanonicalString(transaction) + const ed25519Fulfillment = new cc.Ed25519Sha256() + ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer) + const fulfillmentUri = ed25519Fulfillment.serializeUri() + + input.fulfillment = fulfillmentUri + }) + + return signedTx +} diff --git a/src/transaction/hashTransaction.js b/src/transaction/hashTransaction.js deleted file mode 100644 index 13d1c51..0000000 --- a/src/transaction/hashTransaction.js +++ /dev/null @@ -1,10 +0,0 @@ -import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString' -import sha256Hash from '../sha256Hash' - -export default function hashTransaction(transaction) { - // Safely remove any tx id from the given transaction for hashing - const tx = { ...transaction } - delete tx.id - - return sha256Hash(serializeTransactionIntoCanonicalString(tx)) -} diff --git a/src/transaction/index.js b/src/transaction/index.js deleted file mode 100644 index 01d4a1f..0000000 --- a/src/transaction/index.js +++ /dev/null @@ -1,11 +0,0 @@ -export makeEd25519Condition from './makeEd25519Condition' -export makeSha256Condition from './makeSha256Condition' -export makeThresholdCondition from './makeThresholdCondition' -export makeCreateTransaction from './makeCreateTransaction' -export makeOutput from './makeOutput' -export makeTransaction from './makeTransaction' -export makeTransferTransaction from './makeTransferTransaction' -export serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString' -export signTransaction from './signTransaction' -export ccJsonLoad from './utils/ccJsonLoad' -export ccJsonify from './utils/ccJsonify' diff --git a/src/transaction/makeCreateTransaction.js b/src/transaction/makeCreateTransaction.js deleted file mode 100644 index 8b259de..0000000 --- a/src/transaction/makeCreateTransaction.js +++ /dev/null @@ -1,31 +0,0 @@ -import makeInputTemplate from './makeInputTemplate' -import makeTransaction from './makeTransaction' - - -/** - * @public - * Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by - * the `issuers`. - * @param {object} asset Created asset's data - * @param {object} metadata Metadata for the Transaction - * @param {object[]} outputs Array of Output objects to add to the Transaction. - * Think of these as the recipients of the asset after the transaction. - * For `CREATE` Transactions, this should usually just be a list of - * Outputs wrapping Ed25519 Conditions generated from the issuers' public - * keys (so that the issuers are the recipients of the created asset). - * @param {...string[]} issuers Public key of one or more issuers to the asset being created by this - * Transaction. - * Note: Each of the private keys corresponding to the given public - * keys MUST be used later (and in the same order) when signing the - * Transaction (`signTransaction()`). - * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before - * sending it off! - */ -export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) { - const assetDefinition = { - 'data': asset || null, - } - const inputs = issuers.map((issuer) => makeInputTemplate([issuer])) - - return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) -} diff --git a/src/transaction/makeEd25519Condition.js b/src/transaction/makeEd25519Condition.js deleted file mode 100644 index 3f0ff57..0000000 --- a/src/transaction/makeEd25519Condition.js +++ /dev/null @@ -1,27 +0,0 @@ -import { Buffer } from 'buffer' - -import base58 from 'bs58' -import cc from 'five-bells-condition' - -import ccJsonify from './utils/ccJsonify' - - -/** - * @public - * Create an Ed25519 Cryptocondition from an Ed25519 public key to put into an Output of a Transaction - * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction - * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type - * @returns {object} Ed25519 Condition (that will need to wrapped in an Output) - */ -export default function makeEd25519Condition(publicKey, json = true) { - const publicKeyBuffer = new Buffer(base58.decode(publicKey)) - - const ed25519Fulfillment = new cc.Ed25519Sha256() - ed25519Fulfillment.setPublicKey(publicKeyBuffer) - - if (json) { - return ccJsonify(ed25519Fulfillment) - } - - return ed25519Fulfillment -} diff --git a/src/transaction/makeInputTemplate.js b/src/transaction/makeInputTemplate.js deleted file mode 100644 index f080b06..0000000 --- a/src/transaction/makeInputTemplate.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { - return { - fulfillment, - fulfills, - 'owners_before': publicKeys, - } -} diff --git a/src/transaction/makeOutput.js b/src/transaction/makeOutput.js deleted file mode 100644 index d937570..0000000 --- a/src/transaction/makeOutput.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @public - * Create an Output from a Condition. - * Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition) - * @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) - * @param {string} amount Amount of the output - * @returns {object} An Output usable in a Transaction - */ -export default function makeOutput(condition, amount = '1') { - if (typeof amount !== 'string') { - throw new TypeError('`amount` must be of type string') - } - const publicKeys = [] - const getPublicKeys = details => { - if (details.type === 'ed25519-sha-256') { - if (!publicKeys.includes(details.public_key)) { - publicKeys.push(details.public_key) - } - } else if (details.type === 'threshold-sha-256') { - details.subconditions.map(getPublicKeys) - } - } - getPublicKeys(condition.details) - return { - condition, - 'amount': amount, - 'public_keys': publicKeys, - } -} diff --git a/src/transaction/makeSha256Condition.js b/src/transaction/makeSha256Condition.js deleted file mode 100644 index 1ecded9..0000000 --- a/src/transaction/makeSha256Condition.js +++ /dev/null @@ -1,23 +0,0 @@ -import { Buffer } from 'buffer' - -import cc from 'five-bells-condition' - -import ccJsonify from './utils/ccJsonify' - - -/** - * @public - * Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction - * @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition - * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type - * @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output) - */ -export default function makeSha256Condition(preimage, json = true) { - const sha256Fulfillment = new cc.PreimageSha256() - sha256Fulfillment.preimage = new Buffer(preimage) - - if (json) { - return ccJsonify(sha256Fulfillment) - } - return sha256Fulfillment -} diff --git a/src/transaction/makeThresholdCondition.js b/src/transaction/makeThresholdCondition.js deleted file mode 100644 index 3a8ec11..0000000 --- a/src/transaction/makeThresholdCondition.js +++ /dev/null @@ -1,28 +0,0 @@ -import cc from 'five-bells-condition' - -import ccJsonify from './utils/ccJsonify' - - -/** - * @public - * Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction - * @param {number} threshold - * @param {Array} [subconditions=[]] - * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type - * @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output) - */ -export default function makeThresholdCondition(threshold, subconditions = [], json = true) { - const thresholdCondition = new cc.ThresholdSha256() - thresholdCondition.threshold = threshold - - subconditions.forEach((subcondition) => { - // TODO: add support for Condition and URIs - thresholdCondition.addSubfulfillment(subcondition) - }) - - if (json) { - return ccJsonify(thresholdCondition) - } - - return thresholdCondition -} diff --git a/src/transaction/makeTransaction.js b/src/transaction/makeTransaction.js deleted file mode 100644 index 00c8ce2..0000000 --- a/src/transaction/makeTransaction.js +++ /dev/null @@ -1,28 +0,0 @@ -import hashTransaction from './hashTransaction' - - -function makeTransactionTemplate() { - return { - 'id': null, - 'operation': null, - 'outputs': [], - 'inputs': [], - 'metadata': null, - 'asset': null, - 'version': '1.0', - } -} - - -export default function makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { - const tx = makeTransactionTemplate() - tx.operation = operation - tx.asset = asset - tx.metadata = metadata - tx.inputs = inputs - tx.outputs = outputs - - // Hashing must be done after, as the hash is of the Transaction (up to now) - tx.id = hashTransaction(tx) - return tx -} diff --git a/src/transaction/makeTransferTransaction.js b/src/transaction/makeTransferTransaction.js deleted file mode 100644 index 3d62bd2..0000000 --- a/src/transaction/makeTransferTransaction.js +++ /dev/null @@ -1,49 +0,0 @@ -import makeInputTemplate from './makeInputTemplate' -import makeTransaction from './makeTransaction' - - -/** - * @public - * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills - * the `fulfilledOutputs` of `unspentTransaction`. - * @param {object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill - * its Output Condition) - * @param {object} metadata Metadata for the Transaction - * @param {object[]} outputs Array of Output objects to add to the Transaction. - * Think of these as the recipients of the asset after the transaction. - * For `TRANSFER` Transactions, this should usually just be a list of - * Outputs wrapping Ed25519 Conditions generated from the public keys of - * the recipients. - * @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this - * Transaction fulfills. - * Note that listed public keys listed must be used (and in - * the same order) to sign the Transaction - * (`signTransaction()`). - * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before - * sending it off! - */ -// TODO: -// - Make `metadata` optional argument -export default function makeTransferTransaction( - unspentTransaction, - metadata, - outputs, - ...outputIndices -) { - const inputs = outputIndices.map((outputIndex) => { - const fulfilledOutput = unspentTransaction.outputs[outputIndex] - const transactionLink = { - 'output_index': 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) -} diff --git a/src/transaction/serializeTransactionIntoCanonicalString.js b/src/transaction/serializeTransactionIntoCanonicalString.js deleted file mode 100644 index 382ed32..0000000 --- a/src/transaction/serializeTransactionIntoCanonicalString.js +++ /dev/null @@ -1,18 +0,0 @@ -import stableStringify from 'json-stable-stringify' -import clone from 'clone' - - -/** - * @public - * Canonically serializes a transaction into a string by sorting the keys - * @param {object} (transaction) - * @return {string} a canonically serialized Transaction - */ -export default function serializeTransactionIntoCanonicalString(transaction) { - // BigchainDB signs fulfillments by serializing transactions into a - // "canonical" format where - const tx = clone(transaction) - // TODO: set fulfillments to null - // Sort the keys - return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) -} diff --git a/src/transaction/signTransaction.js b/src/transaction/signTransaction.js deleted file mode 100644 index 32422a7..0000000 --- a/src/transaction/signTransaction.js +++ /dev/null @@ -1,35 +0,0 @@ -import { Buffer } from 'buffer' -import base58 from 'bs58' -import cc from 'five-bells-condition' -import clone from 'clone' - -import serializeTransactionIntoCanonicalString from './serializeTransactionIntoCanonicalString' - - -/** - * @public - * Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction` - * that's been signed. - * Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as - * an exercise for the user. - * @param {object} transaction Transaction to sign. `transaction` is not modified. - * @param {...string} privateKeys Private keys associated with the issuers of the `transaction`. - * Looped through to iteratively sign any Input Fulfillments found in - * the `transaction`. - * @returns {object} The signed version of `transaction`. - */ -export default function signTransaction(transaction, ...privateKeys) { - const signedTx = clone(transaction) - signedTx.inputs.forEach((input, index) => { - const privateKey = privateKeys[index] - const privateKeyBuffer = new Buffer(base58.decode(privateKey)) - const serializedTransaction = serializeTransactionIntoCanonicalString(transaction) - const ed25519Fulfillment = new cc.Ed25519Sha256() - ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer) - const fulfillmentUri = ed25519Fulfillment.serializeUri() - - input.fulfillment = fulfillmentUri - }) - - return signedTx -} diff --git a/src/transaction/utils/ccJsonLoad.js b/src/utils/ccJsonLoad.js similarity index 100% rename from src/transaction/utils/ccJsonLoad.js rename to src/utils/ccJsonLoad.js diff --git a/src/transaction/utils/ccJsonify.js b/src/utils/ccJsonify.js similarity index 100% rename from src/transaction/utils/ccJsonify.js rename to src/utils/ccJsonify.js From 61179c167be0d43be7e0380e49a64c165e25fc7f Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 21:03:15 +0100 Subject: [PATCH 02/11] Made class for Transaction file --- src/transaction.js | 462 +++++++++++++++++++++++---------------------- 1 file changed, 233 insertions(+), 229 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index 7af085b..eeadbc5 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -6,251 +6,255 @@ import cc from 'five-bells-condition' import ccJsonify from './utils/ccJsonify' import sha256Hash from './sha256Hash' -/** - * @public - * Canonically serializes a transaction into a string by sorting the keys - * @param {object} (transaction) - * @return {string} a canonically serialized Transaction - */ -export default function serializeTransactionIntoCanonicalString(transaction) { - // BigchainDB signs fulfillments by serializing transactions into a - // "canonical" format where - const tx = clone(transaction) - // TODO: set fulfillments to null - // Sort the keys - return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) -} +export default class Transaction { + constructor() { } + + /** + * @public + * Canonically serializes a transaction into a string by sorting the keys + * @param {object} (transaction) + * @return {string} a canonically serialized Transaction + */ + serializeTransactionIntoCanonicalString(transaction) { + // BigchainDB signs fulfillments by serializing transactions into a + // "canonical" format where + const tx = clone(transaction) + // TODO: set fulfillments to null + // Sort the keys + return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) + } -export default function makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { - return { - fulfillment, - fulfills, - 'owners_before': publicKeys, - } -} - -export default function hashTransaction(transaction) { - // Safely remove any tx id from the given transaction for hashing - const tx = { ...transaction } - delete tx.id - - return sha256Hash(serializeTransactionIntoCanonicalString(tx)) -} - -function makeTransactionTemplate() { + makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { return { - 'id': null, - 'operation': null, - 'outputs': [], - 'inputs': [], - 'metadata': null, - 'asset': null, - 'version': '1.0', + fulfillment, + fulfills, + 'owners_before': publicKeys, } -} - -export default function makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { - const tx = makeTransactionTemplate() - tx.operation = operation - tx.asset = asset - tx.metadata = metadata - tx.inputs = inputs - tx.outputs = outputs - - // Hashing must be done after, as the hash is of the Transaction (up to now) - tx.id = hashTransaction(tx) - return tx -} - -/** - * @public - * Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by - * the `issuers`. - * @param {object} asset Created asset's data - * @param {object} metadata Metadata for the Transaction - * @param {object[]} outputs Array of Output objects to add to the Transaction. - * Think of these as the recipients of the asset after the transaction. - * For `CREATE` Transactions, this should usually just be a list of - * Outputs wrapping Ed25519 Conditions generated from the issuers' public - * keys (so that the issuers are the recipients of the created asset). - * @param {...string[]} issuers Public key of one or more issuers to the asset being created by this - * Transaction. - * Note: Each of the private keys corresponding to the given public - * keys MUST be used later (and in the same order) when signing the - * Transaction (`signTransaction()`). - * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before - * sending it off! - */ -export default function makeCreateTransaction(asset, metadata, outputs, ...issuers) { - const assetDefinition = { - 'data': asset || null, - } - const inputs = issuers.map((issuer) => makeInputTemplate([issuer])) - - return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) -} - -/** - * @public - * Create an Ed25519 Cryptocondition from an Ed25519 public key to put into an Output of a Transaction - * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction - * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type - * @returns {object} Ed25519 Condition (that will need to wrapped in an Output) - */ -export default function makeEd25519Condition(publicKey, json = true) { - const publicKeyBuffer = new Buffer(base58.decode(publicKey)) - - const ed25519Fulfillment = new cc.Ed25519Sha256() - ed25519Fulfillment.setPublicKey(publicKeyBuffer) - - if (json) { - return ccJsonify(ed25519Fulfillment) } - return ed25519Fulfillment -} + hashTransaction(transaction) { + // Safely remove any tx id from the given transaction for hashing + const tx = { ...transaction } + delete tx.id -/** - * @public - * Create an Output from a Condition. - * Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition) - * @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) - * @param {string} amount Amount of the output - * @returns {object} An Output usable in a Transaction - */ -export default function makeOutput(condition, amount = '1') { - if (typeof amount !== 'string') { - throw new TypeError('`amount` must be of type string') + return sha256Hash(serializeTransactionIntoCanonicalString(tx)) } - const publicKeys = [] - const getPublicKeys = details => { - if (details.type === 'ed25519-sha-256') { - if (!publicKeys.includes(details.public_key)) { - publicKeys.push(details.public_key) - } - } else if (details.type === 'threshold-sha-256') { - details.subconditions.map(getPublicKeys) + + makeTransactionTemplate() { + return { + 'id': null, + 'operation': null, + 'outputs': [], + 'inputs': [], + 'metadata': null, + 'asset': null, + 'version': '1.0', } } - getPublicKeys(condition.details) - return { - condition, - 'amount': amount, - 'public_keys': publicKeys, + + makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { + const tx = makeTransactionTemplate() + tx.operation = operation + tx.asset = asset + tx.metadata = metadata + tx.inputs = inputs + tx.outputs = outputs + + // Hashing must be done after, as the hash is of the Transaction (up to now) + tx.id = hashTransaction(tx) + return tx } -} -/** - * @public - * Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction - * @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition - * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type - * @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output) - */ -export default function makeSha256Condition(preimage, json = true) { - const sha256Fulfillment = new cc.PreimageSha256() - sha256Fulfillment.preimage = new Buffer(preimage) + /** + * @public + * Generate a `CREATE` transaction holding the `asset`, `metadata`, and `outputs`, to be signed by + * the `issuers`. + * @param {object} asset Created asset's data + * @param {object} metadata Metadata for the Transaction + * @param {object[]} outputs Array of Output objects to add to the Transaction. + * Think of these as the recipients of the asset after the transaction. + * For `CREATE` Transactions, this should usually just be a list of + * Outputs wrapping Ed25519 Conditions generated from the issuers' public + * keys (so that the issuers are the recipients of the created asset). + * @param {...string[]} issuers Public key of one or more issuers to the asset being created by this + * Transaction. + * Note: Each of the private keys corresponding to the given public + * keys MUST be used later (and in the same order) when signing the + * Transaction (`signTransaction()`). + * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before + * sending it off! + */ + makeCreateTransaction(asset, metadata, outputs, ...issuers) { + const assetDefinition = { + 'data': asset || null, + } + const inputs = issuers.map((issuer) => makeInputTemplate([issuer])) - if (json) { - return ccJsonify(sha256Fulfillment) + return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) } - return sha256Fulfillment -} -/** - * @public - * Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction - * @param {number} threshold - * @param {Array} [subconditions=[]] - * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type - * @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output) - */ -export default function makeThresholdCondition(threshold, subconditions = [], json = true) { - const thresholdCondition = new cc.ThresholdSha256() - thresholdCondition.threshold = threshold + /** + * @public + * Create an Ed25519 Cryptocondition from an Ed25519 public key to put into an Output of a Transaction + * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction + * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type + * @returns {object} Ed25519 Condition (that will need to wrapped in an Output) + */ + makeEd25519Condition(publicKey, json = true) { + const publicKeyBuffer = new Buffer(base58.decode(publicKey)) - subconditions.forEach((subcondition) => { - // TODO: add support for Condition and URIs - thresholdCondition.addSubfulfillment(subcondition) - }) - - if (json) { - return ccJsonify(thresholdCondition) - } - - return thresholdCondition -} - -/** - * @public - * Generate a `TRANSFER` transaction holding the `asset`, `metadata`, and `outputs`, that fulfills - * the `fulfilledOutputs` of `unspentTransaction`. - * @param {object} unspentTransaction Previous Transaction you have control over (i.e. can fulfill - * its Output Condition) - * @param {object} metadata Metadata for the Transaction - * @param {object[]} outputs Array of Output objects to add to the Transaction. - * Think of these as the recipients of the asset after the transaction. - * For `TRANSFER` Transactions, this should usually just be a list of - * Outputs wrapping Ed25519 Conditions generated from the public keys of - * the recipients. - * @param {...number} OutputIndices Indices of the Outputs in `unspentTransaction` that this - * Transaction fulfills. - * Note that listed public keys listed must be used (and in - * the same order) to sign the Transaction - * (`signTransaction()`). - * @returns {object} Unsigned transaction -- make sure to call signTransaction() on it before - * sending it off! - */ -// TODO: -// - Make `metadata` optional argument -export default function makeTransferTransaction( - unspentTransaction, - metadata, - outputs, - ...outputIndices -) { - const inputs = outputIndices.map((outputIndex) => { - const fulfilledOutput = unspentTransaction.outputs[outputIndex] - const transactionLink = { - 'output_index': 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) -} - -/** - * @public - * Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction` - * that's been signed. - * Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as - * an exercise for the user. - * @param {object} transaction Transaction to sign. `transaction` is not modified. - * @param {...string} privateKeys Private keys associated with the issuers of the `transaction`. - * Looped through to iteratively sign any Input Fulfillments found in - * the `transaction`. - * @returns {object} The signed version of `transaction`. - */ -export default function signTransaction(transaction, ...privateKeys) { - const signedTx = clone(transaction) - signedTx.inputs.forEach((input, index) => { - const privateKey = privateKeys[index] - const privateKeyBuffer = new Buffer(base58.decode(privateKey)) - const serializedTransaction = serializeTransactionIntoCanonicalString(transaction) const ed25519Fulfillment = new cc.Ed25519Sha256() - ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer) - const fulfillmentUri = ed25519Fulfillment.serializeUri() + ed25519Fulfillment.setPublicKey(publicKeyBuffer) - input.fulfillment = fulfillmentUri + if (json) { + return ccJsonify(ed25519Fulfillment) + } + + return ed25519Fulfillment + } + + /** + * @public + * Create an Output from a Condition. + * Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition) + * @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) + * @param {string} amount Amount of the output + * @returns {object} An Output usable in a Transaction + */ + makeOutput(condition, amount = '1') { + if (typeof amount !== 'string') { + throw new TypeError('`amount` must be of type string') + } + const publicKeys = [] + const getPublicKeys = details => { + if (details.type === 'ed25519-sha-256') { + if (!publicKeys.includes(details.public_key)) { + publicKeys.push(details.public_key) + } + } else if (details.type === 'threshold-sha-256') { + details.subconditions.map(getPublicKeys) + } + } + getPublicKeys(condition.details) + return { + condition, + 'amount': amount, + 'public_keys': publicKeys, + } + } + + /** + * @public + * Create a Preimage-Sha256 Cryptocondition from a secret to put into an Output of a Transaction + * @param {string} preimage Preimage to be hashed and wrapped in a crypto-condition + * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type + * @returns {object} Preimage-Sha256 Condition (that will need to wrapped in an Output) + */ + makeSha256Condition(preimage, json = true) { + const sha256Fulfillment = new cc.PreimageSha256() + sha256Fulfillment.preimage = new Buffer(preimage) + + if (json) { + return ccJsonify(sha256Fulfillment) + } + return sha256Fulfillment + } + + /** + * @public + * Create an Sha256 Threshold Cryptocondition from threshold to put into an Output of a Transaction + * @param {number} threshold + * @param {Array} [subconditions=[]] + * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type + * @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output) + */ + makeThresholdCondition(threshold, subconditions = [], json = true) { + const thresholdCondition = new cc.ThresholdSha256() + thresholdCondition.threshold = threshold + + subconditions.forEach((subcondition) => { + // TODO: add support for Condition and URIs + thresholdCondition.addSubfulfillment(subcondition) }) - return signedTx -} + if (json) { + return ccJsonify(thresholdCondition) + } + + return thresholdCondition + } + + /** + * @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 + makeTransferTransaction( + unspentTransaction, + metadata, + outputs, + ...outputIndices + ) { + const inputs = outputIndices.map((outputIndex) => { + const fulfilledOutput = unspentTransaction.outputs[outputIndex] + const transactionLink = { + 'output_index': 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) + } + + /** + * @public + * Sign the given `transaction` with the given `privateKey`s, returning a new copy of `transaction` + * that's been signed. + * Note: Only generates Ed25519 Fulfillments. Thresholds and other types of Fulfillments are left as + * an exercise for the user. + * @param {object} transaction Transaction to sign. `transaction` is not modified. + * @param {...string} privateKeys Private keys associated with the issuers of the `transaction`. + * Looped through to iteratively sign any Input Fulfillments found in + * the `transaction`. + * @returns {object} The signed version of `transaction`. + */ + signTransaction(transaction, ...privateKeys) { + const signedTx = clone(transaction) + signedTx.inputs.forEach((input, index) => { + const privateKey = privateKeys[index] + const privateKeyBuffer = new Buffer(base58.decode(privateKey)) + const serializedTransaction = serializeTransactionIntoCanonicalString(transaction) + const ed25519Fulfillment = new cc.Ed25519Sha256() + ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer) + const fulfillmentUri = ed25519Fulfillment.serializeUri() + + input.fulfillment = fulfillmentUri + }) + + return signedTx + } +} \ No newline at end of file From c8cdf5eadd5447a5e154c7c4740924543c4fb84e Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 21:03:40 +0100 Subject: [PATCH 03/11] Changed export statement at index.js --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 96b539c..c6b45af 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ export Ed25519Keypair from './Ed25519Keypair' -export * as Transaction from './transaction' +export Transaction from './transaction' export Connection from './connection' From 2e1c43bf92bf4d1d59f1ad3c47722f3daf7b9140 Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 21:13:51 +0100 Subject: [PATCH 04/11] ESLint fixes --- src/transaction.js | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index eeadbc5..1d53c82 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -7,8 +7,6 @@ import ccJsonify from './utils/ccJsonify' import sha256Hash from './sha256Hash' export default class Transaction { - constructor() { } - /** * @public * Canonically serializes a transaction into a string by sorting the keys @@ -25,11 +23,11 @@ export default class Transaction { } makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { - return { - fulfillment, - fulfills, - 'owners_before': publicKeys, - } + return { + fulfillment, + fulfills, + 'owners_before': publicKeys, + } } hashTransaction(transaction) { @@ -37,7 +35,7 @@ export default class Transaction { const tx = { ...transaction } delete tx.id - return sha256Hash(serializeTransactionIntoCanonicalString(tx)) + return sha256Hash(this.serializeTransactionIntoCanonicalString(tx)) } makeTransactionTemplate() { @@ -53,7 +51,7 @@ export default class Transaction { } makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { - const tx = makeTransactionTemplate() + const tx = this.makeTransactionTemplate() tx.operation = operation tx.asset = asset tx.metadata = metadata @@ -88,14 +86,15 @@ export default class Transaction { const assetDefinition = { 'data': asset || null, } - const inputs = issuers.map((issuer) => makeInputTemplate([issuer])) + const inputs = issuers.map((issuer) => this.makeInputTemplate([issuer])) - return makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) + return this.makeTransaction('CREATE', assetDefinition, metadata, outputs, inputs) } /** * @public - * Create an Ed25519 Cryptocondition from an Ed25519 public key to put into an Output of a Transaction + * Create an Ed25519 Cryptocondition from an Ed25519 public key + * to put into an Output of a Transaction * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type * @returns {object} Ed25519 Condition (that will need to wrapped in an Output) @@ -116,7 +115,8 @@ export default class Transaction { /** * @public * Create an Output from a Condition. - * Note: Assumes the given Condition was generated from a single public key (e.g. a Ed25519 Condition) + * Note: Assumes the given Condition was generated from a + * single public key (e.g. a Ed25519 Condition) * @param {object} condition Condition (e.g. a Ed25519 Condition from `makeEd25519Condition()`) * @param {string} amount Amount of the output * @returns {object} An Output usable in a Transaction @@ -169,19 +169,19 @@ export default class Transaction { * @returns {object} Sha256 Threshold Condition (that will need to wrapped in an Output) */ makeThresholdCondition(threshold, subconditions = [], json = true) { - const thresholdCondition = new cc.ThresholdSha256() - thresholdCondition.threshold = threshold + const thresholdCondition = new cc.ThresholdSha256() + thresholdCondition.threshold = threshold - subconditions.forEach((subcondition) => { - // TODO: add support for Condition and URIs - thresholdCondition.addSubfulfillment(subcondition) - }) + subconditions.forEach((subcondition) => { + // TODO: add support for Condition and URIs + thresholdCondition.addSubfulfillment(subcondition) + }) - if (json) { - return ccJsonify(thresholdCondition) - } + if (json) { + return ccJsonify(thresholdCondition) + } - return thresholdCondition + return thresholdCondition } /** @@ -219,7 +219,7 @@ export default class Transaction { 'transaction_id': unspentTransaction.id, } - return makeInputTemplate(fulfilledOutput.public_keys, transactionLink) + return this.makeInputTemplate(fulfilledOutput.public_keys, transactionLink) }) const assetLink = { @@ -227,7 +227,7 @@ export default class Transaction { : unspentTransaction.asset.id } - return makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs) + return this.makeTransaction('TRANSFER', assetLink, metadata, outputs, inputs) } /** @@ -247,7 +247,7 @@ export default class Transaction { signedTx.inputs.forEach((input, index) => { const privateKey = privateKeys[index] const privateKeyBuffer = new Buffer(base58.decode(privateKey)) - const serializedTransaction = serializeTransactionIntoCanonicalString(transaction) + const serializedTransaction = this.serializeTransactionIntoCanonicalString(transaction) const ed25519Fulfillment = new cc.Ed25519Sha256() ed25519Fulfillment.sign(new Buffer(serializedTransaction), privateKeyBuffer) const fulfillmentUri = ed25519Fulfillment.serializeUri() @@ -257,4 +257,4 @@ export default class Transaction { return signedTx } -} \ No newline at end of file +} From d7c3276e1262c98db6f69dc06803dd99c228832c Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 21:19:19 +0100 Subject: [PATCH 05/11] Updated test/transaction/test_transaction.js --- test/transaction/test_transaction.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/test/transaction/test_transaction.js b/test/transaction/test_transaction.js index d5a28ed..fb4b780 100644 --- a/test/transaction/test_transaction.js +++ b/test/transaction/test_transaction.js @@ -2,8 +2,6 @@ import test from 'ava' import sinon from 'sinon' import { Transaction } from '../../src' -import * as makeTransaction from '../../src/transaction/makeTransaction' // eslint-disable-line -import makeInputTemplate from '../../src/transaction/makeInputTemplate' import { alice, @@ -70,7 +68,7 @@ test('makeOutput throws TypeError with incorrect amount type', t => { test('Create TRANSFER transaction based on CREATE transaction', t => { - sinon.spy(makeTransaction, 'default') + sinon.spy(Transaction.makeTransaction, 'default') Transaction.makeTransferTransaction( createTx, @@ -83,7 +81,7 @@ test('Create TRANSFER transaction based on CREATE transaction', t => { { id: createTx.id }, metaData, [aliceOutput], - [makeInputTemplate( + [Transaction.makeInputTemplate( [alice.publicKey], { output_index: 0, transaction_id: createTx.id } )] @@ -92,13 +90,13 @@ test('Create TRANSFER transaction based on CREATE transaction', t => { // NOTE: `src/transaction/makeTransaction` is `export default`, hence we // can only mock `makeTransaction.default` with a hack: // See: https://stackoverflow.com/a/33676328/1263876 - t.truthy(makeTransaction.default.calledWith(...expected)) - makeTransaction.default.restore() + t.truthy(Transaction.makeTransaction.default.calledWith(...expected)) + Transaction.makeTransaction.default.restore() }) test('Create TRANSFER transaction based on TRANSFER transaction', t => { - sinon.spy(makeTransaction, 'default') + sinon.spy(Transaction.makeTransaction, 'default') Transaction.makeTransferTransaction( transferTx, @@ -111,12 +109,12 @@ test('Create TRANSFER transaction based on TRANSFER transaction', t => { { id: transferTx.asset.id }, metaData, [aliceOutput], - [makeInputTemplate( + [Transaction.makeInputTemplate( [alice.publicKey], { output_index: 0, transaction_id: transferTx.id } )] ] - t.truthy(makeTransaction.default.calledWith(...expected)) - makeTransaction.default.restore() + t.truthy(Transaction.makeTransaction.default.calledWith(...expected)) + Transaction.makeTransaction.default.restore() }) From c793ffbb711356a04936b246620aa099298899a1 Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 21:32:46 +0100 Subject: [PATCH 06/11] ESLint fixes --- src/transaction.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index 1d53c82..cd1fcf1 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -19,7 +19,7 @@ export default class Transaction { const tx = clone(transaction) // TODO: set fulfillments to null // Sort the keys - return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) + return stableStringify(this.tx, (a, b) => (a.key > b.key ? 1 : -1)) } makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { @@ -59,7 +59,7 @@ export default class Transaction { tx.outputs = outputs // Hashing must be done after, as the hash is of the Transaction (up to now) - tx.id = hashTransaction(tx) + tx.id = this.hashTransaction(tx) return tx } @@ -93,7 +93,7 @@ export default class Transaction { /** * @public - * Create an Ed25519 Cryptocondition from an Ed25519 public key + * Create an Ed25519 Cryptocondition from an Ed25519 public key * to put into an Output of a Transaction * @param {string} publicKey base58 encoded Ed25519 public key for the recipient of the Transaction * @param {boolean} [json=true] If true returns a json object otherwise a crypto-condition type From 9b05b7354f89c5fd1067e61cf441d67ea43f8732 Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 22:25:26 +0100 Subject: [PATCH 07/11] ESLint fixes --- src/transaction.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index cd1fcf1..b49c6e9 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -16,10 +16,10 @@ export default class Transaction { serializeTransactionIntoCanonicalString(transaction) { // BigchainDB signs fulfillments by serializing transactions into a // "canonical" format where - const tx = clone(transaction) + const tx = this.clone(transaction) // TODO: set fulfillments to null // Sort the keys - return stableStringify(this.tx, (a, b) => (a.key > b.key ? 1 : -1)) + return stableStringify(tx, (a, b) => (a.key > b.key ? 1 : -1)) } makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { From 35e1073a2fe569d4f256d913bdd9227ccf36be34 Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 22:49:01 +0100 Subject: [PATCH 08/11] ESLint fixes --- src/transaction.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index b49c6e9..fa71845 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -100,7 +100,7 @@ export default class Transaction { * @returns {object} Ed25519 Condition (that will need to wrapped in an Output) */ makeEd25519Condition(publicKey, json = true) { - const publicKeyBuffer = new Buffer(base58.decode(publicKey)) + const publicKeyBuffer = new Buffer(this.base58.decode(publicKey)) const ed25519Fulfillment = new cc.Ed25519Sha256() ed25519Fulfillment.setPublicKey(publicKeyBuffer) @@ -135,7 +135,7 @@ export default class Transaction { details.subconditions.map(getPublicKeys) } } - getPublicKeys(condition.details) + this.getPublicKeys(condition.details) return { condition, 'amount': amount, @@ -155,7 +155,7 @@ export default class Transaction { sha256Fulfillment.preimage = new Buffer(preimage) if (json) { - return ccJsonify(sha256Fulfillment) + return this.ccJsonify(sha256Fulfillment) } return sha256Fulfillment } @@ -178,7 +178,7 @@ export default class Transaction { }) if (json) { - return ccJsonify(thresholdCondition) + return this.ccJsonify(thresholdCondition) } return thresholdCondition From 202bf16d09a8224e771fe62f9dd5472cce9eeb3d Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 23:02:12 +0100 Subject: [PATCH 09/11] ESLint fixes --- src/transaction.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index fa71845..73cbf3d 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -23,11 +23,12 @@ export default class Transaction { } makeInputTemplate(publicKeys = [], fulfills = null, fulfillment = null) { - return { + const inputTemplate = { fulfillment, fulfills, 'owners_before': publicKeys, } + return inputTemplate } hashTransaction(transaction) { @@ -39,7 +40,7 @@ export default class Transaction { } makeTransactionTemplate() { - return { + const txTemplate = { 'id': null, 'operation': null, 'outputs': [], @@ -48,6 +49,7 @@ export default class Transaction { 'asset': null, 'version': '1.0', } + return txTemplate } makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { From 42de727882244b32fc79ed663732e94ff12292e2 Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 23:07:34 +0100 Subject: [PATCH 10/11] ESLint fixes --- src/transaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction.js b/src/transaction.js index 73cbf3d..3f9fb60 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -49,7 +49,7 @@ export default class Transaction { 'asset': null, 'version': '1.0', } - return txTemplate + return this.txTemplate } makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) { From 3b509b5a48cbeaed7d327c6002bf09ac9d1930ed Mon Sep 17 00:00:00 2001 From: michielmulders Date: Thu, 2 Nov 2017 23:16:35 +0100 Subject: [PATCH 11/11] ESLint fixes --- src/transaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction.js b/src/transaction.js index 3f9fb60..73cbf3d 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -49,7 +49,7 @@ export default class Transaction { 'asset': null, 'version': '1.0', } - return this.txTemplate + return txTemplate } makeTransaction(operation, asset, metadata = null, outputs = [], inputs = []) {