diff --git a/app/models/Transaction.js b/app/models/Transaction.js index c986cf2a..f60653f9 100644 --- a/app/models/Transaction.js +++ b/app/models/Transaction.js @@ -112,8 +112,9 @@ TransactionSchema.statics.explodeTransactionItems = function(txid, cb) { }, next_in); } else { - if ( !i.coinbase ) + if ( !i.coinbase ) { console.log ("TX: %s seems to be multisig IN. Skipping... ", t.txid); + } return next_in(); } }, @@ -154,6 +155,7 @@ TransactionSchema.methods.fillInputValues = function (tx, next) { if (tx.isCoinBase()) return next(); if (! this.rpc) this.rpc = new RpcClient(config.bitcoind); + var network = ( config.network === 'testnet') ? networks.testnet : networks.livenet ; var that = this; async.each(tx.ins, function(i, cb) { @@ -165,21 +167,32 @@ TransactionSchema.methods.fillInputValues = function (tx, next) { var c=0; that.rpc.getRawTransaction(outHashBase64, function(err, txdata) { var txin = new Transaction(); - if (err || ! txdata.result) return cb( new Error('Input TX '+outHashBase64+' not found')); var b = new Buffer(txdata.result,'hex'); txin.parse(b); - - if ( txin.isCoinBase() ) { - return cb(); - } + /* + *We have to parse it anyways. It will have outputs even it is a coinbase tx + if ( txin.isCoinBase() ) { + return cb(); + } + */ txin.outs.forEach( function(j) { // console.log( c + ': ' + util.formatValue(j.v) ); if (c === outIndex) { i.value = j.v; + + // This is used for pay-to-pubkey transaction in which + // the pubkey is not provided on the input + var scriptPubKey = j.getScript(); + var txType = scriptPubKey.classify(); + var hash = scriptPubKey.simpleOutHash(); + if (hash) { + var addr = new Address(network.addressPubkey, hash); + i.addrFromOutput = addr.toString(); + } } c++; }); @@ -224,7 +237,6 @@ TransactionSchema.methods.queryInfo = function (next) { } else { tx.ins.forEach(function(i) { - if (i.value) { that.info.vin[c].value = util.formatValue(i.value); var n = util.valueToBigInt(i.value).toNumber(); @@ -240,6 +252,10 @@ TransactionSchema.methods.queryInfo = function (next) { var addrStr = addr.toString(); that.info.vin[c].addr = addrStr; } + else { + if (i.addrFromOutput) + that.info.vin[c].addr = i.addrFromOutput; + } } else { console.log("TX could not be parsed: %s,%d",txInfo.result.txid, c); diff --git a/lib/Sync.js b/lib/Sync.js index 16d7c94a..b3dfc4ad 100644 --- a/lib/Sync.js +++ b/lib/Sync.js @@ -15,6 +15,7 @@ function spec() { var TransactionItem = require('../app/models/TransactionItem'); function Sync(config) { + this.tx_count =0; this.network = config.networkName === 'testnet' ? networks.testnet: networks.livenet; } @@ -32,7 +33,7 @@ function spec() { if (blockInfo.result.height % 1000 === 0) { var h = blockInfo.result.height, d = blockInfo.result.confirmations; - progress_bar('height', h, h + d); + progress_bar(util.format('Height [txs:%d]',that.tx_count), h, h + d); } that.storeBlock(blockInfo.result, function(err) { @@ -59,6 +60,7 @@ function spec() { }; Sync.prototype.storeTxs = function(txids, cb) { + var that=this; Transaction.createFromArray(txids, function(err) { if (err) return cb(err); @@ -66,10 +68,13 @@ function spec() { // This will trigger an RPC call Transaction.explodeTransactionItems( txid, function(err) { + that.tx_count++; next(err); }); }, - cb); + function(err) { + return cb(); + }); }); }; @@ -159,6 +164,7 @@ function spec() { }; + // Not used Sync.prototype.processTXs = function(reindex, cb) { var that = this; @@ -229,6 +235,15 @@ function spec() { cb(); } }, + function(cb) { + if (opts.destroy) { + console.log('Deleting TXItems...'); + that.db.collections.transactionitems.drop(cb); + } else { + cb(); + } + }, + function(cb) { if (!opts.skip_blocks) { that.syncBlocks(opts.reindex, cb); @@ -236,6 +251,7 @@ function spec() { cb(); } }, +/* Exploding happens on block insertion function(cb) { if (! opts.skip_txs) { that.processTXs(opts.reindex, cb); @@ -244,6 +260,7 @@ function spec() { return cb(); } } +*/ /* We dont sync any contents from TXs, only their IDs are stored function(cb) { if (! opts.skip_txs) { diff --git a/test/model/transaction.js b/test/model/transaction.js index 39daa208..801ed8b2 100644 --- a/test/model/transaction.js +++ b/test/model/transaction.js @@ -29,6 +29,23 @@ describe('Transaction', function(){ done(); }); + + + it('should pool tx\'s object from mongoose', function(done) { + var txid = '7e621eeb02874ab039a8566fd36f4591e65eca65313875221842c53de6907d6c'; + Transaction.fromIdWithInfo(txid, function(err, tx) { + if (err) done(err); + assert.equal(tx.txid, txid); + assert(!tx.info.isCoinBase); + + for(var i=0; i<20; i++) + assert(parseFloat(tx.info.vin[i].value) === parseFloat(50)); + assert(tx.info.vin[0].addr === 'msGKGCy2i8wbKS5Fo1LbWUTJnf1GoFFG59'); + assert(tx.info.vin[1].addr === 'mfye7oHsdrHbydtj4coPXCasKad2eYSv5P'); + done(); + }); + }); + it('should pool tx\'s object from mongoose', function(done) { var txid = '21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237'; Transaction.fromIdWithInfo(txid, function(err, tx) { diff --git a/test/model/txitems.json b/test/model/txitems.json index d900ded3..3441bb68 100644 --- a/test/model/txitems.json +++ b/test/model/txitems.json @@ -38,5 +38,31 @@ "index": 1 } ] + }, + { + "txid": "ca2f42e44455b8a84434de139efea1fe2c7d71414a8939e0a20f518849085c3b", + "items": [ + { + "addr": "mzeiUi4opeheWYveXqp8ebqHyVwYGA2s3x", + "value": -0.01225871, + "index": 0 + }, + { + "addr": "mtMLijHAbG8CsgBbQGajsqav9p9wKUYad5", + "value": -0.01201823, + "index": 1 + }, + { + "addr": "mhqyL1nDQDo1WLH9qH8sjRjx2WwrnmAaXE", + "value": 0.01327746, + "index": 0 + }, + { + "addr": "mkGrySSnxcqRbtPCisApj3zXCQVmUUWbf1", + "value": 0.01049948, + "index": 1 + } + ] } + ]