chain: do not consider potentially malleated blocks invalid.

This commit is contained in:
Christopher Jeffrey 2016-10-20 12:42:05 -07:00
parent 9dfe86e612
commit 8e1b2ea8e9
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -285,13 +285,27 @@ Chain.prototype.isGenesis = function isGenesis(block) {
Chain.prototype.verify = co(function* verify(block, prev) { Chain.prototype.verify = co(function* verify(block, prev) {
var ret = new VerifyResult(); var ret = new VerifyResult();
var i, height, ts, tx, medianTime, commitmentHash, ancestors, state; var i, err, height, ts, tx, medianTime;
var commitmentHash, ancestors, state;
if (!block.verify(ret)) { if (!block.verify(ret)) {
throw new VerifyError(block, err = new VerifyError(block,
'invalid', 'invalid',
ret.reason, ret.reason,
ret.score); ret.score);
// High hash is the only thing an
// adversary couldn't mutate in
// otherwise valid non-contextual
// checks. The block timestamp
// can't be mutated, but our
// adjusted time might be off.
// We may be able to accept the
// block later.
if (ret.reason !== 'high-hash')
err.malleated = true;
throw err;
} }
// Skip the genesis block. Skip all blocks in spv mode. // Skip the genesis block. Skip all blocks in spv mode.
@ -349,17 +363,28 @@ Chain.prototype.verify = co(function* verify(block, prev) {
if (state.hasWitness()) { if (state.hasWitness()) {
commitmentHash = block.commitmentHash; commitmentHash = block.commitmentHash;
if (commitmentHash) { if (commitmentHash) {
// These are totally malleable. Someone
// may have even accidentally sent us
// the non-witness version of the block.
// We don't want to consider this block
// "invalid" if either of these checks
// fail.
if (!block.witnessNonce) { if (!block.witnessNonce) {
throw new VerifyError(block, err = new VerifyError(block,
'invalid', 'invalid',
'bad-witness-merkle-size', 'bad-witness-merkle-size',
100); 100);
err.malleated = true;
throw err;
} }
if (commitmentHash !== block.getCommitmentHash('hex')) { if (commitmentHash !== block.getCommitmentHash('hex')) {
throw new VerifyError(block, err = new VerifyError(block,
'invalid', 'invalid',
'bad-witness-merkle-match', 'bad-witness-merkle-match',
100); 100);
err.malleated = true;
throw err;
} }
} }
} }
@ -368,10 +393,12 @@ Chain.prototype.verify = co(function* verify(block, prev) {
// witness data cannot contain it. // witness data cannot contain it.
if (!commitmentHash) { if (!commitmentHash) {
if (block.hasWitness()) { if (block.hasWitness()) {
throw new VerifyError(block, err = new VerifyError(block,
'invalid', 'invalid',
'unexpected-witness', 'unexpected-witness',
100); 100);
err.malleated = true;
throw err;
} }
} }
@ -842,7 +869,8 @@ Chain.prototype.reconnect = co(function* reconnect(entry) {
view = yield this.verifyContext(block, prev); view = yield this.verifyContext(block, prev);
} catch (e) { } catch (e) {
if (e.type === 'VerifyError') { if (e.type === 'VerifyError') {
this.invalid[entry.hash] = true; if (!e.malleated)
this.invalid[entry.hash] = true;
this.emit('invalid', block, entry.height); this.emit('invalid', block, entry.height);
} }
throw e; throw e;
@ -897,7 +925,8 @@ Chain.prototype.setBestChain = co(function* setBestChain(entry, block, prev) {
block.setHeight(-1); block.setHeight(-1);
if (e.type === 'VerifyError') { if (e.type === 'VerifyError') {
this.invalid[entry.hash] = true; if (!e.malleated)
this.invalid[entry.hash] = true;
this.emit('invalid', block, entry.height); this.emit('invalid', block, entry.height);
} }
@ -1082,7 +1111,8 @@ Chain.prototype._add = co(function* add(block) {
// blocks coming in, not the resolving // blocks coming in, not the resolving
// orphans. // orphans.
if (initial && !block.verify(ret)) { if (initial && !block.verify(ret)) {
this.invalid[hash] = true; if (ret.reason === 'high-hash')
this.invalid[hash] = true;
this.emit('invalid', block, block.getCoinbaseHeight()); this.emit('invalid', block, block.getCoinbaseHeight());
throw new VerifyError(block, 'invalid', ret.reason, ret.score); throw new VerifyError(block, 'invalid', ret.reason, ret.score);
} }