Compare commits
No commits in common. "master" and "bitpay-master" have entirely different histories.
master
...
bitpay-mas
3
.gitignore
vendored
3
.gitignore
vendored
@ -21,8 +21,6 @@ coverage/*
|
||||
**/*.config
|
||||
**/*.creator
|
||||
*.log
|
||||
*.tmp
|
||||
*.tmp.*
|
||||
.DS_Store
|
||||
bin/florincoin*
|
||||
bin/SHA256SUMS.asc
|
||||
@ -33,4 +31,3 @@ flocore-node.json*
|
||||
*.bak
|
||||
*.orig
|
||||
lib/services/insight-api
|
||||
testnet/*
|
||||
|
||||
1
addresses.txt
Normal file
1
addresses.txt
Normal file
@ -0,0 +1 @@
|
||||
mtLDA41NWe9rLm7nuMvAnTs2SbP49cz1ZR
|
||||
@ -31,15 +31,6 @@ function main(parentServicesPath, additionalServices) {
|
||||
node.cli.main(parentServicesPath, additionalServices);
|
||||
}
|
||||
|
||||
// Gracefully Shut Down
|
||||
process.on('SIGTERM', function () {
|
||||
console.log("Shutting down flocore-node")
|
||||
node.stop(function() {
|
||||
console.log("flocore-node successfully stopped!")
|
||||
process.exit(0)
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -226,7 +226,7 @@ Node.prototype.stop = function(callback) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Node;
|
||||
|
||||
@ -201,26 +201,23 @@ function cleanShutdown(_process, node) {
|
||||
return _process.exit(1);
|
||||
}
|
||||
log.info('Halted');
|
||||
process.exit(0);
|
||||
_process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
function exitHandler(options, _process, node, err) {
|
||||
// Handle and log errors other than SIGINT shutdown
|
||||
if (err && err !== "SIGINT") {
|
||||
if (err) {
|
||||
log.error('uncaught exception:', err);
|
||||
if(err.stack) {
|
||||
log.error(err.stack);
|
||||
}
|
||||
if(options.exit)
|
||||
node.stop(function(err) {
|
||||
if(err) {
|
||||
log.error('Failed to stop services: ' + err);
|
||||
}
|
||||
_process.exit(-1);
|
||||
});
|
||||
node.stop(function(err) {
|
||||
if(err) {
|
||||
log.error('Failed to stop services: ' + err);
|
||||
}
|
||||
_process.exit(-1);
|
||||
});
|
||||
}
|
||||
// Handle SIGINT (Ctrl+C)
|
||||
if (options.sigint) {
|
||||
if (!shuttingDown) {
|
||||
shuttingDown = true;
|
||||
@ -230,7 +227,7 @@ function exitHandler(options, _process, node, err) {
|
||||
}
|
||||
|
||||
function registerExitHandlers(_process, node) {
|
||||
_process.on('uncaughtException', exitHandler.bind(null, {exit:false}, _process, node));
|
||||
_process.on('uncaughtException', exitHandler.bind(null, {exit:true}, _process, node));
|
||||
_process.on('SIGINT', exitHandler.bind(null, {sigint:true}, _process, node));
|
||||
}
|
||||
|
||||
|
||||
@ -2,13 +2,11 @@
|
||||
|
||||
function Encoding(servicePrefix) {
|
||||
this.servicePrefix = servicePrefix;
|
||||
this.addressIndex = new Buffer('00', 'hex');
|
||||
this.utxoIndex = new Buffer('01', 'hex');
|
||||
this.addressCache = new Buffer('fe', 'hex');
|
||||
}
|
||||
|
||||
Encoding.prototype.encodeAddressIndexKey = function(address, height, txid, index, input, timestamp) {
|
||||
var buffers = [this.servicePrefix, this.addressIndex];
|
||||
var prefix = new Buffer('00', 'hex');
|
||||
var buffers = [this.servicePrefix, prefix];
|
||||
|
||||
var addressSizeBuffer = new Buffer(1);
|
||||
addressSizeBuffer.writeUInt8(address.length);
|
||||
@ -60,7 +58,8 @@ Encoding.prototype.decodeAddressIndexKey = function(buffer) {
|
||||
};
|
||||
|
||||
Encoding.prototype.encodeUtxoIndexKey = function(address, txid, outputIndex) {
|
||||
var buffers = [this.servicePrefix, this.utxoIndex];
|
||||
var prefix = new Buffer('01', 'hex');
|
||||
var buffers = [this.servicePrefix, prefix];
|
||||
|
||||
var addressSizeBuffer = new Buffer(1);
|
||||
addressSizeBuffer.writeUInt8(address.length);
|
||||
@ -115,53 +114,5 @@ 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, lastBlock, balance, received, sent, txApperances) {
|
||||
|
||||
var buffer = [];
|
||||
|
||||
var balanceBuffer = new Buffer(8);
|
||||
balanceBuffer.writeBigUInt64BE(BigInt(balance));
|
||||
buffer.push(balanceBuffer);
|
||||
|
||||
var receivedBuffer = new Buffer(8);
|
||||
receivedBuffer.writeBigUInt64BE(BigInt(received));
|
||||
buffer.push(receivedBuffer);
|
||||
|
||||
var sentBuffer = new Buffer(8);
|
||||
sentBuffer.writeBigUInt64BE(BigInt(sent));
|
||||
buffer.push(sentBuffer);
|
||||
|
||||
var txApperancesBuffer = new Buffer(4);
|
||||
txApperancesBuffer.writeUInt32BE(txApperances);
|
||||
buffer.push(txApperancesBuffer);
|
||||
|
||||
var txidBuffer = new Buffer(lastTx, 'hex');
|
||||
buffer.push(txidBuffer);
|
||||
|
||||
var blkBuffer = new Buffer(lastBlock, 'hex');
|
||||
buffer.push(blkBuffer);
|
||||
|
||||
return Buffer.concat(buffer);
|
||||
}
|
||||
|
||||
Encoding.prototype.decodeAddressCacheValue = function(buffer) {
|
||||
|
||||
var balance = parseInt(buffer.readBigUInt64BE(0));
|
||||
var received = parseInt(buffer.readBigUInt64BE(8));
|
||||
var sent = parseInt(buffer.readBigUInt64BE(16));
|
||||
var txApperances = buffer.readUInt32BE(24);
|
||||
var lastTx = buffer.slice(28, 60).toString('hex'); //28 + 32 (tx hash buffer length) = 60
|
||||
var lastBlock = buffer.slice(60).toString('hex');
|
||||
return { lastTx, lastBlock, balance, received, sent, txApperances };
|
||||
}
|
||||
|
||||
module.exports = Encoding;
|
||||
|
||||
|
||||
@ -16,9 +16,7 @@ var utils = require('../../utils');
|
||||
var LRU = require('lru-cache');
|
||||
var XXHash = require('xxhash');
|
||||
|
||||
const MAX_TX_QUERY_LIMIT_HISTORY = 1000;
|
||||
const MAX_TX_QUERY_LIMIT_UTXO = 1000;
|
||||
const MAX_TX_QUERY_LIMIT_SUMMARY = 500;
|
||||
|
||||
|
||||
// See rationale about this cache at function getTxList(next)
|
||||
const TXID_LIST_CACHE_ITEMS = 250; // nr of items (this translates to: consecutive
|
||||
@ -69,8 +67,8 @@ AddressService.dependencies = [
|
||||
// then I would pass back [tx1, tx2] in that order
|
||||
//
|
||||
// Instead of passing addresses, with from>0, options.cacheKey can be used to define the address set.
|
||||
//(old one: non-optimized for large data)
|
||||
AddressService.prototype.__getAddressHistory = function(addresses, options, callback) {
|
||||
//
|
||||
AddressService.prototype.getAddressHistory = function(addresses, options, callback) {
|
||||
var self = this;
|
||||
var cacheUsed = false;
|
||||
|
||||
@ -175,106 +173,8 @@ AddressService.prototype.__getAddressHistory = function(addresses, options, call
|
||||
|
||||
};
|
||||
|
||||
AddressService.prototype.getAddressHistory = function(addresses, options, streamer, callback) {
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
//options.from = options.from || 0; //Deprecated, use `after` and `before` option
|
||||
//options.to = options.to || 0xffffffff; //Deprecated, use `after` and `before` option
|
||||
|
||||
if(!_.isFunction(callback)){ //if only 3 args, then streamer is callback
|
||||
callback = streamer;
|
||||
streamer = () => null; //NULL fn
|
||||
}
|
||||
|
||||
if (_.isUndefined(options.queryMempool)) {
|
||||
options.queryMempool = true;
|
||||
}
|
||||
|
||||
if (_.isUndefined(options.mempoolOnly)) {
|
||||
options.mempoolOnly = false;
|
||||
}
|
||||
|
||||
if(_.isUndefined(options.reverse)) {
|
||||
options.reverse = false;
|
||||
}
|
||||
|
||||
var old_support = false;
|
||||
//Quick support for `from` and `to` options (DEPRECATED! Not recommeded to use)
|
||||
if(!_.isUndefined(options.from) || !_.isUndefined(options.to)) {
|
||||
old_support = true;
|
||||
options.from = options.from || 0;
|
||||
options.to = options.to || 0xffffffff; //Max value of to will actually be MAX_TX_QUERY_LIMIT_HISTORY
|
||||
}
|
||||
|
||||
if (_.isString(addresses)) {
|
||||
addresses = [addresses];
|
||||
}
|
||||
|
||||
var results = {
|
||||
totalCount: 0,
|
||||
items: [],
|
||||
}
|
||||
|
||||
async.eachLimit(addresses, 4, function(address, next) {
|
||||
|
||||
var addr_options = Object.assign({}, options), addr_count = 0;
|
||||
|
||||
self._streamAddressSummary(address, addr_options, function(err, tx){
|
||||
|
||||
if(err)
|
||||
return log.error(err);
|
||||
|
||||
addr_count++;
|
||||
|
||||
if(!results.items.some(x => x.txid() === tx.txid())) {//add only if tx not already in array
|
||||
if(!options.reverse)
|
||||
results.items.unshift(tx); //using unshift, so that recent tx (low) are at front
|
||||
else
|
||||
results.items.push(tx);
|
||||
}
|
||||
|
||||
|
||||
if(results.items.length > MAX_TX_QUERY_LIMIT_HISTORY) { //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 = results.items.length - MAX_TX_QUERY_LIMIT_HISTORY;
|
||||
let start_index = (old_support || options.reverse) ? MAX_TX_QUERY_LIMIT_HISTORY : 0;
|
||||
results.items.splice(start_index, del_count);
|
||||
|
||||
results.incomplete = true;
|
||||
|
||||
if(!old_support && addr_count >= MAX_TX_QUERY_LIMIT_HISTORY)
|
||||
addr_options.flag_stop = true; //limit has reached, stop quering db for more tx
|
||||
|
||||
}
|
||||
|
||||
streamer(null, tx);
|
||||
|
||||
}, next);
|
||||
|
||||
}, function(err) {
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
//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 = results.items.length ;
|
||||
|
||||
//Quick support for `from` and `to` options (DEPRECATED! Not recommeded to use)
|
||||
if(old_support) {
|
||||
results.items = results.items.slice(options.from, options.to);
|
||||
}
|
||||
|
||||
callback(null, results);
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
// this is basically the same as _getAddressHistory apart from the summary
|
||||
//(old one: non-optimized for large data)
|
||||
AddressService.prototype.__getAddressSummary = function(address, options, callback) {
|
||||
AddressService.prototype.getAddressSummary = function(address, options, callback) {
|
||||
|
||||
var self = this;
|
||||
|
||||
@ -300,7 +200,7 @@ AddressService.prototype.__getAddressSummary = function(address, options, callba
|
||||
txApperances: 0,
|
||||
};
|
||||
|
||||
self.__getAddressHistory(address, options, function(err, results) { //old fn
|
||||
self.getAddressHistory(address, options, function(err, results) {
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
@ -318,229 +218,6 @@ AddressService.prototype.__getAddressSummary = function(address, options, callba
|
||||
|
||||
};
|
||||
|
||||
AddressService.prototype.getAddressSummary = function(address, options, streamer, callback) {
|
||||
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
//options.from = options.from || 0; //Deprecated, use `after` and `before` option
|
||||
//options.to = options.to || 0xffffffff; //Deprecated, use `after` and `before` option
|
||||
|
||||
if (_.isUndefined(options.queryMempool)) {
|
||||
options.queryMempool = true;
|
||||
}
|
||||
|
||||
if(!_.isFunction(callback)){ //if only 3 args, then streamer is callback
|
||||
callback = streamer;
|
||||
streamer = () => null; //NULL fn
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
|
||||
var result = {
|
||||
addrStr: address,
|
||||
balance: 0,
|
||||
balanceSat: 0,
|
||||
totalReceived: 0,
|
||||
totalReceivedSat: 0,
|
||||
totalSent: 0,
|
||||
totalSentSat: 0,
|
||||
unconfirmedBalance: 0,
|
||||
unconfirmedBalanceSat: 0,
|
||||
unconfirmedTxApperances: 0,
|
||||
txApperances: 0,
|
||||
};
|
||||
|
||||
var useCache = _.isUndefined(options.after) && _.isUndefined(options.before);
|
||||
var lastTx, lastBlock;
|
||||
|
||||
self._loadCache(address, result, useCache, function(err, lastCachedTx) {
|
||||
if(err)
|
||||
log.error(err);
|
||||
|
||||
if(!_.isUndefined(lastCachedTx))
|
||||
options.after = lastCachedTx;
|
||||
|
||||
self._streamAddressSummary(address, options, function(err, tx) {
|
||||
|
||||
if(err)
|
||||
return log.error(err);
|
||||
|
||||
if(tx) {
|
||||
count++;
|
||||
self._aggregateAddressSummaryResult(tx, address, result, options);
|
||||
|
||||
if(tx.confirmations) {
|
||||
lastTx = tx.txid();
|
||||
lastBlock = tx.blockhash;
|
||||
}
|
||||
}
|
||||
|
||||
if(count >= MAX_TX_QUERY_LIMIT_SUMMARY) {//stop quering db when limit reached
|
||||
options.flag_stop = true;
|
||||
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();
|
||||
|
||||
result.lastItem = lastTx;
|
||||
|
||||
callback(null, result);
|
||||
|
||||
//store in cache if needed
|
||||
if(useCache) {
|
||||
if(result.incomplete) //full summary needs to be calculated in background
|
||||
self._cacheSummaryInBackground(address, lastTx, lastBlock, result);
|
||||
else if (!_.isUndefined(lastCachedTx) && !_.isUndefined(lastTx)
|
||||
&& lastTx != lastCachedTx && !self._cacheInstance.has(address)) //update cache if needed
|
||||
self._storeCache(address, lastTx, lastBlock, result);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
AddressService.prototype._cacheInstance = new Set();
|
||||
AddressService.prototype._cacheSummaryInBackground = function(address, lastTx, lastBlock, result){
|
||||
const self = this;
|
||||
|
||||
if(self._cacheInstance.has(address))
|
||||
return;
|
||||
|
||||
self._cacheInstance.add(address);
|
||||
|
||||
const cache = {
|
||||
balanceSat: result.balanceSat,
|
||||
totalReceivedSat: result.totalReceivedSat,
|
||||
totalSentSat: result.totalSentSat,
|
||||
txApperances: result.txApperances,
|
||||
unconfirmedBalanceSat: 0, //unconfirmed (mempool) values should not be cached
|
||||
unconfirmedTxApperances: 0
|
||||
};
|
||||
const options = { queryMempool: false, after: lastTx, noTxList: true };
|
||||
|
||||
self._streamAddressSummary(address, options, function(err, tx) {
|
||||
|
||||
if(err)
|
||||
return log.error(err);
|
||||
|
||||
if(tx) {
|
||||
self._aggregateAddressSummaryResult(tx, address, cache, options);
|
||||
if(tx.confirmations){
|
||||
lastTx = tx.txid();
|
||||
lastBlock = tx.blockhash;
|
||||
}
|
||||
}
|
||||
|
||||
}, function(err) {
|
||||
|
||||
if (err)
|
||||
return log.error(err);
|
||||
|
||||
cache.balanceSat = parseInt(cache.balanceSat.toFixed());
|
||||
cache.totalReceivedSat = parseInt(cache.totalReceivedSat.toFixed());
|
||||
cache.totalSentSat = parseInt(cache.totalSentSat.toFixed());
|
||||
cache.txApperances = parseInt(cache.txApperances.toFixed());
|
||||
|
||||
if(!_.isUndefined(lastTx))
|
||||
self._storeCache(address, lastTx, lastBlock, cache);
|
||||
|
||||
self._cacheInstance.delete(address); //remove from running instance
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
AddressService.prototype._storeCache = function(address, lastCacheTx, lastCacheBlock, result, callback) {
|
||||
const self = this;
|
||||
var key = self._encoding.encodeAddressCacheKey(address);
|
||||
var value = self._encoding.encodeAddressCacheValue(lastCacheTx, lastCacheBlock, result.balanceSat, result.totalReceivedSat, result.totalSentSat, result.txApperances)
|
||||
|
||||
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, callback) {
|
||||
const self = this;
|
||||
|
||||
if(!useCache) //skip if useCache is false (cases like 'after' and/or 'before' parameter is used by client)
|
||||
return callback();
|
||||
|
||||
var key = self._encoding.encodeAddressCacheKey(address);
|
||||
self._db.get(key, function(err, value) {
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
if (!value) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
var addressCache = self._encoding.decodeAddressCacheValue(value);
|
||||
|
||||
var lastCacheTx = addressCache.lastTx, lastCacheBlock = addressCache.lastBlock
|
||||
|
||||
self._block.getBlock(lastCacheBlock, function(err, block) {
|
||||
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!block) { //block not found, probably removed in reorg.
|
||||
//delete the existing cache and recalc values freshly
|
||||
self._deleteCache(address, function() {
|
||||
callback();
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
//values are in satoshis
|
||||
result.balanceSat = addressCache.balance;
|
||||
result.totalReceivedSat = addressCache.received;
|
||||
result.totalSentSat = addressCache.sent;
|
||||
result.txApperances = addressCache.txApperances;
|
||||
|
||||
callback(null, lastCacheTx);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
AddressService.prototype._deleteCache = function(address, callback) {
|
||||
const self = this;
|
||||
var key = self._encoding.encodeAddressCacheKey(address);
|
||||
|
||||
if(!_.isFunction(callback)) //if callback is not passed, call a empty function
|
||||
callback = () => null;
|
||||
|
||||
self._db.del(key, callback);
|
||||
|
||||
}
|
||||
|
||||
AddressService.prototype._setOutputResults = function(tx, address, result) {
|
||||
|
||||
for(var j = 0; j < tx.outputs.length; j++) {
|
||||
@ -588,6 +265,7 @@ AddressService.prototype._getAddressSummaryResult = function(txs, address, resul
|
||||
var self = this;
|
||||
|
||||
for(var i = 0; i < txs.length; i++) {
|
||||
|
||||
var tx = txs[i];
|
||||
|
||||
self._setOutputResults(tx, address, result);
|
||||
@ -605,110 +283,6 @@ AddressService.prototype._getAddressSummaryResult = function(txs, address, resul
|
||||
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;
|
||||
|
||||
let output_val = self._getOutputResults(tx, address);
|
||||
let input_val = self._getInputResults(tx, address);
|
||||
|
||||
//aggregate the result
|
||||
|
||||
if(tx.confirmations) {
|
||||
|
||||
result.txApperances++;
|
||||
|
||||
result.totalReceivedSat += output_val;
|
||||
result.balanceSat += output_val;
|
||||
|
||||
result.totalSentSat += input_val;
|
||||
result.balanceSat -= input_val;
|
||||
|
||||
} else {
|
||||
result.unconfirmedTxApperances++;
|
||||
result.unconfirmedBalanceSat += output_val;
|
||||
result.unconfirmedBalanceSat -= input_val;
|
||||
}
|
||||
|
||||
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_SUMMARY)
|
||||
result.transactions.pop(); //pop the oldest tx in list (when list limit is maxed out)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AddressService.prototype.getAddressUnspentOutputs = function(address, options, callback) {
|
||||
|
||||
var self = this;
|
||||
@ -791,11 +365,6 @@ AddressService.prototype.getAddressUnspentOutputs = function(address, options, c
|
||||
|
||||
utxoStream.on('data', function(data) {
|
||||
|
||||
if(results.length >= MAX_TX_QUERY_LIMIT_UTXO) { //Max array limit reached, end response
|
||||
utxoStream.emit('end');
|
||||
return;
|
||||
}
|
||||
|
||||
var key = self._encoding.decodeUtxoIndexKey(data.key);
|
||||
var value = self._encoding.decodeUtxoIndexValue(data.value);
|
||||
|
||||
@ -871,21 +440,19 @@ AddressService.prototype.stop = function(callback) {
|
||||
|
||||
AddressService.prototype._getTxidStream = function(address, options) {
|
||||
|
||||
var criteria = {};
|
||||
var start = this._encoding.encodeAddressIndexKey(address);
|
||||
var end = Buffer.concat([
|
||||
start.slice(0, address.length + 4),
|
||||
options.endHeightBuf,
|
||||
new Buffer(new Array(83).join('f'), 'hex')
|
||||
]);
|
||||
|
||||
var criteria = {
|
||||
gte: start,
|
||||
lte: end,
|
||||
reverse: true // txids stream from low confirmations to high confirmations
|
||||
};
|
||||
|
||||
if(options.after)
|
||||
criteria.gt = this._encoding.encodeAddressIndexKey(address, options.start, options.after, 0xffffffff, 1, 0xffffffff); //0xffffffff is for getting after the txid
|
||||
else
|
||||
criteria.gte = this._encoding.encodeAddressIndexKey(address, options.start);
|
||||
|
||||
if(options.before)
|
||||
criteria.lt = this._encoding.encodeAddressIndexKey(address, options.end, options.before); //get before the txid
|
||||
else
|
||||
criteria.lte = this._encoding.encodeAddressIndexKey(address, options.end, Array(65).join('f'), 0xffffffff, 1, 0xffffffff);
|
||||
|
||||
//reverse option can be used explictly when latest tx are required
|
||||
if(options.reverse)
|
||||
criteria.reverse = true;
|
||||
// txid stream
|
||||
var txidStream = this._db.createKeyStream(criteria);
|
||||
|
||||
@ -896,7 +463,6 @@ AddressService.prototype._getTxidStream = function(address, options) {
|
||||
return txidStream;
|
||||
};
|
||||
|
||||
//(used by old fn)
|
||||
AddressService.prototype._getAddressTxHistory = function(options, callback) {
|
||||
|
||||
var self = this;
|
||||
@ -925,7 +491,6 @@ AddressService.prototype._getAddressTxHistory = function(options, callback) {
|
||||
|
||||
};
|
||||
|
||||
//(used by old fn)
|
||||
AddressService.prototype._getAddressTxidHistory = function(address, options, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -935,6 +500,9 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
|
||||
|
||||
var results = [];
|
||||
|
||||
options.endHeightBuf = new Buffer(4);
|
||||
options.endHeightBuf.writeUInt32BE(options.end);
|
||||
|
||||
if (_.isUndefined(options.queryMempool)) {
|
||||
options.queryMempool = true;
|
||||
}
|
||||
@ -983,15 +551,7 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
|
||||
|
||||
txIdTransformStream._transform = function(chunk, enc, callback) {
|
||||
var txInfo = self._encoding.decodeAddressIndexKey(chunk);
|
||||
|
||||
if(results.length >= MAX_TX_QUERY_LIMIT_HISTORY) { //Max array limit reached, end response
|
||||
txIdTransformStream.emit('end');
|
||||
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();
|
||||
};
|
||||
|
||||
@ -1003,225 +563,6 @@ AddressService.prototype._getAddressTxidHistory = function(address, options, cal
|
||||
|
||||
};
|
||||
|
||||
AddressService.prototype._streamAddressSummary = function(address, options, streamer, callback) {
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
options.start = options.start || 0;
|
||||
options.end = options.end || 0xffffffff;
|
||||
|
||||
//options.from = options.from || 0; //Deprecated, use `after` and `before` option
|
||||
//options.to = options.to || 0xffffffff; //Deprecated, use `after` and `before` option
|
||||
|
||||
if (_.isUndefined(options.queryMempool)) {
|
||||
options.queryMempool = true;
|
||||
}
|
||||
|
||||
if (_.isUndefined(options.mempoolOnly)) {
|
||||
options.mempoolOnly = false;
|
||||
}
|
||||
|
||||
if (_.isUndefined(options.reverse)) {
|
||||
options.reverse = false;
|
||||
}
|
||||
|
||||
//declare the queue to process tx data
|
||||
var tmpTxList = {}; //store processed txid temporarily to ignore duplication
|
||||
|
||||
var q = async.queue(function(id, cb) {
|
||||
|
||||
//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) {
|
||||
|
||||
return self._mempool.getMempoolTransaction(id.txid, function(err, tx) {
|
||||
|
||||
if (err || !tx) {
|
||||
return cb(err || new Error('Address Service: could not find tx: ' + id.txid));
|
||||
}
|
||||
self._transaction.setTxMetaInfo(tx, options, cb);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
self._transaction.getDetailedTransaction(id.txid, options, cb);
|
||||
|
||||
}, 1);
|
||||
|
||||
//q.pause(); //pause and wait until queue is set (not needed)
|
||||
|
||||
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);
|
||||
|
||||
if((err || options.flag_stop) && !q.killed){
|
||||
|
||||
q.kill();
|
||||
q.killed = true;
|
||||
|
||||
return callback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const waterfall_array = [];
|
||||
|
||||
waterfall_array.push(
|
||||
//Find start height if `after` option is passed
|
||||
function parse_after_id(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();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
waterfall_array.push(
|
||||
//Find end height if `before` option is passed
|
||||
function parse_before_id(next){
|
||||
|
||||
if(_.isUndefined(options.before)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
self._transaction.getTransaction(options.before, options, function(err, tx) {
|
||||
|
||||
if(tx && tx.confirmations && tx.height <= options.end) {
|
||||
|
||||
options.end = tx.height;
|
||||
|
||||
} else {
|
||||
|
||||
delete options.before;
|
||||
|
||||
}
|
||||
|
||||
next();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// stream the confirmed txids out of the address index
|
||||
function query_confirmed_txids(next) {
|
||||
|
||||
if (options.mempoolOnly) { //Option to query from mempool only (ie, unconfirmed txs only)
|
||||
return 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
|
||||
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
|
||||
function query_mempool_txids(next) {
|
||||
|
||||
if (!options.queryMempool || !_.isUndefined(options.before)) { //if queryMempool=false or options.before is given a valid value, then do not query mempool
|
||||
return next();
|
||||
}
|
||||
|
||||
self._mempool.getTxidsByAddress(address, 'both', function(err, mempoolTxids) {
|
||||
|
||||
if (mempoolTxids.length <= 0) {
|
||||
return next();
|
||||
}
|
||||
|
||||
mempoolTxids.map(id => q.push(id, chunkCallback));
|
||||
next();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if(options.reverse){ //when queried txs in reverse key order, mempool first then confirmed
|
||||
waterfall_array.push(query_mempool_txids);
|
||||
waterfall_array.push(query_confirmed_txids);
|
||||
} else { //when queried tx in key order, confirmed tx 1st, then mempool
|
||||
waterfall_array.push(query_confirmed_txids);
|
||||
waterfall_array.push(query_mempool_txids);
|
||||
}
|
||||
|
||||
waterfall_array.push(
|
||||
//wait for queue to complete
|
||||
function end_fall(next) {
|
||||
|
||||
if(!q.started || q.idle()) //No tx in query (or) already finished querying
|
||||
return next();
|
||||
|
||||
else
|
||||
q.drain = () => next();
|
||||
|
||||
});
|
||||
|
||||
async.waterfall(waterfall_array, callback);
|
||||
|
||||
}
|
||||
|
||||
AddressService.prototype._removeBlock = function(block, callback) {
|
||||
|
||||
var self = this;
|
||||
@ -1289,7 +630,7 @@ AddressService.prototype._removeInput = function(input, tx, block, index, callba
|
||||
}
|
||||
|
||||
address.network = self._network;
|
||||
address = address.toString(self._network);
|
||||
address = address.toString();
|
||||
|
||||
assert(block && block.__ts && block.__height, 'Missing block or block values.');
|
||||
|
||||
@ -1333,7 +674,7 @@ AddressService.prototype._removeOutput = function(output, tx, block, index, call
|
||||
}
|
||||
|
||||
address.network = self._network;
|
||||
address = address.toString(self._network);
|
||||
address = address.toString();
|
||||
|
||||
assert(block && block.__ts && block.__height, 'Missing block or block values.');
|
||||
|
||||
@ -1402,7 +743,7 @@ AddressService.prototype._processInput = function(tx, input, index, opts) {
|
||||
}
|
||||
|
||||
address.network = this._network;
|
||||
address = address.toString(this._network);
|
||||
address = address.toString();
|
||||
|
||||
var txid = tx.txid();
|
||||
var timestamp = this._timestamp.getTimestampSync(opts.block.rhash());
|
||||
@ -1440,7 +781,7 @@ AddressService.prototype._processOutput = function(tx, output, index, opts) {
|
||||
}
|
||||
|
||||
address.network = this._network;
|
||||
address = address.toString(this._network);
|
||||
address = address.toString();
|
||||
|
||||
var txid = tx.txid();
|
||||
var timestamp = this._timestamp.getTimestampSync(opts.block.rhash());
|
||||
|
||||
@ -242,7 +242,7 @@ ProcessSerial.prototype._write = function(block, enc, callback) {
|
||||
|
||||
self.block.once('concurrentaddblock', function() {
|
||||
if(!check()) {
|
||||
var err = 'Concurrent block ' + self.block.concurrentTip.__height + ' is less than ' + block.__height;
|
||||
var err = new Error('Concurrent block ' + self.block.concurrentTip.__height + ' is less than ' + block.__height);
|
||||
return self.emit('error', err);
|
||||
}
|
||||
self._process(block, callback);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var Block = require('fcoin').Block;
|
||||
var Block = require('fcoin').block;
|
||||
// stores -- block header as key, block itself as value (optionally)
|
||||
|
||||
function Encoding(servicePrefix) {
|
||||
|
||||
@ -13,8 +13,6 @@ var bcoin = require('fcoin');
|
||||
var _ = require('lodash');
|
||||
var LRU = require('lru-cache');
|
||||
|
||||
const MAX_IGNORED_BLOCK = 16; //Maximum ignored block allowed before trigging sync again
|
||||
|
||||
var BlockService = function(options) {
|
||||
|
||||
BaseService.call(this, options);
|
||||
@ -233,8 +231,8 @@ BlockService.prototype._resetTip = function(callback) {
|
||||
self._header.getAllHeaders(function(err, headers) {
|
||||
|
||||
if (err || !headers) {
|
||||
log.error(err || 'headers required'); return callback(err);
|
||||
}
|
||||
return callback(err || new Error('headers required'));
|
||||
}
|
||||
|
||||
log.info('Block Service: retrieved all the headers for lookups.');
|
||||
|
||||
@ -254,18 +252,13 @@ BlockService.prototype._resetTip = function(callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!_block) {
|
||||
if (!_block) {
|
||||
log.debug('Block Service: block: ' + header.hash + ' was not found, proceeding to older blocks.');
|
||||
}
|
||||
}
|
||||
|
||||
block = _block;
|
||||
header = headers.getIndex(--height);
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (header == false) {
|
||||
log.error('Header not found for reset.');
|
||||
}
|
||||
// assert(header, 'Header not found for reset.');
|
||||
assert(header, 'Header not found for reset.');
|
||||
|
||||
if (!block) {
|
||||
log.debug('Block Service: trying block: ' + header.hash);
|
||||
@ -278,8 +271,8 @@ BlockService.prototype._resetTip = function(callback) {
|
||||
}, function(err) {
|
||||
|
||||
if (err || !block) {
|
||||
log.error(err ||
|
||||
'Block Service: none of the blocks from the headers match what is already indexed in the block service.'); return callback(err);
|
||||
return callback(err ||
|
||||
new Error('Block Service: none of the blocks from the headers match what is already indexed in the block service.'));
|
||||
}
|
||||
|
||||
self._setTip({ hash: block.rhash(), height: height + 1 }, callback);
|
||||
@ -377,8 +370,8 @@ BlockService.prototype._loadRecentBlockHashes = function(callback) {
|
||||
self.getBlock(hash, function(err, block) {
|
||||
|
||||
if (err || !block) {
|
||||
log.error(err || 'Block Service: attempted to retrieve block: ' + hash +
|
||||
' but was not in the index.'); return callback(err);
|
||||
return callback(err || new Error('Block Service: attempted to retrieve block: ' + hash +
|
||||
' but was not in the index.'));
|
||||
}
|
||||
|
||||
var prevHash = bcoin.util.revHex(block.prevBlock);
|
||||
@ -394,11 +387,7 @@ BlockService.prototype._loadRecentBlockHashes = function(callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (self._recentBlockHashes.length != times) {
|
||||
log.error('Block Service: did not load enough recent block hashes from the index.');
|
||||
}
|
||||
//assert(self._recentBlockHashes.length === times, 'Block Service: did not load enough recent block hashes from the index.');
|
||||
assert(self._recentBlockHashes.length === times, 'Block Service: did not load enough recent block hashes from the index.');
|
||||
log.info('Block Service: loaded: ' + self._recentBlockHashes.length + ' hashes from the index.');
|
||||
callback();
|
||||
|
||||
@ -417,7 +406,7 @@ BlockService.prototype._getTimeSinceLastBlock = function(callback) {
|
||||
self._header.getBlockHeader(Math.max(self._tip.height - 1, 0), function(err, header) {
|
||||
|
||||
if(err || !header) {
|
||||
log.error(err || 'Block Service: we should have a header in order to get time since last block.'); return callback(err);
|
||||
return callback(err || new Error('Block Service: we should have a header in order to get time since last block.'));
|
||||
}
|
||||
|
||||
async.map([ self._tip.hash, header.hash ], function(hash, next) {
|
||||
@ -639,7 +628,6 @@ BlockService.prototype._startBlockSubscription = function() {
|
||||
}
|
||||
|
||||
this._subscribedBlock = true;
|
||||
this._ignoredBlockCount = 0; //SZ: reset the ignored count to 0 when subscription starts
|
||||
|
||||
log.info('Block Service: starting p2p block subscription.');
|
||||
this._bus.on('p2p/block', this._queueBlock.bind(this));
|
||||
@ -668,7 +656,7 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
|
||||
if (self._reorgToBlock) {
|
||||
return self._header.getBlockHeader(self._reorgToBlock, function(err, header) {
|
||||
if (err || !header) {
|
||||
log.error(err || 'Block Service: header not found to reorg to.'); return callback(err);
|
||||
return callback(err || new Error('Block Service: header not found to reorg to.'));
|
||||
}
|
||||
callback(null, header);
|
||||
});
|
||||
@ -723,19 +711,12 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
|
||||
// any of our recent block hashes in its indexes.
|
||||
// if some joker mines a block using an orphan block as its prev block, then the effect of this will be
|
||||
// us detecting a reorg, but not actually reorging anything
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (!_.isUndefined(header)) {
|
||||
if (header == false) {
|
||||
log.error('Block Service: we could not locate any of our recent block hashes in the header service ' + 'index. Perhaps our header service sync\'ed to the wrong chain?');
|
||||
}
|
||||
}
|
||||
// assert(header, 'Block Service: we could not locate any of our recent block hashes in the header service ' + 'index. Perhaps our header service sync\'ed to the wrong chain?');
|
||||
if (!_.isUndefined(header.height)) {
|
||||
if (header.height > self._tip.height) {
|
||||
log.error('Block Service: we found a common ancestor header whose ' + 'height was greater than our current tip. This should be impossible.');
|
||||
}
|
||||
// assert(header.height <= self._tip.height, 'Block Service: we found a common ancestor header whose ' + 'height was greater than our current tip. This should be impossible.');
|
||||
}
|
||||
assert(header, 'Block Service: we could not locate any of our recent block hashes in the header service ' +
|
||||
'index. Perhaps our header service sync\'ed to the wrong chain?');
|
||||
|
||||
assert(header.height <= self._tip.height, 'Block Service: we found a common ancestor header whose ' +
|
||||
'height was greater than our current tip. This should be impossible.');
|
||||
|
||||
callback(null, header);
|
||||
|
||||
});
|
||||
@ -758,13 +739,13 @@ BlockService.prototype._findBlocksToRemove = function(commonHeader, callback) {
|
||||
self._getBlock(hash, function(err, block) {
|
||||
|
||||
if (err || !block) {
|
||||
return next(err || 'Block Service: block not found in index.');
|
||||
return next(err || new Error('Block Service: block not found in index.'));
|
||||
}
|
||||
|
||||
self._timestamp.getTimestamp(block.rhash(), function(err, timestamp) {
|
||||
|
||||
if (err || !timestamp) {
|
||||
log.error(err || 'timestamp missing from reorg.'); return callback(err);
|
||||
return callback(err || new Error('timestamp missing from reorg.'));
|
||||
}
|
||||
|
||||
block.__height = height;
|
||||
@ -834,10 +815,8 @@ BlockService.prototype._handleReorg = function(callback) {
|
||||
|
||||
blocksToRemove = _blocksToRemove;
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (blocksToRemove.length < 1 || blocksToRemove.length > self._recentBlockHashes.length) {
|
||||
log.error('Block Service: the number of blocks to remove looks to be incorrect.'); }
|
||||
// assert(blocksToRemove.length >= 1 && blocksToRemove.length <= self._recentBlockHashes.length, 'Block Service: the number of blocks to remove looks to be incorrect.');
|
||||
assert(blocksToRemove.length >= 1 && blocksToRemove.length <= self._recentBlockHashes.length,
|
||||
'Block Service: the number of blocks to remove looks to be incorrect.');
|
||||
|
||||
log.warn('Block Service: chain reorganization detected, current height/hash: ' + self._tip.height + '/' +
|
||||
self._tip.hash + ' common ancestor hash: ' + commonAncestorHeader.hash + ' at height: ' + commonAncestorHeader.height +
|
||||
@ -941,15 +920,6 @@ BlockService.prototype._processBlock = function(block, callback) {
|
||||
return self._saveBlock(block, callback);
|
||||
}
|
||||
|
||||
//SZ: count the ignored blocks. if many blocks ignored, trigger sync process
|
||||
if(self._ignoredBlockCount < MAX_IGNORED_BLOCK)
|
||||
self._ignoredBlockCount++;
|
||||
else {
|
||||
self._ignoredBlockCount = 0;
|
||||
self._removeAllSubscriptions();
|
||||
self._startSync();
|
||||
}
|
||||
|
||||
// reorg -- in this case, we will not handle the reorg right away
|
||||
// instead, we will skip the block and wait for the eventual call to
|
||||
// "onHeaders" function. When the header service calls this function,
|
||||
@ -965,7 +935,6 @@ BlockService.prototype._saveBlock = function(block, callback) {
|
||||
|
||||
var self = this;
|
||||
block.__height = self._tip.height + 1;
|
||||
self._ignoredBlockCount = 0; //SZ: a block is saved, reset the ignored count
|
||||
|
||||
var services = self.node.services;
|
||||
|
||||
@ -1013,9 +982,7 @@ BlockService.prototype._saveBlock = function(block, callback) {
|
||||
BlockService.prototype._handleError = function(err) {
|
||||
if (!this.node.stopping) {
|
||||
log.error('Block Service: handle error ' + err);
|
||||
//FLO Crash Error Resolution by RanchiMall 10th May 2021
|
||||
//return this.node.stop();
|
||||
return;
|
||||
return this.node.stop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1110,7 +1077,7 @@ BlockService.prototype._startSync = function() {
|
||||
this.on('next block', this._sync.bind(this));
|
||||
this.on('synced', this._onSynced.bind(this));
|
||||
clearInterval(this._reportInterval);
|
||||
this._reportInterval = setInterval(this._logProgress.bind(this), 5000);
|
||||
this._reportingInterval = setInterval(this._logProgress.bind(this), 5000);
|
||||
return this._sync();
|
||||
}
|
||||
|
||||
|
||||
@ -315,7 +315,7 @@ Reorg.prototype.findCommonAncestorAndNewHashes = function(oldTipHash, newTipHash
|
||||
}
|
||||
|
||||
if(!mainPosition && !forkPosition) {
|
||||
return next('Unknown common ancestor');
|
||||
return next(new Error('Unknown common ancestor'));
|
||||
}
|
||||
|
||||
next();
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
var _ = require('lodash');
|
||||
var levelup = require('levelup');
|
||||
var leveldown = require('leveldown');
|
||||
var mkdirp = require('mkdirp');
|
||||
@ -50,8 +49,7 @@ DB.dependencies = [];
|
||||
DB.prototype._onError = function(err) {
|
||||
if (!this._stopping) {
|
||||
log.error('Db Service: error: ' + err);
|
||||
//FLO Crash Error Resolution by RanchiMall 10th May 2021
|
||||
//this.node.stop();
|
||||
this.node.stop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -96,7 +94,7 @@ DB.prototype.get = function(key, options, callback) {
|
||||
var cb = callback;
|
||||
var opts = options;
|
||||
|
||||
if (!_.isFunction(callback)) {
|
||||
if (typeof callback !== 'function') {
|
||||
cb = options;
|
||||
opts = {};
|
||||
}
|
||||
@ -119,9 +117,7 @@ DB.prototype.get = function(key, options, callback) {
|
||||
|
||||
} else {
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 20th May 2021.
|
||||
//cb(new Error('Shutdown sequence underway, not able to complete the query'));
|
||||
log.error('Shutdown sequence underway, not able to complete the query');
|
||||
cb(new Error('Shutdown sequence underway, not able to complete the query'));
|
||||
}
|
||||
|
||||
};
|
||||
@ -132,40 +128,17 @@ DB.prototype.put = function(key, value, callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (Buffer.isBuffer(key) == false) {
|
||||
log.error('key NOT a buffer as expected.');
|
||||
}
|
||||
// assert(Buffer.isBuffer(key), 'key NOT a buffer as expected.');
|
||||
assert(Buffer.isBuffer(key), 'key NOT a buffer as expected.');
|
||||
|
||||
if (value) {
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (Buffer.isBuffer(value) == false) {
|
||||
log.error('value exists but NOT a buffer as expected.');
|
||||
}
|
||||
//assert(Buffer.isBuffer(value), 'value exists but NOT a buffer as expected.');
|
||||
|
||||
assert(Buffer.isBuffer(value), 'value exists but NOT a buffer as expected.');
|
||||
|
||||
}
|
||||
|
||||
this._store.put(key, value, callback);
|
||||
};
|
||||
|
||||
DB.prototype.del = function(key, callback) {
|
||||
|
||||
if (this._stopping) {
|
||||
callback();
|
||||
}
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (Buffer.isBuffer(key) == false) {
|
||||
log.error('key NOT a buffer as expected.');
|
||||
}
|
||||
// assert(Buffer.isBuffer(key), 'key NOT a buffer as expected.');
|
||||
|
||||
this._store.del(key, callback);
|
||||
}
|
||||
|
||||
DB.prototype.batch = function(ops, callback) {
|
||||
|
||||
if (this._stopping) {
|
||||
@ -174,18 +147,11 @@ DB.prototype.batch = function(ops, callback) {
|
||||
|
||||
for(var i = 0; i < ops.length; i++) {
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (Buffer.isBuffer(ops[i].key) == false) {
|
||||
log.error('key NOT a buffer as expected.');
|
||||
}
|
||||
//assert(Buffer.isBuffer(ops[i].key), 'key NOT a buffer as expected.');
|
||||
assert(Buffer.isBuffer(ops[i].key), 'key NOT a buffer as expected.');
|
||||
|
||||
if (ops[i].value) {
|
||||
// FLOSight Error Correction from RanchiMall 20th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (Buffer.isBuffer(ops[i].value) == false) {
|
||||
log.error('value exists but NOT a buffer as expected.');
|
||||
}
|
||||
//assert(Buffer.isBuffer(ops[i].value), 'value exists but NOT a buffer as expected.');
|
||||
|
||||
assert(Buffer.isBuffer(ops[i].value), 'value exists but NOT a buffer as expected.');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,15 +7,12 @@ var index = require('../../');
|
||||
var log = index.log;
|
||||
var utils = require('../../utils');
|
||||
var async = require('async');
|
||||
// var BN = require('bn.js');
|
||||
var BN = require('bcrypto/lib/bn.js')
|
||||
var BN = require('bn.js');
|
||||
var consensus = require('fcoin').consensus;
|
||||
var assert = require('assert');
|
||||
var constants = require('../../constants');
|
||||
var bcoin = require('fcoin');
|
||||
|
||||
const SYNC_CHECK_INTERVAL = 1000 * 60 * 15; //15 mins
|
||||
|
||||
var HeaderService = function(options) {
|
||||
|
||||
BaseService.call(this, options);
|
||||
@ -147,11 +144,7 @@ HeaderService.prototype._adjustTipBackToCheckpoint = function() {
|
||||
|
||||
HeaderService.prototype._setGenesisBlock = function(callback) {
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (this._tip.hash != this.GENESIS_HASH) {
|
||||
log.error('Expected tip hash to be genesis hash, but it was not.');
|
||||
}
|
||||
// assert(this._tip.hash === this.GENESIS_HASH, 'Expected tip hash to be genesis hash, but it was not.');
|
||||
assert(this._tip.hash === this.GENESIS_HASH, 'Expected tip hash to be genesis hash, but it was not.');
|
||||
|
||||
var genesisHeader = {
|
||||
hash: this.GENESIS_HASH,
|
||||
@ -418,10 +411,7 @@ HeaderService.prototype._getDBOpForLastHeader = function(nextHeader) {
|
||||
this._lastHeader.nextHash = nextHeader.hash;
|
||||
var keyHash = this._encoding.encodeHeaderHashKey(this._lastHeader.hash);
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (this._lastHeader.height < 0) { log.error('Trying to save a header with incorrect height.');
|
||||
}
|
||||
// assert(this._lastHeader.height >= 0, 'Trying to save a header with incorrect height.');
|
||||
assert(this._lastHeader.height >= 0, 'Trying to save a header with incorrect height.');
|
||||
|
||||
var keyHeight = this._encoding.encodeHeaderHeightKey(this._lastHeader.height);
|
||||
var value = this._encoding.encodeHeaderValue(this._lastHeader);
|
||||
@ -475,12 +465,9 @@ HeaderService.prototype._onHeaders = function(headers) {
|
||||
for(var i = 0; i < transformedHeaders.length; i++) {
|
||||
|
||||
var header = transformedHeaders[i];
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (self._lastHeader.hash != header.prevHash) {
|
||||
log.error('headers not in order: ' + self._lastHeader.hash + ' -and- ' + header.prevHash + ' Last header at height: ' + self._lastHeader.height);
|
||||
}
|
||||
// assert(self._lastHeader.hash === header.prevHash, 'headers not in order: ' + self._lastHeader.hash + ' -and- ' + header.prevHash + ' Last header at height: ' + self._lastHeader.height);
|
||||
|
||||
assert(self._lastHeader.hash === header.prevHash, 'headers not in order: ' + self._lastHeader.hash +
|
||||
' -and- ' + header.prevHash + ' Last header at height: ' + self._lastHeader.height);
|
||||
|
||||
var ops = self._onHeader(header);
|
||||
|
||||
@ -497,9 +484,8 @@ HeaderService.prototype._onHeaders = function(headers) {
|
||||
};
|
||||
|
||||
HeaderService.prototype._handleError = function(err) {
|
||||
log.error('Error in Header Service: ' + err);
|
||||
return;
|
||||
//this.node.stop();
|
||||
log.error('Header Service: ' + err);
|
||||
this.node.stop();
|
||||
};
|
||||
|
||||
HeaderService.prototype._saveHeaders = function(dbOps, callback) {
|
||||
@ -524,7 +510,6 @@ HeaderService.prototype._saveHeaders = function(dbOps, callback) {
|
||||
HeaderService.prototype._onHeadersSave = function(callback) {
|
||||
var self = this;
|
||||
|
||||
self._syncUnresponsive = false; //SZ: got response from peer
|
||||
self._logProgress();
|
||||
|
||||
if (!self._syncComplete()) {
|
||||
@ -532,12 +517,6 @@ HeaderService.prototype._onHeadersSave = function(callback) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
//SZ: clear the interval check as sync is completed
|
||||
if(self._syncCheckInterval){
|
||||
clearInterval(self._syncCheckInterval);
|
||||
self._syncCheckInterval = null;
|
||||
}
|
||||
|
||||
self._endHeaderSubscription(); // we don't need headers any more
|
||||
self._startBlockSubscription(); // we need new blocks coming tu us aynchronuously
|
||||
|
||||
@ -594,15 +573,12 @@ HeaderService.prototype._startBlockSubscription = function() {
|
||||
};
|
||||
|
||||
HeaderService.prototype._syncComplete = function() {
|
||||
// Check if we have reached the last block that we can download.
|
||||
var bestHeight = Math.max(this._bestHeight, this._lastHeader.height);
|
||||
|
||||
var syncComplete = bestHeight === this._tip.height
|
||||
// we always ask for the max number of headers, which is 2000.
|
||||
// so any response with < 2000 means we have reached the end of the headers list.
|
||||
// we could make an extra call if the number of total headers is multiple of 2000.
|
||||
return this._lastHeaderCount < 2000;
|
||||
|
||||
if (syncComplete && this._initialSync)
|
||||
log.info("Header Service: Sync Complete!")
|
||||
|
||||
return syncComplete
|
||||
};
|
||||
|
||||
HeaderService.prototype._setBestHeader = function() {
|
||||
@ -617,7 +593,7 @@ HeaderService.prototype._getHeader = function(height, hash, callback) {
|
||||
/*jshint -W018 */
|
||||
if (!hash && !(height >= 0)) {
|
||||
/*jshint +W018 */
|
||||
return callback('invalid arguments');
|
||||
return callback(new Error('invalid arguments'));
|
||||
}
|
||||
|
||||
if (height === self._lastHeader.height || hash === self._lastHeader.hash) {
|
||||
@ -716,23 +692,6 @@ HeaderService.prototype._startSync = function() {
|
||||
// common case
|
||||
if (numNeeded > 0) {
|
||||
log.info('Header Service: Gathering: ' + numNeeded + ' ' + 'header(s) from the peer-to-peer network.');
|
||||
|
||||
//SZ: Adding interval check for sync with peer is responsive or not
|
||||
//(only if fcoin is started by flocore)
|
||||
if(self._p2p._bcoin){
|
||||
self._syncUnresponsive = true;
|
||||
self._syncCheckInterval = setInterval(() => {
|
||||
//check the best height
|
||||
if(self._bestHeight < self._p2p._bcoin._bcoin.pool.chain.height)
|
||||
self._bestHeight = self._p2p._bcoin._bcoin.pool.chain.height;
|
||||
//call sync again if unresponsive
|
||||
if(self._syncUnresponsive)
|
||||
self._sync();
|
||||
else //reset unresponsive as true
|
||||
self._syncUnresponsive = true;
|
||||
}, SYNC_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
return self._sync();
|
||||
}
|
||||
|
||||
@ -814,11 +773,9 @@ HeaderService.prototype._findReorgConditionInNewPeer = function(callback) {
|
||||
|
||||
// nothing matched...
|
||||
// at this point, we should wonder if we are connected to the wrong network
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (false) {
|
||||
log.error('We tried to find a common header between current set of headers ' + 'and the new peer\'s set of headers, but there were none. This should be impossible ' + ' if the new peer is using the same genesis block.');
|
||||
}
|
||||
// assert(true, 'We tried to find a common header between current set of headers ' +'and the new peer\'s set of headers, but there were none. This should be impossible ' +' if the new peer is using the same genesis block.');
|
||||
assert(true, 'We tried to find a common header between current set of headers ' +
|
||||
'and the new peer\'s set of headers, but there were none. This should be impossible ' +
|
||||
' if the new peer is using the same genesis block.');
|
||||
});
|
||||
|
||||
self._getP2PHeaders(self.GENESIS_HASH);
|
||||
@ -919,11 +876,7 @@ HeaderService.prototype._sync = function() {
|
||||
|
||||
HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (blockCount < 1) {
|
||||
log.error('Header Service: block count to getEndHash must be at least 1.');
|
||||
}
|
||||
// assert(blockCount >= 1, 'Header Service: block count to getEndHash must be at least 1.');
|
||||
assert(blockCount >= 1, 'Header Service: block count to getEndHash must be at least 1.');
|
||||
|
||||
var self = this;
|
||||
|
||||
@ -934,7 +887,7 @@ HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
|
||||
}
|
||||
|
||||
if (numResultsNeeded <= 0) {
|
||||
return callback('Header Service: block service is mis-aligned ');
|
||||
return callback(new Error('Header Service: block service is mis-aligned '));
|
||||
}
|
||||
|
||||
var startingHeight = tip.height + 1;
|
||||
@ -964,11 +917,8 @@ HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
|
||||
if (streamErr) {
|
||||
return streamErr;
|
||||
}
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (results.length != numResultsNeeded) {
|
||||
log.error('getEndHash returned incorrect number of results.');
|
||||
}
|
||||
// assert(results.length === numResultsNeeded, 'getEndHash returned incorrect number of results.');
|
||||
|
||||
assert(results.length === numResultsNeeded, 'getEndHash returned incorrect number of results.');
|
||||
|
||||
var index = numResultsNeeded - 1;
|
||||
var endHash = index <= 0 || !results[index] ? 0 : results[index];
|
||||
@ -986,11 +936,7 @@ HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
|
||||
};
|
||||
|
||||
HeaderService.prototype.getLastHeader = function() {
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (this._lastHeader == false) {
|
||||
log.error('Last header should be populated.'); return;
|
||||
}
|
||||
// assert(this._lastHeader, 'Last header should be populated.');
|
||||
assert(this._lastHeader, 'Last header should be populated.');
|
||||
return this._lastHeader;
|
||||
};
|
||||
|
||||
@ -1003,7 +949,7 @@ HeaderService.prototype._adjustHeadersForCheckPointTip = function(callback) {
|
||||
var start = self._encoding.encodeHeaderHeightKey(self._tip.height);
|
||||
var end = self._encoding.encodeHeaderHeightKey(0xffffffff);
|
||||
|
||||
log.info('Header Service: Getting last header synced at height: ' + self._tip.height);
|
||||
log.info('Getting last header synced at height: ' + self._tip.height);
|
||||
|
||||
var criteria = {
|
||||
gte: start,
|
||||
@ -1023,7 +969,6 @@ HeaderService.prototype._adjustHeadersForCheckPointTip = function(callback) {
|
||||
// any records with a height greater than our current tip height can be scheduled for removal
|
||||
// because they will be replaced shortly
|
||||
// and for every height record, we must also remove its hash record
|
||||
|
||||
if (header.height > self._tip.height) {
|
||||
removalOps.push({
|
||||
type: 'del',
|
||||
@ -1047,14 +992,8 @@ HeaderService.prototype._adjustHeadersForCheckPointTip = function(callback) {
|
||||
if (streamErr) {
|
||||
return streamErr;
|
||||
}
|
||||
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (self._lastHeader == false) {
|
||||
log.error('The last synced header was not in the database.');
|
||||
}
|
||||
//assert(self._lastHeader, 'The last synced header was not in the database.');
|
||||
|
||||
assert(self._lastHeader, 'The last synced header was not in the database.');
|
||||
self._tip.hash = self._lastHeader.hash;
|
||||
self._tip.height = self._lastHeader.height;
|
||||
self._db.batch(removalOps, callback);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var tx = require('fcoin').TX;
|
||||
var tx = require('fcoin').tx;
|
||||
|
||||
function Encoding(servicePrefix) {
|
||||
this.servicePrefix = servicePrefix;
|
||||
|
||||
@ -247,7 +247,7 @@ MempoolService.prototype._onTransaction = function(tx) {
|
||||
self._db.batch(ops, function(err) {
|
||||
if(err) {
|
||||
log.error(err);
|
||||
// self.node.stop();
|
||||
self.node.stop();
|
||||
}
|
||||
|
||||
for (var i = 0; i < self._subscriptions.transaction.length; i++) {
|
||||
|
||||
@ -3,50 +3,46 @@
|
||||
var index = require('../../');
|
||||
var log = index.log;
|
||||
var bcoin = require('fcoin');
|
||||
// var bzmq = require('bzmq');
|
||||
|
||||
var Bcoin = function(options) {
|
||||
this._config = this._getConfig(options);
|
||||
};
|
||||
|
||||
Bcoin.prototype.start = function(callback) {
|
||||
this._bcoin = new bcoin.FullNode(this._config);
|
||||
var self = this;
|
||||
self._bcoin = bcoin.fullnode(self._config);
|
||||
|
||||
log.info('Starting fcoin FullNode...');
|
||||
log.info('Starting Fcoin full node...');
|
||||
|
||||
this._bcoin.open().then(() => {
|
||||
this._bcoin.connect().then(() => {
|
||||
this._bcoin.startSync();
|
||||
self._bcoin.open().then(function() {
|
||||
self._bcoin.connect().then(function() {
|
||||
log.info('Waiting for Fcoin to sync');
|
||||
self._bcoin.startSync();
|
||||
// this will instruct the p2p service to start trying to connect to bcoin right away
|
||||
callback();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Bcoin.prototype.stop = function(callback) {
|
||||
this._bcoin.close().then(() => {
|
||||
log.info("fcoin shutdown")
|
||||
callback()
|
||||
});
|
||||
Bcoin.prototype.stop = function() {
|
||||
this._bcoin.stopSync();
|
||||
this._bcoin.disconnect();
|
||||
this._bcoin.close();
|
||||
};
|
||||
|
||||
// --- privates
|
||||
|
||||
Bcoin.prototype._getConfig = function(options) {
|
||||
var config = {
|
||||
db: 'leveldb',
|
||||
checkpoints: true,
|
||||
network: options.network || 'main',
|
||||
port: options.port,
|
||||
|
||||
logFile: true,
|
||||
listen: true,
|
||||
logConsole: true,
|
||||
logLevel: 'info',
|
||||
|
||||
// indexTx: true,
|
||||
// indexAddress: true,
|
||||
|
||||
checkpoints: true,
|
||||
memory: false,
|
||||
workers: true,
|
||||
listen: true
|
||||
port: options.port,
|
||||
persistent: true,
|
||||
workers: true
|
||||
};
|
||||
if (options.prefix) {
|
||||
config.prefix = options.prefix;
|
||||
|
||||
@ -8,8 +8,7 @@ var log = index.log;
|
||||
var BaseService = require('../../service');
|
||||
var assert = require('assert');
|
||||
var Bcoin = require('./bcoin');
|
||||
var BcoinBlock = require('fcoin').Block;
|
||||
var BcoinTx = require('fcoin').TX;
|
||||
var BcoinTx = require('fcoin').tx;
|
||||
var Networks = require('flocore-lib').Networks;
|
||||
var BitcoreRPC = require('bitcoind-rpc');
|
||||
var LRU = require('lru-cache');
|
||||
@ -90,7 +89,7 @@ P2P.prototype.getP2PBlock = function(opts, callback) {
|
||||
|
||||
self.once(opts.blockHash, callback);
|
||||
|
||||
peer.sendMessage(self.messages.GetBlocks(blockFilter, { Block: BcoinBlock }));
|
||||
peer.sendMessage(self.messages.GetBlocks(blockFilter));
|
||||
};
|
||||
|
||||
P2P.prototype.getHeaders = function(filter) {
|
||||
@ -254,10 +253,10 @@ P2P.prototype._initCache = function() {
|
||||
};
|
||||
|
||||
P2P.prototype._initRPC = function (options) {
|
||||
var port = 7313
|
||||
var port = 7312
|
||||
|
||||
if (this.node.network === 'testnet')
|
||||
port = 17313
|
||||
port = 17312
|
||||
|
||||
this._config = options.rpc || {
|
||||
user: 'flocore',
|
||||
@ -278,7 +277,7 @@ P2P.prototype._initP2P = function() {
|
||||
if (this.node.network === 'regtest') {
|
||||
Networks.enableRegtest();
|
||||
}
|
||||
this.messages = new p2p.Messages({ network: Networks.get(this.node.network), Transaction: BcoinTx, Block: BcoinBlock });
|
||||
this.messages = new p2p.Messages({ network: Networks.get(this.node.network), Transaction: BcoinTx });
|
||||
this._peerHeights = [];
|
||||
this._peers = [];
|
||||
this._peerIndex = 0;
|
||||
@ -364,8 +363,7 @@ P2P.prototype._matchNetwork = function(network) {
|
||||
log.error('Configured network: "' + this.node.network +
|
||||
'" does not match our peer\'s reported network: "' +
|
||||
network.name + '".');
|
||||
// return this.node.stop();
|
||||
return ;
|
||||
return this.node.stop();
|
||||
}
|
||||
|
||||
return this.node.network === network.name ? network.name : network.alias;
|
||||
@ -425,12 +423,7 @@ P2P.prototype._setListeners = function() {
|
||||
|
||||
P2P.prototype._setResourceFilter = function(filter) {
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (filter == false || filter.startHash == false) {
|
||||
log.error('A "startHash" field is required to retrieve headers or blocks');
|
||||
}
|
||||
// assert(filter && filter.startHash, 'A "startHash" field is required to retrieve headers or blocks');
|
||||
|
||||
assert(filter && filter.startHash, 'A "startHash" field is required to retrieve headers or blocks');
|
||||
if (!filter.endHash) {
|
||||
filter.endHash = 0;
|
||||
}
|
||||
@ -439,6 +432,9 @@ P2P.prototype._setResourceFilter = function(filter) {
|
||||
};
|
||||
|
||||
P2P.prototype._startBcoin = function(callback) {
|
||||
|
||||
var self = this;
|
||||
|
||||
var network;
|
||||
var port;
|
||||
if (['livenet', 'live', 'main', 'mainnet'].indexOf(this.node.network) !== -1) {
|
||||
@ -449,16 +445,16 @@ P2P.prototype._startBcoin = function(callback) {
|
||||
port = this._configPeers[0].port || 17312;
|
||||
} else {
|
||||
network = this.node.network;
|
||||
port = this._configPeers[0].port || 17412;
|
||||
port = this._configPeers[0].port || 48444;
|
||||
}
|
||||
|
||||
this._bcoin = new Bcoin({
|
||||
self._bcoin = new Bcoin({
|
||||
network: network,
|
||||
prefix: this.node.datadir,
|
||||
prefix: self.node.datadir,
|
||||
port: port
|
||||
});
|
||||
|
||||
this._bcoin.start(callback);
|
||||
self._bcoin.start(callback);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var Tx = require('fcoin').TX;
|
||||
var Tx = require('fcoin').tx;
|
||||
|
||||
function Encoding(servicePrefix) {
|
||||
this.servicePrefix = servicePrefix;
|
||||
|
||||
@ -7,7 +7,6 @@ var _ = require('lodash');
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var LRU = require('lru-cache');
|
||||
var log = require('../../index').log;
|
||||
|
||||
function TransactionService(options) {
|
||||
BaseService.call(this, options);
|
||||
@ -114,7 +113,7 @@ TransactionService.prototype.getTransaction = function(txid, options, callback)
|
||||
|
||||
var self = this;
|
||||
|
||||
if (!_.isFunction(callback)) {
|
||||
if (typeof callback !== 'function') {
|
||||
callback = options;
|
||||
}
|
||||
|
||||
@ -185,11 +184,8 @@ TransactionService.prototype.setTxMetaInfo = function(tx, options, callback) {
|
||||
|
||||
var inputSatoshis = 0;
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (tx.__inputValues.length != tx.inputs.length) {
|
||||
log.error('Transaction Service: input values length is not the same as the number of inputs.');
|
||||
}
|
||||
// assert(tx.__inputValues.length === tx.inputs.length, 'Transaction Service: input values length is not the same as the number of inputs.');
|
||||
assert(tx.__inputValues.length === tx.inputs.length,
|
||||
'Transaction Service: input values length is not the same as the number of inputs.');
|
||||
|
||||
tx.__inputValues.forEach(function(val) {
|
||||
|
||||
@ -312,18 +308,13 @@ TransactionService.prototype._getInputValues = function(tx, options, callback) {
|
||||
// if not in mempool or tx index, we just don't have it, yet?
|
||||
function(txid, tx, next) {
|
||||
if (!tx) {
|
||||
return next(log.error('Transaction Service: prev transacion: (' + input.prevout.txid() + ') for tx: ' +
|
||||
return next(new Error('Transaction Service: prev transacion: (' + input.prevout.txid() + ') for tx: ' +
|
||||
_tx.txid() + ' at input index: ' + outputIndex + ' is missing from the index or not in the memory pool. It could be' +
|
||||
' that the parent tx has not yet been relayed to us, but will be relayed in the near future.'));
|
||||
}
|
||||
|
||||
var output = tx.outputs[outputIndex];
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (output == false) {
|
||||
log.error('Expected an output, but did not get one for tx: ' + tx.txid() + ' outputIndex: ' + outputIndex);
|
||||
}
|
||||
// assert(output, 'Expected an output, but did not get one for tx: ' + tx.txid() + ' outputIndex: ' + outputIndex);
|
||||
assert(output, 'Expected an output, but did not get one for tx: ' + tx.txid() + ' outputIndex: ' + outputIndex);
|
||||
|
||||
next(null, output.value);
|
||||
}
|
||||
@ -383,11 +374,7 @@ TransactionService.prototype.onBlock = function(block, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (block.txs.length != operations.length) {
|
||||
log.error('It seems we are not indexing the correct number of transactions.');
|
||||
}
|
||||
// assert(block.txs.length === operations.length, 'It seems we are not indexing the correct number of transactions.');
|
||||
assert(block.txs.length === operations.length, 'It seems we are not indexing the correct number of transactions.');
|
||||
|
||||
callback(null, _.flattenDeep(operations));
|
||||
});
|
||||
@ -489,30 +476,19 @@ TransactionService.prototype._processTransaction = function(tx, opts, callback)
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (inputValues == false || inputValues.length != tx.inputs.length) {
|
||||
log.error('Input values missing from tx.');
|
||||
}
|
||||
// assert(inputValues && inputValues.length === tx.inputs.length, 'Input values missing from tx.');
|
||||
assert(inputValues && inputValues.length === tx.inputs.length,
|
||||
'Input values missing from tx.');
|
||||
|
||||
// inputValues
|
||||
tx.__inputValues = inputValues;
|
||||
|
||||
// timestamp
|
||||
tx.__timestamp = self._getBlockTimestamp(opts.block.rhash());
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (tx.__timestamp == false) {
|
||||
log.error('Timestamp is required when saving a transaction.');
|
||||
}
|
||||
// assert(tx.__timestamp, 'Timestamp is required when saving a transaction.');
|
||||
assert(tx.__timestamp, 'Timestamp is required when saving a transaction.');
|
||||
|
||||
// height
|
||||
tx.__height = opts.block.__height;
|
||||
// FLOSight Error Correction from RanchiMall 17th May 2021. removed the unhandled assert and replaced by looging of error
|
||||
if (tx.__height == false) {
|
||||
log.error('Block height is required when saving a trasnaction.');
|
||||
}
|
||||
//assert(tx.__height, 'Block height is required when saving a trasnaction.');
|
||||
assert(tx.__height, 'Block height is required when saving a trasnaction.');
|
||||
|
||||
// block hash
|
||||
tx.__blockhash = opts.block.rhash();
|
||||
|
||||
@ -4,7 +4,6 @@ var fs = require('fs');
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
var express = require('express');
|
||||
var express_ws = require('express-ws');
|
||||
var bodyParser = require('body-parser');
|
||||
var socketio = require('socket.io');
|
||||
var inherits = require('util').inherits;
|
||||
@ -106,7 +105,7 @@ WebService.prototype.setupAllRoutes = function() {
|
||||
|
||||
if(service.getRoutePrefix && service.setupRoutes) {
|
||||
this.app.use('/' + this.node.services[key].getRoutePrefix(), subApp);
|
||||
this.node.services[key].setupRoutes(subApp, express, express_ws);
|
||||
this.node.services[key].setupRoutes(subApp, express);
|
||||
} else {
|
||||
log.debug('No routes defined for: ' + key);
|
||||
}
|
||||
|
||||
@ -175,7 +175,7 @@ utils.getAddress = function(item, network) {
|
||||
return;
|
||||
}
|
||||
address.network = network;
|
||||
return address.toString(network);
|
||||
return address.toString();
|
||||
};
|
||||
|
||||
module.exports = utils;
|
||||
|
||||
4540
package-lock.json
generated
4540
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
@ -5,12 +5,12 @@
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"author": "BitPay <dev@bitpay.com>",
|
||||
"version": "5.0.9-beta-rm",
|
||||
"version": "5.0.0-beta.69",
|
||||
"main": "./index.js",
|
||||
"repository": "git://github.com/ranchimall/flocore-node.git",
|
||||
"homepage": "https://github.com/ranchimall/flocore-node",
|
||||
"repository": "git://github.com/oipwg/flocore-node.git",
|
||||
"homepage": "https://github.com/oipwg/flocore-node",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ranchimall/flocore-node/issues"
|
||||
"url": "https://github.com/oipwg/flocore-node/issues"
|
||||
},
|
||||
"bin": {
|
||||
"flocore-node": "./bin/flocore-node"
|
||||
@ -36,19 +36,18 @@
|
||||
"commander": "^2.8.1",
|
||||
"errno": "^0.1.4",
|
||||
"express": "^4.13.3",
|
||||
"express-ws": "^5.0.2",
|
||||
"fcoin": "^1.1.4",
|
||||
"flocore-lib": "^0.15.2",
|
||||
"flocore-message": "^1.0.7",
|
||||
"flocore-p2p": "^5.0.0-beta.8",
|
||||
"fcoin": "1.0.0-beta.20",
|
||||
"flocore-lib": "0.15.1",
|
||||
"flocore-p2p": "5.0.0-beta.6",
|
||||
"florincoind-rpc": "0.7.1",
|
||||
"flosight-api": "github:ranchimall/flosight-api",
|
||||
"flosight-ui": "github:ranchimall/flosight-ui",
|
||||
"flosight-api": "^5.0.0-beta.68",
|
||||
"flosight-ui": "^5.0.0-beta.72",
|
||||
"leveldown": "^2.0.0",
|
||||
"levelup": "^2.0.0",
|
||||
"liftoff": "^2.2.0",
|
||||
"lodash": "^4.17.12",
|
||||
"lodash": "^4.17.4",
|
||||
"lru-cache": "^4.1.1",
|
||||
"memwatch-next": "^0.3.0",
|
||||
"mkdirp": "0.5.0",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"socket.io": "^1.4.5",
|
||||
@ -61,7 +60,7 @@
|
||||
"istanbul": "^0.4.3",
|
||||
"jshint": "^2.9.2",
|
||||
"jshint-stylish": "^2.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"mocha": "3.2.0",
|
||||
"proxyquire": "^1.3.1",
|
||||
"rimraf": "^2.4.2",
|
||||
"sinon": "^1.15.4"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user