work on chain. check for low der sigs.
This commit is contained in:
parent
46b2983eb3
commit
575843acef
@ -223,26 +223,37 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() {
|
||||
return merkleTree[merkleTree.length - 1];
|
||||
};
|
||||
|
||||
Block.prototype._debug = function debug() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
if (!this.chain)
|
||||
return;
|
||||
|
||||
args.unshift('debug');
|
||||
|
||||
return this.chain.emit.apply(this.chain, args);
|
||||
};
|
||||
|
||||
Block.prototype._verify = function _verify() {
|
||||
var uniq = {};
|
||||
var i, tx, hash;
|
||||
|
||||
// Check proof of work
|
||||
if (!utils.testTarget(this.bits, this.hash())) {
|
||||
this.chain.emit('debug', 'Block failed POW test: %s', this.rhash);
|
||||
this._debug('Block failed POW test: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check timestamp against now + 2 hours
|
||||
if (this.ts > utils.now() + 2 * 60 * 60) {
|
||||
this.chain.emit('debug', 'Block timestamp is too high: %s', this.rhash);
|
||||
this._debug('Block timestamp is too high: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the partial merkle tree if we are a merkleblock.
|
||||
if (this.subtype === 'merkleblock') {
|
||||
if (!this._verifyPartial()) {
|
||||
this.chain.emit('debug', 'Block failed merkle test: %s', this.rhash);
|
||||
this._debug('Block failed merkle test: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -254,13 +265,13 @@ Block.prototype._verify = function _verify() {
|
||||
// Size can't be bigger than MAX_BLOCK_SIZE
|
||||
if (this.txs.length > constants.block.maxSize
|
||||
|| this.size() > constants.block.maxSize) {
|
||||
this.chain.emit('debug', 'Block is too large: %s', this.rhash);
|
||||
this._debug('Block is too large: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// First TX must be a coinbase
|
||||
if (!this.txs.length || !this.txs[0].isCoinbase()) {
|
||||
this.chain.emit('debug', 'Block has no coinbase: %s', this.rhash);
|
||||
this._debug('Block has no coinbase: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -270,14 +281,14 @@ Block.prototype._verify = function _verify() {
|
||||
|
||||
// The rest of the txs must not be coinbases
|
||||
if (i > 0 && tx.isCoinbase()) {
|
||||
this.chain.emit('debug', 'Block more than one coinbase: %s', this.rhash);
|
||||
this._debug('Block more than one coinbase: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for duplicate txids
|
||||
hash = tx.hash('hex');
|
||||
if (uniq[hash]) {
|
||||
this.chain.emit('debug', 'Block has duplicate txids: %s', this.rhash);
|
||||
this._debug('Block has duplicate txids: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
uniq[hash] = true;
|
||||
@ -285,14 +296,14 @@ Block.prototype._verify = function _verify() {
|
||||
|
||||
// Check merkle root
|
||||
if (this.getMerkleRoot() !== this.merkleRoot) {
|
||||
this.chain.emit('debug', 'Block failed merkleroot test: %s', this.rhash);
|
||||
this._debug('Block failed merkleroot test: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Block.prototype.postVerify = function postVerify() {
|
||||
Block.prototype.verifyContext = function verifyContext() {
|
||||
var flags = {};
|
||||
var sigops = 0;
|
||||
var prev, height, ts, i, j, tx, cb, input;
|
||||
@ -310,7 +321,7 @@ Block.prototype.postVerify = function postVerify() {
|
||||
|
||||
// Ensure it's not an orphan
|
||||
if (!prev) {
|
||||
this.chain.emit('debug', 'Block has no previous entry: %s', this.rhash);
|
||||
this._debug('Block has no previous entry: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -318,41 +329,41 @@ Block.prototype.postVerify = function postVerify() {
|
||||
|
||||
// Ensure the timestamp is correct
|
||||
if (this.ts <= prev.getMedianTime()) {
|
||||
this.chain.emit('debug', 'Block time is lower than median: %s', this.rhash);
|
||||
this._debug('Block time is lower than median: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the miner's target is equal to what we expect
|
||||
if (this.bits !== this.chain.target(prev, this)) {
|
||||
this.chain.emit('debug', 'Block is using wrong target: %s', this.rhash);
|
||||
this._debug('Block is using wrong target: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 2 blocks (coinbase height)
|
||||
// once the majority of blocks are using it.
|
||||
if (this.version < 2 && prev.isOutdated(2)) {
|
||||
this.chain.emit('debug', 'Block is outdated (v2): %s', this.rhash);
|
||||
this._debug('Block is outdated (v2): %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 3 blocks (sig validation)
|
||||
// once the majority of blocks are using it.
|
||||
if (this.version < 3 && prev.isOutdated(3)) {
|
||||
this.chain.emit('debug', 'Block is outdated (v3): %s', this.rhash);
|
||||
this._debug('Block is outdated (v3): %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 4 blocks (checklocktimeverify)
|
||||
// once the majority of blocks are using it.
|
||||
if (this.version < 4 && prev.isOutdated(4)) {
|
||||
this.chain.emit('debug', 'Block is outdated (v4): %s', this.rhash);
|
||||
this._debug('Block is outdated (v4): %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow version 8 blocks (locktime median past)
|
||||
// once the majority of blocks are using it.
|
||||
// if (this.version < 8 && prev.isOutdated(8)) {
|
||||
// this.chain.emit('debug', 'Block is outdated (v8): %s', this.rhash);
|
||||
// this._debug('Block is outdated (v8): %s', this.rhash);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
@ -362,13 +373,13 @@ Block.prototype.postVerify = function postVerify() {
|
||||
|
||||
// Make sure the coinbase is parseable.
|
||||
if (!cb) {
|
||||
this.chain.emit('debug', 'Block has malformed coinbase: %s', this.rhash);
|
||||
this._debug('Block has malformed coinbase: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure coinbase height is equal to the actual height.
|
||||
if (cb.height !== height) {
|
||||
this.chain.emit('debug', 'Block has bad coinbase height: %s', this.rhash);
|
||||
this._debug('Block has bad coinbase height: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -406,7 +417,7 @@ Block.prototype.postVerify = function postVerify() {
|
||||
// Transactions must be finalized with
|
||||
// regards to nSequence and nLockTime.
|
||||
if (!tx.isFinal(height, ts)) {
|
||||
this.chain.emit('debug', 'TX is not final: %s (%s)', this.rhash, i);
|
||||
this._debug('TX is not final: %s (%s)', this.rhash, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -416,7 +427,7 @@ Block.prototype.postVerify = function postVerify() {
|
||||
// if (tx.sigops(true) > constants.script.maxTxSigops) {
|
||||
// // Block 71036 abused checksig to
|
||||
// // include a huge number of sigops.
|
||||
// this.chain.emit('debug', 'Block TX has too many sigops: %s', this.rhash);
|
||||
// this._debug('Block TX has too many sigops: %s', this.rhash);
|
||||
// if (!(network.type === 'main' && height === 71036))
|
||||
// return false;
|
||||
// }
|
||||
@ -430,7 +441,7 @@ Block.prototype.postVerify = function postVerify() {
|
||||
sigops += tx.sigops();
|
||||
|
||||
if (sigops > constants.script.maxBlockSigops) {
|
||||
this.chain.emit('debug', 'Block has too many sigops: %s', this.rhash);
|
||||
this._debug('Block has too many sigops: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -439,7 +450,7 @@ Block.prototype.postVerify = function postVerify() {
|
||||
// Blocks 91842 and 91880 created duplicate
|
||||
// txids by using the same exact output script
|
||||
// and extraNonce.
|
||||
this.chain.emit('debug', 'Block is overwriting txids: %s', this.rhash);
|
||||
this._debug('Block is overwriting txids: %s', this.rhash);
|
||||
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
|
||||
return false;
|
||||
}
|
||||
@ -461,13 +472,13 @@ Block.prototype.postVerify = function postVerify() {
|
||||
|
||||
// Verify the script
|
||||
if (!tx.verify(j, true, flags)) {
|
||||
this.chain.emit('debug', 'Block has invalid inputs: %s', this.rhash);
|
||||
this._debug('Block has invalid inputs: %s', this.rhash);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure tx is not double spending an output
|
||||
// if (this.chain.isSpent(input.out.hash, input.out.index)) {
|
||||
// this.chain.emit('debug', 'Block is using spent inputs: %s', this.rhash);
|
||||
// this._debug('Block is using spent inputs: %s', this.rhash);
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
|
||||
@ -179,12 +179,6 @@ Chain.prototype._addIndex = function _addIndex(entry, save) {
|
||||
// could be used if you want to be on the overly
|
||||
// safe (see: paranoid) side.
|
||||
// this.resetLastCheckpoint(entry.height);
|
||||
this.emit('fork', {
|
||||
height: entry.height,
|
||||
expected: checkpoint,
|
||||
received: entry.hash,
|
||||
checkpoint: true
|
||||
});
|
||||
return Chain.codes.badCheckpoint;
|
||||
}
|
||||
}
|
||||
@ -294,18 +288,26 @@ Chain.prototype.add = function add(block, peer) {
|
||||
var total = 0;
|
||||
|
||||
for (;;) {
|
||||
hash = block.hash('hex');
|
||||
prevHash = block.prevBlock;
|
||||
|
||||
// Find the previous block height/index.
|
||||
prevHeight = this.index.heights[prevHash];
|
||||
|
||||
// Validate the block we want to add.
|
||||
// This is only necessary for new
|
||||
// blocks coming in, not the resolving
|
||||
// orphans.
|
||||
if (block === initial && !block.verify()) {
|
||||
code = Chain.codes.invalid;
|
||||
this.emit('invalid', {
|
||||
height: prevHeight + 1,
|
||||
hash: hash,
|
||||
peer: peer
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
hash = block.hash('hex');
|
||||
prevHash = block.prevBlock;
|
||||
|
||||
// If the block is already known to be
|
||||
// an orphan, ignore it.
|
||||
if (this.orphan.map[prevHash]) {
|
||||
@ -320,7 +322,8 @@ Chain.prototype.add = function add(block, peer) {
|
||||
height: -1,
|
||||
expected: this.orphan.map[prevHash].hash('hex'),
|
||||
received: hash,
|
||||
checkpoint: null
|
||||
checkpoint: null,
|
||||
peer: peer
|
||||
});
|
||||
code = Chain.codes.forked;
|
||||
break;
|
||||
@ -329,9 +332,6 @@ Chain.prototype.add = function add(block, peer) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the previous block height/index.
|
||||
prevHeight = this.index.heights[prevHash];
|
||||
|
||||
// If previous block wasn't ever seen,
|
||||
// add it current to orphans and break.
|
||||
if (prevHeight == null) {
|
||||
@ -344,6 +344,7 @@ Chain.prototype.add = function add(block, peer) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a new chain entry.
|
||||
entry = new ChainBlock(this, {
|
||||
hash: hash,
|
||||
version: block.version,
|
||||
@ -381,8 +382,9 @@ Chain.prototype.add = function add(block, peer) {
|
||||
this.emit('fork', {
|
||||
height: prevHeight + 1,
|
||||
expected: tip.hash,
|
||||
received: entry.hash,
|
||||
checkpoint: null
|
||||
received: hash,
|
||||
checkpoint: null,
|
||||
peer: peer
|
||||
});
|
||||
code = Chain.codes.forked;
|
||||
break;
|
||||
@ -391,10 +393,13 @@ Chain.prototype.add = function add(block, peer) {
|
||||
// Do "contextual" verification on our block
|
||||
// now that we're certain its previous
|
||||
// block is in the chain.
|
||||
// if (0)
|
||||
if (!block.postVerify()) {
|
||||
throw new Error;
|
||||
if (!block.verifyContext()) {
|
||||
code = Chain.codes.invalid;
|
||||
this.emit('invalid', {
|
||||
height: prevHeight + 1,
|
||||
hash: hash,
|
||||
peer: peer
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@ -412,6 +417,19 @@ Chain.prototype.add = function add(block, peer) {
|
||||
// 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 (code === Chain.codes.badCheckpoint) {
|
||||
this.emit('fork', {
|
||||
height: entry.height,
|
||||
expected: network.checkpoints[entry.height],
|
||||
received: entry.hash,
|
||||
checkpoint: true,
|
||||
peer: peer
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// Should never happen, but... something
|
||||
// went wrong. Ignore this block.
|
||||
if (code !== Chain.codes.okay)
|
||||
break;
|
||||
|
||||
|
||||
@ -177,20 +177,35 @@ Pool.prototype._init = function _init() {
|
||||
});
|
||||
|
||||
this.chain.on('fork', function(data) {
|
||||
var peer = self.peers.load;
|
||||
|
||||
this.emit('debug',
|
||||
'Fork at height %d: expected=%s received=%s checkpoint=%s',
|
||||
self.emit('debug',
|
||||
'Fork at height %d: expected=%s received=%s checkpoint=%s peer=%s',
|
||||
data.height,
|
||||
utils.revHex(data.expected),
|
||||
utils.revHex(data.received),
|
||||
data.checkpoint
|
||||
data.checkpoint,
|
||||
data.peer ? data.peer.host : ''
|
||||
);
|
||||
|
||||
if (!peer)
|
||||
if (!data.peer)
|
||||
return;
|
||||
|
||||
peer.destroy();
|
||||
data.peer.destroy();
|
||||
});
|
||||
|
||||
this.chain.on('invalid', function(data) {
|
||||
self.emit('debug',
|
||||
'Invalid block at height: %d: hash=%s peer=%s',
|
||||
data.height,
|
||||
utils.revHex(data.hash),
|
||||
data.peer ? data.peer.host : ''
|
||||
);
|
||||
|
||||
if (!data.peer)
|
||||
return;
|
||||
|
||||
// We should technically use a ban score
|
||||
// here instead of killing the peer.
|
||||
data.peer.destroy();
|
||||
});
|
||||
|
||||
this.options.wallets.forEach(function(w) {
|
||||
|
||||
@ -791,6 +791,8 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
||||
if (flags.strictder !== false) {
|
||||
if (!script.isValidSignature(sig))
|
||||
return false;
|
||||
if (!script.isLowDER(sig))
|
||||
return false;
|
||||
}
|
||||
|
||||
type = sig[sig.length - 1];
|
||||
@ -860,6 +862,8 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
|
||||
if (flags.strictder !== false) {
|
||||
if (!script.isValidSignature(sig))
|
||||
return false;
|
||||
if (!script.isLowDER(sig))
|
||||
return false;
|
||||
}
|
||||
|
||||
type = sig[sig.length - 1];
|
||||
|
||||
@ -1085,7 +1085,7 @@ TX.prototype.fill = function fill(txs) {
|
||||
return inputs.length === this.inputs.length;
|
||||
};
|
||||
|
||||
// Used for postVerify/ContextualBlockCheck and miner isFinalTx call.
|
||||
// Used for verifyContext/ContextualBlockCheck and miner isFinalTx call.
|
||||
// BIP113 will require that time-locked transactions have nLockTime set to
|
||||
// less than the median time of the previous block they're contained in.
|
||||
TX.prototype.isFinalBlock = function isFinalBlock(block, prev, useMedian) {
|
||||
@ -1096,17 +1096,29 @@ TX.prototype.isFinalBlock = function isFinalBlock(block, prev, useMedian) {
|
||||
|
||||
// Used in AcceptToMemoryPool
|
||||
TX.prototype.isFinalMempool = function isFinalMempool(useMedian) {
|
||||
var height = this.chain.height() + 1;
|
||||
var ts = useMedian
|
||||
var height, ts;
|
||||
|
||||
if (!this.chain)
|
||||
return true;
|
||||
|
||||
height = this.chain.height() + 1;
|
||||
ts = useMedian
|
||||
? this.chain.getTip().getMedianTime()
|
||||
: utils.now();
|
||||
|
||||
return this.isFinal(height, ts);
|
||||
};
|
||||
|
||||
// Used in the original bitcoind code for AcceptBlock
|
||||
TX.prototype.isFinalLegacy = function isFinalLegacy(block) {
|
||||
var ts = block ? block.ts : utils.now();
|
||||
var height = this.chain.height();
|
||||
var ts, height;
|
||||
|
||||
if (!this.chain)
|
||||
return true;
|
||||
|
||||
ts = block ? block.ts : utils.now();
|
||||
height = this.chain.height();
|
||||
|
||||
return this.isFinal(height, ts);
|
||||
};
|
||||
|
||||
|
||||
@ -22,6 +22,10 @@ pool.on('error', function(err) {
|
||||
utils.print('Error: %s', err.message);
|
||||
});
|
||||
|
||||
pool.on('debug', function() {
|
||||
utils.print.apply(utils, arguments);
|
||||
});
|
||||
|
||||
console.log('Updating bcoin preloaded chain...');
|
||||
|
||||
pool.on('block', function(block) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user