diff --git a/lib/services/address/index.js b/lib/services/address/index.js index 92e9ccab..f928139b 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -717,4 +717,33 @@ AddressService.prototype._processTransaction = function(tx, opts) { }; +// TODO seems spendy +AddressService.prototype._getInputInfoForAddress = function(address) { + + var self = this; + var inputs = []; + var start = self._encoding.encodeAddressIndexKey(address); + + var criteria = { + gte: start, + lt: Buffer.concat(start.slice(0, address.length + 4), new Buffer(new Array(address.length + 5).join('f'), 'hex')) + }; + + // all the info about this address + var stream = self._db.createKeyStream(criteria); + + stream.on('data', function(data) { + var info = self._encoding.decodeAddressIndexKey(data); + //only returning + if (info.input) { + inputs.push(info); + } + }); + + stream.on('end', function() { + return inputs; + }); + +}; + module.exports = AddressService; diff --git a/lib/services/transaction/index.js b/lib/services/transaction/index.js index b0ae7354..4173e5f8 100644 --- a/lib/services/transaction/index.js +++ b/lib/services/transaction/index.js @@ -15,6 +15,15 @@ function TransactionService(options) { this._header = this.node.services.header; this._p2p = this.node.services.p2p; this._timestamp = this.node.services.timestamp; + this._address = this.node.services.address; + this._network = this.node.network; + + if (this._network === 'livenet') { + this._network = 'main'; + } + if (this._network === 'regtest') { + this._network = 'testnet'; + } } inherits(TransactionService, BaseService); @@ -37,8 +46,116 @@ TransactionService.prototype.getAPIMethods = function() { ]; }; -TransactionService.prototype.getDetailedTransaction = - TransactionService.prototype.getTransaction = function(txid, options, callback) { +TransactionService.prototype._getDoubleSpentTxID = function(tx, callback) { + // for there to be a tx in our mempool that is double spending this tx, + // then at least one other tx in the mempool must be spending at least one of the + // outputs that this tx is spending + + // TODO + // we don't index the mempool to easily handle this because we would have to exhaustively + // search through all of the mempool txs + + // we should probably have an index whose key is prevtxid + output index + spendingtxid and no value + // then we could quickly loop over all inputs and get their spending txids in a list. + // then subtract the list and this will be your double spending txids. + + // when a new block comes in, it may confirm up to one of those tx's. It should be very easily to + // delete the correct one because we have the block and the tx. + return callback(); + +}; + +TransactionService.prototype._getConfirmationsForInputs = function(tx, callback) { + // for every input, check to see if its referenced input is confirmed. +}; + +TransactionService.prototype._getSpentInformationForOutputs = function(tx, callback) { + + var self = this; + + async.mapLimit(tx.outputs, 4, function(output, next) { + + var address = output.getAddress(); + + if (!address) { + return next(); + } + + address.network = self._network; + address = address.toString(); + + self._address._getInputInfoForAddress(address, next); + + }, function(err, inputGroups) { + + if(err) { + return callback(err); + } + + // we have an array for every output representing all the input info for the address + // we need to take each txid in the input info and get the tx but only if the height is greater this + // tx's height + + + + + + + }); + +}; + +TransactionService.prototype.getDetailedTransaction = function(txid, options, callback) { + + var self = this; + + self.getTransaction(txid, options, function(err, tx) { + + if(err) { + return callback(err); + } + + if (!tx) { + return callback(); + } + + // add in the following: + // 1. double spend tx id + // 2. is confirmed + // 3. for every input: is input confirmed + // 4. for every output: spent tx id (some future tx) + // 5. for every output: spent tx index + // 6. for every output: spent tx height + + // is confirmed: does this tx appear in at least one block + tx.isConfirmed = tx.confirmations > 0; + + async.parallel([ + function(next) { + // double spend tx: did another tx in our mempool attempt to spend ANY of the same outputs that our inputs are trying to spend? + self._getDoubleSpentTxID(tx, next); + }, + // is input confirmed: on every input, place a field for whether or not the input's output is confirmed + function(next) { + self._getConfirmationsForInputs(tx, next); + }, + // get spent inforamtion for outputs + function(next) { + self._getSpentInformationForOutputs(tx, next); + } + ], function(err) { + + if(err) { + return callback(err); + } + + callback(null, tx); + }); + }); + +}; + +TransactionService.prototype.getTransaction = function(txid, options, callback) { var self = this;