Cache address-summary

Store cache of address summary in db when address has more than MAX_TX_QUERY_LIMIT
This commit is contained in:
sairajzero 2023-04-17 20:13:29 +05:30
parent 0a3a1b5ea6
commit 3982807b32
2 changed files with 144 additions and 35 deletions

View File

@ -2,11 +2,13 @@
function Encoding(servicePrefix) {
this.servicePrefix = servicePrefix;
this.addressIndex = new Buffer('00', 'hex');
this.utxoIndex = new Buffer('01', 'hex');
this.addressCache = new Buffer('ff', 'hex');
}
Encoding.prototype.encodeAddressIndexKey = function(address, height, txid, index, input, timestamp) {
var prefix = new Buffer('00', 'hex');
var buffers = [this.servicePrefix, prefix];
var buffers = [this.servicePrefix, this.addressIndex];
var addressSizeBuffer = new Buffer(1);
addressSizeBuffer.writeUInt8(address.length);
@ -58,8 +60,7 @@ Encoding.prototype.decodeAddressIndexKey = function(buffer) {
};
Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) {
var prefix = new Buffer('01', 'hex');
var buffers = [this.servicePrefix, prefix];
var buffers = [this.servicePrefix, this.utxoIndex];
var addressSizeBuffer = new Buffer(1);
addressSizeBuffer.writeUInt8(address.length);
@ -114,5 +115,60 @@ Encoding.prototype.decodeUtxoIndexValue = function(buffer) {
};
};
Encoding.prototype.encodeAddressCacheKey = function(address) {
return Buffer.concat([this.servicePrefix, this.addressCache, new Buffer(address, 'utf8')]);
}
Encoding.prototype.decodeAddressCacheKey = function(buffer) {
return buffer.slice(3).toString('utf8');
}
Encoding.prototype.encodeAddressCacheValue = function(lastTx, balance, received, sent, txApperances, unconfirmedBalance, unconfirmedTxApperances) {
var buffer = [];
var balanceBuffer = new Buffer(4);
balanceBuffer.writeUInt32BE(balance || 0);
buffer.push(balanceBuffer);
var receivedBuffer = new Buffer(4);
receivedBuffer.writeUInt32BE(received || 0);
buffer.push(receivedBuffer);
var sentBuffer = new Buffer(4);
sentBuffer.writeUInt32BE(sent || 0);
buffer.push(sentBuffer);
var txApperancesBuffer = new Buffer(4);
txApperancesBuffer.writeUInt32BE(txApperances || 0);
buffer.push(txApperancesBuffer);
var unconfirmedBalanceBuffer = new Buffer(4);
unconfirmedBalanceBuffer.writeUInt32BE(unconfirmedBalance || 0);
buffer.push(unconfirmedBalanceBuffer);
var unconfirmedTxApperancesBuffer = new Buffer(4);
unconfirmedTxApperancesBuffer.writeUInt32BE(unconfirmedTxApperances || 0);
buffer.push(unconfirmedTxApperancesBuffer);
var txidBuffer = new Buffer(lastTx || Array(65).join('0'), 'hex');
buffer.push(txidBuffer);
return Buffer.concat(buffers);
}
Encoding.prototype.decodeAddressCacheValue = function(buffer) {
var balance = buffer.readUInt32BE(0);
var received = buffer.readUInt32BE(4);
var sent = buffer.readUInt32BE(8);
var txApperances = buffer.readUInt32BE(12);
var unconfirmedBalance = buffer.readUInt32BE(16);
var unconfirmedTxApperances = buffer.readUInt32BE(20);
var lastTx = buffer.slice(24).toString('hex');
return { lastTx, balance, received, sent, txApperances, unconfirmedBalance, unconfirmedTxApperances };
}
module.exports = Encoding;

View File

