Added cache miss function for input values.
This commit is contained in:
parent
5ff8e7c6c1
commit
a8d709caf6
@ -202,8 +202,7 @@ P2P.prototype._hasPeers = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
P2P.prototype._initCache = function() {
|
P2P.prototype._initCache = function() {
|
||||||
this._inv = LRU(2000);
|
this._inv = LRU(1000);
|
||||||
this._cache = [];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
P2P.prototype._initP2P = function() {
|
P2P.prototype._initP2P = function() {
|
||||||
@ -332,7 +331,7 @@ P2P.prototype._setResourceFilter = function(filter, resource) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
P2P.prototype._startBcoin = function() {
|
P2P.prototype._startBcoin = function() {
|
||||||
const network = ['livenet', 'live', 'main', 'mainnet'].indexOf(this.node.network) !== -1? 'main' : 'testnet'
|
const network = ['livenet', 'live', 'main', 'mainnet'].indexOf(this.node.network) !== -1? 'main' : 'testnet';
|
||||||
this._bcoin = new Bcoin({
|
this._bcoin = new Bcoin({
|
||||||
network: network,
|
network: network,
|
||||||
prefix: this.node.datadir
|
prefix: this.node.datadir
|
||||||
|
|||||||
@ -8,6 +8,8 @@ var _ = require('lodash');
|
|||||||
var LRU = require('lru-cache');
|
var LRU = require('lru-cache');
|
||||||
var Unit = require('bitcore-lib').Unit;
|
var Unit = require('bitcore-lib').Unit;
|
||||||
var log = require('../../index').log;
|
var log = require('../../index').log;
|
||||||
|
var async = require('async');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
function TransactionService(options) {
|
function TransactionService(options) {
|
||||||
BaseService.call(this, options);
|
BaseService.call(this, options);
|
||||||
@ -16,7 +18,7 @@ function TransactionService(options) {
|
|||||||
this._block = this.node.services.block;
|
this._block = this.node.services.block;
|
||||||
this._p2p = this.node.services.p2p;
|
this._p2p = this.node.services.p2p;
|
||||||
this._timestamp = this.node.services.timestamp;
|
this._timestamp = this.node.services.timestamp;
|
||||||
this._inputValuesCache = LRU(1E6); // this should speed up syncing
|
this._inputValuesCache = LRU(500000); // this should speed up syncing
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(TransactionService, BaseService);
|
inherits(TransactionService, BaseService);
|
||||||
@ -48,9 +50,11 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
|||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
var _tx;
|
||||||
var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool;
|
var queryMempool = _.isUndefined(options.queryMempool) ? true : options.queryMempool;
|
||||||
|
|
||||||
var key = self.encoding.encodeTransactionKey(txid);
|
var key = self.encoding.encodeTransactionKey(txid);
|
||||||
|
|
||||||
self._db.get(key, function(err, tx) {
|
self._db.get(key, function(err, tx) {
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
@ -67,9 +71,8 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
|||||||
|
|
||||||
if (memTx) {
|
if (memTx) {
|
||||||
memTx.confirmations = 0;
|
memTx.confirmations = 0;
|
||||||
return callback(null, memTx);
|
_tx = memTx;
|
||||||
}
|
}
|
||||||
return callback();
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,16 +80,61 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
|||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
tx.confirmations = self._p2p.getBestHeight - tx.__height;
|
tx.confirmations = self._p2p.getBestHeight - tx.__height;
|
||||||
return callback(null, tx);
|
_tx = tx;
|
||||||
}
|
}
|
||||||
return callback();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_tx) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this could cause crazy amounts of recursion if input values are missing from the entire chain of txs
|
||||||
|
self._addMissingInputValues(_tx, callback);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TransactionService.prototype._addMissingInputValues = function(tx, callback) {
|
||||||
|
|
||||||
|
// if we have cache misses from when we populated input values,
|
||||||
|
// then we must go and find them after the fact (lazy-load).
|
||||||
|
var self = this;
|
||||||
|
async.eachOfLimit(tx.inputs, 4, function(input, index, next) {
|
||||||
|
|
||||||
|
var inputSatoshis = tx.__inputValues[index];
|
||||||
|
|
||||||
|
if (inputSatoshis >= 0) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputIndex = input.prevout.index;
|
||||||
|
self.getTransaction(input.prevout.txid(), function(err, _tx) {
|
||||||
|
|
||||||
|
if (err || !_tx) {
|
||||||
|
return next(err || new Error('tx not found for tx id: ' + input.prevout.txid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
var output = _tx.outputs[outputIndex];
|
||||||
|
assert(output, 'Expected an output, but did not get one for tx: ' + _tx.txid() + ' outputIndex: ' + outputIndex);
|
||||||
|
tx.__inputValues[index] = Unit.fromBTC(output.value).toSatoshis();
|
||||||
|
next();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}, function(err) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, tx);
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
TransactionService.prototype.sendTransaction = function(tx, callback) {
|
TransactionService.prototype.sendTransaction = function(tx, callback) {
|
||||||
this._p2p.sendTransaction(tx, callback);
|
this._p2p.sendTransaction(tx, callback);
|
||||||
};
|
};
|
||||||
@ -216,6 +264,10 @@ TransactionService.prototype._processTransaction = function(tx, opts) {
|
|||||||
|
|
||||||
// input values
|
// input values
|
||||||
tx.__inputValues = this._getInputValues(tx); //if there are any nulls here, this is a cache miss
|
tx.__inputValues = this._getInputValues(tx); //if there are any nulls here, this is a cache miss
|
||||||
|
if (_.compact(tx.__inputValues).length < tx.inputs.length) {
|
||||||
|
log.debug('Transaction Service: Cache miss for tx id: ' + tx.txid());
|
||||||
|
}
|
||||||
|
|
||||||
//timestamp
|
//timestamp
|
||||||
tx.__timestamp = this._getBlockTimestamp(opts.block.rhash());
|
tx.__timestamp = this._getBlockTimestamp(opts.block.rhash());
|
||||||
//height
|
//height
|
||||||
|
|||||||
@ -122,4 +122,18 @@ describe('Transaction Service', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#_addMissingInputValues', function() {
|
||||||
|
it('should add missing input values on a tx', function(done) {
|
||||||
|
sandbox.stub(txService, 'getTransaction').callsArgWith(1, null, tx);
|
||||||
|
tx.__inputValues = [];
|
||||||
|
txService._addMissingInputValues(tx, function(err, tx) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
tx.__inputValues.should.deep.equal([113903300000000, 113903300000000, 50000000000000, 113903300000000 ]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user