use getheaders.
This commit is contained in:
parent
3e5995f741
commit
484b1f2817
@ -42,14 +42,22 @@ function Block(data, subtype) {
|
|||||||
this.network = data.network || false;
|
this.network = data.network || false;
|
||||||
this.relayedBy = data.relayedBy || '0.0.0.0';
|
this.relayedBy = data.relayedBy || '0.0.0.0';
|
||||||
|
|
||||||
|
this.valid = null;
|
||||||
|
this._hash = null;
|
||||||
|
|
||||||
// List of matched TXs
|
// List of matched TXs
|
||||||
this.tx = [];
|
this.tx = [];
|
||||||
this.invalid = false;
|
|
||||||
|
|
||||||
if (this.subtype === 'merkleblock') {
|
if (!this.subtype) {
|
||||||
// Verify partial merkle tree and fill `ts` array
|
if (this.hashes.length)
|
||||||
this.invalid = !this._verifyMerkle();
|
this.subtype = 'merkleblock';
|
||||||
} else if (this.subtype === 'block') {
|
else if (this.txs.length)
|
||||||
|
this.subtype = 'block';
|
||||||
|
else
|
||||||
|
this.subtype = 'header';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.subtype === 'block') {
|
||||||
this.txs = this.txs.map(function(tx) {
|
this.txs = this.txs.map(function(tx) {
|
||||||
tx.network = self.network;
|
tx.network = self.network;
|
||||||
tx.relayedBy = self.relayedBy;
|
tx.relayedBy = self.relayedBy;
|
||||||
@ -67,11 +75,9 @@ function Block(data, subtype) {
|
|||||||
// this.height = height;
|
// this.height = height;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
this.invalid = !this._checkBlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._hash = null;
|
this.verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.prototype.hash = function hash(enc) {
|
Block.prototype.hash = function hash(enc) {
|
||||||
@ -97,7 +103,14 @@ Block.prototype.abbr = function abbr() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.verify = function verify() {
|
Block.prototype.verify = function verify() {
|
||||||
return !this.invalid && utils.testTarget(this.bits, this.hash());
|
if (this.valid == null)
|
||||||
|
this.valid = this._verify();
|
||||||
|
return this.valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
Block.verify = function verify(data, subtype) {
|
||||||
|
var block = new Block(data, subtype);
|
||||||
|
return block.verify();
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.render = function render() {
|
Block.prototype.render = function render() {
|
||||||
@ -112,7 +125,7 @@ Block.prototype.hasTX = function hasTX(hash) {
|
|||||||
return this.tx.indexOf(hash) !== -1;
|
return this.tx.indexOf(hash) !== -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype._verifyMerkle = function verifyMerkle() {
|
Block.prototype._verifyPartial = function _verifyPartial() {
|
||||||
var height = 0;
|
var height = 0;
|
||||||
var tx = [];
|
var tx = [];
|
||||||
var i = 0;
|
var i = 0;
|
||||||
@ -121,7 +134,7 @@ Block.prototype._verifyMerkle = function verifyMerkle() {
|
|||||||
var flags = this.flags;
|
var flags = this.flags;
|
||||||
var i, root;
|
var i, root;
|
||||||
|
|
||||||
if (this.subtype === 'block')
|
if (this.subtype !== 'merkleblock')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Count leaves
|
// Count leaves
|
||||||
@ -203,7 +216,7 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() {
|
|||||||
|
|
||||||
// This mimics the behavior of CheckBlockHeader()
|
// This mimics the behavior of CheckBlockHeader()
|
||||||
// and CheckBlock() in bitcoin/src/main.cpp.
|
// and CheckBlock() in bitcoin/src/main.cpp.
|
||||||
Block.prototype._checkBlock = function checkBlock() {
|
Block.prototype._verify = function _verify() {
|
||||||
var i, unique, hash, merkleRoot;
|
var i, unique, hash, merkleRoot;
|
||||||
|
|
||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
@ -214,6 +227,14 @@ Block.prototype._checkBlock = function checkBlock() {
|
|||||||
if (this.ts > (Date.now() / 1000) + 2 * 60 * 60)
|
if (this.ts > (Date.now() / 1000) + 2 * 60 * 60)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (this.subtype === 'merkleblock') {
|
||||||
|
if (!this._verifyPartial())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.subtype !== 'block')
|
||||||
|
return true;
|
||||||
|
|
||||||
// Size can't be bigger than MAX_BLOCK_SIZE
|
// Size can't be bigger than MAX_BLOCK_SIZE
|
||||||
if (this.txs.length > constants.block.maxSize
|
if (this.txs.length > constants.block.maxSize
|
||||||
|| this.size() > constants.block.maxSize) {
|
|| this.size() > constants.block.maxSize) {
|
||||||
@ -389,9 +410,10 @@ Block.fromJSON = function fromJSON(json) {
|
|||||||
|
|
||||||
parser = new bcoin.protocol.parser();
|
parser = new bcoin.protocol.parser();
|
||||||
|
|
||||||
data = json.subtype === 'merkleblock'
|
if (json.subtype === 'merkleblock')
|
||||||
? parser.parseMerkleBlock(raw)
|
data = parser.parseMerkleBlock(raw);
|
||||||
: parser.parseBlock(raw);
|
else if (json.subtype === 'block' || json.subtype === 'header')
|
||||||
|
data = parser.parseBlock(raw);
|
||||||
|
|
||||||
data.network = json.network;
|
data.network = json.network;
|
||||||
data.relayedBy = json.relayedBy;
|
data.relayedBy = json.relayedBy;
|
||||||
|
|||||||
@ -48,6 +48,7 @@ function Chain(options) {
|
|||||||
hashes: [],
|
hashes: [],
|
||||||
ts: [],
|
ts: [],
|
||||||
heights: [],
|
heights: [],
|
||||||
|
lookup: {},
|
||||||
lastTs: 0
|
lastTs: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ function Chain(options) {
|
|||||||
this.fromJSON(preload);
|
this.fromJSON(preload);
|
||||||
|
|
||||||
// Last TS after preload, needed for fill percent
|
// Last TS after preload, needed for fill percent
|
||||||
this.index.lastTs = this.index.ts[0];
|
this.index.lastTs = this.index.ts[this.index.ts.length - 1];
|
||||||
|
|
||||||
bcoin.chain.global = this;
|
bcoin.chain.global = this;
|
||||||
|
|
||||||
@ -177,6 +178,8 @@ Chain.prototype._addIndex = function _addIndex(hash, ts, height) {
|
|||||||
this.index.hashes.splice(pos, 0, hash);
|
this.index.hashes.splice(pos, 0, hash);
|
||||||
this.index.heights.splice(pos, 0, height);
|
this.index.heights.splice(pos, 0, height);
|
||||||
this.index.bloom.add(hash, 'hex');
|
this.index.bloom.add(hash, 'hex');
|
||||||
|
// this.index.lookup[hash] = pos;
|
||||||
|
// this.index.lookup[height] = pos;
|
||||||
|
|
||||||
this._save(hash, {
|
this._save(hash, {
|
||||||
ts: ts,
|
ts: ts,
|
||||||
@ -196,6 +199,7 @@ Chain.prototype.resetLastCheckpoint = function resetLastCheckpoint(height) {
|
|||||||
Chain.prototype.resetHeight = function resetHeight(height) {
|
Chain.prototype.resetHeight = function resetHeight(height) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var index = this.index.heights.indexOf(height);
|
var index = this.index.heights.indexOf(height);
|
||||||
|
var ahead = this.index.hashes.slice(index + 1);
|
||||||
|
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
throw new Error('Cannot reset to height of ' + height);
|
throw new Error('Cannot reset to height of ' + height);
|
||||||
@ -212,21 +216,22 @@ Chain.prototype.resetHeight = function resetHeight(height) {
|
|||||||
this.index.hashes.forEach(function(hash) {
|
this.index.hashes.forEach(function(hash) {
|
||||||
self.index.bloom.add(hash, 'hex');
|
self.index.bloom.add(hash, 'hex');
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype._heightByTime = function _heightByTime(ts) {
|
this.index.lastTs = Math.min(
|
||||||
for (var i = this.index.ts.length - 1; i >= 0; i--) {
|
this.index.lastTs,
|
||||||
if (ts >= this.index.ts[i])
|
this.index.ts[this.index.ts.length - 1]
|
||||||
return this.index.heights[i];
|
);
|
||||||
}
|
|
||||||
return -1;
|
ahead.forEach(function(hash) {
|
||||||
|
self._delete(hash);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.resetTime = function resetTime(ts) {
|
Chain.prototype.resetTime = function resetTime(ts) {
|
||||||
var height = this._heightByTime(ts);
|
var entry = this.byTime(ts);
|
||||||
if (height === -1)
|
if (!entry)
|
||||||
return;
|
return;
|
||||||
return this.resetHeight(height);
|
return this.resetHeight(entry.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._killFork = function _killFork(probe) {
|
Chain.prototype._killFork = function _killFork(probe) {
|
||||||
@ -407,20 +412,6 @@ Chain.prototype.has = function has(hash, noIndex, cb) {
|
|||||||
return cb(false);
|
return cb(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.byHeight = function byHeight(height) {
|
|
||||||
var index = this.index.heights.indexOf(height);
|
|
||||||
|
|
||||||
if (index === -1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
index: index,
|
|
||||||
hash: this.index.hashes[index],
|
|
||||||
ts: this.index.ts[index],
|
|
||||||
height: this.index.heights[index]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype.byHash = function byHash(hash) {
|
Chain.prototype.byHash = function byHash(hash) {
|
||||||
if (Array.isArray(hash))
|
if (Array.isArray(hash))
|
||||||
hash = utils.toHex(hash);
|
hash = utils.toHex(hash);
|
||||||
@ -440,6 +431,28 @@ Chain.prototype.byHash = function byHash(hash) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chain.prototype.byHeight = function byHeight(height) {
|
||||||
|
var index = this.index.heights.indexOf(height);
|
||||||
|
|
||||||
|
if (index === -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
index: index,
|
||||||
|
hash: this.index.hashes[index],
|
||||||
|
ts: this.index.ts[index],
|
||||||
|
height: this.index.heights[index]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Chain.prototype.byTime = function byTime(ts) {
|
||||||
|
for (var i = this.index.ts.length - 1; i >= 0; i--) {
|
||||||
|
if (ts >= this.index.ts[i])
|
||||||
|
return this.byHeight(this.index.heights[i]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
Chain.prototype.hasBlock = function hasBlock(hash) {
|
Chain.prototype.hasBlock = function hasBlock(hash) {
|
||||||
if (Array.isArray(hash))
|
if (Array.isArray(hash))
|
||||||
hash = utils.toHex(hash);
|
hash = utils.toHex(hash);
|
||||||
@ -508,33 +521,6 @@ Chain.prototype.getTip = function() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.get = function get(hash, force, cb) {
|
|
||||||
var i, block;
|
|
||||||
|
|
||||||
if (typeof force === 'function') {
|
|
||||||
cb = force;
|
|
||||||
force = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cached block found
|
|
||||||
if (!force) {
|
|
||||||
if (this.block.bloom.test(hash, 'hex')) {
|
|
||||||
block = this.getCache(hash);
|
|
||||||
if (block) {
|
|
||||||
bcoin.utils.nextTick(cb.bind(null, block));
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
// False positive:
|
|
||||||
// assert(false);
|
|
||||||
}
|
|
||||||
if (this.hasOrphan(hash))
|
|
||||||
return cb(this.getOrphan(hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.request.add(hash, cb))
|
|
||||||
this.emit('missing', hash, null, null);
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype.isFull = function isFull() {
|
Chain.prototype.isFull = function isFull() {
|
||||||
// < 40m since last block
|
// < 40m since last block
|
||||||
if (this.request.count)
|
if (this.request.count)
|
||||||
@ -546,11 +532,25 @@ Chain.prototype.isFull = function isFull() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.fillPercent = function fillPercent() {
|
Chain.prototype.fillPercent = function fillPercent() {
|
||||||
var total = (+new Date() / 1000 - 40 * 60) - this.index.lastTs;
|
var total = (+new Date() / 1000 - 40 * 60) - this.index.ts[0];
|
||||||
var current = this.index.ts[this.index.ts.length - 1] - this.index.lastTs;
|
var current = this.index.ts[this.index.ts.length - 1] - this.index.ts[0];
|
||||||
return Math.max(0, Math.min(current / total, 1));
|
return Math.max(0, Math.min(current / total, 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chain.prototype.hashRange = function hashRange(start, end) {
|
||||||
|
var hashes;
|
||||||
|
|
||||||
|
start = this.chain.byTime(start);
|
||||||
|
end = this.chain.byTime(end);
|
||||||
|
|
||||||
|
if (!start || !end)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
hashes = this.chain.index.hashes.slice(start.index, end.index + 1);
|
||||||
|
|
||||||
|
return hashes;
|
||||||
|
};
|
||||||
|
|
||||||
Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
|
Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
|
||||||
var ts, hashes, heights, zip, i, count;
|
var ts, hashes, heights, zip, i, count;
|
||||||
|
|
||||||
@ -591,31 +591,22 @@ Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
|
|||||||
return cb(hashes, count);
|
return cb(hashes, count);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.getLast = function getLast(cb) {
|
|
||||||
if (this.loading) {
|
|
||||||
this.once('load', function() {
|
|
||||||
this.getLast(cb);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cb = utils.asyncify(cb);
|
|
||||||
return cb(this.index.hashes[this.index.hashes.length - 1]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype.getStartHeight = function getStartHeight() {
|
Chain.prototype.getStartHeight = function getStartHeight() {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.locatorHashes = function locatorHashes(start) {
|
Chain.prototype.locatorHashes = function locatorHashes(start) {
|
||||||
assert(start == null);
|
if (start != null) {
|
||||||
|
if (typeof start === 'number')
|
||||||
|
start = this.byHeight(start);
|
||||||
|
else
|
||||||
|
start = this.byHash(start) || start;
|
||||||
|
|
||||||
if (this.index.hashes.length === 1)
|
if (start && start.index != null)
|
||||||
return [this.index.hashes[0]];
|
start = start.index;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return bcoin.fullChain.prototype.locatorHashes.call(this, start);
|
||||||
this.index.hashes[this.index.hashes.length - 1],
|
|
||||||
this.index.hashes[0]
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) {
|
Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) {
|
||||||
|
|||||||
@ -64,7 +64,7 @@ function Chain(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Last TS after preload, needed for fill percent
|
// Last TS after preload, needed for fill percent
|
||||||
this.index.lastTs = this.index.entries[0].ts;
|
this.index.lastTs = this.index.entries[this.index.entries.length - 1].ts;
|
||||||
|
|
||||||
bcoin.chain.global = this;
|
bcoin.chain.global = this;
|
||||||
|
|
||||||
@ -145,7 +145,10 @@ Chain.prototype.resetLastCheckpoint = function resetLastCheckpoint(height) {
|
|||||||
|
|
||||||
Chain.prototype.resetHeight = function resetHeight(height) {
|
Chain.prototype.resetHeight = function resetHeight(height) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var forked = this.index.entries.slice(height + 1);
|
var ahead = this.index.entries.slice(height + 1);
|
||||||
|
|
||||||
|
if (height >= this.index.entries - 1)
|
||||||
|
throw new Error('Cannot reset to height of ' + height);
|
||||||
|
|
||||||
this.orphan.map = {};
|
this.orphan.map = {};
|
||||||
this.orphan.bmap = {};
|
this.orphan.bmap = {};
|
||||||
@ -157,26 +160,21 @@ Chain.prototype.resetHeight = function resetHeight(height) {
|
|||||||
}, {});
|
}, {});
|
||||||
this.index.hashes.length = height + 1;
|
this.index.hashes.length = height + 1;
|
||||||
|
|
||||||
this.index.lastTs = this.index.entries[0].ts;
|
this.index.lastTs = Math.min(
|
||||||
|
this.index.lastTs,
|
||||||
|
this.index.entries[this.index.entries.length - 1].ts
|
||||||
|
);
|
||||||
|
|
||||||
forked.forEach(function(entry) {
|
ahead.forEach(function(entry) {
|
||||||
self._delete(entry);
|
self._delete(entry.hash);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype._heightByTime = function _heightByTime(ts) {
|
|
||||||
for (var i = this.index.entries.length - 1; i >= 0; i--) {
|
|
||||||
if (ts >= this.index.entries[i].ts)
|
|
||||||
return this.index.entries[i].height;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype.resetTime = function resetTime(ts) {
|
Chain.prototype.resetTime = function resetTime(ts) {
|
||||||
var height = this._heightByTime(ts);
|
var entry = this.byTime(ts);
|
||||||
if (height === -1)
|
if (!entry)
|
||||||
return;
|
return;
|
||||||
return this.resetHeight(height);
|
return this.resetHeight(entry.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.add = function add(block) {
|
Chain.prototype.add = function add(block) {
|
||||||
@ -301,6 +299,14 @@ Chain.prototype.byHash = function byHash(hash) {
|
|||||||
return this.byHeight(this.index.heights[hash]);
|
return this.byHeight(this.index.heights[hash]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chain.prototype.byTime = function byTime(ts) {
|
||||||
|
for (var i = this.index.entries.length - 1; i >= 0; i--) {
|
||||||
|
if (ts >= this.index.entries[i].ts)
|
||||||
|
return this.index.entries[i];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
Chain.prototype.hasBlock = function hasBlock(hash) {
|
Chain.prototype.hasBlock = function hasBlock(hash) {
|
||||||
return !!this.byHash(hash);
|
return !!this.byHash(hash);
|
||||||
};
|
};
|
||||||
@ -336,10 +342,6 @@ Chain.prototype.getTip = function getTip() {
|
|||||||
return this.index.entries[this.index.entries.length - 1];
|
return this.index.entries[this.index.entries.length - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.get = function get(hash, force, cb) {
|
|
||||||
assert(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
Chain.prototype.isFull = function isFull() {
|
Chain.prototype.isFull = function isFull() {
|
||||||
var last = this.index.entries[this.index.entries.length - 1].ts;
|
var last = this.index.entries[this.index.entries.length - 1].ts;
|
||||||
var delta = (+new Date() / 1000) - last;
|
var delta = (+new Date() / 1000) - last;
|
||||||
@ -352,19 +354,22 @@ Chain.prototype.fillPercent = function fillPercent() {
|
|||||||
return Math.max(0, Math.min(current / total, 1));
|
return Math.max(0, Math.min(current / total, 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
|
Chain.prototype.hashRange = function hashRange(start, end) {
|
||||||
assert(false);
|
var hashes;
|
||||||
|
|
||||||
|
start = this.chain.byTime(start);
|
||||||
|
end = this.chain.byTime(end);
|
||||||
|
|
||||||
|
if (!start || !end)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
hashes = this.chain.index.hashes.slice(start.height, end.height + 1);
|
||||||
|
|
||||||
|
return hashes;
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.getLast = function getLast(cb) {
|
Chain.prototype.hashesInRange = function hashesInRange(start, end, cb) {
|
||||||
if (this.loading) {
|
assert(false);
|
||||||
this.once('load', function() {
|
|
||||||
this.getLast(cb);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cb = utils.asyncify(cb);
|
|
||||||
return cb(this.index.hashes[this.index.hashes.length - 1]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.getStartHeight = function getStartHeight() {
|
Chain.prototype.getStartHeight = function getStartHeight() {
|
||||||
@ -387,8 +392,10 @@ Chain.prototype.locatorHashes = function locatorHashes(start) {
|
|||||||
|
|
||||||
if (typeof start === 'string') {
|
if (typeof start === 'string') {
|
||||||
// Hash
|
// Hash
|
||||||
if (this.index.heights[start])
|
if (this.index.heights[start] != null)
|
||||||
top = this.index.heights[start];
|
top = this.index.heights[start];
|
||||||
|
else
|
||||||
|
hashes.push(start);
|
||||||
} else if (typeof start === 'number') {
|
} else if (typeof start === 'number') {
|
||||||
// Height
|
// Height
|
||||||
top = start;
|
top = start;
|
||||||
@ -396,7 +403,8 @@ Chain.prototype.locatorHashes = function locatorHashes(start) {
|
|||||||
|
|
||||||
i = top;
|
i = top;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
hashes.push(chain[i]);
|
if (chain[i])
|
||||||
|
hashes.push(chain[i]);
|
||||||
i = i - step;
|
i = i - step;
|
||||||
if (i <= 0) {
|
if (i <= 0) {
|
||||||
hashes.push(chain[0]);
|
hashes.push(chain[0]);
|
||||||
|
|||||||
@ -502,7 +502,7 @@ Peer.prototype._handleInv = function handleInv(items) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (blocks.length === 1)
|
if (blocks.length === 1)
|
||||||
this.bestBlock = utils.toHex(blocks[0]);
|
this.bestHash = utils.toHex(blocks[0]);
|
||||||
|
|
||||||
this.emit('blocks', blocks);
|
this.emit('blocks', blocks);
|
||||||
|
|
||||||
|
|||||||
@ -94,9 +94,9 @@ function Pool(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.block = {
|
this.block = {
|
||||||
lastHash: null,
|
|
||||||
bestHeight: 0,
|
bestHeight: 0,
|
||||||
bestHash: null
|
bestHash: null,
|
||||||
|
type: this.options.fullNode ? 'block' : 'filtered'
|
||||||
};
|
};
|
||||||
|
|
||||||
this.request = {
|
this.request = {
|
||||||
@ -154,13 +154,11 @@ Pool.prototype._init = function _init() {
|
|||||||
for (i = 0; i < this.size; i++)
|
for (i = 0; i < this.size; i++)
|
||||||
this._addPeer(0);
|
this._addPeer(0);
|
||||||
|
|
||||||
this._load();
|
|
||||||
|
|
||||||
this.chain.on('missing', function(hash, preload, parent) {
|
this.chain.on('missing', function(hash, preload, parent) {
|
||||||
if (!self.options.fullNode) {
|
if (!self.options.fullNode) {
|
||||||
self._request('filtered', hash, { force: true });
|
self._request(self.block.type, hash, { force: true });
|
||||||
self._scheduleRequests();
|
self._scheduleRequests();
|
||||||
self._loadRange(preload);
|
// self._loadRange(preload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -226,7 +224,7 @@ Pool.prototype._addLoader = function _addLoader() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function load() {
|
function load() {
|
||||||
self._load();
|
// self._load();
|
||||||
}
|
}
|
||||||
|
|
||||||
interval = setInterval(load, this.load.interval);
|
interval = setInterval(load, this.load.interval);
|
||||||
@ -236,7 +234,6 @@ Pool.prototype._addLoader = function _addLoader() {
|
|||||||
if (self.chain.isFull()) {
|
if (self.chain.isFull()) {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
self.emit('full');
|
self.emit('full');
|
||||||
self.block.lastHash = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,89 +242,68 @@ Pool.prototype._addLoader = function _addLoader() {
|
|||||||
|
|
||||||
timer = setTimeout(destroy, this.load.timeout);
|
timer = setTimeout(destroy, this.load.timeout);
|
||||||
|
|
||||||
|
peer.on('merkleblock', function(block) {
|
||||||
|
self._handleBlock(block, peer);
|
||||||
|
});
|
||||||
|
|
||||||
peer.on('block', function(block) {
|
peer.on('block', function(block) {
|
||||||
self._handleBlock(block, peer);
|
self._handleBlock(block, peer);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Split blocks and request them using multiple peers
|
|
||||||
peer.on('blocks', function(hashes) {
|
peer.on('blocks', function(hashes) {
|
||||||
var i, hash;
|
self._handleInv(hashes, peer);
|
||||||
|
});
|
||||||
|
|
||||||
self.emit('blocks', hashes);
|
// Split blocks and request them using multiple peers
|
||||||
|
peer.on('headers', function(headers) {
|
||||||
|
var i, header, last, block;
|
||||||
|
|
||||||
if (hashes.length === 0) {
|
if (headers.length === 0)
|
||||||
// Reset global load
|
|
||||||
self.block.lastHash = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!self.options.fullNode) {
|
|
||||||
// Request each block
|
|
||||||
for (i = 0; i < hashes.length; i++) {
|
|
||||||
self._request('filtered', hashes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push our getblocks packet
|
|
||||||
self._scheduleRequests();
|
|
||||||
|
|
||||||
// The part of the response is in chain, no need to escalate requests
|
|
||||||
async.every(hashes, function(hash, cb) {
|
|
||||||
self.chain.has(utils.toHex(hash), function(res) {
|
|
||||||
cb(!res);
|
|
||||||
});
|
|
||||||
}, function(allNew) {
|
|
||||||
if (!allNew) {
|
|
||||||
self.block.lastHash = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store last hash to continue global load
|
|
||||||
self.block.lastHash = hashes[hashes.length - 1];
|
|
||||||
|
|
||||||
clearTimeout(timer);
|
|
||||||
|
|
||||||
// Reinstantiate timeout
|
|
||||||
if (self._load())
|
|
||||||
timer = setTimeout(destroy, self.load.timeout);
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < hashes.length; i++) {
|
|
||||||
hash = hashes[i];
|
|
||||||
|
|
||||||
// Resolve orphan chain
|
|
||||||
if (self.chain.hasOrphan(hash)) {
|
|
||||||
peer.loadBlocks(
|
|
||||||
self.chain.locatorHashes(),
|
|
||||||
self.chain.getOrphanRoot(hash)
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restart the entire getblocks process
|
|
||||||
if (i === hashes.length - 1)
|
|
||||||
peer.loadBlocks(self.chain.locatorHashes(), 0);
|
|
||||||
|
|
||||||
// Request block if we don't have it
|
|
||||||
if (!self.chain.hasBlock(hash) && !self.chain.hasOrphan(hash))
|
|
||||||
self._request('block', hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit('debug',
|
self.emit('debug',
|
||||||
'Requesting %s block packets from %s with getdata',
|
'Recieved %s headers from %s',
|
||||||
self.request.active,
|
headers.length,
|
||||||
peer.address
|
peer.address);
|
||||||
);
|
|
||||||
|
|
||||||
// Push our getblocks packet
|
self.emit('headers', headers);
|
||||||
|
|
||||||
|
for (i = 0; i < headers.length; i++) {
|
||||||
|
block = bcoin.block(headers[i], 'header');
|
||||||
|
|
||||||
|
if (last && block.prevBlock !== last.hash('hex'))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!block.verify())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!self.chain.hasBlock(block) && !self.chain.hasOrphan(block))
|
||||||
|
self._request(self.block.type, block.hash('hex'));
|
||||||
|
|
||||||
|
// We could do headers-first:
|
||||||
|
// self._addIndex(block, peer);
|
||||||
|
|
||||||
|
// Resolve orphan chain
|
||||||
|
// if (self.chain.hasOrphan(block)) {
|
||||||
|
// peer.loadHeaders(
|
||||||
|
// self.chain.locatorHashes(),
|
||||||
|
// self.chain.getOrphanRoot(block)
|
||||||
|
// );
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
last = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart the getheaders process
|
||||||
|
if (last && headers.length >= 1999)
|
||||||
|
peer.loadHeaders(self.chain.locatorHashes(last), 0);
|
||||||
|
// peer.loadHeaders([last.hash('hex')], 0);
|
||||||
|
|
||||||
|
// Schedule our requests
|
||||||
self._scheduleRequests();
|
self._scheduleRequests();
|
||||||
|
|
||||||
// Store last hash because we can
|
// Reset interval to avoid calling getheaders unnecessarily
|
||||||
self.block.lastHash = hashes[hashes.length - 1];
|
|
||||||
|
|
||||||
// Reset interval to avoid calling getblocks unnecessarily
|
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
interval = setInterval(load, self.load.interval);
|
interval = setInterval(load, self.load.interval);
|
||||||
|
|
||||||
@ -337,34 +313,44 @@ Pool.prototype._addLoader = function _addLoader() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype._handleMerkle = function _handleMerkle(block, peer) {
|
Pool.prototype._handleInv = function _handleInv(hashes, peer) {
|
||||||
if (this.options.fullNode)
|
var i, hash;
|
||||||
return;
|
|
||||||
|
|
||||||
this._response(block);
|
for (i = 0; i < hashes.length; i++) {
|
||||||
this.chain.add(block);
|
hash = utils.toHex(hashes[i]);
|
||||||
this.emit('chain-progress', this.chain.fillPercent(), peer);
|
if (!this.chain.hasBlock(hash) && !this.chain.hasOrphan(hash))
|
||||||
this.emit('block', block, peer);
|
this.peers.load.loadHeaders(this.chain.locatorHashes(), hash);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var hash, size, orphan, err;
|
|
||||||
|
|
||||||
if (!this.options.fullNode)
|
var requested = this._response(block);
|
||||||
|
|
||||||
|
// Someone is sending us blocks without us requesting them.
|
||||||
|
if (!requested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Emulate bip37 - emit all the "watched" txs
|
// Emulate bip37 - emit all the "watched" txs
|
||||||
if (this.listeners('watched').length > 0) {
|
if (this.options.fullNode
|
||||||
utils.nextTick(function() {
|
&& this.listeners('watched').length > 0
|
||||||
block.txs.forEach(function(tx) {
|
&& block.verify()) {
|
||||||
if (self.isWatched(tx))
|
block.txs.forEach(function(tx) {
|
||||||
self.emit('watched', tx, peer);
|
if (self.isWatched(tx))
|
||||||
});
|
self.emit('watched', tx, peer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._response(block);
|
if (!this._addIndex(block, peer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.emit('block', block, peer);
|
||||||
|
};
|
||||||
|
|
||||||
|
Pool.prototype._addIndex = function _addIndex(block, peer) {
|
||||||
|
var self = this;
|
||||||
|
var hash, size, orphan, err;
|
||||||
|
|
||||||
hash = block.hash('hex');
|
hash = block.hash('hex');
|
||||||
size = this.chain.size();
|
size = this.chain.size();
|
||||||
@ -374,26 +360,25 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
if (err)
|
if (err)
|
||||||
this.emit('chain-error', err, peer);
|
this.emit('chain-error', err, peer);
|
||||||
|
|
||||||
this.emit('_block', block, peer);
|
|
||||||
|
|
||||||
if (this.chain.hasOrphan(block)) {
|
if (this.chain.hasOrphan(block)) {
|
||||||
// Resolve orphan chain
|
// Resolve orphan chain
|
||||||
peer.loadBlocks(
|
// peer.loadHeaders(
|
||||||
this.chain.locatorHashes(),
|
// this.chain.locatorHashes(),
|
||||||
this.chain.getOrphanRoot(block)
|
// this.chain.getOrphanRoot(block)
|
||||||
);
|
// );
|
||||||
// Emit our orphan if it is new
|
// Emit our orphan if it is new
|
||||||
if (!orphan)
|
if (!orphan)
|
||||||
this.emit('orphan', block, peer);
|
this.emit('orphan', block, peer);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not emit if nothing was added to the chain
|
// Do not emit if nothing was added to the chain
|
||||||
if (this.chain.size() === size)
|
if (this.chain.size() === size)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
this.emit('chain-progress', this.chain.fillPercent(), peer);
|
this.emit('chain-progress', this.chain.fillPercent(), peer);
|
||||||
this.emit('block', block, peer);
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.isFull = function isFull() {
|
Pool.prototype.isFull = function isFull() {
|
||||||
@ -442,31 +427,16 @@ Pool.prototype._load = function _load() {
|
|||||||
|
|
||||||
if (this.peers.load) {
|
if (this.peers.load) {
|
||||||
this.emit('debug',
|
this.emit('debug',
|
||||||
'Requesting inv packet from %s with getblocks',
|
'Requesting headers packet from %s with getheaders',
|
||||||
this.peers.load.address);
|
this.peers.load.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.options.fullNode) {
|
if (!this.peers.load) {
|
||||||
next = function(hash) {
|
this._addLoader();
|
||||||
if (!self.peers.load)
|
|
||||||
self._addLoader();
|
|
||||||
else
|
|
||||||
self.peers.load.loadBlocks([hash], 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load more blocks, starting from last hash
|
|
||||||
if (this.block.lastHash)
|
|
||||||
next(this.block.lastHash);
|
|
||||||
else
|
|
||||||
this.chain.getLast(next);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.peers.load)
|
this.peers.load.loadHeaders(this.chain.locatorHashes(), 0);
|
||||||
this._addLoader();
|
|
||||||
else
|
|
||||||
this.peers.load.loadBlocks(this.chain.locatorHashes(), 0);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -531,7 +501,7 @@ Pool.prototype._addPeer = function _addPeer(backoff) {
|
|||||||
peer.on('merkleblock', function(block) {
|
peer.on('merkleblock', function(block) {
|
||||||
// Reset backoff, peer seems to be responsive
|
// Reset backoff, peer seems to be responsive
|
||||||
backoff = 0;
|
backoff = 0;
|
||||||
self._handleMerkle(block, peer);
|
self._handleBlock(block, peer);
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('block', function(block) {
|
peer.on('block', function(block) {
|
||||||
@ -565,10 +535,8 @@ Pool.prototype._addPeer = function _addPeer(backoff) {
|
|||||||
self.emit('addr', addr, peer);
|
self.emit('addr', addr, peer);
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('blocks', function(blocks) {
|
peer.on('blocks', function(hashes) {
|
||||||
if (blocks.length === 1)
|
self._handleInv(hashes, peer);
|
||||||
self.block.bestHash = peer.bestBlock;
|
|
||||||
self.emit('blocks', blocks, peer);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('txs', function(txs) {
|
peer.on('txs', function(txs) {
|
||||||
@ -834,6 +802,7 @@ Pool.prototype.searchWallet = function(w) {
|
|||||||
|
|
||||||
Pool.prototype.search = function search(id, range, e) {
|
Pool.prototype.search = function search(id, range, e) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var hashes, pending, listener, timeout, done, total;
|
||||||
|
|
||||||
if (this.options.fullNode)
|
if (this.options.fullNode)
|
||||||
return;
|
return;
|
||||||
@ -862,72 +831,70 @@ Pool.prototype.search = function search(id, range, e) {
|
|||||||
// Last 5 days by default, this covers 1000 blocks that we have in the
|
// Last 5 days by default, this covers 1000 blocks that we have in the
|
||||||
// chain by default
|
// chain by default
|
||||||
if (!range.end)
|
if (!range.end)
|
||||||
range.end = +new Date() / 1000;
|
range.end = +new Date() / 1000 | 0;
|
||||||
if (!range.start)
|
if (!range.start)
|
||||||
range.start = +new Date() / 1000 - 432000;
|
range.start = (+new Date() / 1000 | 0) - 432000;
|
||||||
|
|
||||||
this.chain.hashesInRange(range.start, range.end, function(hashes, count) {
|
|
||||||
var waiting = count;
|
|
||||||
|
|
||||||
self.emit('debug',
|
|
||||||
'Search for %s (%s) hashes between %s and %s',
|
|
||||||
hashes.length,
|
|
||||||
count,
|
|
||||||
new Date(range.start * 1000).toISOString(),
|
|
||||||
new Date(range.end * 1000).toISOString()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
if (range.start < this.chain.lastTs) {
|
||||||
if (id)
|
if (id)
|
||||||
self.watch(id);
|
this.watch(id);
|
||||||
|
|
||||||
self._loadRange(hashes, true);
|
done = function(res) {
|
||||||
|
e.emit('end', res);
|
||||||
|
clearInterval(timeout);
|
||||||
|
self.removeListener('block', listener);
|
||||||
|
if (id)
|
||||||
|
self.unwatch(id);
|
||||||
|
};
|
||||||
|
|
||||||
hashes = hashes.slice().reverse();
|
this.on('block', listener = function(block) {
|
||||||
hashes.forEach(function(hash, i) {
|
if (block.ts >= range.end)
|
||||||
// Get the block that is in index
|
done();
|
||||||
self.chain.request.add(hash, function(block) {
|
|
||||||
loadBlock(block, hashes[i + 1]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadBlock(block, stop) {
|
total = (range.end - range.start) / network.powTargetSpacing | 0;
|
||||||
// Stop block reached
|
if (total === 0)
|
||||||
if (block.hash('hex') === stop)
|
total = 1;
|
||||||
return;
|
|
||||||
|
|
||||||
// Get block's prev and request it and all of it's parents up to
|
timeout = setTimeout(done.bind(null, true), total * 10 * 1000);
|
||||||
// the next known block hash
|
|
||||||
self.chain.request.add(block.prevBlock, function(prev) {
|
|
||||||
done();
|
|
||||||
|
|
||||||
// First hash loaded
|
this.chain.resetTime(range.start);
|
||||||
if (!stop)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Continue loading blocks
|
if (this.peers.load)
|
||||||
loadBlock(prev, stop);
|
this.peers.load.destroy();
|
||||||
});
|
|
||||||
|
this._load();
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashes = this.chain.hashRange(range.start, range.end);
|
||||||
|
pending = hashes.length;
|
||||||
|
|
||||||
|
if (id)
|
||||||
|
this.watch(id);
|
||||||
|
|
||||||
|
done = function() {
|
||||||
|
pending--;
|
||||||
|
assert(pending >= 0);
|
||||||
|
e.emit('progress', count - pending, count);
|
||||||
|
if (pending === 0) {
|
||||||
|
if (id)
|
||||||
|
self.unwatch(id);
|
||||||
|
e.emit('end');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function done() {
|
hashes.forEach(function(hash) {
|
||||||
waiting--;
|
self._request('filtered', hash, { force: true }, done);
|
||||||
assert(waiting >= 0);
|
|
||||||
e.emit('progress', count - waiting, count);
|
|
||||||
if (waiting === 0) {
|
|
||||||
if (id)
|
|
||||||
self.unwatch(id);
|
|
||||||
e.emit('end');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty search
|
|
||||||
if (hashes.length === 0) {
|
|
||||||
bcoin.utils.nextTick(function() {
|
|
||||||
e.emit('end', true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (hashes.length === 0) {
|
||||||
|
bcoin.utils.nextTick(function() {
|
||||||
|
e.emit('end', true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -958,8 +925,8 @@ Pool.prototype._request = function _request(type, hash, options, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Block should be not in chain, or be requested
|
// Block should be not in chain, or be requested
|
||||||
if (!options.force && (type === 'block' || type === 'filtered'))
|
// if (!options.force && (type === 'block' || type === 'filtered'))
|
||||||
return this.chain.has(hash, true, next);
|
// return this.chain.has(hash, true, next);
|
||||||
|
|
||||||
return next(false);
|
return next(false);
|
||||||
};
|
};
|
||||||
@ -1021,38 +988,36 @@ Pool.prototype._doRequests = function _doRequests() {
|
|||||||
if (above && below && this.load.hiReached)
|
if (above && below && this.load.hiReached)
|
||||||
this._load();
|
this._load();
|
||||||
|
|
||||||
if (!this.options.fullNode) {
|
if (this.options.fullNode) {
|
||||||
mapReq = function(item) {
|
req = items.map(function(item) {
|
||||||
return item.start(this.peers.block[i]);
|
return item.start(this.peers.load);
|
||||||
};
|
}, this);
|
||||||
|
|
||||||
// Split list between peers
|
this.peers.load.getData(req);
|
||||||
red = this.redundancy;
|
|
||||||
count = this.peers.block.length;
|
|
||||||
split = Math.ceil(items.length * red / count);
|
|
||||||
for (i = 0, off = 0; i < count; i += red, off += split) {
|
|
||||||
req = items.slice(off, off + split).map(mapReq, this);
|
|
||||||
for (j = 0; j < red && i + j < count; j++)
|
|
||||||
this.peers.block[i + j].getData(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
req = items.map(function(item) {
|
mapReq = function(item) {
|
||||||
return item.start(this.peers.load);
|
return item.start(this.peers.block[i]);
|
||||||
}, this);
|
};
|
||||||
|
|
||||||
this.peers.load.getData(req);
|
// Split list between peers
|
||||||
|
red = this.redundancy;
|
||||||
|
count = this.peers.block.length;
|
||||||
|
split = Math.ceil(items.length * red / count);
|
||||||
|
for (i = 0, off = 0; i < count; i += red, off += split) {
|
||||||
|
req = items.slice(off, off + split).map(mapReq, this);
|
||||||
|
for (j = 0; j < red && i + j < count; j++)
|
||||||
|
this.peers.block[i + j].getData(req);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.getBlock = function getBlock(hash, cb) {
|
Pool.prototype.getBlock = function getBlock(hash, cb) {
|
||||||
var type = this.options.fullNode ? 'block' : 'filtered';
|
this._request('block', hash, { force: true }, function(block) {
|
||||||
|
cb(null, block);
|
||||||
if (this.chain.request.add(hash, cb)) {
|
});
|
||||||
this._request(type, hash, { force: true });
|
this._scheduleRequests();
|
||||||
this._scheduleRequests();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.sendBlock = function sendBlock(block) {
|
Pool.prototype.sendBlock = function sendBlock(block) {
|
||||||
@ -1188,15 +1153,26 @@ Pool.prototype.toJSON = function toJSON() {
|
|||||||
return {
|
return {
|
||||||
v: 1,
|
v: 1,
|
||||||
type: 'pool',
|
type: 'pool',
|
||||||
chain: this.chain.toJSON()
|
chain: this.chain.toJSON(),
|
||||||
|
requests: this.request.queue.map(function(item) {
|
||||||
|
return {
|
||||||
|
type: item.type,
|
||||||
|
hash: item.hash
|
||||||
|
};
|
||||||
|
})
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.fromJSON = function fromJSON(json) {
|
Pool.prototype.fromJSON = function fromJSON(json) {
|
||||||
assert.equal(json.v, 1);
|
assert.equal(json.v, 1);
|
||||||
assert.equal(json.type, 'pool');
|
assert.equal(json.type, 'pool');
|
||||||
|
|
||||||
this.chain.fromJSON(json.chain);
|
this.chain.fromJSON(json.chain);
|
||||||
|
|
||||||
|
json.requests.forEach(function(item) {
|
||||||
|
this._request(item.type, item.hash);
|
||||||
|
}, this);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user