'use strict'; var should = require('should'); var sinon = require('sinon'); var bitcore = require('bitcore-lib'); var TxController = require('../lib/transactions'); var bcoin = require('bcoin'); var _ = require('lodash'); describe('Transactions', function() { describe('/tx/:txid', function() { it('should have correct data', function(done) { var insight = { "txid": "eac9723230b8b632117ac3d75288d6f8eb81cf1ea553eb9fd42562d5f767d54a", "version": 1, "locktime": 0, "vin": [ { "txid": "46e58a68bb9ec9b458a9599dc2bac1e1fa09ad15c29c7f923c8f6f0aa33d6456", "vout": 1, "sequence": 4294967295, "n": 0, "scriptSig": { "hex": "47304402203ddb49db43074b421ec6d5604ae91aac37f4715139e0c83ea1145379e8cbf02702207fbc92c4038ad501989b097844ae4e337c9388f0713110620b40e582b85fdff3012102cd90aa18ec8e3b35c0447ffc713c945cb837429d33d075d1b0f050c72ea838d2", "asm": "304402203ddb49db43074b421ec6d5604ae91aac37f4715139e0c83ea1145379e8cbf02702207fbc92c4038ad501989b097844ae4e337c9388f0713110620b40e582b85fdff301 02cd90aa18ec8e3b35c0447ffc713c945cb837429d33d075d1b0f050c72ea838d2" }, "addr": "1NqgMfGUeELP2BfxD4hQuJSRq2d3DVJcCi", "valueSat": 1546063700, "value": 15.460637, "doubleSpentTxID": null } ], "vout": [ { "value": "0.37100000", "n": 0, "scriptPubKey": { "hex": "76a914bc345e0e0e5b0dbddb7b35ef3430fedd528dd1b788ac", "asm": "OP_DUP OP_HASH160 bc345e0e0e5b0dbddb7b35ef3430fedd528dd1b7 OP_EQUALVERIFY OP_CHECKSIG", "addresses": [ "1JA8mcfrBv1YYsASAp9jtohm8x2q7LnUhs" ], "type": "pubkeyhash" } }, { "value": "15.08763700", "n": 1, "scriptPubKey": { "hex": "76a914c2c74d7519d4425fc1a253f066d980164341554a88ac", "asm": "OP_DUP OP_HASH160 c2c74d7519d4425fc1a253f066d980164341554a OP_EQUALVERIFY OP_CHECKSIG", "addresses": [ "1Jktr121Hm63qtWBMV8dCNJNW2KtWXy4fp" ], "type": "pubkeyhash" } } ], "blockhash": "0000000000000000009d2e9b7a984d55c6c99ba62f98e9bc7dad8b1e779045a3", "blockheight": 481763, "confirmations": 4, "time": 1503507151, "blocktime": 1503507151, "valueOut": 15.458637, "size": 225, "valueIn": 15.460637, "fees": 0.002 }; var bcoinTx = bcoin.tx.fromRaw('010000000156643da30a6f8f3c927f9cc215ad09fae1c1bac29d59a958b4c99ebb688ae546010000006a47304402203ddb49db43074b421ec6d5604ae91aac37f4715139e0c83ea1145379e8cbf02702207fbc92c4038ad501989b097844ae4e337c9388f0713110620b40e582b85fdff3012102cd90aa18ec8e3b35c0447ffc713c945cb837429d33d075d1b0f050c72ea838d2ffffffff02e0193602000000001976a914bc345e0e0e5b0dbddb7b35ef3430fedd528dd1b788ac34e8ed59000000001976a914c2c74d7519d4425fc1a253f066d980164341554a88ac00000000', 'hex'); bcoinTx.__blockhash = '0000000000000000009d2e9b7a984d55c6c99ba62f98e9bc7dad8b1e779045a3'; bcoinTx.__height = 481763; bcoinTx.__inputValues = [ 1546063700 ]; bcoinTx.__timestamp = 1503507151; bcoinTx.inputSatoshis = [ 1546063700 ]; bcoinTx.feeSatoshis = 200000; bcoinTx.outputSatoshis = 1545863700; var node = { services: { block: { getTip: sinon.stub().returns({ height: 481766 }) }, transaction: { getDetailedTransaction: sinon.stub().callsArgWith(1, null, bcoinTx) } } }; var transactions = new TxController(node); var txid = 'eac9723230b8b632117ac3d75288d6f8eb81cf1ea553eb9fd42562d5f767d54a'; var req = { params: { txid: txid } }; var res = {}; var next = function() { should(req.transaction).eql(insight); done(); }; transactions.transaction(req, res, next); }); }); describe('/txs', function() { var sandbox = sinon.sandbox.create(); afterEach(function() { sandbox.restore(); }); it('by block hash', function(done) { var blockOverview = { hash: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7', height: 533974, chainWork: '0000000000000000000000000000000000000000000000054626b1839ade284a', prevHash: '00000000000001a55f3214e9172eb34b20e0bc5bd6b8007f3f149fca2c8991a4', txids: [ '9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a7a1cde251e54ccfdd5' ] }; var bcoinTx = bcoin.tx.fromRaw('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010bffffffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac00000000', 'hex'); bcoinTx.__blockhash = '000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd'; bcoinTx.__height = 2; bcoinTx.__inputValues = [ 1546063700 ]; bcoinTx.__timestamp = 1231469744; bcoinTx.inputSatoshis = [ 1546063700 ]; bcoinTx.feeSatoshis = 0; bcoinTx.outputSatoshis = 5000000000; var node = { services: { block: { getTip: sinon.stub().returns({ height: 481773 }), getBlockOverview: sinon.stub().callsArgWith(1, null, blockOverview), }, transaction: { getDetailedTransaction: sinon.stub().callsArgWith(2, null, bcoinTx) } } }; var transactions = new TxController(node); var insight = { "pagesTotal": 1, "txs": [ { "txid": "9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a7a1cde251e54ccfdd5", "version": 1, "locktime": 0, "vin": [ { "coinbase": "04ffff001d010b", "sequence": 4294967295, "n": 0 } ], "vout": [ { "value": "50.00000000", "n": 0, "scriptPubKey": { "hex": "41047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac", "asm": "047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77 OP_CHECKSIG", "addresses": [ "1HLoD9E4SDFFPDiYfNYnkBLQ85Y51J3Zb1" ], "type": "pubkeyhash" } } ], "blockhash": "000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd", "blockheight": 2, "confirmations": 481772, "time": 1231469744, "blocktime": 1231469744, "isCoinBase": true, "valueOut": 50, "size": 134 } ] }; var req = { query: { block: '0000000000000afa0c3c0afd450c793a1e300ec84cbe9555166e06132f19a8f7' } }; var res = { jsonp: function(data) { should(data).eql(insight); done(); } }; transactions.list(req, res); }); it('by address, single/coinbase', function(done) { var hex = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3103835807244d696e656420627920416e74506f6f6c6a2f4542312f4144362f4e59412f1d205999aaa02b1200001fff0200ffffffff026fb2a54c000000001976a914ad7309dfc032d7f6b652e0c29ee353e63fffec6688ac0000000000000000266a24aa21a9ed55882e9fed16c5d3b6d77e4160a56f58c70d354d02888a99486125b638231c8100000000'; var bcoinTx = bcoin.tx.fromRaw(hex, 'hex'); bcoinTx.__height = 481411; bcoinTx.outputSatoshis = 1285927535; bcoinTx.__timestamp = 1503242912; bcoinTx.__blockhash = '000000000000000000926a0cd4a05ef116514cbf1852edc306d13eb951ec0b54'; var node = { services: { block: { getTip: sinon.stub().returns({ height: 534223 }) }, address: { getAddressHistory: sinon.stub().callsArgWith(2, null, { totalCount: 1, from: 0, to: 0xffffffff, items: [bcoinTx] }) } } }; var insight = { "pagesTotal": 1, "txs": [ { "txid": "1c01a2090db0850e1f1049bea02e4bbf44b6790dfeb8e054f2beb69339ef52d4", "version": 1, "locktime": 0, "vin": [ { "coinbase": "03835807244d696e656420627920416e74506f6f6c6a2f4542312f4144362f4e59412f1d205999aaa02b1200001fff0200", "sequence": 4294967295, "n": 0 } ], "vout": [ { "value": "12.85927535", "n": 0, "scriptPubKey": { "hex": "76a914ad7309dfc032d7f6b652e0c29ee353e63fffec6688ac", "asm": "OP_DUP OP_HASH160 ad7309dfc032d7f6b652e0c29ee353e63fffec66 OP_EQUALVERIFY OP_CHECKSIG", "addresses": [ "1Gp7iCzDGMZiV55Kt8uKsux6VyoHe1aJaN" ], "type": "pubkeyhash" } }, { "value": "0.00000000", "n": 1, "scriptPubKey": { "hex": "6a24aa21a9ed55882e9fed16c5d3b6d77e4160a56f58c70d354d02888a99486125b638231c81", "asm": "OP_RETURN aa21a9ed55882e9fed16c5d3b6d77e4160a56f58c70d354d02888a99486125b638231c81" } } ], "blockhash": "000000000000000000926a0cd4a05ef116514cbf1852edc306d13eb951ec0b54", "blockheight": 481411, "confirmations": 52813, "time": 1503242912, "blocktime": 1503242912, "isCoinBase": true, "valueOut": 12.85927535, "size": 181 } ] }; var req = { query: { address: 'mkPvAKZ2rar6qeG3KjBtJHHMSP1wFZH7Er' } }; var res = { jsonp: function(data) { should(data).eql(insight); done(); } }; var transactions = new TxController(node); transactions.list(req, res); }); }); describe('/rawtx/:txid', function() { it('should give the correct data', function(done) { var hex = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2303d6250800feb0aae355fe263600000963676d696e6572343208ae5800000000000000ffffffff01c018824a000000001976a91468bedce8982d25c3b6b03f6238cbad00378b8ead88ac00000000'; var node = { services: { block: { getTip: sinon.stub().returns({ height: 534233 }) }, transaction: { getTransaction: sinon.stub().callsArgWith(1, null, bcoin.tx.fromRaw(new Buffer(hex, 'hex'))) } } }; var transactions = new TxController(node); var res = {}; var req = { params: { txid: txid } }; var next = function() { should(req.rawTransaction.rawtx).eql(hex); done(); }; var txid = '25a988e54b02e0e5df146a0f8fa7b9db56210533a9f04bdfda5f4ceb6f77aadd'; transactions.rawTransaction(req, res, next); }); }); describe('#transformInvTransaction', function() { it('should give the correct data', function() { var insight = { 'txid': 'a15a7c257af596704390d345ff3ea2eed4cd02ce8bfb8afb700bff82257e49fb', 'valueOut': 0.02038504, 'vout': [ { '3DQYCLG6rZdtV2Xw8y4YtozZjNHYoKsLuo': 45000 }, { '12WvZmssxT85f81dD6wcmWznxbnFkEpNMS': 1993504 } ], 'isRBF': false }; var rawTx = '01000000011760bc271a397bfb65b7506d430d96ebb1faff467ed957516238a9670e806a86010000006b483045022100f0056ae68a34cdb4194d424bd727c18f82653bca2a198e0d55ab6b4ee88bbdb902202a5745af4f72a5dbdca1e3d683af4667728a8b20e8001e0f8308a4d329ce3f96012102f3af6e66b61c9d99c74d9a9c3c1bec014a8c05d28bf339c8f5f395b5ce319e7dffffffff02c8af00000000000017a9148083b541ea15f1d18c5ca5e1fd47f9035cce24ed87206b1e00000000001976a91410a0e70cd91a45e0e6e409e227ab285bd61592b188ac00000000'; var tx = bitcore.Transaction().fromBuffer(new Buffer(rawTx, 'hex')); var node = { services: { block: { getTip: sinon.stub().returns({ height: 534233 }) } }, network: bitcore.Networks.livenet }; var transactions = new TxController(node); var result = transactions.transformInvTransaction(tx); should(result).eql(insight); }); it('will not include null values in vout array', function() { var insight = { 'txid': '716d54157c31e52c820494c6c2b8af1b64352049f4dcc80632aa15742a7f82c4', 'valueOut': 12.5002, 'vout': [ { 'n4eY3qiP9pi32MWC6FcJFHciSsfNiYFYgR': 12.5002 * 1e8 } ], 'isRBF': false }; var rawTx = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0403ebc108ffffffff04a0ca814a000000001976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000226a200000000000000000000000000000000000000000000000000000ffff0000000000000000000000001b6a1976a914fdb9fb622b0db8d9121475a983288a0876f4de4888ac0000000000000000326a303a791c8e85200500d89769b4f958e4db6b3ec388ddaa30233c4517d942d440c24ae903bff40d97ca06465fcf2714000000000000'; var tx = bitcore.Transaction().fromBuffer(new Buffer(rawTx, 'hex')); var node = { services: { block: { getTip: sinon.stub().returns({ height: 534233 }) } }, network: bitcore.Networks.testnet }; var transactions = new TxController(node); var result = transactions.transformInvTransaction(tx); should(result).eql(insight); }); it('should detect RBF txs', function() { var testCases = [ { rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f93598893578893588851ffffffff01501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', expected: false, }, { rawTx: '01000000017fa897c3556271c34cb28c03c196c2d912093264c9d293cb4980a2635474467d010000000f5355540b6f935988935788935888510000000001501e0000000000001976a914aa2482ce71d219018ef334f6cc551ee88abd920888ac00000000', expected: true, }, ]; var node = { services: { block: { getTip: sinon.stub().returns({ height: 534233 }) } }, network: bitcore.Networks.livenet }; var transactions = new TxController(node); _.each(testCases, function(tc) { var tx = bitcore.Transaction().fromBuffer(new Buffer(tc.rawTx, 'hex')); var result = transactions.transformInvTransaction(tx); should.exist(result.isRBF); result.isRBF.should.equal(tc.expected); }); }); }); });