refactor.

This commit is contained in:
Christopher Jeffrey 2016-04-04 14:07:16 -07:00
parent 79aa613662
commit 9e61d0ee86
7 changed files with 97 additions and 104 deletions

View File

@ -419,7 +419,7 @@ Block.prototype.toCompact = function toCompact() {
p.writeVarint(this.txs.length); p.writeVarint(this.txs.length);
this.txs.forEach(function(tx) { this.txs.forEach(function(tx) {
p.writeBytes(tx.hash()); p.writeHash(tx.hash());
}); });
return p.render(); return p.render();

View File

@ -43,6 +43,7 @@ function Chain(node, options) {
this.tip = null; this.tip = null;
this.height = -1; this.height = -1;
this.segwitActive = null; this.segwitActive = null;
this.spv = !!options.spv;
this.orphan = { this.orphan = {
map: {}, map: {},
@ -241,7 +242,7 @@ Chain.prototype._preload = function _preload(callback) {
if (!this.options.preload) if (!this.options.preload)
return callback(); return callback();
if (!this.options.spv) if (!this.spv)
return callback(); return callback();
if (network.type !== 'main') if (network.type !== 'main')
@ -478,7 +479,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
// Only allow version 5 blocks (segwit) // Only allow version 5 blocks (segwit)
// once the majority of blocks are using it. // once the majority of blocks are using it.
if (network.segwitHeight !== -1 && height >= network.segwitHeight) { if (network.type === 'segnet3' && height >= network.segwitHeight) {
if (block.version < 5 && prev.isOutdated(5)) if (block.version < 5 && prev.isOutdated(5))
return done(new VerifyError(block, 'obsolete', 'bad-version', 0)); return done(new VerifyError(block, 'obsolete', 'bad-version', 0));
} }
@ -591,7 +592,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
var self = this; var self = this;
var height = prev.height + 1; var height = prev.height + 1;
if (this.options.spv || block.type !== 'block') if (this.spv || block.type !== 'block')
return callback(); return callback();
if (block.isGenesis()) if (block.isGenesis())
@ -628,7 +629,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
var scriptCheck = true; var scriptCheck = true;
var historical = false; var historical = false;
if (this.options.spv || block.type !== 'block') if (this.spv || block.type !== 'block')
return callback(); return callback();
if (block.isGenesis()) if (block.isGenesis())
@ -1551,31 +1552,7 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) {
start = start.hash('hex'); start = start.hash('hex');
} }
function getTop(callback) { function build(err, top) {
if (typeof start === 'string') {
return self.db.getHeight(start, function(err, top) {
if (err)
return callback(err);
if (top === -1) {
// We could simply `return [start]` here,
// but there is no standardized "spacing"
// for locator hashes. Pretend this hash
// is our tip. This is useful for getheaders
// when not using headers-first.
hashes.push(start);
top = self.height;
}
return callback(null, top);
});
} else if (typeof start === 'number') {
top = start;
}
return callback(null, top);
}
return getTop(function(err, top) {
if (err) if (err)
return callback(err); return callback(err);
@ -1611,7 +1588,31 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) {
return callback(err); return callback(err);
return callback(null, hashes); return callback(null, hashes);
}); });
}); }
if (typeof start === 'string') {
return self.db.getHeight(start, function(err, top) {
if (err)
return build(err);
if (top === -1) {
// We could simply `return [start]` here,
// but there is no standardized "spacing"
// for locator hashes. Pretend this hash
// is our tip. This is useful for getheaders
// when not using headers-first.
hashes.push(start);
top = self.height;
}
return build(null, top);
});
}
if (typeof start === 'number')
top = start;
return build(null, top);
}; };
Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) { Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) {
@ -1662,7 +1663,7 @@ Chain.prototype.getTargetAsync = function getTargetAsync(last, block, callback)
Chain.prototype.getTarget = function getTarget(last, block, ancestors) { Chain.prototype.getTarget = function getTarget(last, block, ancestors) {
var powLimit = utils.toCompact(network.powLimit); var powLimit = utils.toCompact(network.powLimit);
var ts, first, i, prev; var ts, first, i;
// Genesis // Genesis
if (!last) if (!last)
@ -1680,14 +1681,11 @@ Chain.prototype.getTarget = function getTarget(last, block, ancestors) {
return powLimit; return powLimit;
i = 1; i = 1;
prev = ancestors; while (ancestors[i]
while (prev[i]
&& last.height % network.powDiffInterval !== 0 && last.height % network.powDiffInterval !== 0
&& last.bits === powLimit) { && last.bits === powLimit) {
last = prev[i++]; last = ancestors[i++];
} }
return last.bits;
} }
return last.bits; return last.bits;
} }
@ -1744,7 +1742,6 @@ Chain.prototype.findLocator = function findLocator(locator, callback) {
}, callback); }, callback);
}; };
// https://github.com/bitcoin/bitcoin/pull/7648/files
Chain.prototype.getState = function getState(prev, id, callback) { Chain.prototype.getState = function getState(prev, id, callback) {
var self = this; var self = this;
var period = network.minerConfirmationWindow; var period = network.minerConfirmationWindow;
@ -1957,15 +1954,15 @@ Chain.prototype.isSegwitActive = function isSegwitActive(callback, force) {
if (err) if (err)
return callback(err); return callback(err);
if (!prev.isUpgraded(5)) { if (self.tip.version >= 5 && prev.isUpgraded(5)) {
prev.free(); prev.free();
self.segwitActive = false; self.segwitActive = true;
return callback(null, false); return callback(null, true);
} }
prev.free(); prev.free();
self.segwitActive = true; self.segwitActive = false;
return callback(null, true); return callback(null, false);
}); });
}); });
}; };

