Fixed address/transaction indexing.
This commit is contained in:
parent
abf52f8136
commit
bf7cd67269
@ -16,7 +16,8 @@ var AddressService = function(options) {
|
|||||||
BaseService.call(this, options);
|
BaseService.call(this, options);
|
||||||
this._db = this.node.services.db;
|
this._db = this.node.services.db;
|
||||||
this._tx = this.node.services.transaction;
|
this._tx = this.node.services.transaction;
|
||||||
this._network = this.node.getNetworkName();
|
this._network = this.node.network;
|
||||||
|
this._timestamp = this.node.services.timestamp;
|
||||||
this._p2p = this.node.services.p2p;
|
this._p2p = this.node.services.p2p;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,7 +27,8 @@ AddressService.dependencies = [
|
|||||||
'p2p',
|
'p2p',
|
||||||
'db',
|
'db',
|
||||||
'block',
|
'block',
|
||||||
'transaction'
|
'transaction',
|
||||||
|
'timestamp'
|
||||||
];
|
];
|
||||||
|
|
||||||
// ---- public function prototypes
|
// ---- public function prototypes
|
||||||
@ -406,7 +408,6 @@ AddressService.prototype._onReorg = function(commonAncestorHeader, oldBlockList)
|
|||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype.onBlock = function(block, callback) {
|
AddressService.prototype.onBlock = function(block, callback) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (self.node.stopping) {
|
if (self.node.stopping) {
|
||||||
@ -415,28 +416,26 @@ AddressService.prototype.onBlock = function(block, callback) {
|
|||||||
|
|
||||||
var operations = [];
|
var operations = [];
|
||||||
|
|
||||||
block.txs.forEach(function(tx) {
|
for(var i = 0; i < block.txs.length; i++) {
|
||||||
operations.concat(self._processTransaction(tx, { block: block }));
|
var tx = block.txs[i];
|
||||||
});
|
var ops = self._processTransaction(tx, { block: block });
|
||||||
|
operations.push(ops);
|
||||||
if (operations && operations.length > 0) {
|
|
||||||
|
|
||||||
self._db.batch(operations);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
setImmediate(function() {
|
|
||||||
callback(null, operations);
|
operations = _.flatten(operations);
|
||||||
});
|
callback(null, operations);
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._processInput = function(tx, input, opts) {
|
AddressService.prototype._processInput = function(tx, input, opts) {
|
||||||
|
|
||||||
var address = input.address;
|
var address = input.getAddress();
|
||||||
|
|
||||||
if(!address) {
|
if(!address) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address.network = this._network;
|
||||||
|
address = address.toString();
|
||||||
var txid = tx.txid();
|
var txid = tx.txid();
|
||||||
// address index
|
// address index
|
||||||
var addressKey = this._encoding.encodeAddressIndexKey(address, opts.block.height, txid);
|
var addressKey = this._encoding.encodeAddressIndexKey(address, opts.block.height, txid);
|
||||||
@ -463,22 +462,23 @@ AddressService.prototype._processInput = function(tx, input, opts) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._processOutput = function(tx, output, index, opts) {
|
AddressService.prototype._processOutput = function(tx, output, index, opts) {
|
||||||
|
var address = output.getAddress();
|
||||||
var address = output.address;
|
|
||||||
|
|
||||||
if(!address) {
|
if(!address) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address.network = this._network;
|
||||||
|
var address = address.toString();
|
||||||
var txid = tx.txid();
|
var txid = tx.txid();
|
||||||
var addressKey = this._encoding.encodeAddressIndexKey(address, opts.block.height, txid);
|
var addressKey = this._encoding.encodeAddressIndexKey(address, opts.block.height, txid);
|
||||||
var utxoKey = this._encoding.encodeUtxoIndexKey(address, txid, index);
|
var utxoKey = this._encoding.encodeUtxoIndexKey(address, txid, index);
|
||||||
var utxoValue = this._encoding.encodeUtxoIndexValue(
|
var utxoValue = this._encoding.encodeUtxoIndexValue(
|
||||||
opts.block.height,
|
opts.block.height,
|
||||||
Unit.fromBTC(output.value).toSatoshis(),
|
Unit.fromBTC(output.value).toSatoshis(),
|
||||||
|
this._timestamp.getTimestampSync(opts.block.rhash()),
|
||||||
output.script.toRaw()
|
output.script.toRaw()
|
||||||
);
|
);
|
||||||
|
|
||||||
var operations = [{
|
var operations = [{
|
||||||
type: 'put',
|
type: 'put',
|
||||||
key: addressKey
|
key: addressKey
|
||||||
@ -490,6 +490,8 @@ AddressService.prototype._processOutput = function(tx, output, index, opts) {
|
|||||||
value: utxoValue
|
value: utxoValue
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return operations;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AddressService.prototype._processTransaction = function(tx, opts) {
|
AddressService.prototype._processTransaction = function(tx, opts) {
|
||||||
@ -505,12 +507,13 @@ AddressService.prototype._processTransaction = function(tx, opts) {
|
|||||||
outputOperations = _.flatten(_.compact(outputOperations));
|
outputOperations = _.flatten(_.compact(outputOperations));
|
||||||
|
|
||||||
var inputOperations = tx.inputs.map(function(input) {
|
var inputOperations = tx.inputs.map(function(input) {
|
||||||
self._processInput(tx, input, _opts);
|
return self._processInput(tx, input, _opts);
|
||||||
});
|
});
|
||||||
|
|
||||||
inputOperations = _.flatten(_.compact(inputOperations));
|
inputOperations = _.flatten(_.compact(inputOperations));
|
||||||
|
|
||||||
return outputOperations.concat(inputOperations);
|
outputOperations.concat(inputOperations);
|
||||||
|
return outputOperations;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -193,6 +193,9 @@ HeaderService.prototype._onBlock = function(block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < this.subscriptions.block.length; i++) {
|
for (var i = 0; i < this.subscriptions.block.length; i++) {
|
||||||
|
var prevHeader = this._headers.get(header.prevHash);
|
||||||
|
assert(prevHeader, 'We must have a previous header in order to calculate this block\'s data.');
|
||||||
|
block.height = prevHeader.height + 1;
|
||||||
this.subscriptions.block[i].emit('header/block', block, header);
|
this.subscriptions.block[i].emit('header/block', block, header);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -218,7 +221,7 @@ HeaderService.prototype._onHeaders = function(headers) {
|
|||||||
headerListLength = headers.length;
|
headerListLength = headers.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
var prevHeader = this._headers.get(header.prevHash);
|
var prevHeader = self._headers.get(header.prevHash);
|
||||||
assert(prevHeader, 'We must have a previous header in order to calculate this header\'s data.');
|
assert(prevHeader, 'We must have a previous header in order to calculate this header\'s data.');
|
||||||
|
|
||||||
header.height = prevHeader.height + 1;
|
header.height = prevHeader.height + 1;
|
||||||
@ -429,8 +432,6 @@ HeaderService.prototype._getPersistedHeaders = function(callback) {
|
|||||||
|
|
||||||
var tipHeader = self._headers.getIndex(self._tip.height);
|
var tipHeader = self._headers.getIndex(self._tip.height);
|
||||||
self._tip.hash = tipHeader.hash;
|
self._tip.hash = tipHeader.hash;
|
||||||
self._lastChainwork = tipHeader.chainwork;
|
|
||||||
|
|
||||||
self._db.batch(removalOps, callback);
|
self._db.batch(removalOps, callback);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -119,9 +119,7 @@ MempoolService.prototype.onBlock = function(block, callback) {
|
|||||||
key: self._encoding.encodeMempoolTransactionKey(tx.txid())
|
key: self._encoding.encodeMempoolTransactionKey(tx.txid())
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
setImmediate(function() {
|
callback(null, ops);
|
||||||
callback(null, ops);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MempoolService.prototype._onTransaction = function(tx) {
|
MempoolService.prototype._onTransaction = function(tx) {
|
||||||
|
|||||||
@ -45,14 +45,13 @@ TransactionService.prototype.getDetailedTransaction = function(txid, options, ca
|
|||||||
this.getTransaction(txid, options, callback);
|
this.getTransaction(txid, options, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionService.prototype.getTransaction = function(txid, options, callback) {
|
TransactionService.prototype._getTransaction = function(txid, options, callback) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var _tx;
|
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) {
|
||||||
|
|
||||||
@ -69,6 +68,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (memTx) {
|
if (memTx) {
|
||||||
|
memTx = self._encoding.decodeTransactionValue(memTx);
|
||||||
memTx.confirmations = 0;
|
memTx.confirmations = 0;
|
||||||
_tx = memTx;
|
_tx = memTx;
|
||||||
}
|
}
|
||||||
@ -78,7 +78,9 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
|
tx = self._encoding.decodeTransactionValue(tx);
|
||||||
tx.confirmations = self._p2p.getBestHeight - tx.__height;
|
tx.confirmations = self._p2p.getBestHeight - tx.__height;
|
||||||
|
tx.blockHash = self._header.get(tx.__height).hash;
|
||||||
_tx = tx;
|
_tx = tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +90,49 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
|||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this could cause crazy amounts of recursion if input values are missing from the entire chain of txs
|
var outputSatoshis = 0;
|
||||||
self._addMissingInputValues(_tx, options, callback);
|
_tx.outputs.forEach(function(output) {
|
||||||
|
outputSatoshis += output.value;
|
||||||
|
});
|
||||||
|
_tx.outputs.forEach(function(output) {
|
||||||
|
outputSatoshis += output.value;
|
||||||
|
});
|
||||||
|
_tx.outputSatoshis = outputSatoshis;
|
||||||
|
if (!_tx.inputs[0].isCoinbase()) {
|
||||||
|
var inputSatoshis = 0;
|
||||||
|
_tx.__inputValues.forEach(function(val) {
|
||||||
|
if (val >- 0) {
|
||||||
|
inputSatoshis += val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var feeSatoshis = inputSatoshis - outputSatoshis;
|
||||||
|
_tx.inputSatosbis = inputSatoshis;
|
||||||
|
_tx.feeSatosbis = feeSatoshis;
|
||||||
|
}
|
||||||
|
callback(null, _tx);
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionService.prototype.getTransaction = function(txid, options, callback) {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (typeof callback !== 'function') {
|
||||||
|
callback = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
self._getTransaction(txid, options, function(err, tx) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tx) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
self._addMissingInputValues(tx, options, callback);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -109,7 +152,7 @@ TransactionService.prototype._addMissingInputValues = function(tx, options, call
|
|||||||
}
|
}
|
||||||
|
|
||||||
var outputIndex = input.prevout.index;
|
var outputIndex = input.prevout.index;
|
||||||
self.getTransaction(input.prevout.txid(), options, function(err, _tx) {
|
self._getTransaction(input.prevout.txid(), options, function(err, _tx) {
|
||||||
|
|
||||||
if (err || !_tx) {
|
if (err || !_tx) {
|
||||||
return next(err || new Error('tx not found for tx id: ' + input.prevout.txid()));
|
return next(err || new Error('tx not found for tx id: ' + input.prevout.txid()));
|
||||||
@ -122,7 +165,6 @@ TransactionService.prototype._addMissingInputValues = function(tx, options, call
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@ -81,11 +81,12 @@ utils.SimpleMap = function SimpleMap() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.set = function (key, value, pos) {
|
this.set = function (key, value, pos) {
|
||||||
object[key] = array.length;
|
|
||||||
|
|
||||||
if (pos >= 0) {
|
if (pos >= 0) {
|
||||||
|
object[key] = pos;
|
||||||
array[pos] = value;
|
array[pos] = value;
|
||||||
} else {
|
} else {
|
||||||
|
object[key] = array.length;
|
||||||
array.push(value);
|
array.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user