Compare commits

...

60 Commits
master ... dev

Author SHA1 Message Date
sairajzero
35f5a82d4b fix 2023-02-06 17:54:47 +05:30
sairajzero
a396c4a24e ws fix 2023-02-06 17:45:32 +05:30
sairajzero
fe9741fdf3 fix 2023-02-06 01:54:41 +05:30
sairajzero
9da18c7073 checkpoint 2023-02-05 23:10:25 +05:30
sairajzero
7663026227 logs 2023-02-05 23:05:12 +05:30
sairajzero
8d4f9f5a6e Update index.js 2023-02-05 23:02:38 +05:30
sairajzero
1d53646101 Inc MAX_TX_QUERY_LIMIT = 100 2023-02-05 22:48:52 +05:30
sairajzero
e5c86ebe5f Update index.js 2023-02-05 22:45:43 +05:30
sairajzero
5ab1214fa4 Update index.js 2023-02-05 22:41:15 +05:30
sairajzero
c5690aa490 Update index.js 2023-02-05 22:30:24 +05:30
sairajzero
40b2e64a8f test 2023-02-05 22:26:53 +05:30
sairajzero
cb89be8263 logging 2023-02-05 19:09:49 +05:30
sairajzero
85c1c02c74 Update index.js 2023-02-05 18:35:32 +05:30
sairajzero
263c892b1d Update index.js 2023-02-05 18:33:21 +05:30
sairajzero
373600dbb9 Update index.js 2023-02-05 18:08:03 +05:30
sairajzero
f05d83ff6d Update index.js 2023-02-05 17:42:22 +05:30
sairajzero
bcfe9741bd Update index.js 2023-02-05 17:04:21 +05:30
sairajzero
a24916243f Update index.js 2023-02-05 16:29:39 +05:30
sairajzero
0b646fe453 Update index.js 2023-02-05 16:23:34 +05:30
sairajzero
76eb2debdd Update index.js 2023-02-05 16:17:45 +05:30
sairajzero
ed79adb910 Update index.js 2023-02-05 16:13:41 +05:30
sairajzero
5e6340be78 log 2023-02-05 06:03:14 +05:30
sairajzero
9b59e5791a Update index.js 2023-02-05 05:58:38 +05:30
sairajzero
cf9aaae4f6 Update index.js 2023-02-05 05:56:31 +05:30
sairajzero
6b78cfbfd8 Update index.js 2023-02-05 05:46:15 +05:30
sairajzero
c712b17465 Improvements 2023-02-05 03:14:05 +05:30
sairajzero
729072738b API improvements 2023-02-04 20:34:42 +05:30
sairajzero
450e6b9d21 test log 2023-02-02 18:57:33 +05:30
sairajzero
14e9371306 test log 2023-02-02 18:46:11 +05:30
sairajzero
0b0ba0d630 test 2023-02-02 18:40:42 +05:30
sairajzero
8ca0688153 test log 2023-02-02 18:36:49 +05:30
sairajzero
6347ae261f test 2023-02-02 18:30:32 +05:30
sairajzero
bb54d958bb test log 2023-02-02 18:24:31 +05:30
sairajzero
8729078765 improve handling of duplicate tx query 2023-02-02 18:18:07 +05:30
sairajzero
c32a7cb57a fix 2023-01-28 21:03:56 +05:30
sairajzero
6e9f946607 Update index.js 2023-01-28 21:01:10 +05:30
sairajzero
88c276ad49 fix 2023-01-28 20:20:11 +05:30
sairajzero
40b42019ab log 2023-01-28 19:29:56 +05:30
sairajzero
015dbb650d Update index.js 2023-01-28 19:08:45 +05:30
sairajzero
2c3997d245 Update index.js 2023-01-28 18:32:37 +05:30
sairajzero
def559a86a Update index.js 2023-01-28 18:14:29 +05:30
sairajzero
635c344268 bug fix 2023-01-28 17:24:48 +05:30
sairajzero
f73ccfd02e Update index.js 2023-01-28 17:20:34 +05:30
sairajzero
35c506ac65 Fix: aggregation of duplicate values
Fixed: _aggregateAddressSummaryResult to handle duplicate tx data
2023-01-28 17:18:18 +05:30
sairajzero
eb1c6331d8 resetting _getAddressSummaryResult to old 2023-01-28 16:46:16 +05:30
sairajzero
99a96d3f34 log 2023-01-28 15:49:57 +05:30
sairajzero
aa5d986217 logger 2023-01-28 15:38:24 +05:30
sairajzero
2870fe8aa3 Update index.js 2023-01-28 02:57:07 +05:30
sairajzero
113a12aaf4 Checkpoint 2023-01-28 02:05:53 +05:30
sairajzero
c757c2246b Update package-lock.json 2023-01-28 02:05:21 +05:30
sairajzero
648d627149 log 2023-01-28 01:52:55 +05:30
sairajzero
69a829a6eb Update index.js 2023-01-28 01:46:39 +05:30
sairajzero
09a934f65b test-fix 2023-01-28 01:41:49 +05:30
sairajzero
66fa217f10 log: check-fix 2023-01-28 01:36:08 +05:30
sairajzero
d2bb1c6acb logging 2023-01-28 01:30:44 +05:30
sairajzero
3cd4806d12 logging 2023-01-28 01:24:26 +05:30
sairajzero
2de483ada3 logger 2023-01-28 01:16:07 +05:30
sairajzero
9e0ebda278 logging 2023-01-28 01:10:19 +05:30
sairajzero
f899f5671d Adding debug logs 2023-01-28 01:03:38 +05:30
sairajzero
6e2ffdf298 bug fixes 2023-01-28 00:58:09 +05:30
3 changed files with 609 additions and 618 deletions