View File

@ -39,6 +39,7 @@ function ChainDB(chain, options) {
this.keepBlocks = options.keepBlocks || 288; this.keepBlocks = options.keepBlocks || 288;
this.prune = !!options.prune; this.prune = !!options.prune;
this.spv = !!options.spv;
// Need to cache up to the retarget interval // Need to cache up to the retarget interval
// if we're going to be checking the damn // if we're going to be checking the damn
@ -65,8 +66,8 @@ ChainDB.prototype._init = function _init() {
if (this.loaded) if (this.loaded)
return; return;
this.db = bcoin.ldb((this.options.spv ? 'spv' : '') + 'chain', { this.db = bcoin.ldb(this.spv ? 'spvchain' : 'chain', {
compression: false, compression: true,
cacheSize: 16 << 20, cacheSize: 16 << 20,
writeBufferSize: 8 << 20 writeBufferSize: 8 << 20
}); });
@ -577,7 +578,7 @@ ChainDB.prototype.has = function has(height, callback) {
}; };
ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback) { ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback) {
if (this.options.spv) if (this.spv)
return utils.nextTick(callback); return utils.nextTick(callback);
batch.put('b/b/' + block.hash('hex'), block.toCompact()); batch.put('b/b/' + block.hash('hex'), block.toCompact());
@ -595,7 +596,7 @@ ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback
ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) { ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
var self = this; var self = this;
if (this.options.spv) if (this.spv)
return utils.nextTick(callback); return utils.nextTick(callback);
this._ensureHistory(hash, function(err, block) { this._ensureHistory(hash, function(err, block) {
@ -618,7 +619,7 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) { ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
var self = this; var self = this;
if (this.options.spv) { if (this.spv) {
self.emit('add block', block); self.emit('add block', block);
return utils.nextTick(callback); return utils.nextTick(callback);
} }
@ -689,7 +690,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callback) { ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callback) {
var self = this; var self = this;
if (this.options.spv) if (this.spv)
return utils.nextTick(callback); return utils.nextTick(callback);
this._ensureHistory(hash, function(err, block) { this._ensureHistory(hash, function(err, block) {
@ -699,8 +700,10 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
if (!block) if (!block)
return callback(); return callback();
if (typeof hash === 'string') if (self.options.paranoid) {
assert(block.hash('hex') === hash); if (typeof hash === 'string')
assert(block.hash('hex') === hash, 'Database is corrupt.');
}
block.txs.forEach(function(tx) { block.txs.forEach(function(tx) {
var hash = tx.hash('hex'); var hash = tx.hash('hex');
@ -1040,8 +1043,8 @@ ChainDB.prototype.getTX = function getTX(hash, callback) {
return callback(e); return callback(e);
} }
if (self.options.paranoid && tx.hash('hex') !== hash) if (self.options.paranoid)
return callback(new Error('ChainDB is corrupt. All is lost.')); assert(tx.hash('hex') === hash, 'Database is corrupt.');
return callback(null, tx); return callback(null, tx);
}); });
@ -1234,6 +1237,10 @@ ChainDB.prototype.getBlock = function getBlock(hash, callback) {
delete block.hashes; delete block.hashes;
block = new bcoin.block(block); block = new bcoin.block(block);
if (self.options.paranoid)
assert(block.hash('hex') === hash, 'Database is corrupt.');
return callback(null, block); return callback(null, block);
}); });
}); });
@ -1251,8 +1258,9 @@ ChainDB.prototype._getTX = function _getTX(hash, callback) {
ChainDB.prototype.isUnspentTX = function isUnspentTX(hash, callback) { ChainDB.prototype.isUnspentTX = function isUnspentTX(hash, callback) {
return callback(null, false); return callback(null, false);
if (this.options.spv) if (this.spv)
return callback(null, false); return callback(null, false);
return this.isSpentTX(hash, function(err, spent) { return this.isSpentTX(hash, function(err, spent) {
if (err) if (err)
return callback(err); return callback(err);
@ -1292,7 +1300,7 @@ ChainDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) { ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
var futureHeight; var futureHeight;
if (this.options.spv) if (this.spv)
return callback(); return callback();
if (!this.prune) if (!this.prune)

View File

@ -268,7 +268,7 @@ Miner.prototype.createBlock = function createBlock(callback) {
// Set up the witness nonce and // Set up the witness nonce and
// commitment output for segwit. // commitment output for segwit.
block.witness = true; block.witness = true;
block.witnessNonce = utils.nonce().toBuffer(); block.witnessNonce = utils.nonce().toBuffer('le', 8);
coinbase.inputs[0].witness.items[0] = block.witnessNonce; coinbase.inputs[0].witness.items[0] = block.witnessNonce;
coinbase.addOutput({ coinbase.addOutput({
script: new bcoin.script([]), script: new bcoin.script([]),

View File

@ -47,6 +47,7 @@ function Peer(pool, options) {
this.haveWitness = false; this.haveWitness = false;
this.hashContinue = null; this.hashContinue = null;
this.filter = null; this.filter = null;
this.relay = true;
this.challenge = null; this.challenge = null;
this.lastPong = 0; this.lastPong = 0;
@ -229,7 +230,7 @@ Peer.prototype.broadcast = function broadcast(items) {
var result = []; var result = [];
var payload = []; var payload = [];
if (this.version && this.version.relay === false) if (!this.relay)
return; return;
if (this.destroyed) if (this.destroyed)
@ -522,24 +523,19 @@ Peer.prototype._handleFilterLoad = function _handleFilterLoad(payload) {
this.filter = new bcoin.bloom(size, payload.n, payload.tweak); this.filter = new bcoin.bloom(size, payload.n, payload.tweak);
this.filter.filter = payload.filter; this.filter.filter = payload.filter;
this.filter.update = payload.update; this.filter.update = payload.update;
if (this.version) this.relay = true;
this.version.relay = true;
}; };
Peer.prototype._handleFilterAdd = function _handleFilterAdd(payload) { Peer.prototype._handleFilterAdd = function _handleFilterAdd(payload) {
if (this.filter) if (this.filter)
this.filter.add(payload.data); this.filter.add(payload.data);
this.relay = true;
if (this.version)
this.version.relay = true;
}; };
Peer.prototype._handleFilterClear = function _handleFilterClear(payload) { Peer.prototype._handleFilterClear = function _handleFilterClear(payload) {
if (this.filter) if (this.filter)
this.filter.reset(); this.filter.reset();
this.relay = true;
if (this.version)
this.version.relay = true;
}; };
Peer.prototype._handleUTXOs = function _handleUTXOs(payload) { Peer.prototype._handleUTXOs = function _handleUTXOs(payload) {
@ -795,6 +791,9 @@ Peer.prototype._handleVersion = function handleVersion(payload) {
if (payload.witness) if (payload.witness)
this.haveWitness = true; this.haveWitness = true;
if (payload.relay === false)
this.relay = false;
// ACK // ACK
this._write(this.framer.verack()); this._write(this.framer.verack());
this.version = payload; this.version = payload;

View File

@ -642,7 +642,7 @@ Framer.merkleBlock = function _merkleBlock(block, writer) {
var p = new BufferWriter(writer); var p = new BufferWriter(writer);
var i; var i;
p.write32(block.version); p.writeU32(block.version);
p.writeHash(block.prevBlock); p.writeHash(block.prevBlock);
p.writeHash(block.merkleRoot); p.writeHash(block.merkleRoot);
p.writeU32(block.ts); p.writeU32(block.ts);

View File

@ -375,8 +375,6 @@ Parser.parseVersion = function parseVersion(p) {
assert(ts >= 0, 'Timestamp is negative.'); assert(ts >= 0, 'Timestamp is negative.');
assert(height >= 0, 'Height is negative.'); assert(height >= 0, 'Height is negative.');
this.version = version;
return { return {
version: version, version: version,
services: services, services: services,
@ -476,7 +474,7 @@ Parser.parseMerkleBlock = function parseMerkleBlock(p) {
p = new BufferReader(p); p = new BufferReader(p);
p.start(); p.start();
version = p.readU32(); // Technically signed version = p.readU32();
prevBlock = p.readHash(); prevBlock = p.readHash();
merkleRoot = p.readHash(); merkleRoot = p.readHash();
ts = p.readU32(); ts = p.readU32();
@ -735,8 +733,8 @@ Parser.parseCoin = function parseCoin(p, extended) {
}; };
Parser.parseTX = function parseTX(p) { Parser.parseTX = function parseTX(p) {
var inCount, txIn, tx; var inCount, inputs;
var outCount, txOut; var outCount, outputs;
var version, locktime, i; var version, locktime, i;
var raw; var raw;
@ -749,20 +747,16 @@ Parser.parseTX = function parseTX(p) {
version = p.readU32(); // Technically signed version = p.readU32(); // Technically signed
inCount = p.readVarint(); inCount = p.readVarint();
txIn = new Array(inCount); inputs = new Array(inCount);
for (i = 0; i < inCount; i++) { for (i = 0; i < inCount; i++) {
tx = Parser.parseInput(p); inputs[i] = Parser.parseInput(p);
inputs[i].witness = { items: [] };
txIn[i] = tx;
txIn[i].witness = { items: [] };
} }
outCount = p.readVarint(); outCount = p.readVarint();
txOut = new Array(outCount); outputs = new Array(outCount);
for (i = 0; i < outCount; i++) { for (i = 0; i < outCount; i++)
tx = Parser.parseOutput(p); outputs[i] = Parser.parseOutput(p);
txOut[i] = tx;
}
locktime = p.readU32(); locktime = p.readU32();
@ -771,8 +765,8 @@ Parser.parseTX = function parseTX(p) {
return { return {
version: version, version: version,
flag: 1, flag: 1,
inputs: txIn, inputs: inputs,
outputs: txOut, outputs: outputs,
locktime: locktime, locktime: locktime,
_witnessSize: 0, _witnessSize: 0,
_raw: raw, _raw: raw,
@ -796,8 +790,8 @@ Parser.isWitnessTX = function isWitnessTX(p) {
}; };
Parser.parseWitnessTX = function parseWitnessTX(p) { Parser.parseWitnessTX = function parseWitnessTX(p) {
var inCount, txIn, tx; var inCount, inputs, witness;
var outCount, txOut; var outCount, outputs;
var marker, flag; var marker, flag;
var version, locktime, i; var version, locktime, i;
var witnessSize = 0; var witnessSize = 0;
@ -819,24 +813,20 @@ Parser.parseWitnessTX = function parseWitnessTX(p) {
inCount = p.readVarint(); inCount = p.readVarint();
txIn = new Array(inCount); inputs = new Array(inCount);
for (i = 0; i < inCount; i++) { for (i = 0; i < inCount; i++)
tx = Parser.parseInput(p); inputs[i] = Parser.parseInput(p);
txIn[i] = tx;
}
outCount = p.readVarint(); outCount = p.readVarint();
txOut = new Array(outCount); outputs = new Array(outCount);
for (i = 0; i < outCount; i++) { for (i = 0; i < outCount; i++)
tx = Parser.parseOutput(p); outputs[i] = Parser.parseOutput(p);
txOut[i] = tx;
}
for (i = 0; i < inCount; i++) { for (i = 0; i < inCount; i++) {
tx = Parser.parseWitness(p); witness = Parser.parseWitness(p);
txIn[i].witness = tx; inputs[i].witness = witness;
witnessSize += tx._size; witnessSize += witness._size;
} }
locktime = p.readU32(); locktime = p.readU32();
@ -846,8 +836,8 @@ Parser.parseWitnessTX = function parseWitnessTX(p) {
return { return {
version: version, version: version,
flag: flag, flag: flag,
inputs: txIn, inputs: inputs,
outputs: txOut, outputs: outputs,
locktime: locktime, locktime: locktime,
_raw: raw, _raw: raw,
_size: raw.length, _size: raw.length,
@ -898,11 +888,10 @@ Parser.parseReject = function parseReject(p) {
ccode = p.readU8(); ccode = p.readU8();
reason = p.readVarString('ascii'); reason = p.readVarString('ascii');
try { if (p.left() >= 32)
data = p.readHash(); data = p.readHash();
} catch (e) { else
data = null; data = null;
}
return { return {
message: message, message: message,
@ -919,7 +908,7 @@ Parser.parseAddress = function parseAddress(p, full) {
p = new BufferReader(p); p = new BufferReader(p);
p.start(); p.start();
if (full && this.version >= 31402) if (full) // only version >= 31402
ts = p.readU32(); ts = p.readU32();
else else
ts = 0; ts = 0;