Added locating double spend txs.

This commit is contained in:
Chris Kleeschulte 2017-10-06 10:30:26 -04:00
parent 1e04e08411
commit 7c392e9c94
No known key found for this signature in database
GPG Key ID: 33195D27EF6BDB7F
2 changed files with 148 additions and 2 deletions

View File

@ -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;

View File

@ -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;