From 38e061e0c5bbb4444414e5015578a646d4b8cca3 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 19 Jul 2016 20:33:31 -0400 Subject: [PATCH 1/4] address: include options to trim transaction results --- lib/addresses.js | 12 +++++++++--- lib/transactions.js | 38 ++++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index c4838bc2d..48bb6e0bf 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -183,7 +183,13 @@ AddressController.prototype.multitxs = function(req, res, next) { return self.common.handleErrors(err, res); } - self.transformAddressHistoryForMultiTxs(result.items, function(err, items) { + var transformOptions = { + noAsm: req.query.noAsm ? true : false, + noScriptSig: req.query.noScriptSig ? true : false, + noSpent: req.query.noSpent ? true : false + }; + + self.transformAddressHistoryForMultiTxs(result.items, transformOptions, function(err, items) { if (err) { return self.common.handleErrors(err, res); } @@ -198,7 +204,7 @@ AddressController.prototype.multitxs = function(req, res, next) { }); }; -AddressController.prototype.transformAddressHistoryForMultiTxs = function(txinfos, callback) { +AddressController.prototype.transformAddressHistoryForMultiTxs = function(txinfos, options, callback) { var self = this; var items = txinfos.map(function(txinfo) { @@ -210,7 +216,7 @@ AddressController.prototype.transformAddressHistoryForMultiTxs = function(txinfo async.map( items, function(item, next) { - self.txController.transformTransaction(item, next); + self.txController.transformTransaction(item, options, next); }, callback ); diff --git a/lib/transactions.js b/lib/transactions.js index 9217800f1..a3c51e52d 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -44,7 +44,11 @@ TxController.prototype.transaction = function(req, res, next) { }); }; -TxController.prototype.transformTransaction = function(transaction, callback) { +TxController.prototype.transformTransaction = function(transaction, options, callback) { + if (_.isFunction(options)) { + callback = options; + options = {}; + } $.checkArgument(_.isFunction(callback)); var confirmations = 0; @@ -67,10 +71,10 @@ TxController.prototype.transformTransaction = function(transaction, callback) { } ]; } else { - transformed.vin = transaction.inputs.map(this.transformInput.bind(this)); + transformed.vin = transaction.inputs.map(this.transformInput.bind(this, options)); } - transformed.vout = transaction.outputs.map(this.transformOutput.bind(this)); + transformed.vout = transaction.outputs.map(this.transformOutput.bind(this, options)); transformed.blockhash = transaction.blockHash; transformed.blockheight = transaction.height; @@ -96,19 +100,22 @@ TxController.prototype.transformTransaction = function(transaction, callback) { callback(null, transformed); }; -TxController.prototype.transformInput = function(input, index) { +TxController.prototype.transformInput = function(options, input, index) { // Input scripts are validated and can be assumed to be valid var transformed = { txid: input.prevTxId, vout: input.outputIndex, - scriptSig: { - asm: input.scriptAsm, - hex: input.script - }, sequence: input.sequence, n: index }; + if (!options.noScriptSig) { + transformed.scriptSig = { + asm: options.noAsm ? undefined : input.scriptAsm, + hex: input.script + }; + } + transformed.addr = input.address; transformed.valueSat = input.satoshis; transformed.value = input.satoshis / 1e8; @@ -120,21 +127,24 @@ TxController.prototype.transformInput = function(input, index) { return transformed; }; -TxController.prototype.transformOutput = function(output, index) { +TxController.prototype.transformOutput = function(options, output, index) { var transformed = { value: (output.satoshis / 1e8).toFixed(8), n: index, scriptPubKey: { hex: output.script, - asm: output.scriptAsm + asm: options.noAsm ? undefined : output.scriptAsm //reqSigs: null, // TODO - }, - spentTxId: output.spentTxId || null, - spentIndex: _.isUndefined(output.spentIndex) ? null : output.spentIndex, - spentHeight: output.spentHeight || null + } //spentTs: undefined // TODO }; + if (!options.noSpent) { + transformed.spentTxId = output.spentTxId || null; + transformed.spentIndex = _.isUndefined(output.spentIndex) ? null : output.spentIndex; + transformed.spentHeight = output.spentHeight || null; + } + if (output.address) { transformed.scriptPubKey.addresses = [output.address]; var address = bitcore.Address(output.address); //TODO return type from bitcore-node From 67fc186293d78dbb2c56a17dd63c016ecb7a355f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 20 Jul 2016 10:36:16 -0400 Subject: [PATCH 2/4] test: address txs trim results --- lib/transactions.js | 13 ++-- test/addresses.js | 151 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 143 insertions(+), 21 deletions(-) diff --git a/lib/transactions.js b/lib/transactions.js index a3c51e52d..ec98f9eb0 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -111,9 +111,11 @@ TxController.prototype.transformInput = function(options, input, index) { if (!options.noScriptSig) { transformed.scriptSig = { - asm: options.noAsm ? undefined : input.scriptAsm, hex: input.script }; + if (!options.noAsm) { + transformed.scriptSig.asm = input.scriptAsm; + } } transformed.addr = input.address; @@ -132,13 +134,14 @@ TxController.prototype.transformOutput = function(options, output, index) { value: (output.satoshis / 1e8).toFixed(8), n: index, scriptPubKey: { - hex: output.script, - asm: options.noAsm ? undefined : output.scriptAsm - //reqSigs: null, // TODO + hex: output.script } - //spentTs: undefined // TODO }; + if (!options.noAsm) { + transformed.scriptPubKey.asm = output.scriptAsm; + } + if (!options.noSpent) { transformed.spentTxId = output.spentTxId || null; transformed.spentIndex = _.isUndefined(output.spentIndex) ? null : output.spentIndex; diff --git a/test/addresses.js b/test/addresses.js index 81bd58197..167d1ea47 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -108,7 +108,7 @@ var tx = { outputIndex: 1, sequence: 4294967295, script: '473044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e40141040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', - scriptAsm: '71 0x3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 65 0x040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', + scriptAsm: '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d', satoshis: 53540000, }, { @@ -117,7 +117,7 @@ var tx = { outputIndex: 2, sequence: 4294967295, script: '473044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b014104d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', - scriptAsm: '71 0x3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 65 0x04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', + scriptAsm: '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2', satoshis: 299829, } ], @@ -125,17 +125,20 @@ var tx = { { satoshis: 220000, script: '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', + scriptAsm: 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', address: 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' }, { satoshis: 53320000, address: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK', - script: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac' + script: '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', + scriptAsm: 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG' }, { address: 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', satoshis: 289829, - script: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac' + script: '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', + scriptAsm: 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG' } ], locktime: 0 @@ -523,41 +526,157 @@ describe('Addresses', function() { var todos = { 'items': [ { - 'vin': [ + 'vout': [ { - 'scriptSig': { - 'asm': '3044022054233934268b30be779fad874ef42e8db928ba27a1b612d5f111b3ee95eb271c022024272bbaf2dcc4050bd3b9dfa3c93884f6ba6ad7d257598b8245abb65b5ab1e401 040682fdb281a8533e21e13dfd1fcfa424912a85b6cdc4136b5842c85de05ac1f0e4a013f20702adeb53329de13b2ef388e5ed6244676f4f1ee4ee685ab607964d' + 'scriptPubKey': { + 'reqSigs': 1, } }, { - 'scriptSig': { - 'asm': '3044022044938ac3f8fcb8da29011df6397ed28cc7e894cdc35d596d4f3623bd8c7e465f022014829c6e0bd7ee97a1bcfef6b85c5fd232653f289394fc6ce6ebb41c73403f1b01 04d9ccf88efc6e5be3151fae5e848efd94c91d75e7bf621f9f724a8caff51415338525d3239fae6b93826edf759dd562f77693e55dfa852ffd96a92d683db590f2' + 'scriptPubKey': { + 'reqSigs': 1, + } + }, + { + 'scriptPubKey': { + 'reqSigs': 1, } } ], + 'firstSeenTs': 1441108193 + } + ] + }; + + var node = { + getAddressHistory: sinon.stub().callsArgWith(2, null, txinfos2), + services: { + bitcoind: { + height: 534232 + } + }, + network: 'testnet' + }; + + var addresses = new AddressController(node); + + var req = { + addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', + query: {}, + body: {} + }; + + var res = { + jsonp: function(data) { + var merged = _.merge(data, todos); + should(merged).eql(insight); + done(); + } + }; + + addresses.multitxs(req, res); + }); + it('should have trimmed data', function(done) { + var insight = { + 'totalItems': 1, + 'from': 0, + 'to': 1, + 'items': [ + { + 'txid': '63b68becb0e514b32317f4b29a5cf0627d4087e54ac17f686fcb1d9a27680f73', + 'version': 1, + 'locktime': 0, + 'vin': [ + { + 'txid': 'ea97726ffc529808094ae5568342267931a058375a20147535a0d095837079f3', + 'vout': 1, + 'sequence': 4294967295, + 'n': 0, + 'addr': 'moFfnRwt77pApKnnU6m5uocFaa43aAYpt5', + 'valueSat': 53540000, + 'value': 0.5354, + 'doubleSpentTxID': null + }, + { + 'txid': '980a9cc2dbc2d3464eb9900ae6d579a03045408563320f62d99316c3d4ff58b7', + 'vout': 2, + 'sequence': 4294967295, + 'n': 1, + 'addr': 'n1XJBAyU4hNR4xRtY3UxnmAteoJX83p5qv', + 'valueSat': 299829, + 'value': 0.00299829, + 'doubleSpentTxID': null + } + ], 'vout': [ { + 'value': '0.00220000', + 'n': 0, 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914b9bbd76588d9e4e09f0369a9aa0b2749a11c4e8d88ac', 'reqSigs': 1, 'type': 'pubkeyhash', - 'addresses': [] + 'addresses': [ + 'mxT2KzTUQvsaYYothDtjcdvyAdaHA9ofMp' + ] } }, { + 'value': '0.53320000', + 'n': 1, 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 d2ec20bb8e5f25a52f730384b803d95683250e0b OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914d2ec20bb8e5f25a52f730384b803d95683250e0b88ac', 'reqSigs': 1, 'type': 'pubkeyhash', - 'addresses': [] + 'addresses': [ + 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK' + ], } }, { + 'value': '0.00289829', + 'n': 2, 'scriptPubKey': { - 'asm': 'OP_DUP OP_HASH160 583df9fa56ad961051e00ca93e68dfaf1eab9ec5 OP_EQUALVERIFY OP_CHECKSIG', + 'hex': '76a914583df9fa56ad961051e00ca93e68dfaf1eab9ec588ac', 'reqSigs': 1, 'type': 'pubkeyhash', - 'addresses': [] + 'addresses': [ + 'moZY18rGNmh4YCPeugtGW46AkkWMQttBUD' + ] + } + } + ], + 'blockhash': '0000000000000041ddc94ecf4f86a456a83b2e320c36c6f0c13ff92c7e75f013', + 'blockheight': 534181, + 'confirmations': 52, + 'time': 1441116143, + 'blocktime': 1441116143, + 'valueOut': 0.53829829, + 'size': 470, + 'valueIn': 0.53839829, + 'fees': 0.0001, + 'firstSeenTs': 1441108193 + } + ] + }; + + var todos = { + 'items': [ + { + 'vout': [ + { + 'scriptPubKey': { + 'reqSigs': 1, + } + }, + { + 'scriptPubKey': { + 'reqSigs': 1, + } + }, + { + 'scriptPubKey': { + 'reqSigs': 1, } } ], @@ -580,7 +699,7 @@ describe('Addresses', function() { var req = { addrs: 'mzkD4nmQ8ixqxySdBgsXTpgvAMK5iRZpNK,moZY18rGNmh4YCPeugtGW46AkkWMQttBUD', - query: {}, + query: {noSpent: '1', noScriptSig: '1', noAsm: '1'}, body: {} }; From 5e72240be98acbab8737b441a4cb5d5bf8f66bc8 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 20 Jul 2016 10:45:23 -0400 Subject: [PATCH 3/4] docs: add address trimmed txs options to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index be3626923..e5b99f61e 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,9 @@ POST params: addrs: 2NF2baYuJAkCKo5onjUKEPdARQkZ6SYyKd5,2NAre8sX2povnjy4aeiHKeEh97Qhn97tB1f from (optional): 0 to (optional): 20 +noAsm (optional): 1 (will omit script asm from results) +noScriptSig (optional): 1 (will omit the scriptSig from all inputs) +noSpent (option): 1 (will omit spent information per output) ``` Sample output: From 5eb32cf64c4284b78d7d3955a5bc34e014c4afb9 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 20 Jul 2016 10:48:00 -0400 Subject: [PATCH 4/4] test: address trim transform options --- lib/addresses.js | 14 ++++++++----- test/addresses.js | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 48bb6e0bf..b45bc18ec 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -169,6 +169,14 @@ AddressController.prototype.transformUtxo = function(utxoArg) { return utxo; }; +AddressController.prototype._getTransformOptions = function(req) { + return { + noAsm: parseInt(req.query.noAsm) ? true : false, + noScriptSig: parseInt(req.query.noScriptSig) ? true : false, + noSpent: parseInt(req.query.noSpent) ? true : false + }; +}; + AddressController.prototype.multitxs = function(req, res, next) { var self = this; @@ -183,11 +191,7 @@ AddressController.prototype.multitxs = function(req, res, next) { return self.common.handleErrors(err, res); } - var transformOptions = { - noAsm: req.query.noAsm ? true : false, - noScriptSig: req.query.noScriptSig ? true : false, - noSpent: req.query.noSpent ? true : false - }; + var transformOptions = self._getTransformOptions(req); self.transformAddressHistoryForMultiTxs(result.items, transformOptions, function(err, items) { if (err) { diff --git a/test/addresses.js b/test/addresses.js index 167d1ea47..6f27f8433 100644 --- a/test/addresses.js +++ b/test/addresses.js @@ -714,4 +714,57 @@ describe('Addresses', function() { addresses.multitxs(req, res); }); }); + describe('#_getTransformOptions', function() { + it('will return false with value of string "0"', function() { + var node = {}; + var addresses = new AddressController(node); + var req = { + query: { + noAsm: '0', + noScriptSig: '0', + noSpent: '0' + } + }; + var options = addresses._getTransformOptions(req); + options.should.eql({ + noAsm: false, + noScriptSig: false, + noSpent: false + }); + }); + it('will return true with value of string "1"', function() { + var node = {}; + var addresses = new AddressController(node); + var req = { + query: { + noAsm: '1', + noScriptSig: '1', + noSpent: '1' + } + }; + var options = addresses._getTransformOptions(req); + options.should.eql({ + noAsm: true, + noScriptSig: true, + noSpent: true + }); + }); + it('will return true with value of number "1"', function() { + var node = {}; + var addresses = new AddressController(node); + var req = { + query: { + noAsm: 1, + noScriptSig: 1, + noSpent: 1 + } + }; + var options = addresses._getTransformOptions(req); + options.should.eql({ + noAsm: true, + noScriptSig: true, + noSpent: true + }); + }); + }); });