diff --git a/README.md b/README.md index 4626b4fcb..49dd41418 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,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: diff --git a/lib/addresses.js b/lib/addresses.js index c4838bc2d..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,7 +191,9 @@ AddressController.prototype.multitxs = function(req, res, next) { return self.common.handleErrors(err, res); } - self.transformAddressHistoryForMultiTxs(result.items, function(err, items) { + var transformOptions = self._getTransformOptions(req); + + self.transformAddressHistoryForMultiTxs(result.items, transformOptions, function(err, items) { if (err) { return self.common.handleErrors(err, res); } @@ -198,7 +208,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 +220,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..ec98f9eb0 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,24 @@ 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 = { + hex: input.script + }; + if (!options.noAsm) { + transformed.scriptSig.asm = input.scriptAsm; + } + } + transformed.addr = input.address; transformed.valueSat = input.satoshis; transformed.value = input.satoshis / 1e8; @@ -120,21 +129,25 @@ 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 - //reqSigs: null, // TODO - }, - spentTxId: output.spentTxId || null, - spentIndex: _.isUndefined(output.spentIndex) ? null : output.spentIndex, - spentHeight: output.spentHeight || null - //spentTs: undefined // TODO + hex: output.script + } }; + if (!options.noAsm) { + transformed.scriptPubKey.asm = output.scriptAsm; + } + + 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 diff --git a/test/addresses.js b/test/addresses.js index 81bd58197..6f27f8433 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: {} }; @@ -595,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 + }); + }); + }); });