@ -340,46 +340,99 @@ AddressService.prototype.getAddressSummary = function(address, options, streamer
txApperances: 0,
};
self._streamAddressSummary(address, options, function(err, tx) {
var useCache = _.isUndefined(options.after);
self._loadCache(address, result, useCache, function(err, lastCachedTx) {
if(err)
return log.error(err);
if(tx) {
count++;
self._aggregateAddressSummaryResult(tx, address, result, options);
}
if(count >= MAX_TX_QUERY_LIMIT) {//stop quering db when limit reached
options.flag_stop = true;
result.lastItem = tx.txid();
result.incomplete = true;
}
log.error(err);
streamer(null, tx);
if(!_.isUndefined(lastCachedTx))
options.after = lastCachedTx;
}, function(err) {
self._streamAddressSummary(address, options, function(err, tx) {
if(err)
return log.error(err);
if(tx) {
count++;
self._aggregateAddressSummaryResult(tx, address, result, options);
}
if(count >= MAX_TX_QUERY_LIMIT) {//stop quering db when limit reached
options.flag_stop = true;
result.lastItem = tx.txid();
result.incomplete = true;
}
streamer(null, tx);
}, function(err) {
if (err) {
return callback(err);
}
result.balanceSat = parseInt(result.balanceSat.toFixed());
result.totalReceivedSat = parseInt(result.totalReceivedSat.toFixed());
result.totalSentSat = parseInt(result.totalSentSat.toFixed());
result.txApperances = parseInt(result.txApperances.toFixed());
result.unconfirmedBalanceSat = parseInt(result.unconfirmedBalanceSat.toFixed());
result.unconfirmedTxApperances = parseInt(result.unconfirmedTxApperances.toFixed());
result.balance = Unit.fromSatoshis(result.balanceSat).toBTC();
result.totalReceived = Unit.fromSatoshis(result.totalReceivedSat).toBTC();
result.totalSent = Unit.fromSatoshis(result.totalSentSat).toBTC();
result.unconfirmedBalance = Unit.fromSatoshis(result.unconfirmedBalanceSat).toBTC();
callback(null, result);
//store in cache if needed
if(useCache && result.incomplete)
this._storeCache(address, result.lastItem, result);
});
})
}
AddressService.prototype._storeCache = function(address, lastCacheTx, result, callback) {
var key = self._encoding.encodeAddressCacheKey(address);
var value = self._encoding.encodeAddressCacheValue(lastCacheTx, result.balanceSat, result.totalReceivedSat, result.totalSentSat, result.txApperances, result.unconfirmedBalanceSat, result.unconfirmedTxApperances)
if(!_.isFunction(callback)) //if callback is not passed, call a empty function
callback = () => null;
self._db.put(key, value, callback);
}
AddressService.prototype._loadCache = function(address, result, useCache, next) {
if(!useCache) //skip if useCache is false (cases like 'after' parameter is used by client)
next();
self._db.get(self._encoding.encodeAddressCacheKey(address), function(err, value) {
if (err) {
return callback(err);
return next(err);
}
if (!value) {
return next();
}
var addressCache = self._encoding.decodeAddressCacheValue(value);
//values are in satoshis
result.balanceSat = addressCache.balance;
result.totalReceivedSat = addressCache.received;
result.totalSentSat = addressCache.sent;
result.txApperances = addressCache.txApperances;
result.unconfirmedBalanceSat = addressCache.unconfirmedBalance;
result.unconfirmedTxApperances = addressCache.unconfirmedTxApperances;
next(null, addressCache.lastTx);
result.balanceSat = parseInt(result.balanceSat.toFixed());
result.totalReceivedSat = parseInt(result.totalReceivedSat.toFixed());
result.totalSentSat = parseInt(result.totalSentSat.toFixed());
result.txApperances = parseInt(result.txApperances.toFixed());
result.unconfirmedBalanceSat = parseInt(result.unconfirmedBalanceSat.toFixed());
result.unconfirmedTxApperances = parseInt(result.unconfirmedTxApperances.toFixed());
result.balance = Unit.fromSatoshis(result.balanceSat).toBTC();
result.totalReceived = Unit.fromSatoshis(result.totalReceivedSat).toBTC();
result.totalSent = Unit.fromSatoshis(result.totalSentSat).toBTC();
result.unconfirmedBalance = Unit.fromSatoshis(result.unconfirmedBalanceSat).toBTC();
callback(null, result);
});
}
AddressService.prototype._setOutputResults = function(tx, address, result) {