keep all pending blocks off the heap.

This commit is contained in:
Christopher Jeffrey 2016-02-24 20:05:06 -08:00
parent 41c84c1937
commit 4cea71fe65
5 changed files with 141 additions and 25 deletions

View File

@ -68,6 +68,7 @@ bcoin.tx = require('./bcoin/tx');
bcoin.mtx = require('./bcoin/mtx');
bcoin.txpool = require('./bcoin/tx-pool');
bcoin.abstractblock = require('./bcoin/abstractblock');
bcoin.compactblock = require('./bcoin/compactblock');
bcoin.block = require('./bcoin/block');
bcoin.merkleblock = require('./bcoin/merkleblock');
bcoin.headers = require('./bcoin/headers');

View File

@ -456,6 +456,9 @@ Chain.prototype._verify = function _verify(block, prev) {
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
var height, ts, i, tx, cb, coinbaseHeight, medianTime, locktimeMedian;
if (!block.verify())
return flags;
// Skip the genesis block
if (block.isGenesis())
return flags;
@ -1018,7 +1021,7 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
(function next(block) {
var hash = block.hash('hex');
var prevHash = block.prevBlock;
var prevHeight, height, entry, checkpoint, prev, orphan;
var prevHeight, height, checkpoint, prev, orphan;
// Find the previous block height/index.
prevHeight = self.db.getHeight(prevHash);
@ -1115,24 +1118,12 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
return done();
}
// Create a new chain entry.
entry = new bcoin.chainblock(self, {
hash: hash,
version: block.version,
prevBlock: prevHash,
merkleRoot: block.merkleRoot,
ts: block.ts,
bits: block.bits,
nonce: block.nonce,
height: prevHeight + 1
});
// Verify the checkpoint.
checkpoint = network.checkpoints[entry.height];
checkpoint = network.checkpoints[height];
if (checkpoint) {
self.emit('checkpoint', block, {
height: entry.height,
hash: entry.hash,
height: height,
hash: hash,
checkpoint: checkpoint
}, peer);
@ -1142,14 +1133,14 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
// so we don't do it. The misbehaving peer has
// been killed and hopefully we find a peer
// who isn't trying to fool us.
if (entry.hash !== checkpoint) {
if (hash !== checkpoint) {
self.purgeOrphans();
self.purgePending();
self.emit('fork', block, {
height: entry.height,
height: height,
expected: checkpoint,
received: entry.hash,
received: hash,
checkpoint: true
}, peer);
@ -1171,26 +1162,46 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
assert(prev);
if (block.type === 'compactblock') {
block = block.toBlock(peer);
if (!block)
return done(new Error('Failed to parse block.'));
if (block._raw === initial._raw)
initial = block;
}
// Do "contextual" verification on our block
// now that we're certain its previous
// block is in the chain.
self._verifyContext(block, prev, function(err, verified) {
var existing;
var entry, existing;
if (err)
return done(err);
if (!verified) {
self.invalid[entry.hash] = true;
self.invalid[hash] = true;
self.emit('invalid', block, {
height: entry.height,
hash: entry.hash,
height: height,
hash: hash,
seen: false,
chain: false
}, peer);
return done();
}
// Create a new chain entry.
entry = new bcoin.chainblock(self, {
hash: hash,
version: block.version,
prevBlock: block.prevBlock,
merkleRoot: block.merkleRoot,
ts: block.ts,
bits: block.bits,
nonce: block.nonce,
height: height
});
// Real fork resolution would just be this.
// if (entry.chainwork.cmp(self.tip.chainwork) > 0)
// return self.setBestChain(entry);

51
lib/bcoin/compactblock.js Normal file
View File

@ -0,0 +1,51 @@
/**
* compactblock.js - compact block object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* https://github.com/indutny/bcoin
*/
var bcoin = require('../bcoin');
var bn = require('bn.js');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var network = bcoin.protocol.network;
/**
* CompactBlock
*/
function CompactBlock(data) {
var self = this;
if (!(this instanceof CompactBlock))
return new CompactBlock(data);
bcoin.abstractblock.call(this, data);
this.type = 'compactblock';
this.coinbaseHeight = data.coinbaseHeight;
}
utils.inherits(CompactBlock, bcoin.abstractblock);
CompactBlock.prototype._verify = function _verify() {
return this.verifyHeaders();
};
CompactBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
return this.coinbaseHeight;
};
CompactBlock.prototype.toBlock = function toBlock(peer) {
var block = peer.parser.parseBlock(this._raw);
if (!block)
return;
return new bcoin.block(block);
};
/**
* Expose
*/
module.exports = CompactBlock;

View File

@ -415,7 +415,7 @@ Peer.prototype._onPacket = function onPacket(packet) {
return this._handleReject(payload);
if (cmd === 'block') {
payload = bcoin.block(payload);
payload = bcoin.compactblock(payload);
} else if (cmd === 'merkleblock') {
payload = bcoin.merkleblock(payload);
this.lastBlock = payload;

View File

@ -123,8 +123,11 @@ Parser.prototype.parsePayload = function parsePayload(cmd, p) {
if (cmd === 'headers')
return this.parseHeaders(p);
// if (cmd === 'block')
// return this.parseBlock(p);
if (cmd === 'block')
return this.parseBlock(p);
return this.parseBlockCompact(p);
if (cmd === 'tx')
return this.parseTX(p);
@ -358,6 +361,56 @@ Parser.prototype.parseBlock = function parseBlock(p) {
};
};
Parser.prototype.parseBlockCompact = function parseBlockCompact(p) {
var height = -1;
var i, result, off, totalTX, tx;
var inCount, input, s, version;
if (p.length < 81)
return this._error('Invalid block size');
version = utils.read32(p, 0);
result = utils.readIntv(p, 80);
off = result.off;
totalTX = result.r;
if (version > 1 && totalTX > 0) {
if (p.length < off + 10)
return this._error('Invalid tx size');
inCount = utils.readIntv(p, off + 4);
off = inCount.off;
inCount = inCount.r;
if (inCount > 0) {
input = this.parseInput(p.slice(off));
if (!input)
return this._error('Invalid tx count for block');
}
}
if (input) {
s = bcoin.script.decode(input.script);
if (Buffer.isBuffer(s[0]))
height = bcoin.script.num(s[0], true);
}
return {
version: version,
prevBlock: p.slice(4, 36),
merkleRoot: p.slice(36, 68),
ts: utils.readU32(p, 68),
bits: utils.readU32(p, 72),
nonce: utils.readU32(p, 76),
totalTX: totalTX,
coinbaseHeight: height,
txs: [],
_raw: p,
_size: p.length
};
};
Parser.prototype.parseInput = function parseInput(p) {
var scriptLen, off;