new chaindb. allow for real fork resolution.
This commit is contained in:
parent
6de9e54667
commit
04c5f94997
1651
lib/bcoin/chain.js
1651
lib/bcoin/chain.js
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,7 @@ var fs = bcoin.fs;
|
|||||||
* ChainBlock
|
* ChainBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ChainBlock(chain, data) {
|
function ChainBlock(chain, data, prev) {
|
||||||
if (!(this instanceof ChainBlock))
|
if (!(this instanceof ChainBlock))
|
||||||
return new ChainBlock(chain, data);
|
return new ChainBlock(chain, data);
|
||||||
|
|
||||||
@ -31,18 +31,14 @@ function ChainBlock(chain, data) {
|
|||||||
this.bits = data.bits;
|
this.bits = data.bits;
|
||||||
this.nonce = data.nonce;
|
this.nonce = data.nonce;
|
||||||
this.height = data.height;
|
this.height = data.height;
|
||||||
this.chainwork = data.chainwork || this.getChainwork();
|
this.chainwork = data.chainwork || this.getChainwork(prev);
|
||||||
|
|
||||||
|
assert(this.chainwork);
|
||||||
|
|
||||||
|
this.previous = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
ChainBlock.BLOCK_SIZE = 112;
|
ChainBlock.BLOCK_SIZE = 116;
|
||||||
|
|
||||||
ChainBlock.prototype.__defineGetter__('prev', function() {
|
|
||||||
return this.chain.db.getSync(this.height - 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
ChainBlock.prototype.__defineGetter__('next', function() {
|
|
||||||
return this.chain.db.getSync(this.height + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
ChainBlock.prototype.getProof = function getProof() {
|
ChainBlock.prototype.getProof = function getProof() {
|
||||||
var target = utils.fromCompact(this.bits);
|
var target = utils.fromCompact(this.bits);
|
||||||
@ -51,16 +47,12 @@ ChainBlock.prototype.getProof = function getProof() {
|
|||||||
return new bn(1).ushln(256).div(target.addn(1));
|
return new bn(1).ushln(256).div(target.addn(1));
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.getChainwork = function getChainwork() {
|
ChainBlock.prototype.getChainwork = function getChainwork(prev) {
|
||||||
var prev;
|
|
||||||
|
|
||||||
// Workaround for genesis block
|
// Workaround for genesis block
|
||||||
// being added _in_ chaindb.
|
// being added _in_ chaindb.
|
||||||
if (!this.chain.db)
|
if (!this.chain.db)
|
||||||
return this.getProof();
|
return this.getProof();
|
||||||
|
|
||||||
prev = this.prev;
|
|
||||||
|
|
||||||
return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
|
return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,43 +60,6 @@ ChainBlock.prototype.isGenesis = function isGenesis() {
|
|||||||
return this.hash === network.genesis.hash;
|
return this.hash === network.genesis.hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.getMedianTime = function getMedianTime() {
|
|
||||||
var entry = this;
|
|
||||||
var median = [];
|
|
||||||
var timeSpan = constants.block.medianTimespan;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
for (i = 0; i < timeSpan && entry; i++, entry = entry.prev)
|
|
||||||
median.push(entry.ts);
|
|
||||||
|
|
||||||
median = median.sort();
|
|
||||||
|
|
||||||
return median[median.length / 2 | 0];
|
|
||||||
};
|
|
||||||
|
|
||||||
ChainBlock.prototype.isOutdated = function isOutdated(version) {
|
|
||||||
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
|
|
||||||
};
|
|
||||||
|
|
||||||
ChainBlock.prototype.isUpgraded = function isUpgraded(version) {
|
|
||||||
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
|
|
||||||
};
|
|
||||||
|
|
||||||
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required) {
|
|
||||||
var entry = this;
|
|
||||||
var found = 0;
|
|
||||||
var majorityWindow = network.block.majorityWindow;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
for (i = 0; i < majorityWindow && found < required && entry; i++) {
|
|
||||||
if (entry.version >= version)
|
|
||||||
found++;
|
|
||||||
entry = entry.prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found >= required;
|
|
||||||
};
|
|
||||||
|
|
||||||
ChainBlock.prototype.toJSON = function toJSON() {
|
ChainBlock.prototype.toJSON = function toJSON() {
|
||||||
return {
|
return {
|
||||||
hash: this.hash,
|
hash: this.hash,
|
||||||
@ -131,14 +86,14 @@ ChainBlock.prototype.toRaw = function toRaw() {
|
|||||||
utils.writeU32(res, this.ts, 68);
|
utils.writeU32(res, this.ts, 68);
|
||||||
utils.writeU32(res, this.bits, 72);
|
utils.writeU32(res, this.bits, 72);
|
||||||
utils.writeU32(res, this.nonce, 76);
|
utils.writeU32(res, this.nonce, 76);
|
||||||
utils.copy(new Buffer(this.chainwork.toArray('be', 32)), res, 80);
|
utils.writeU32(res, this.height, 80);
|
||||||
|
utils.copy(new Buffer(this.chainwork.toArray('be', 32)), res, 84);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
ChainBlock.fromRaw = function fromRaw(chain, height, p) {
|
ChainBlock.fromRaw = function fromRaw(chain, p) {
|
||||||
return new ChainBlock(chain, {
|
return new ChainBlock(chain, {
|
||||||
height: height,
|
|
||||||
hash: utils.toHex(utils.dsha256(p.slice(0, 80))),
|
hash: utils.toHex(utils.dsha256(p.slice(0, 80))),
|
||||||
version: utils.read32(p, 0),
|
version: utils.read32(p, 0),
|
||||||
prevBlock: utils.toHex(p.slice(4, 36)),
|
prevBlock: utils.toHex(p.slice(4, 36)),
|
||||||
@ -146,10 +101,153 @@ ChainBlock.fromRaw = function fromRaw(chain, height, p) {
|
|||||||
ts: utils.readU32(p, 68),
|
ts: utils.readU32(p, 68),
|
||||||
bits: utils.readU32(p, 72),
|
bits: utils.readU32(p, 72),
|
||||||
nonce: utils.readU32(p, 76),
|
nonce: utils.readU32(p, 76),
|
||||||
chainwork: new bn(p.slice(80, 112), 'be')
|
height: utils.readU32(p, 80),
|
||||||
|
chainwork: new bn(p.slice(84, 116), 'be')
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.getMedianTimeAsync = function getMedianTime(callback) {
|
||||||
|
var self = this;
|
||||||
|
var median = [];
|
||||||
|
var timeSpan = constants.block.medianTimespan;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
(function next(err, entry) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
if (!entry || i >= timeSpan) {
|
||||||
|
median = median.sort();
|
||||||
|
return callback(null, median[median.length / 2 | 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
median[i] = entry.ts;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
self.chain.db.get(entry.prevBlock, next);
|
||||||
|
})(null, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isOutdatedAsync = function isOutdated(version, callback) {
|
||||||
|
return this.isSuperMajority(version, network.block.majorityRejectOutdated, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isUpgradedAsync = function isUpgraded(version, callback) {
|
||||||
|
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isSuperMajorityAsync = function isSuperMajority(version, required, callback) {
|
||||||
|
var self = this;
|
||||||
|
var found = 0;
|
||||||
|
var majorityWindow = network.block.majorityWindow;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
(function next(err, entry) {
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
if (!entry || i >= majorityWindow || found >= required)
|
||||||
|
return callback(null, found >= required);
|
||||||
|
|
||||||
|
if (entry.version >= version)
|
||||||
|
found++;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
self.chain.db.get(entry.prevBlock, next);
|
||||||
|
})(null, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.alloc = function alloc(callback) {
|
||||||
|
var majorityWindow = network.block.majorityWindow;
|
||||||
|
var medianTimespan = constants.block.medianTimespan;
|
||||||
|
var powDiffInterval = network.powDiffInterval;
|
||||||
|
var allowMinDiff = network.powAllowMinDifficultyBlocks;
|
||||||
|
var max = Math.max(majorityWindow, medianTimespan);
|
||||||
|
if ((this.height + 1) % powDiffInterval === 0 || allowMinDiff)
|
||||||
|
max = Math.max(max, powDiffInterval);
|
||||||
|
return this._alloc(max, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype._alloc = function _alloc(max, callback) {
|
||||||
|
var self = this;
|
||||||
|
var entry = this;
|
||||||
|
|
||||||
|
assert(this.previous.length === 0);
|
||||||
|
|
||||||
|
// Try to do this iteratively and synchronously
|
||||||
|
// so we don't have to wait on nextTicks.
|
||||||
|
for (;;) {
|
||||||
|
this.previous.push(entry);
|
||||||
|
|
||||||
|
if (this.previous.length >= max)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
if (!this.chain.db.cacheHash.has(entry.prevBlock))
|
||||||
|
break;
|
||||||
|
|
||||||
|
entry = this.chain.db.cacheHash.get(entry.prevBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
(function next(err, entry) {
|
||||||
|
if (err) {
|
||||||
|
self.free();
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
self.previous.push(entry);
|
||||||
|
|
||||||
|
if (self.previous.length >= max)
|
||||||
|
return callback();
|
||||||
|
|
||||||
|
self.chain.db.get(entry.prevBlock, next);
|
||||||
|
})(null, entry);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.free = function free() {
|
||||||
|
this.previous.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.getMedianTime = function getMedianTime() {
|
||||||
|
var entry = this;
|
||||||
|
var median = [];
|
||||||
|
var timeSpan = constants.block.medianTimespan;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < timeSpan && entry; i++, entry = this.previous[i])
|
||||||
|
median.push(entry.ts);
|
||||||
|
|
||||||
|
median = median.sort();
|
||||||
|
|
||||||
|
return median[median.length / 2 | 0];
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isOutdated = function isOutdated(version) {
|
||||||
|
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isUpgraded = function isUpgraded(version) {
|
||||||
|
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required) {
|
||||||
|
var entry = this;
|
||||||
|
var found = 0;
|
||||||
|
var majorityWindow = network.block.majorityWindow;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < majorityWindow && found < required && entry; i++) {
|
||||||
|
if (entry.version >= version)
|
||||||
|
found++;
|
||||||
|
entry = this.previous[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return found >= required;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -37,8 +37,11 @@ CompactBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
|
|||||||
return this.coinbaseHeight;
|
return this.coinbaseHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
CompactBlock.prototype.toBlock = function toBlock(peer) {
|
CompactBlock.prototype.toBlock = function toBlock() {
|
||||||
return new bcoin.block(bcoin.protocol.parser.parseBlock(this._raw));
|
var block = new bcoin.block(bcoin.protocol.parser.parseBlock(this._raw));
|
||||||
|
if (this.valid != null)
|
||||||
|
block.valid = this.valid;
|
||||||
|
return block;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -81,6 +81,23 @@ LRU.prototype._compact = function _compact() {
|
|||||||
item.prev = null;
|
item.prev = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LRU.prototype.reset = function reset() {
|
||||||
|
var item, next;
|
||||||
|
|
||||||
|
for (item = this.head; item; item = next) {
|
||||||
|
delete this.data[item.key];
|
||||||
|
next = item.next;
|
||||||
|
item.prev = null;
|
||||||
|
item.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!item);
|
||||||
|
|
||||||
|
this.size = 0;
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
};
|
||||||
|
|
||||||
LRU.prototype.set = function set(key, value) {
|
LRU.prototype.set = function set(key, value) {
|
||||||
var item;
|
var item;
|
||||||
|
|
||||||
|
|||||||
@ -108,6 +108,7 @@ Fullnode.prototype._init = function _init() {
|
|||||||
self.emit('wallet tx', tx, ids);
|
self.emit('wallet tx', tx, ids);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (0)
|
||||||
this.on('tx', function(tx) {
|
this.on('tx', function(tx) {
|
||||||
self.walletdb.addTX(tx, function(err) {
|
self.walletdb.addTX(tx, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
@ -116,6 +117,7 @@ Fullnode.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Emit events for valid blocks and TXs.
|
// Emit events for valid blocks and TXs.
|
||||||
|
if (0)
|
||||||
this.chain.on('block', function(block) {
|
this.chain.on('block', function(block) {
|
||||||
self.emit('block', block);
|
self.emit('block', block);
|
||||||
block.txs.forEach(function(tx) {
|
block.txs.forEach(function(tx) {
|
||||||
@ -128,6 +130,7 @@ Fullnode.prototype._init = function _init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Update the mempool.
|
// Update the mempool.
|
||||||
|
if (0)
|
||||||
this.chain.on('add block', function(block) {
|
this.chain.on('add block', function(block) {
|
||||||
self.mempool.addBlock(block);
|
self.mempool.addBlock(block);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -243,7 +243,7 @@ Pool.prototype._init = function _init() {
|
|||||||
Pool.prototype.getBlocks = function getBlocks(peer, top, stop) {
|
Pool.prototype.getBlocks = function getBlocks(peer, top, stop) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.chain.onFlush(function() {
|
this.chain.onFlush(function() {
|
||||||
self.chain.getLocatorAsync(top, function(err, locator) {
|
self.chain.getLocator(top, function(err, locator) {
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ Pool.prototype.resolveOrphan = function resolveOrphan(peer, top, orphan) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
assert(orphan);
|
assert(orphan);
|
||||||
this.chain.onFlush(function() {
|
this.chain.onFlush(function() {
|
||||||
self.chain.getLocatorAsync(top, function(err, locator) {
|
self.chain.getLocator(top, function(err, locator) {
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
@ -280,10 +280,10 @@ Pool.prototype.resolveOrphan = function resolveOrphan(peer, top, orphan) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.chain.has(orphan.soil)) {
|
// if (self.chain.has(orphan.soil)) {
|
||||||
utils.debug('Already have orphan "soil". Race condition?');
|
// utils.debug('Already have orphan "soil". Race condition?');
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
peer.getBlocks(locator, orphan.root);
|
peer.getBlocks(locator, orphan.root);
|
||||||
});
|
});
|
||||||
@ -293,7 +293,7 @@ Pool.prototype.resolveOrphan = function resolveOrphan(peer, top, orphan) {
|
|||||||
Pool.prototype.getHeaders = function getHeaders(peer, top, stop) {
|
Pool.prototype.getHeaders = function getHeaders(peer, top, stop) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.chain.onFlush(function() {
|
this.chain.onFlush(function() {
|
||||||
self.chain.getLocatorAsync(top, function(err, locator) {
|
self.chain.getLocator(top, function(err, locator) {
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
|
|
||||||
@ -564,8 +564,11 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
|
|||||||
if (!header.verify())
|
if (!header.verify())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!self.chain.has(hash))
|
self.chain.has(hash, function(err, has) {
|
||||||
self.getData(peer, self.block.type, hash);
|
assert(!err);
|
||||||
|
if (!has)
|
||||||
|
self.getData(peer, self.block.type, hash);
|
||||||
|
});
|
||||||
|
|
||||||
last = hash;
|
last = hash;
|
||||||
}
|
}
|
||||||
@ -608,39 +611,51 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
|
|||||||
|
|
||||||
this.emit('blocks', hashes);
|
this.emit('blocks', hashes);
|
||||||
|
|
||||||
|
var req = [];
|
||||||
this.chain.onFlush(function() {
|
this.chain.onFlush(function() {
|
||||||
for (i = 0; i < hashes.length; i++) {
|
utils.forEachSerial(hashes, function(hash, next, i) {
|
||||||
hash = hashes[i];
|
|
||||||
|
|
||||||
// Resolve orphan chain.
|
// Resolve orphan chain.
|
||||||
if (self.chain.hasOrphan(hash)) {
|
if (self.chain.hasOrphan(hash)) {
|
||||||
utils.debug('Peer sent a hash that is already a known orphan.');
|
utils.debug('Peer sent a hash that is already a known orphan.');
|
||||||
self.resolveOrphan(peer, null, hash);
|
self.resolveOrphan(peer, null, hash);
|
||||||
continue;
|
return utils.nextTick(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request a block if we don't have it.
|
// Request a block if we don't have it.
|
||||||
if (!self.chain.has(hash)) {
|
self.chain.has(hash, function(err, has) {
|
||||||
self.getData(peer, self.block.type, hash);
|
assert(!err);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normally we request the hashContinue.
|
if (!has) {
|
||||||
// In the odd case where we already have
|
req.push([peer, self.block.type, hash]);
|
||||||
// it, we can do one of two things: either
|
return next();
|
||||||
// force re-downloading of the block to
|
}
|
||||||
// continue the sync, or do a getblocks
|
|
||||||
// from the last hash.
|
|
||||||
if (i === hashes.length - 1) {
|
|
||||||
// Request more hashes:
|
|
||||||
// self.getBlocks(peer, hash, null);
|
|
||||||
|
|
||||||
// Re-download the block (traditional method):
|
// Normally we request the hashContinue.
|
||||||
self.getData(peer, self.block.type, hash, { force: true });
|
// In the odd case where we already have
|
||||||
|
// it, we can do one of two things: either
|
||||||
|
// force re-downloading of the block to
|
||||||
|
// continue the sync, or do a getblocks
|
||||||
|
// from the last hash.
|
||||||
|
if (i === hashes.length - 1) {
|
||||||
|
// Request more hashes:
|
||||||
|
// self.getBlocks(peer, hash, null);
|
||||||
|
|
||||||
continue;
|
// Re-download the block (traditional method):
|
||||||
}
|
req.push([peer, self.block.type, hash, { force: true }]);
|
||||||
}
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
}, function(err) {
|
||||||
|
if (err)
|
||||||
|
return self.emit('error', err);
|
||||||
|
|
||||||
|
req.forEach(function(item) {
|
||||||
|
self.getData(item[0], item[1], item[2], item[3]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset interval to avoid calling getblocks unnecessarily
|
// Reset interval to avoid calling getblocks unnecessarily
|
||||||
@ -659,12 +674,15 @@ Pool.prototype._handleInv = function _handleInv(hashes, peer) {
|
|||||||
|
|
||||||
for (i = 0; i < hashes.length; i++) {
|
for (i = 0; i < hashes.length; i++) {
|
||||||
hash = utils.toHex(hashes[i]);
|
hash = utils.toHex(hashes[i]);
|
||||||
if (!this.chain.has(hash)) {
|
this.chain.has(hash, function(err, has) {
|
||||||
|
assert(!err);
|
||||||
|
if (has)
|
||||||
|
return;
|
||||||
if (this.options.headers)
|
if (this.options.headers)
|
||||||
this.getHeaders(this.peers.load, null, hash);
|
this.getHeaders(this.peers.load, null, hash);
|
||||||
else
|
else
|
||||||
this.getData(peer, this.block.type, hash);
|
this.getData(peer, this.block.type, hash);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -720,7 +738,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer, callback) {
|
|||||||
self.chain.orphan.count,
|
self.chain.orphan.count,
|
||||||
self.request.activeBlocks,
|
self.request.activeBlocks,
|
||||||
peer.queue.block.length,
|
peer.queue.block.length,
|
||||||
self.chain.getCurrentTarget(),
|
0,
|
||||||
self.peers.all.length,
|
self.peers.all.length,
|
||||||
self.chain.pending.length,
|
self.chain.pending.length,
|
||||||
self.chain.bestHeight,
|
self.chain.bestHeight,
|
||||||
@ -1327,7 +1345,7 @@ Pool.prototype.searchWallet = function(wallet, callback) {
|
|||||||
if (!height || height === -1)
|
if (!height || height === -1)
|
||||||
height = self.chain.height - (7 * 24 * 6);
|
height = self.chain.height - (7 * 24 * 6);
|
||||||
|
|
||||||
self.chain.resetHeightAsync(height, function(err) {
|
self.chain.resetHeight(height, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
utils.debug('Failed to reset height: %s', err.stack + '');
|
utils.debug('Failed to reset height: %s', err.stack + '');
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -1349,7 +1367,7 @@ Pool.prototype.searchWallet = function(wallet, callback) {
|
|||||||
if (!ts)
|
if (!ts)
|
||||||
ts = utils.now() - 7 * 24 * 3600;
|
ts = utils.now() - 7 * 24 * 3600;
|
||||||
|
|
||||||
self.chain.resetTimeAsync(ts, function(err) {
|
self.chain.resetTime(ts, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
utils.debug('Failed to reset time: %s', err.stack + '');
|
utils.debug('Failed to reset time: %s', err.stack + '');
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -1416,7 +1434,7 @@ Pool.prototype.search = function search(id, range, callback) {
|
|||||||
this.on('block', onBlock);
|
this.on('block', onBlock);
|
||||||
|
|
||||||
if (range.start < this.chain.tip.ts) {
|
if (range.start < this.chain.tip.ts) {
|
||||||
this.chain.resetTimeAsync(range.start, function(err) {
|
this.chain.resetTime(range.start, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return done(err);
|
return done(err);
|
||||||
|
|
||||||
@ -1446,50 +1464,57 @@ Pool.prototype.getData = function getData(peer, type, hash, options, callback) {
|
|||||||
if (Buffer.isBuffer(hash))
|
if (Buffer.isBuffer(hash))
|
||||||
hash = utils.toHex(hash);
|
hash = utils.toHex(hash);
|
||||||
|
|
||||||
if (this.request.map[hash]) {
|
function has(cb) {
|
||||||
if (callback)
|
if (!options.force && type !== self.tx.type)
|
||||||
this.request.map[hash].callback.push(callback);
|
return self.chain.has(hash, cb);
|
||||||
return;
|
return cb(null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.force && type !== self.tx.type) {
|
has(function(err, res) {
|
||||||
if (this.chain.has(hash))
|
assert(!err);
|
||||||
|
if (res)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (options.noQueue)
|
if (self.request.map[hash]) {
|
||||||
return;
|
if (callback)
|
||||||
|
self.request.map[hash].callback.push(callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
item = new LoadRequest(this, peer, type, hash, callback);
|
item = new LoadRequest(self, peer, type, hash, callback);
|
||||||
|
|
||||||
if (type === self.tx.type) {
|
if (options.noQueue)
|
||||||
if (peer.queue.tx.length === 0) {
|
return;
|
||||||
utils.nextTick(function() {
|
|
||||||
utils.debug(
|
|
||||||
'Requesting %d/%d txs from %s with getdata',
|
|
||||||
peer.queue.tx.length,
|
|
||||||
self.request.activeTX,
|
|
||||||
peer.host);
|
|
||||||
|
|
||||||
peer.getData(peer.queue.tx);
|
if (type === self.tx.type) {
|
||||||
peer.queue.tx.length = 0;
|
if (peer.queue.tx.length === 0) {
|
||||||
|
utils.nextTick(function() {
|
||||||
|
utils.debug(
|
||||||
|
'Requesting %d/%d txs from %s with getdata',
|
||||||
|
peer.queue.tx.length,
|
||||||
|
self.request.activeTX,
|
||||||
|
peer.host);
|
||||||
|
|
||||||
|
peer.getData(peer.queue.tx);
|
||||||
|
peer.queue.tx.length = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
peer.queue.tx.push(item.start());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peer.queue.block.length === 0) {
|
||||||
|
self.chain.onFlush(function() {
|
||||||
|
utils.nextTick(function() {
|
||||||
|
self.scheduleRequests(peer);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
peer.queue.tx.push(item.start());
|
peer.queue.block.push(item);
|
||||||
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peer.queue.block.length === 0) {
|
|
||||||
this.chain.onFlush(function() {
|
|
||||||
utils.nextTick(function() {
|
|
||||||
self.scheduleRequests(peer);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
peer.queue.block.push(item);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.scheduleRequests = function scheduleRequests(peer) {
|
Pool.prototype.scheduleRequests = function scheduleRequests(peer) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user