View File

@ -16,7 +16,7 @@ var utils = require('../../utils');
var LRU = require('lru-cache'); var LRU = require('lru-cache');
var XXHash = require('xxhash'); var XXHash = require('xxhash');
const MAX_TX_QUERY_LIMIT = 1000; const MAX_TX_QUERY_LIMIT = 100;
// See rationale about this cache at function getTxList(next) // See rationale about this cache at function getTxList(next)
const TXID_LIST_CACHE_ITEMS = 250; // nr of items (this translates to: consecutive const TXID_LIST_CACHE_ITEMS = 250; // nr of items (this translates to: consecutive
@ -177,10 +177,10 @@ AddressService.prototype.getAddressHistory = function(addresses, options, stream
var self = this; var self = this;
options = options || {}; options = options || {};
options.from = options.from || 0; //options.from = options.from || 0; //Deprecated, use `after` option
options.to = options.to || 0xffffffff; //options.to = options.to || 0xffffffff; //Deprecated, use `after` option
if(!callback){ //if only 3 args, then streamer is callback if(typeof callback !== 'function'){ //if only 3 args, then streamer is callback
callback = streamer; callback = streamer;
streamer = () => null; //NULL fn streamer = () => null; //NULL fn
} }
@ -189,6 +189,13 @@ AddressService.prototype.getAddressHistory = function(addresses, options, stream
options.queryMempool = true; options.queryMempool = true;
} }
//Quick support for `from` and `to` options (DEPRECATED! Not recommeded to use)
if( !_.isUndefined(options.from) || !_.isUndefined(options.to)) {
options.old_support = true;
options.from = options.from || 0;
options.to = options.to || 0xffffffff; //Max value of to will actually be MAX_TX_QUERY_LIMIT
}
if (_.isString(addresses)) { if (_.isString(addresses)) {
addresses = [addresses]; addresses = [addresses];
} }
@ -202,13 +209,23 @@ AddressService.prototype.getAddressHistory = function(addresses, options, stream
self._streamAddressSummary(address, options, function(err, tx){ self._streamAddressSummary(address, options, function(err, tx){
results.totalCount++;
if(err) if(err)
return log.error(err); return log.error(err);
if(!options.txNotNeeded && results.items.length < MAX_TX_QUERY_LIMIT) if(!options.txNotNeeded) {
results.items.push(tx); results.totalCount++;
if(!results.items.some(x => x.txid() === tx.txid())) //push only if tx not already in array
results.items.unshift(tx); //using unshift, so that recent tx (low) are at front
if(results.items.length > MAX_TX_QUERY_LIMIT) { //remove items from array when overflown
results.items.sort((a, b) => (b.__height || 0xffffffff) - (a.__height || 0xffffffff) || b.txid().localeCompare(a.txid()));
let del_count = options.old_support ? results.items.length : results.items.length - MAX_TX_QUERY_LIMIT;
let start_index = options.old_support ? MAX_TX_QUERY_LIMIT : 0;
results.items.splice(start_index, del_count);
}
}
streamer(null, tx); streamer(null, tx);
@ -216,11 +233,20 @@ AddressService.prototype.getAddressHistory = function(addresses, options, stream
}, function(err) { }, function(err) {
console.debug("END @getAddressHistory");
if (err) { if (err) {
return callback(err); return callback(err);
} }
//TODO: sorting of tx list (results.items) //sort items in desc block-height, then asc txid (if same height)
results.items.sort((a, b) => (b.__height || 0xffffffff) - (a.__height || 0xffffffff) || b.txid().localeCompare(a.txid()));
results.totalCount = parseInt(results.totalCount.toFixed());
//Quick support for `from` and `to` options (DEPRECATED! Not recommeded to use)
if(options.old_support) {
results.items = results.items.slice(options.from, options.to);
}
callback(null, results); callback(null, results);
}) })
@ -254,7 +280,7 @@ AddressService.prototype.__getAddressSummary = function(address, options, callba
txApperances: 0, txApperances: 0,
}; };
self.getAddressHistory(address, options, function(err, results) { self.__getAddressHistory(address, options, function(err, results) { //old fn
if (err) { if (err) {
return callback(err); return callback(err);
@ -277,15 +303,15 @@ AddressService.prototype.getAddressSummary = function(address, options, streamer
var self = this; var self = this;
options = options || {}; options = options || {};
options.from = options.from || 0; //options.from = options.from || 0; //Deprecated
options.to = options.to || 0xffffffff; //options.to = options.to || 0xffffffff; //Deprecated
options.txNotNeeded = true; //no need to store tx details in result options.txNotNeeded = true; //no need to store tx details in result
if (_.isUndefined(options.queryMempool)) { if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true; options.queryMempool = true;
} }
if(!callback){ //if only 3 args, then streamer is callback if(typeof callback !== 'function'){ //if only 3 args, then streamer is callback
callback = streamer; callback = streamer;
streamer = () => null; //NULL fn streamer = () => null; //NULL fn
} }
@ -304,15 +330,13 @@ AddressService.prototype.getAddressSummary = function(address, options, streamer
txApperances: 0, txApperances: 0,
}; };
self._aggregateAddressSummaryResult(tx, address, result);
self.getAddressHistory(address, options, function(err, tx) { self.getAddressHistory(address, options, function(err, tx) {
if(err) if(err)
return log.error(err); return log.error(err);
if(tx) if(tx)
self._aggregateAddressSummaryResult(tx, address, result); self._aggregateAddressSummaryResult(tx, address, result, options);
streamer(null, tx); streamer(null, tx);
@ -322,6 +346,13 @@ AddressService.prototype.getAddressSummary = function(address, options, streamer
return callback(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.balance = Unit.fromSatoshis(result.balanceSat).toBTC();
result.totalReceived = Unit.fromSatoshis(result.totalReceivedSat).toBTC(); result.totalReceived = Unit.fromSatoshis(result.totalReceivedSat).toBTC();
result.totalSent = Unit.fromSatoshis(result.totalSentSat).toBTC(); result.totalSent = Unit.fromSatoshis(result.totalSentSat).toBTC();
@ -375,10 +406,13 @@ AddressService.prototype._setInputResults = function(tx, address, result) {
} }
}; };
AddressService.prototype._aggregateAddressSummaryResult = function (tx, address, result, options){ AddressService.prototype._getAddressSummaryResult = function(txs, address, result, options) {
var self = this; var self = this;
for(var i = 0; i < txs.length; i++) {
var tx = txs[i];
self._setOutputResults(tx, address, result); self._setOutputResults(tx, address, result);
self._setInputResults(tx, address, result); self._setInputResults(tx, address, result);
@ -391,17 +425,109 @@ AddressService.prototype._aggregateAddressSummaryResult = function (tx, address,
} }
AddressService.prototype._getAddressSummaryResult = function(txs, address, result, options) { return result;
};
AddressService.prototype._getOccurrenceCount = function(tx, address) {
let count = 0;
for(var i = 0; i < tx.inputs.length; i++) {
var input = tx.inputs[i];
if(utils.getAddress(input, this._network) === address)
count++;
}
for(var j = 0; j < tx.outputs.length; j++) {
var output = tx.outputs[j];
if(utils.getAddress(output, this._network) === address)
count++;
}
return count;
}
AddressService.prototype._getOutputResults = function(tx, address) {
let value = 0;
for(var j = 0; j < tx.outputs.length; j++) {
var output = tx.outputs[j];
if (utils.getAddress(output, this._network) === address)
value += output.value;
}
return value;
};
AddressService.prototype._getInputResults = function(tx, address) {
let value = 0;
for(var i = 0; i < tx.inputs.length; i++) {
var input = tx.inputs[i];
if (utils.getAddress(input, this._network) === address)
value += tx.__inputValues[i];
}
return value;
};
AddressService.prototype._aggregateAddressSummaryResult = function (tx, address, result, options) {
var self = this; var self = this;
for(var i = 0; i < txs.length; i++) { let output_val = self._getOutputResults(tx, address);
var tx = txs[i]; let input_val = self._getInputResults(tx, address);
self._aggregateAddressSummaryResult(tx, address, result, options);
//aggregate the result
result.txApperances++;
result.totalReceivedSat += output_val;
result.balanceSat += output_val;
result.totalSentSat += input_val;
result.balanceSat -= input_val;
if(!tx.confirmations){
result.unconfirmedTxApperances++;
result.unconfirmedBalanceSat += output_val;
result.unconfirmedBalanceSat -= input_val;
} }
return result; if (!options.noTxList) {
};
if (!result.transactions) {
result.transactions = [];
}
let txid = tx.txid();
if(!result.transactions.includes(txid)) { //push txid only if its not in the array
result.transactions.unshift(txid); //using unshift, so that recent tx (low confirmation) are at front
if(result.transactions.length > MAX_TX_QUERY_LIMIT)
result.transactions.pop(); //pop the oldest tx in list (when list limit is maxed out)
}
}
}
AddressService.prototype.getAddressUnspentOutputs = function(address, options, callback) { AddressService.prototype.getAddressUnspentOutputs = function(address, options, callback) {
@ -565,18 +691,28 @@ AddressService.prototype.stop = function(callback) {
AddressService.prototype._getTxidStream = function(address, options) { AddressService.prototype._getTxidStream = function(address, options) {
var start = this._encoding.encodeAddressIndexKey(address); var start;
if(options.after) {
start = this._encoding.encodeAddressIndexKey(address, options.start, options.after, 0xffffffff, 1, 0xffffffff); //0xffffffff is for getting after the txid
} else {
start = this._encoding.encodeAddressIndexKey(address, options.start);
}
var endHeightBuf = new Buffer(4);
endHeightBuf.writeUInt32BE(options.end);
var end = Buffer.concat([ var end = Buffer.concat([
start.slice(0, address.length + 4), start.slice(0, address.length + 4),
options.endHeightBuf, endHeightBuf,
new Buffer(new Array(83).join('f'), 'hex') new Buffer(new Array(83).join('f'), 'hex')
]); ]);
var criteria = { var criteria = {
gte: start, gte: start,
lte: end, lte: end
reverse: true // txids stream from low confirmations to high confirmations //reverse: true // txids stream from low confirmations to high confirmations
}; };
//NOTE: commentted reverse to keep the order in asc when reading to preserve continuity when using `after` option
// txid stream // txid stream
var txidStream = this._db.createKeyStream(criteria); var txidStream = this._db.createKeyStream(criteria);
@ -588,6 +724,7 @@ AddressService.prototype._getTxidStream = function(address, options) {
return txidStream; return txidStream;
}; };
//(used by old fn)
AddressService.prototype._getAddressTxHistory = function(options, callback) { AddressService.prototype._getAddressTxHistory = function(options, callback) {
var self = this; var self = this;
@ -616,6 +753,7 @@ AddressService.prototype._getAddressTxHistory = function(options, callback) {
}; };
//(used by old fn)
AddressService.prototype._getAddressTxidHistory = function(address, options, callback) { AddressService.prototype._getAddressTxidHistory = function(address, options, callback) {
var self = this; var self = this;
@ -625,9 +763,6 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
var results = []; var results = [];
options.endHeightBuf = new Buffer(4);
options.endHeightBuf.writeUInt32BE(options.end);
if (_.isUndefined(options.queryMempool)) { if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true; options.queryMempool = true;
} }
@ -682,7 +817,9 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
return; return;
} }
if(!results.some(r => r.txid == txInfo.txid)) //add txid to array only if its not already there
results.push({ txid: txInfo.txid, height: txInfo.height }); results.push({ txid: txInfo.txid, height: txInfo.height });
callback(); callback();
}; };
@ -701,25 +838,29 @@ AddressService.prototype._streamAddressSummary = function(address, options, stre
options.start = options.start || 0; options.start = options.start || 0;
options.end = options.end || 0xffffffff; options.end = options.end || 0xffffffff;
options.from = options.from || 0; //TODO: check from/to options are working or not //options.from = options.from || 0; //Deprecated, use `after` option
options.to = options.to || 0xffffffff; //options.to = options.to || 0xffffffff; //Deprecated, use `after` option
if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true;
}
options.endHeightBuf = new Buffer(4);
options.endHeightBuf.writeUInt32BE(options.end);
if (_.isUndefined(options.queryMempool)) { if (_.isUndefined(options.queryMempool)) {
options.queryMempool = true; options.queryMempool = true;
} }
//declare the queue to process tx data //declare the queue to process tx data
var tmpTxList = {}; //store processed txid temporarily to ignore duplication
var q = async.queue(function(task, cb) { var q = async.queue(function(id, cb) {
let {id, options} = task; //duplication finding
if(id.txid in tmpTxList){
tmpTxList[id.txid][0]++;
if(tmpTxList[id.txid][1] !== null && tmpTxList[id.txid][0] >= tmpTxList[id.txid][1]) //all duplications are found for this txid
delete tmpTxList[id.txid];
return cb();
} else tmpTxList[id.txid] = [1, null];
if (id.height === 0xffffffff) { if (id.height === 0xffffffff) {
@ -738,14 +879,29 @@ AddressService.prototype._streamAddressSummary = function(address, options, stre
}, 4); }, 4);
q.pause(); //pause and wait until queue is set //q.pause(); //pause and wait until queue is set (not needed)
function process_chunk(err, tx){ function chunkCallback(err, tx){
if(q.killed || (!err && !tx)) //no error or tx data (duplicate calls will have empty tx value)
return;
if(tx){
let txid = tx.txid();
tmpTxList[txid][1] = self._getOccurrenceCount(tx, address);
if(tmpTxList[txid][0] >= tmpTxList[txid][1]) //all duplications are found for this txid
delete tmpTxList[txid];
}
streamer(err, tx); streamer(err, tx);
if(err){ if((err || options.flag_stop) && !q.killed){
console.debug("KILL", options.flag_stop)
q.kill(); q.kill();
q.killed = true;
return callback(); return callback();
} }
@ -754,6 +910,68 @@ AddressService.prototype._streamAddressSummary = function(address, options, stre
async.waterfall([ async.waterfall([
//Find start height if `after` option is passed
function(next){
if(_.isUndefined(options.after)) {
return next();
}
self._transaction.getTransaction(options.after, options, function(err, tx) {
if(tx && tx.confirmations && tx.height >= options.start) {
options.start = tx.height;
} else {
delete options.after;
}
next();
});
},
// stream the rest of the confirmed txids out of the address index
function(next) {
var txIdTransformStream = new Transform({ objectMode: true });
txIdTransformStream._flush = function(cb) {
txIdTransformStream.emit('end');
cb();
};
txIdTransformStream.on('error', function(err) {
log.error('Address Service: txstream err: ' + err);
txIdTransformStream.unpipe();
});
txIdTransformStream.on('end', function() {
next();
});
txIdTransformStream._transform = function(chunk, enc, cb) {
if(options.flag_stop){//stop data query
console.debug("FLAG STOP:", options.flag_stop)
return txIdTransformStream.unpipe();
}
var txInfo = self._encoding.decodeAddressIndexKey(chunk);
q.push({ txid: txInfo.txid, height: txInfo.height }, chunkCallback);
cb();
};
var txidStream = self._getTxidStream(address, options);
txidStream.pipe(txIdTransformStream);
},
// query the mempool for relevant txs for this address // query the mempool for relevant txs for this address
function(next) { function(next) {
@ -771,41 +989,23 @@ AddressService.prototype._streamAddressSummary = function(address, options, stre
return next(); return next();
} }
mempoolTxids.map(id => q.push(id, process_chunk)); mempoolTxids.map(id => q.push(id, chunkCallback));
next(); next();
}, },
// stream the rest of the confirmed txids out of the address index
//wait for queue to complete
function(next) { function(next) {
var txIdTransformStream = new Transform({ objectMode: true }); console.debug("WAITING FOR QUEUE TO COMPLETE", q.started)
txIdTransformStream._flush = function(cb) { if(!q.started) //No tx in query
txIdTransformStream.emit('end'); return next();
cb();
};
txIdTransformStream.on('error', function(err) { else
log.error('Address Service: txstream err: ' + err); q.drain = () => next();
txIdTransformStream.unpipe();
});
txIdTransformStream.on('end', function() {
q.resume();
});
txIdTransformStream._transform = function(chunk, enc, cb) {
var txInfo = self._encoding.decodeAddressIndexKey(chunk);
q.push({ txid: txInfo.txid, height: txInfo.height }, process_chunk);
cb();
};
var txidStream = self._getTxidStream(address, options);
txidStream.pipe(txIdTransformStream);
q.drain(next);
} }
], callback); ], callback);
} }

View File

@ -100,13 +100,15 @@ WebService.prototype.stop = function(callback) {
* all of the exposed HTTP routes. * all of the exposed HTTP routes.
*/ */
WebService.prototype.setupAllRoutes = function() { WebService.prototype.setupAllRoutes = function() {
for(var key in this.node.services) { const self = this;
for(var key in self.node.services) {
var subApp = new express(); var subApp = new express();
var service = this.node.services[key]; var service = self.node.services[key];
if(service.getRoutePrefix && service.setupRoutes) { if(service.getRoutePrefix && service.setupRoutes) {
this.app.use('/' + this.node.services[key].getRoutePrefix(), subApp); self.app.use('/' + self.node.services[key].getRoutePrefix(), subApp);
this.node.services[key].setupRoutes(subApp, express, express_ws); self.node.services[key].setupRoutes(subApp, express, a => express_ws(a, self.server));
} else { } else {
log.debug('No routes defined for: ' + key); log.debug('No routes defined for: ' + key);
} }

863
package-lock.json generated

File diff suppressed because it is too large Load Diff