more cleanup.
This commit is contained in:
parent
8d98abd080
commit
d4238225d4
@ -59,7 +59,7 @@ Logger.prototype.warn = function() {
|
|||||||
*/
|
*/
|
||||||
Logger.prototype._log = function(color) {
|
Logger.prototype._log = function(color) {
|
||||||
if (!this.permitWrites) {
|
if (!this.permitWrites) {
|
||||||
return;
|
//return;
|
||||||
}
|
}
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
args = args.slice(1);
|
args = args.slice(1);
|
||||||
|
|||||||
@ -389,24 +389,6 @@ Bitcoin.prototype.start = function(callback) {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin.prototype._getAddressDetailsForOutput = function(output, outputIndex, result, addressStrings) {
|
|
||||||
if (!output.address) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var address = output.address;
|
|
||||||
if (addressStrings.indexOf(address) >= 0) {
|
|
||||||
if (!result.addresses[address]) {
|
|
||||||
result.addresses[address] = {
|
|
||||||
inputIndexes: [],
|
|
||||||
outputIndexes: [outputIndex]
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
result.addresses[address].outputIndexes.push(outputIndex);
|
|
||||||
}
|
|
||||||
result.satoshis += output.satoshis;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Bitcoin.prototype._maybeGetBlockHash = function(blockArg, callback) {
|
Bitcoin.prototype._maybeGetBlockHash = function(blockArg, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (_.isNumber(blockArg) || (blockArg.length < 40 && /^[0-9]+$/.test(blockArg))) {
|
if (_.isNumber(blockArg) || (blockArg.length < 40 && /^[0-9]+$/.test(blockArg))) {
|
||||||
@ -432,6 +414,7 @@ Bitcoin.prototype.getRawBlock = function(blockArg, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
self._tryAllClients(function(client, done) {
|
self._tryAllClients(function(client, done) {
|
||||||
|
|
||||||
self.client.getBlock(blockhash, false, function(err, response) {
|
self.client.getBlock(blockhash, false, function(err, response) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(self._wrapRPCError(err));
|
return done(self._wrapRPCError(err));
|
||||||
|
|||||||
@ -168,11 +168,9 @@ DB.prototype.start = function(callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.node.once('ready', function() {
|
this.node.once('ready', function() {
|
||||||
// start syncing
|
|
||||||
log.permitWrites = false;
|
log.permitWrites = false;
|
||||||
self._sync.initialSync();
|
self._sync.initialSync();
|
||||||
|
|
||||||
// Notify that there is a new tip
|
|
||||||
self.node.services.bitcoind.on('tip', function() {
|
self.node.services.bitcoind.on('tip', function() {
|
||||||
self._sync.sync();
|
self._sync.sync();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -18,7 +18,6 @@ function BlockStream(highWaterMark, bitcoind, lastHeight) {
|
|||||||
this.stopping = false;
|
this.stopping = false;
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
this.processing = false;
|
this.processing = false;
|
||||||
this.latestHeightRetrieved = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inherits(BlockStream, Readable);
|
inherits(BlockStream, Readable);
|
||||||
@ -33,11 +32,10 @@ function ProcessConcurrent(highWaterMark, db) {
|
|||||||
|
|
||||||
inherits(ProcessConcurrent, Transform);
|
inherits(ProcessConcurrent, Transform);
|
||||||
|
|
||||||
function ProcessSerial(highWaterMark, db, tip, progressBar) {
|
function ProcessSerial(highWaterMark, db, tip) {
|
||||||
Writable.call(this, {objectMode: true, highWaterMark: highWaterMark});
|
Writable.call(this, {objectMode: true, highWaterMark: highWaterMark});
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.tip = tip;
|
this.tip = tip;
|
||||||
this.progressBar = progressBar;
|
|
||||||
this.processBlockStartTime = [];
|
this.processBlockStartTime = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +68,6 @@ function Sync(node, db) {
|
|||||||
|
|
||||||
inherits(Sync, EventEmitter);
|
inherits(Sync, EventEmitter);
|
||||||
|
|
||||||
// Use a concurrent strategy to sync
|
|
||||||
Sync.prototype.initialSync = function() {
|
Sync.prototype.initialSync = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
@ -78,33 +75,12 @@ Sync.prototype.initialSync = function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lastReportedBlock = self.db.tip.__height;
|
|
||||||
self.progressBar = new ProgressBar('[:bar] :percent :current blks, :blockspersec blks/sec, :elapsed secs', {
|
|
||||||
complete: green,
|
|
||||||
incomplete: red,
|
|
||||||
total: self.node.services.bitcoind.height,
|
|
||||||
clear: true
|
|
||||||
});
|
|
||||||
|
|
||||||
self.progressBar.tick(self.db.tip.__height, {
|
|
||||||
blockspersec: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
var timer = setInterval(function () {
|
|
||||||
var tick = self.db.tip.__height - self.lastReportedBlock;
|
|
||||||
self.progressBar.tick(tick, { blockspersec: tick });
|
|
||||||
self.lastReportedBlock = self.db.tip.__height;
|
|
||||||
if (self.progressBar.complete) {
|
|
||||||
clearInterval(timer);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
self.syncing = true;
|
self.syncing = true;
|
||||||
|
|
||||||
self.blockStream = new BlockStream(self.highWaterMark, self.node.services.bitcoind, self.db.tip.__height);
|
self.blockStream = new BlockStream(self.highWaterMark, self.node.services.bitcoind, self.db.tip.__height);
|
||||||
var processConcurrent = new ProcessConcurrent(self.highWaterMark, self.db);
|
var processConcurrent = new ProcessConcurrent(self.highWaterMark, self.db);
|
||||||
var writeStream = new WriteStream(self.highWaterMark, self.db);
|
var writeStream = new WriteStream(self.highWaterMark, self.db);
|
||||||
var processSerial = new ProcessSerial(self.highWaterMark, self.db, self.db.tip, self.progressBar);
|
var processSerial = new ProcessSerial(self.highWaterMark, self.db, self.db.tip);
|
||||||
|
|
||||||
self._handleErrors(self.blockStream);
|
self._handleErrors(self.blockStream);
|
||||||
self._handleErrors(processConcurrent);
|
self._handleErrors(processConcurrent);
|
||||||
@ -122,11 +98,34 @@ Sync.prototype.initialSync = function() {
|
|||||||
|
|
||||||
self.blockStream
|
self.blockStream
|
||||||
.pipe(processSerial);
|
.pipe(processSerial);
|
||||||
|
|
||||||
|
self.lastReportedBlock = self.db.tip.__height;
|
||||||
|
self.progressBar = new ProgressBar('[:bar] :percent :current blks, :blockspersec blks/sec, :elapsed secs', {
|
||||||
|
complete: green,
|
||||||
|
incomplete: red,
|
||||||
|
total: self.node.services.bitcoind.height,
|
||||||
|
clear: true
|
||||||
|
});
|
||||||
|
|
||||||
|
self.progressBar.tick(self.db.tip.__height, {
|
||||||
|
blockspersec: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
var timer = setInterval(function () {
|
||||||
|
var tick = self.db.tip.__height - self.lastReportedBlock;
|
||||||
|
|
||||||
|
self.progressBar.tick(tick, { blockspersec: tick });
|
||||||
|
|
||||||
|
self.lastReportedBlock = self.db.tip.__height;
|
||||||
|
|
||||||
|
if (!self.syncing) {
|
||||||
|
self.progressBar.terminate();
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get concurrent and serial block operations and write them together block by block
|
|
||||||
// Useful for when we are fully synced and we want to advance the concurrentTip and
|
|
||||||
// the tip together
|
|
||||||
Sync.prototype.sync = function() {
|
Sync.prototype.sync = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
if(this.syncing || this.db.reorg) {
|
if(this.syncing || this.db.reorg) {
|
||||||
@ -140,7 +139,6 @@ Sync.prototype.sync = function() {
|
|||||||
this._handleErrors(this.blockStream);
|
this._handleErrors(this.blockStream);
|
||||||
this._handleErrors(processBoth);
|
this._handleErrors(processBoth);
|
||||||
|
|
||||||
//TODO what should happen here
|
|
||||||
processBoth.on('finish', function() {
|
processBoth.on('finish', function() {
|
||||||
self.syncing = false;
|
self.syncing = false;
|
||||||
});
|
});
|
||||||
@ -166,7 +164,6 @@ Sync.prototype._handleErrors = function(stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(err.reorg2) {
|
if(err.reorg2) {
|
||||||
// squelch this error
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +181,9 @@ BlockStream.prototype._read = function() {
|
|||||||
BlockStream.prototype._process = function() {
|
BlockStream.prototype._process = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// TODO push null when we've fully synced
|
if (!self.syncing) {
|
||||||
|
return self.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.processing) {
|
if(this.processing) {
|
||||||
return;
|
return;
|
||||||
@ -206,8 +205,6 @@ BlockStream.prototype._process = function() {
|
|||||||
block.__height = height;
|
block.__height = height;
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
// we're getting blocks from bitcoind too fast?
|
|
||||||
// it pauses at 8100
|
|
||||||
next(null, block);
|
next(null, block);
|
||||||
}, 1);
|
}, 1);
|
||||||
});
|
});
|
||||||
@ -218,6 +215,11 @@ BlockStream.prototype._process = function() {
|
|||||||
|
|
||||||
for(var i = 0; i < blocks.length; i++) {
|
for(var i = 0; i < blocks.length; i++) {
|
||||||
self.push(blocks[i]);
|
self.push(blocks[i]);
|
||||||
|
if (blocks[i].hash === self.bitcoind.tip) {
|
||||||
|
self.syncing = false;
|
||||||
|
self.emit('synced');
|
||||||
|
break;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
@ -234,7 +236,6 @@ BlockStream.prototype._process = function() {
|
|||||||
|
|
||||||
ProcessSerial.prototype._write = function(block, enc, callback) {
|
ProcessSerial.prototype._write = function(block, enc, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.processBlockStartTime = process.hrtime();
|
|
||||||
|
|
||||||
function check() {
|
function check() {
|
||||||
return self.db.concurrentTip.__height >= block.__height;
|
return self.db.concurrentTip.__height >= block.__height;
|
||||||
@ -347,9 +348,7 @@ WriteStream.prototype._write = function(obj, enc, callback) {
|
|||||||
|
|
||||||
self.db.concurrentTip = obj.concurrentTip;
|
self.db.concurrentTip = obj.concurrentTip;
|
||||||
self.db.emit('concurrentaddblock');
|
self.db.emit('concurrentaddblock');
|
||||||
//if(self.db.concurrentTip.__height - self.lastConcurrentOutputHeight >= 100) {
|
self.lastConcurrentOutputHeight = self.db.concurrentTip.__height;
|
||||||
self.lastConcurrentOutputHeight = self.db.concurrentTip.__height;
|
|
||||||
//}
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -390,7 +389,6 @@ ProcessBoth.prototype._write = function(block, encoding, callback) {
|
|||||||
}
|
}
|
||||||
self.db.tip = block;
|
self.db.tip = block;
|
||||||
self.db.concurrentTip = block;
|
self.db.concurrentTip = block;
|
||||||
console.log('Tip:', self.db.tip.__height);
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,23 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
|
||||||
* The UntrustedMempool Service builds upon the Database Service. It is also an adjunct to the
|
|
||||||
* Transaction Service's memory pool to provide block explorers the chance to report on
|
|
||||||
* transactions that are bouncing around bitcoin's peer network, but are not necessarily going
|
|
||||||
* to be validated into your trusted node's memory pool or even sent over the zmq socket.
|
|
||||||
* The strategy is to permanently save txs in the database that are unlikely to ever make it
|
|
||||||
* into a block. The reason for this is so the block explorer can have a historical record of these
|
|
||||||
* transactions. There is also an LRU cache that contains all of the transactions from the pool,
|
|
||||||
* regardless of validation status. When a block comes in, we can prune out the transactions that
|
|
||||||
* exist in the block because we know the transaction service has already indexed them.
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {Node} options.node - An instance of the node
|
|
||||||
* @param {String} options.name - An optional name of the service
|
|
||||||
* @param {Integer} options.maxPeers - An optional number of maximum peers to connect to
|
|
||||||
* @param {Array} options.peers - A list of ip addresses to explicitly connect to (this disables use of seeds)
|
|
||||||
* @param {Integer} options.maxMempoolSize - Maximum size of the mempool in this service
|
|
||||||
*/
|
|
||||||
|
|
||||||
var p2p = require('bitcore-p2p');
|
var p2p = require('bitcore-p2p');
|
||||||
var messages = new p2p.Messages();
|
var messages = new p2p.Messages();
|
||||||
var LRU = require('lru-cache');
|
var LRU = require('lru-cache');
|
||||||
@ -28,9 +10,9 @@ var index = require('../');
|
|||||||
var log = index.log;
|
var log = index.log;
|
||||||
var Service = require('../../service');
|
var Service = require('../../service');
|
||||||
|
|
||||||
var UntrustedMempool = function(options) {
|
var P2P = function(options) {
|
||||||
if (!(this instanceof UntrustedMempool)) {
|
if (!(this instanceof P2P)) {
|
||||||
return new UntrustedMempool(options);
|
return new P2P(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
Service.call(this, options);
|
Service.call(this, options);
|
||||||
@ -39,13 +21,17 @@ var UntrustedMempool = function(options) {
|
|||||||
this._peers = this.options.peers;
|
this._peers = this.options.peers;
|
||||||
this._maxMempoolSize = this.options.maxMempoolSize || 100 * 1024 * 1024;
|
this._maxMempoolSize = this.options.maxMempoolSize || 100 * 1024 * 1024;
|
||||||
this._synced = false;
|
this._synced = false;
|
||||||
|
this.initialHeight = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
util.inherits(UntrustedMempool, Service);
|
util.inherits(P2P, Service);
|
||||||
|
|
||||||
UntrustedMempool.dependencies = [ 'bitcoind', 'db' ];
|
P2P.dependencies = [ 'bitcoind', 'db' ];
|
||||||
|
|
||||||
UntrustedMempool.prototype.start = function(callback) {
|
P2P.prototype.start = function(callback) {
|
||||||
|
//Step 1: connect to peer(s) as per config
|
||||||
|
//Step 2: memoize the tip
|
||||||
|
//Step 3: wait for other services to register listeners
|
||||||
var self = this;
|
var self = this;
|
||||||
self.once('synced', function() {
|
self.once('synced', function() {
|
||||||
self._initPrefix(callback);
|
self._initPrefix(callback);
|
||||||
@ -56,7 +42,7 @@ UntrustedMempool.prototype.start = function(callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype.stop = function(callback) {
|
P2P.prototype.stop = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
self._pool.disconnect();
|
self._pool.disconnect();
|
||||||
@ -64,7 +50,7 @@ UntrustedMempool.prototype.stop = function(callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype._initPrefix = function(callback) {
|
P2P.prototype._initPrefix = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.node.services.db.getPrefix(self.name, function(err, prefix) {
|
self.node.services.db.getPrefix(self.name, function(err, prefix) {
|
||||||
if(err) {
|
if(err) {
|
||||||
@ -75,7 +61,7 @@ UntrustedMempool.prototype._initPrefix = function(callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype._initCache = function() {
|
P2P.prototype._initCache = function() {
|
||||||
this._inv = LRU(2000);
|
this._inv = LRU(2000);
|
||||||
this._cache = LRU({
|
this._cache = LRU({
|
||||||
max: this._maxMempoolSize,
|
max: this._maxMempoolSize,
|
||||||
@ -83,7 +69,7 @@ UntrustedMempool.prototype._initCache = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype._initPool = function() {
|
P2P.prototype._initPool = function() {
|
||||||
var opts = {};
|
var opts = {};
|
||||||
var _addrs = [];
|
var _addrs = [];
|
||||||
if (this.addrs && _.isArray(this.addrs)) {
|
if (this.addrs && _.isArray(this.addrs)) {
|
||||||
@ -103,11 +89,11 @@ UntrustedMempool.prototype._initPool = function() {
|
|||||||
this._setupListeners();
|
this._setupListeners();
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype.validTx = function(tx) {
|
P2P.prototype.validTx = function(tx) {
|
||||||
return tx;
|
return tx;
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype._setupListeners = function() {
|
P2P.prototype._setupListeners = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self._pool.on('peerready', function(peer, addr) {
|
self._pool.on('peerready', function(peer, addr) {
|
||||||
@ -144,15 +130,15 @@ UntrustedMempool.prototype._setupListeners = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype.getAPIMethods = function() {
|
P2P.prototype.getAPIMethods = function() {
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype.getPublishEvents = function() {
|
P2P.prototype.getPublishEvents = function() {
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
UntrustedMempool.prototype.blockHandler = function(block, connected, callback) {
|
P2P.prototype.blockHandler = function(block, connected, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var operations = [];
|
var operations = [];
|
||||||
@ -173,4 +159,4 @@ UntrustedMempool.prototype.blockHandler = function(block, connected, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = UntrustedMempool;
|
module.exports = P2P;
|
||||||
40
lib/services/p2p/testp2p.js
Normal file
40
lib/services/p2p/testp2p.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var p2p = require('bitcore-p2p');
|
||||||
|
var messages = new p2p.Messages();
|
||||||
|
var opts = {};
|
||||||
|
opts.addrs = [ { ip: { v4: '192.168.3.5' } } ];
|
||||||
|
opts.dnsSeed = false;
|
||||||
|
opts.maxPeers = 1;
|
||||||
|
opts.network = 'livenet';
|
||||||
|
var pool = new p2p.Pool(opts);
|
||||||
|
|
||||||
|
pool.on('peerready', function(peer, addr) {
|
||||||
|
console.log('Connected to peer: ' + addr.ip.v4);
|
||||||
|
peer.sendMessage(messages.MemPool());
|
||||||
|
});
|
||||||
|
|
||||||
|
pool.on('peerdisconnect', function(peer, addr) {
|
||||||
|
console.log('Disconnected from peer: ' + addr.ip.v4);
|
||||||
|
});
|
||||||
|
|
||||||
|
pool.on('peerinv', function(peer, message) {
|
||||||
|
var invList = [];
|
||||||
|
message.inventory.forEach(function(inv) {
|
||||||
|
invList.push(inv);
|
||||||
|
});
|
||||||
|
peer.sendMessage(messages.GetData(invList));
|
||||||
|
});
|
||||||
|
|
||||||
|
pool.on('peertx', function(peer, message) {
|
||||||
|
var tx = new bitcore.Transaction(message.transaction);
|
||||||
|
if (self.validTx(tx)) {
|
||||||
|
return self._cache.set(tx.id, tx);
|
||||||
|
}
|
||||||
|
return self._operations.push({
|
||||||
|
type: 'put',
|
||||||
|
key: new Buffer(tx.id),
|
||||||
|
value: tx.toBuffer()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user