global debugging. script.isEncoded.

This commit is contained in:
Christopher Jeffrey 2016-01-20 12:23:40 -08:00
parent 03c117b009
commit f6dc42924b
9 changed files with 109 additions and 91 deletions

View File

@ -10,6 +10,8 @@ var bn = require('bn.js');
var hash = require('hash.js');
var async = require('async');
bcoin.debug = +process.env.BCOIN_DEBUG === 1;
bcoin.ecdsa = elliptic.ec('secp256k1');
bcoin.utils = require('./bcoin/utils');
bcoin.bloom = require('./bcoin/bloom');

View File

@ -223,37 +223,26 @@ 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._debug('Block failed POW test: %s', this.rhash);
utils.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._debug('Block timestamp is too high: %s', this.rhash);
utils.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._debug('Block failed merkle test: %s', this.rhash);
utils.debug('Block failed merkle test: %s', this.rhash);
return false;
}
}
@ -265,13 +254,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._debug('Block is too large: %s', this.rhash);
utils.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._debug('Block has no coinbase: %s', this.rhash);
utils.debug('Block has no coinbase: %s', this.rhash);
return false;
}
@ -281,14 +270,14 @@ Block.prototype._verify = function _verify() {
// The rest of the txs must not be coinbases
if (i > 0 && tx.isCoinbase()) {
this._debug('Block more than one coinbase: %s', this.rhash);
utils.debug('Block more than one coinbase: %s', this.rhash);
return false;
}
// Check for duplicate txids
hash = tx.hash('hex');
if (uniq[hash]) {
this._debug('Block has duplicate txids: %s', this.rhash);
utils.debug('Block has duplicate txids: %s', this.rhash);
return false;
}
uniq[hash] = true;
@ -296,7 +285,7 @@ Block.prototype._verify = function _verify() {
// Check merkle root
if (this.getMerkleRoot() !== this.merkleRoot) {
this._debug('Block failed merkleroot test: %s', this.rhash);
utils.debug('Block failed merkleroot test: %s', this.rhash);
return false;
}
@ -321,7 +310,7 @@ Block.prototype.verifyContext = function verifyContext() {
// Ensure it's not an orphan
if (!prev) {
this._debug('Block has no previous entry: %s', this.rhash);
utils.debug('Block has no previous entry: %s', this.rhash);
return false;
}
@ -329,41 +318,41 @@ Block.prototype.verifyContext = function verifyContext() {
// Ensure the timestamp is correct
if (this.ts <= prev.getMedianTime()) {
this._debug('Block time is lower than median: %s', this.rhash);
utils.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._debug('Block is using wrong target: %s', this.rhash);
utils.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._debug('Block is outdated (v2): %s', this.rhash);
utils.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._debug('Block is outdated (v3): %s', this.rhash);
utils.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._debug('Block is outdated (v4): %s', this.rhash);
utils.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._debug('Block is outdated (v8): %s', this.rhash);
// utils.debug('Block is outdated (v8): %s', this.rhash);
// return false;
// }
@ -373,13 +362,13 @@ Block.prototype.verifyContext = function verifyContext() {
// Make sure the coinbase is parseable.
if (!cb) {
this._debug('Block has malformed coinbase: %s', this.rhash);
utils.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._debug('Block has bad coinbase height: %s', this.rhash);
utils.debug('Block has bad coinbase height: %s', this.rhash);
return false;
}
}
@ -417,7 +406,7 @@ Block.prototype.verifyContext = function verifyContext() {
// Transactions must be finalized with
// regards to nSequence and nLockTime.
if (!tx.isFinal(height, ts)) {
this._debug('TX is not final: %s (%s)', this.rhash, i);
utils.debug('TX is not final: %s (%s)', this.rhash, i);
return false;
}
@ -427,7 +416,7 @@ Block.prototype.verifyContext = function verifyContext() {
// if (tx.sigops(true) > constants.script.maxTxSigops) {
// // Block 71036 abused checksig to
// // include a huge number of sigops.
// this._debug('Block TX has too many sigops: %s', this.rhash);
// utils.debug('Block TX has too many sigops: %s', this.rhash);
// if (!(network.type === 'main' && height === 71036))
// return false;
// }
@ -441,7 +430,7 @@ Block.prototype.verifyContext = function verifyContext() {
sigops += tx.sigops();
if (sigops > constants.script.maxBlockSigops) {
this._debug('Block has too many sigops: %s', this.rhash);
utils.debug('Block has too many sigops: %s', this.rhash);
return false;
}
@ -450,7 +439,7 @@ Block.prototype.verifyContext = function verifyContext() {
// Blocks 91842 and 91880 created duplicate
// txids by using the same exact output script
// and extraNonce.
this._debug('Block is overwriting txids: %s', this.rhash);
utils.debug('Block is overwriting txids: %s', this.rhash);
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
return false;
}
@ -472,13 +461,13 @@ Block.prototype.verifyContext = function verifyContext() {
// Verify the script
if (!tx.verify(j, true, flags)) {
this._debug('Block has invalid inputs: %s', this.rhash);
utils.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._debug('Block is using spent inputs: %s', this.rhash);
// utils.debug('Block is using spent inputs: %s', this.rhash);
// return false;
// }
}

View File

@ -29,6 +29,9 @@ function Chain(options) {
this.storage = this.options.storage;
this.strict = this.options.strict || false;
if (this.options.debug)
bcoin.debug = true;
this.tip = null;
this.orphan = {
@ -132,7 +135,7 @@ Chain.prototype._init = function _init() {
}
utils.nextTick(function() {
self.emit('debug', 'Chain is loading.');
utils.debug('Chain is loading.');
});
s = this.storage.createReadStream({
@ -152,7 +155,7 @@ Chain.prototype._init = function _init() {
s.on('end', function() {
self.loading = false;
self.emit('load');
self.emit('debug', 'Chain successfully loaded.');
utils.debug('Chain successfully loaded.');
});
};
@ -472,7 +475,7 @@ Chain.prototype.add = function add(block, peer) {
if (code !== Chain.codes.okay) {
if (!(this.options.multiplePeers && code === Chain.codes.newOrphan))
this.emit('debug', 'Chain Error: %s', Chain.msg(code));
utils.debug('Chain Error: %s', Chain.msg(code));
}
return total;

View File

@ -66,17 +66,17 @@ Miner.prototype._init = function _init() {
// });
this.on('block', function(block) {
self.chain.emit('debug',
utils.debug(
'Found block: %d (%s)',
block.height,
block.hash('hex'));
// Emit the block hex as a failsafe (in case we can't send it)
self.chain.emit('debug', 'Block: %s', utils.toHex(block.render()));
utils.debug('Block: %s', utils.toHex(block.render()));
self.pool.sendBlock(block);
});
this.on('status', function(stat) {
self.chain.emit('debug',
utils.debug(
'hashrate=%dkhs hashes=%d target=%d height=%d best=%s',
stat.hashrate / 1000 | 0,
stat.hashes,
@ -294,12 +294,12 @@ Miner.prototype.iterate = function iterate() {
// Make sure our block is valid
if (!self.block.verify())
return self.emit('debug', '%s did not verify.', hash);
return utils.debug('%s did not verify.', hash);
// Add our block to the chain
res = self.chain.add(self.block);
if (res > 0)
return self.emit('debug', '%s could not be added to chain.', hash);
return utils.debug('%s could not be added to chain.', hash);
// Emit our newly found block
self.emit('block', self.block);

View File

@ -139,7 +139,7 @@ Peer.prototype._init = function init() {
if (this.pool.options.fullNode) {
this.once('version', function() {
self.pool.emit('debug',
utils.debug(
'Sent version (%s): height=%s',
self.host, this.pool.chain.height());
});
@ -475,7 +475,7 @@ Peer.prototype._handleAddr = function handleAddr(addrs) {
});
}, this);
this.pool.emit('debug',
utils.debug(
'Recieved %d peers (seeds=%d, peers=%d).',
addrs.length,
this.pool.seeds.length,
@ -575,10 +575,10 @@ Peer.prototype._handleHeaders = function handleHeaders(headers) {
};
Peer.prototype.loadHeaders = function loadHeaders(hashes, stop) {
this.emit('debug',
utils.debug(
'Requesting headers packet from %s with getheaders',
this.host);
this.pool.emit('debug', 'Height: %s, Hash: %s, Stop: %s',
utils.debug('Height: %s, Hash: %s, Stop: %s',
this.pool.chain.getHeight(hashes[0]),
hashes ? utils.revHex(hashes[0]) : 0,
stop ? utils.revHex(stop) : 0);
@ -586,10 +586,10 @@ Peer.prototype.loadHeaders = function loadHeaders(hashes, stop) {
};
Peer.prototype.loadBlocks = function loadBlocks(hashes, stop) {
this.emit('debug',
utils.debug(
'Requesting inv packet from %s with getblocks',
this.host);
this.pool.emit('debug', 'Height: %s, Hash: %s, Stop: %s',
utils.debug('Height: %s, Hash: %s, Stop: %s',
this.pool.chain.getHeight(hashes[0]),
hashes ? utils.revHex(hashes[0]) : 0,
stop ? utils.revHex(stop) : 0);
@ -603,14 +603,14 @@ Peer.prototype.loadItems = function loadItems(hashes, stop) {
};
Peer.prototype.loadMempool = function loadMempool() {
this.emit('debug',
utils.debug(
'Requesting inv packet from %s with mempool',
this.host);
this._write(this.framer.mempool());
};
Peer.prototype.reject = function reject(details) {
this.emit('debug',
utils.debug(
'Sending reject packet to %s',
this.host);
this._write(this.framer.reject(details));

View File

@ -29,6 +29,9 @@ function Pool(options) {
this.options = options || {};
if (this.options.debug)
bcoin.debug = true;
if (this.options.network)
network.set(this.options.network);
@ -154,11 +157,6 @@ function Pool(options) {
this.options.wallets = this.options.wallets || [];
this.wallets = [];
this.chain.on('debug', function() {
var args = Array.prototype.slice.call(arguments);
self.emit.apply(self, ['debug'].concat(args));
});
Pool.global = this;
this.loading = true;
@ -186,7 +184,7 @@ Pool.prototype._init = function _init() {
});
this.chain.on('fork', function(data, peer) {
self.emit('debug',
utils.debug(
'Fork at height %d: expected=%s received=%s checkpoint=%s peer=%s',
data.height,
utils.revHex(data.expected),
@ -202,7 +200,7 @@ Pool.prototype._init = function _init() {
});
this.chain.on('invalid', function(data, peer) {
self.emit('debug',
utils.debug(
'Invalid block at height: %d: hash=%s peer=%s',
data.height,
utils.revHex(data.hash),
@ -293,12 +291,12 @@ Pool.prototype.createConnection = function createConnection(peer, pool, options)
socket = net.connect(addr.port, addr.host);
}
pool.emit('debug',
utils.debug(
'Connecting to %s:%d (priority=%s)',
addr.host, addr.port, options.priority);
socket.on('connect', function() {
pool.emit('debug',
utils.debug(
'Connected to %s:%d (priority=%s)',
addr.host, addr.port, options.priority);
});
@ -319,7 +317,7 @@ Pool.prototype._addLoader = function _addLoader() {
peer = this._createPeer(750 * Math.random(), true);
peer.once('socket', function() {
self.emit('debug', 'Added loader peer: %s', peer.host);
utils.debug('Added loader peer: %s', peer.host);
});
this.peers.load = peer;
@ -420,7 +418,7 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
if (headers.length === 0)
return;
this.emit('debug',
utils.debug(
'Recieved %s headers from %s',
headers.length,
peer.host);
@ -475,7 +473,7 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
if (hashes.length === 0)
return;
this.emit('debug',
utils.debug(
'Recieved %s block hashes from %s',
hashes.length,
peer.host);
@ -494,7 +492,7 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
// Make sure the peer doesn't send us
// more than 200 orphans every 3 minutes.
if (this.orphaning(peer)) {
this.emit('debug', 'Peer is orphaning (%s)', peer.host);
utils.debug('Peer is orphaning (%s)', peer.host);
this.misbehaving(peer, 100);
return;
}
@ -566,7 +564,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Ensure the block was not invalid last time.
// Someone might be sending us bad blocks to DoS us.
if (this.block.invalid[block.hash('hex')]) {
this.emit('debug', 'Peer is sending an invalid chain (%s)', peer.host);
utils.debug('Peer is sending an invalid chain (%s)', peer.host);
this.misbehaving(peer, 100);
return false;
}
@ -574,7 +572,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Ensure this is not a continuation
// of an invalid chain.
if (this.block.invalid[block.prevBlock]) {
this.emit('debug',
utils.debug(
'Peer is sending an invalid continuation chain (%s)',
peer.host);
this.misbehaving(peer, 100);
@ -583,14 +581,14 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Ignore if we already have.
if (this.chain.has(block)) {
this.emit('debug', 'Already have block %s (%s)', block.height, peer.host);
utils.debug('Already have block %s (%s)', block.height, peer.host);
this.misbehaving(peer, 1);
return false;
}
// Make sure the block is valid.
if (!block.verify()) {
this.emit('debug',
utils.debug(
'Block verification failed for %s (%s)',
block.rhash, peer.host);
this.block.invalid[block.hash('hex')] = true;
@ -601,7 +599,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Someone is sending us blocks without
// us requesting them.
if (!requested) {
this.emit('debug',
utils.debug(
'Recieved unrequested block: %s (%s)',
block.rhash, peer.host);
}
@ -616,7 +614,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Make sure the peer doesn't send us
// more than 200 orphans every 3 minutes.
if (this.orphaning(peer)) {
this.emit('debug', 'Peer is orphaning (%s)', peer.host);
utils.debug('Peer is orphaning (%s)', peer.host);
this.misbehaving(peer, 100);
return false;
}
@ -634,7 +632,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
this.chain.getOrphanRoot(block)
);
this.emit('debug', 'Handled orphan %s (%s)', block.rhash, peer.host);
utils.debug('Handled orphan %s (%s)', block.rhash, peer.host);
return false;
}
@ -749,15 +747,10 @@ Pool.prototype._createPeer = function _createPeer(backoff, priority) {
self.emit('error', err, peer);
});
peer.on('debug', function() {
var args = Array.prototype.slice.call(arguments);
self.emit.apply(self, ['debug'].concat(args));
});
peer.on('reject', function(payload) {
var data = utils.revHex(utils.toHex(payload.data));
self.emit('debug',
utils.debug(
'Reject: msg=%s ccode=%s reason=%s data=%s',
payload.message,
payload.ccode,
@ -800,7 +793,7 @@ Pool.prototype._createPeer = function _createPeer(backoff, priority) {
if (version.height > self.block.bestHeight)
self.block.bestHeight = version.height;
self.emit('version', version, peer);
self.emit('debug',
utils.debug(
'Received version from %s: version=%d height=%d agent=%s',
peer.host, peer.version.v, peer.version.height, peer.version.agent);
});
@ -907,7 +900,7 @@ Pool.prototype._removePeer = function _removePeer(peer) {
this.peers.all.splice(i, 1);
if (this.peers.load === peer) {
this.emit('debug', 'Removed loader peer (%s).', peer.host);
utils.debug('Removed loader peer (%s).', peer.host);
this.peers.load = null;
}
};
@ -1129,8 +1122,8 @@ Pool.prototype.searchWallet = function(w) {
}
utils.nextTick(function() {
self.emit('debug', 'Wallet time: %s', new Date(ts * 1000));
self.emit('debug',
utils.debug('Wallet time: %s', new Date(ts * 1000));
utils.debug(
'Reverted chain to height=%d (%s)',
self.chain.height(),
new Date(self.chain.getTip().ts * 1000)
@ -1374,7 +1367,7 @@ Pool.prototype._doRequests = function _doRequests() {
return item.start(this.peers.load);
}, this);
this.emit('debug',
utils.debug(
'Requesting %s/%s items from %s with getdata',
req.length,
this.request.queue.length,
@ -1467,7 +1460,7 @@ Pool.prototype.sendTX = function sendTX(tx) {
// isStandardInputs as well.
if (tx.full()) {
if (!tx.verify(null, true)) {
this.emit('debug',
utils.debug(
'Could not relay TX (%s). It does not verify.',
tx.rhash);
return;
@ -1637,7 +1630,7 @@ Pool.prototype.usableSeed = function usableSeed(priority, connecting) {
// This should never happen: priority sockets
// should _always_ get an address.
if (priority) {
this.emit('debug',
utils.debug(
'We had to connect to a random peer. Something is not right.');
return seeds[Math.random() * (seeds.length - 1) | 0];
@ -1718,7 +1711,7 @@ Pool.prototype.misbehaving = function misbehaving(peer, dos) {
if (peer._banscore >= constants.banScore) {
this.peers.misbehaving[peer.host] = utils.now();
this.emit('debug', 'Ban threshold exceeded for %s', peer.host);
utils.debug('Ban threshold exceeded for %s', peer.host);
peer.destroy();
return true;
}

View File

@ -998,6 +998,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
}
default: {
// Unknown operation
utils.debug('Unknown opcode "%s" at offset %d', o, pc);
return false;
}
}
@ -1222,7 +1223,25 @@ script.size = function size(s) {
};
script.isEncoded = function isEncoded(s) {
return utils.isBytes(s);
var i, b;
if (!Array.isArray(data))
return false;
for (i = 0; i < data.length; i++) {
b = data[i];
if (typeof b !== 'number')
return false;
if (constants.opcodesByVal[b] == null) {
if (b >= 0x01 && b <= 0x4b)
continue;
return false;
}
}
return true;
};
script._lockTime = function _lockTime(s) {
@ -1725,6 +1744,10 @@ script.isScripthashInput = function isScripthashInput(s, data, strict) {
if (script.isKeyEncoding(raw))
return false;
// Ensure this is a valid encoded script
// if (!script.isEncoded(raw))
// return false;
// Check data against last array in case
// a raw redeem script was passed in.
if (data && utils.isEqual(data, raw))

View File

@ -711,21 +711,29 @@ utils.isBytes = function isBytes(data) {
return true;
};
utils._inspect = function inspect(obj) {
utils._inspect = function _inspect(obj, color) {
return typeof obj !== 'string'
? util.inspect(obj, null, 20, true)
? util.inspect(obj, null, 20, color !== false)
: obj;
};
utils.print = function print(msg) {
return typeof msg === 'object'
? process.stdout.write(utils._inspect(msg) + '\n')
? process.stdout.write(utils._inspect(msg, !!process.stdout.isTTY) + '\n')
: console.log.apply(console, arguments);
};
utils.debug = function debug() {
var args = Array.prototype.slice.call(arguments);
args[0] = '\x1b[31m' + args[0] + '\x1b[m';
var args;
if (!bcoin.debug)
return;
args = Array.prototype.slice.call(arguments);
// if (typeof args[0] === 'string' && process.stdout.isTTY)
// args[0] = '\x1b[32m' + args[0] + '\x1b[m';
return utils.print.apply(null, args);
};

View File

@ -122,7 +122,7 @@ function Wallet(options, passphrase) {
}, this);
if (this.redeem) {
if (!bcoin.script.isEncoded(this.redeem))
if (!utils.isBytes(this.redeem))
this.redeem = bcoin.script.encode(this.redeem);
this.type = 'scripthash';
this.subtype = null;