refactor. work.

This commit is contained in:
Christopher Jeffrey 2016-01-07 13:39:08 -08:00
parent 42fbef82ed
commit df420a4a8b
11 changed files with 253 additions and 134 deletions

View File

@ -216,63 +216,79 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() {
return merkleTree[merkleTree.length - 1]; return merkleTree[merkleTree.length - 1];
}; };
// This mimics the behavior of CheckBlockHeader()
// and CheckBlock() in bitcoin/src/main.cpp.
Block.prototype._verify = function _verify() { Block.prototype._verify = function _verify() {
var uniq = {}; var uniq = {};
var i, tx, hash; var i, tx, hash;
// Check proof of work matches claimed amount // Check proof of work
if (!utils.testTarget(this.bits, this.hash())) if (!utils.testTarget(this.bits, this.hash())) {
this.chain.emit('debug', 'Block failed POW test: %s', this.rhash);
return false; return false;
// Check timestamp
if (this.ts > utils.now() + 2 * 60 * 60)
return false;
if (this.subtype === 'merkleblock') {
if (!this._verifyPartial())
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);
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);
return false;
}
}
// Merkleblock and headers cannot do anymore tests.
if (this.subtype !== 'block') if (this.subtype !== 'block')
return true; return true;
// Size can't be bigger than MAX_BLOCK_SIZE // Size can't be bigger than MAX_BLOCK_SIZE
if (this.txs.length > constants.block.maxSize if (this.txs.length > constants.block.maxSize
|| this.size() > constants.block.maxSize) { || this.size() > constants.block.maxSize) {
this.chain.emit('debug', 'Block is too large: %s', this.rhash);
return false; return false;
} }
// First TX must be a coinbase // First TX must be a coinbase
if (!this.txs.length || !this.txs[0].isCoinbase()) if (!this.txs.length || !this.txs[0].isCoinbase()) {
this.chain.emit('debug', 'Block has no coinbase: %s', this.rhash);
return false; return false;
}
// Test all txs // Test all txs
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];
// The rest of the txs must not be coinbases // The rest of the txs must not be coinbases
if (i > 0 && tx.isCoinbase()) if (i > 0 && tx.isCoinbase()) {
this.chain.emit('debug', 'Block more than one coinbase: %s', this.rhash);
return false; return false;
}
// Check for duplicate txids // Check for duplicate txids
hash = tx.hash('hex'); hash = tx.hash('hex');
if (uniq[hash]) if (uniq[hash]) {
this.chain.emit('debug', 'Block has duplicate txids: %s', this.rhash);
return false; return false;
}
uniq[hash] = true; uniq[hash] = true;
} }
// Check merkle root // Check merkle root
if (this.getMerkleRoot() !== this.merkleRoot) if (this.getMerkleRoot() !== this.merkleRoot) {
this.chain.emit('debug', 'Block failed merkleroot test: %s', this.rhash);
return false; return false;
}
return true; return true;
}; };
Block.prototype.postVerify = function postVerify() { Block.prototype.postVerify = function postVerify() {
var flags = {}; var flags = {};
var prev, height, i, j, tx, cb, sigops, input; var sigops = 0;
var prev, height, ts, i, j, tx, cb, input;
if (this.subtype !== 'block') if (this.subtype !== 'block')
return true; return true;
@ -284,96 +300,121 @@ Block.prototype.postVerify = function postVerify() {
return true; return true;
prev = this.chain.getBlock(this.prevBlock); prev = this.chain.getBlock(this.prevBlock);
height = prev.height + 1;
// Ensure it's not an orphan // Ensure it's not an orphan
if (!prev) { if (!prev) {
console.log('NO PREV: %s', height); this.chain.emit('debug', 'Block has no previous entry: %s', this.rhash);
return false; return false;
} }
height = prev.height + 1;
// Ensure the timestamp is correct // Ensure the timestamp is correct
if (this.ts <= prev.getMedianTime()) { if (this.ts <= prev.getMedianTime()) {
console.log('BAD TIME: %s', height); this.chain.emit('debug', 'Block time is lower than median: %s', this.rhash);
return false; return false;
} }
// Test all txs
for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i];
// TXs must be finalized with regards to seq and locktime
if (!tx.isFinal(this, prev)) {
console.log('IS NOT FINAL: %s', height);
return false;
}
}
// Ensure the miner's target is equal to what we expect // Ensure the miner's target is equal to what we expect
if (this.bits !== this.chain.target(prev, this)) { if (this.bits !== this.chain.target(prev, this)) {
console.log('BAD TARGET: %s', height); this.chain.emit('debug', 'Block is using wrong target: %s', this.rhash);
return false; return false;
} }
// Only allow version 2 blocks (coinbase height) // Only allow version 2 blocks (coinbase height)
// once the majority of blocks are using it. // once the majority of blocks are using it.
if (this.version < 2 && prev.isOutdated(2)) { if (this.version < 2 && prev.isOutdated(2)) {
console.log('OUTDATED 2: %s', height); this.chain.emit('debug', 'Block is outdated (v2): %s', this.rhash);
return false; return false;
} }
// Only allow version 3 blocks (sig validation) // Only allow version 3 blocks (sig validation)
// once the majority of blocks are using it. // once the majority of blocks are using it.
if (this.version < 3 && prev.isOutdated(3)) { if (this.version < 3 && prev.isOutdated(3)) {
console.log('OUTDATED 3: %s', height); this.chain.emit('debug', 'Block is outdated (v3): %s', this.rhash);
return false; return false;
} }
// Only allow version 4 blocks (checklocktimeverify) // Only allow version 4 blocks (checklocktimeverify)
// once the majority of blocks are using it. // once the majority of blocks are using it.
if (this.version < 4 && prev.isOutdated(4)) { if (this.version < 4 && prev.isOutdated(4)) {
console.log('OUTDATED 4: %s', height); this.chain.emit('debug', 'Block is outdated (v4): %s', this.rhash);
return false; return false;
} }
// Make sure the height contained in the // Only allow version 8 blocks (locktime median past)
// coinbase is correct. // 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);
// return false;
// }
// Make sure the height contained in the coinbase is correct.
if (this.version >= 2 && prev.isUpgraded(2)) { if (this.version >= 2 && prev.isUpgraded(2)) {
cb = bcoin.script.isCoinbase(this.txs[0].inputs[0].script, this); cb = bcoin.script.isCoinbase(this.txs[0].inputs[0].script, this);
// Make sure the coinbase is parseable.
if (!cb) { if (!cb) {
console.log('BAD COINBASE: %s', height); this.chain.emit('debug', 'Block has malformed coinbase: %s', this.rhash);
return false; return false;
} }
// Make sure coinbase height is equal to the actual height.
if (cb.height !== height) { if (cb.height !== height) {
console.log('BAD COINBASE HEIGHT: %s', height); this.chain.emit('debug', 'Block has bad coinbase height: %s', this.rhash);
return false; return false;
} }
} }
// Signature validation is now enforced (bip66) // Signature validation is now enforced (bip66)
if (this.version >= 3 && prev.isUpgraded(3)) if (!(this.version >= 3 && prev.isUpgraded(3)))
flags.strictder = true; flags.strictder = false;
// CHECKLOCKTIMEVERIFY is now usable (bip65) // CHECKLOCKTIMEVERIFY is now usable (bip65)
if (this.version >= 4 && prev.isUpgraded(4)) if (!(this.version >= 4 && prev.isUpgraded(4)))
flags.cltv = true; flags.cltv = false;
// Check for sigops limits // Use nLockTime median past (bip113)
sigops = 0; // https://github.com/btcdrak/bips/blob/d4c9a236ecb947866c61aefb868b284498489c2b/bip-0113.mediawiki
// Support version bits:
// https://gist.github.com/sipa/bf69659f43e763540550
// http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html
// if (this.version >= 8 && prev.isUpgraded(8))
// flags.locktimeMedian = true;
// If we are an ancestor of a checkpoint, we can
// skip the input verification.
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
flags.scriptChecks = false;
// Get timestamp for tx.isFinal().
ts = flags.locktimeMedian
? prev.getMedianTime()
: this.ts;
// Check all transactions
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];
// 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);
return false;
}
// Check for tx sigops limits
// Bitcoind does not check for this when accepting // Bitcoind does not check for this when accepting
// a block even though it probably should. // a block even though it probably should.
// if (tx.sigops(true) > constants.script.maxTxSigops) { // if (tx.sigops(true) > constants.script.maxTxSigops) {
// // Block 71036 abused checksig to // // Block 71036 abused checksig to
// // include a huge number of sigops. // // include a huge number of sigops.
// this.chain.emit('debug', 'Block TX has too many sigops: %s', this.rhash);
// if (!(network.type === 'main' && height === 71036)) // if (!(network.type === 'main' && height === 71036))
// return false; // return false;
// } // }
// Check for block sigops limits
// Start counting P2SH sigops once block // Start counting P2SH sigops once block
// timestamps reach March 31st, 2012. // timestamps reach March 31st, 2012.
if (this.ts >= constants.block.bip16time) if (this.ts >= constants.block.bip16time)
@ -382,50 +423,46 @@ Block.prototype.postVerify = function postVerify() {
sigops += tx.sigops(); sigops += tx.sigops();
if (sigops > constants.script.maxBlockSigops) { if (sigops > constants.script.maxBlockSigops) {
console.log('BAD SIGOPS: %s', height); this.chain.emit('debug', 'Block has too many sigops: %s', this.rhash);
return false; return false;
} }
}
// BIP30 - Ensure there are no duplicate txids // BIP30 - Ensure there are no duplicate txids
for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i];
if (this.chain.index[tx.hash('hex')]) { if (this.chain.index[tx.hash('hex')]) {
// Blocks 91842 and 91880 created duplicate // Blocks 91842 and 91880 created duplicate
// txids by carefully crafting the coinbases. // txids by carefully crafting the coinbases.
if (!(network.type === 'main' && height === 91842 && height === 91880)) this.chain.emit('debug', 'Block is overwriting txids: %s', this.rhash);
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
return false; return false;
} }
}
// If we are an ancestor of a checkpoint, // Verify the inputs of every tx (CheckInputs)
// we can skip the input verification. if (flags.scriptChecks !== false) {
if (height < network.checkpoints.lastHeight && !network.checkpoints[height]) if (tx.isCoinbase())
flags.noScriptChecks = true;
// Verify the inputs of every tx (CheckInputs)
for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i];
if (tx.isCoinbase())
continue;
if (flags.noScriptChecks)
continue;
for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
if (!input.out.tx)
continue; continue;
assert(input.out.tx); for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
if (!tx.verify(j, true, flags)) // We need the previous output in order
return false; // to verify the script.
if (!input.out.tx)
continue;
// if (this.chain.isSpent(input.out.hash, input.out.index)) assert(input.out.tx);
// return false;
// Verify the script
if (!tx.verify(j, true, flags)) {
this.chain.emit('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);
// return false;
// }
}
} }
} }

View File

@ -50,6 +50,12 @@ function Chain(options) {
this.request = new utils.RequestCache(); this.request = new utils.RequestCache();
this.fromJSON(require('./protocol/preload-full'));
this.storage = null;
//this.resetHeight(133000);
this.resetHeight(145000);
if (0)
this.fromJSON({ this.fromJSON({
v: 2, v: 2,
type: 'chain', type: 'chain',
@ -608,7 +614,10 @@ Chain.prototype.height = function height() {
return this.getTip().height; return this.getTip().height;
}; };
// /home/chjj/bitcoin/src/pow.cpp Chain.prototype.currentTarget = function currentTarget() {
return this.target(this.getTip());
};
Chain.prototype.target = function target(last, block) { Chain.prototype.target = function target(last, block) {
var powLimit = utils.toCompact(network.powLimit); var powLimit = utils.toCompact(network.powLimit);
var ts, first, i; var ts, first, i;

View File

@ -139,7 +139,9 @@ Miner.prototype.addBlock = function addBlock(block) {
}; };
Miner.prototype.addTX = function addTX(tx) { Miner.prototype.addTX = function addTX(tx) {
var full = this.index.inputs.every(function(input) { var full, ts;
full = this.index.inputs.every(function(input) {
return !!input.out.tx; return !!input.out.tx;
}); });
@ -160,7 +162,12 @@ Miner.prototype.addTX = function addTX(tx) {
if (tx.isCoinbase()) if (tx.isCoinbase())
return; return;
if (!tx.isFinal(this.block, this.last)) // Get timestamp for tx.isFinal() - bip113
ts = this.block.version === 8
? this.last.getMedianTime()
: this.block.ts;
if (!tx.isFinal(this.last.height + 1, ts))
return; return;
// Deliver me from the block size debate, please // Deliver me from the block size debate, please

View File

@ -548,6 +548,10 @@ Peer.prototype.loadHeaders = function loadHeaders(hashes, stop) {
this.emit('debug', this.emit('debug',
'Requesting headers packet from %s with getheaders', 'Requesting headers packet from %s with getheaders',
this.host); this.host);
this.pool.emit('debug', 'Height: %s, Hash: %s, Stop: %s',
this.pool.chain.getHeight(hashes[0]),
hashes ? utils.revHex(hashes[0]) : 0,
stop ? utils.revHex(stop) : 0);
this._write(this.framer.getHeaders(hashes, stop)); this._write(this.framer.getHeaders(hashes, stop));
}; };
@ -555,6 +559,10 @@ Peer.prototype.loadBlocks = function loadBlocks(hashes, stop) {
this.emit('debug', this.emit('debug',
'Requesting inv packet from %s with getblocks', 'Requesting inv packet from %s with getblocks',
this.host); this.host);
this.pool.emit('debug', 'Height: %s, Hash: %s, Stop: %s',
this.pool.chain.getHeight(hashes[0]),
hashes ? utils.revHex(hashes[0]) : 0,
stop ? utils.revHex(stop) : 0);
this._write(this.framer.getBlocks(hashes, stop)); this._write(this.framer.getBlocks(hashes, stop));
}; };
@ -571,6 +579,13 @@ Peer.prototype.loadMempool = function loadMempool() {
this._write(this.framer.mempool()); this._write(this.framer.mempool());
}; };
Peer.prototype.reject = function reject(details) {
this.emit('debug',
'Sending reject packet to %s',
this.host);
this._write(this.framer.reject(details));
};
/** /**
* Expose * Expose
*/ */

View File

@ -42,7 +42,7 @@ function Pool(options) {
this.destroyed = false; this.destroyed = false;
this.size = options.size || 32; this.size = options.size || 32;
this.parallel = options.parallel || 2000; this.parallel = options.parallel || 2000;
this.redundancy = options.redundancy || 2; this.redundancy = options.redundancy || 1;
this.seeds = options.seeds this.seeds = options.seeds
? options.seeds.slice() ? options.seeds.slice()
: network.seeds.slice(); : network.seeds.slice();
@ -320,10 +320,14 @@ Pool.prototype._addLoader = function _addLoader() {
}); });
peer.on('merkleblock', function(block) { peer.on('merkleblock', function(block) {
self._startInterval();
self._startTimer();
self._handleBlock(block, peer); self._handleBlock(block, peer);
}); });
peer.on('block', function(block) { peer.on('block', function(block) {
self._startInterval();
self._startTimer();
self._handleBlock(block, peer); self._handleBlock(block, peer);
}); });
@ -346,7 +350,6 @@ Pool.prototype._addLoader = function _addLoader() {
}; };
Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) { Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
var reqs = 0;
var i, header, last, block; var i, header, last, block;
assert(this.options.headers); assert(this.options.headers);
@ -375,10 +378,8 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
if (!block.verify()) if (!block.verify())
break; break;
if (!this.chain.has(block)) { if (!this.chain.has(block))
this._request(this.block.type, block.hash('hex')); this._request(this.block.type, block.hash('hex'));
reqs++;
}
last = block; last = block;
} }
@ -401,15 +402,9 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
// Reset timeout to avoid killing the loader // Reset timeout to avoid killing the loader
this._startTimer(); this._startTimer();
this.emit('debug',
'Requesting %s block packets from %s with getdata',
reqs, peer.host
);
}; };
Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) { Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
var reqs = 0;
var i, hash; var i, hash;
assert(!this.options.headers); assert(!this.options.headers);
@ -435,7 +430,6 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
// Request block if we don't have it // Request block if we don't have it
if (!this.chain.has(hash)) { if (!this.chain.has(hash)) {
this._request(this.block.type, hash); this._request(this.block.type, hash);
reqs++;
continue; continue;
} }
@ -457,11 +451,6 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
// Reset timeout to avoid killing the loader // Reset timeout to avoid killing the loader
this._startTimer(); this._startTimer();
this.emit('debug',
'Requesting %s block packets from %s with getdata',
reqs, peer.host
);
}; };
Pool.prototype._handleInv = function _handleInv(hashes, peer) { Pool.prototype._handleInv = function _handleInv(hashes, peer) {
@ -490,10 +479,6 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
var requested = this._response(block); var requested = this._response(block);
// Someone is sending us blocks without us requesting them.
if (!requested)
return;
// Emulate bip37 - emit all the "watched" txs // Emulate bip37 - emit all the "watched" txs
if (this.options.fullNode && this.listeners('watched').length > 0) { if (this.options.fullNode && this.listeners('watched').length > 0) {
block.txs.forEach(function(tx) { block.txs.forEach(function(tx) {
@ -503,15 +488,21 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
} }
// Ignore if we already have // Ignore if we already have
if (this.chain.has(block)) if (this.chain.has(block)) {
this.emit('debug', 'Already have block %s (%s)', block.height, peer.host);
return; return;
}
// Make sure the block is valid // Make sure the block is valid
if (!block.verify()) { if (!block.verify()) {
this.emit('debug', 'Block verification failed for %s', block.hash('hex')); this.emit('debug', 'Block verification failed for %s (%s)', block.rhash, peer.host);
return; return;
} }
// Someone is sending us blocks without us requesting them.
if (!requested)
this.emit('debug', 'Recieved unrequested block: %s (%s)', block.rhash, peer.host);
// Resolve orphan chain // Resolve orphan chain
if (!this.options.headers) { if (!this.options.headers) {
if (!this.chain.hasBlock(block.prevBlock)) { if (!this.chain.hasBlock(block.prevBlock)) {
@ -521,10 +512,11 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// the height until later. // the height until later.
if (this._addIndex(block, peer)) if (this._addIndex(block, peer))
this.emit('pool block', block, peer); this.emit('pool block', block, peer);
peer.loadBlocks( this.peers.load.loadBlocks(
this.chain.locatorHashes(), this.chain.locatorHashes(),
this.chain.getOrphanRoot(block) this.chain.getOrphanRoot(block)
); );
this.emit('debug', 'Handled orphan %s (%s)', block.rhash, peer.host);
return; return;
} }
} }
@ -786,11 +778,6 @@ Pool.prototype._removePeer = function _removePeer(peer) {
if (this.peers.load === peer) { if (this.peers.load === peer) {
this.emit('debug', 'Removed loader peer (%s).', peer.host); this.emit('debug', 'Removed loader peer (%s).', peer.host);
this.peers.load = null; this.peers.load = null;
// i = this.seeds.indexOf(peer.host);
// if (i === -1)
// i = this.seeds.indexOf(peer.host + ':' + peer.port);
// if (i !== -1)
// this.seeds.splice(i, 1);
} }
}; };
@ -1236,6 +1223,9 @@ Pool.prototype._doRequests = function _doRequests() {
if (above && below && this.load.hiReached) if (above && below && this.load.hiReached)
this._load(); this._load();
if (items.length === 0)
return;
if (this.options.multiplePeers) { if (this.options.multiplePeers) {
mapReq = function(item) { mapReq = function(item) {
return item.start(this.peers.block[i]); return item.start(this.peers.block[i]);
@ -1258,6 +1248,12 @@ Pool.prototype._doRequests = function _doRequests() {
return item.start(this.peers.load); return item.start(this.peers.load);
}, this); }, this);
this.emit('debug',
'Requesting %s/%s items from %s with getdata',
req.length,
this.request.queue.length,
this.peers.load.host);
this.peers.load.getData(req); this.peers.load.getData(req);
}; };
@ -1506,16 +1502,17 @@ LoadRequest.prototype.start = function start(peer) {
var reqType; var reqType;
assert(!this.active); assert(!this.active);
assert(!this.timer);
assert(!this.peer);
this.active = true; this.active = true;
this.pool.request.active++; this.pool.request.active++;
assert(!this.timer); // this.timer = setTimeout(function() {
this.timer = setTimeout(function() { // self.timer = null;
self.timer = null; // self.retry();
self.retry(); // }, this.pool.requestTimeout);
}, this.pool.requestTimeout);
assert(!this.peer);
this.peer = peer; this.peer = peer;
this.peer.once('close', this.onclose); this.peer.once('close', this.onclose);

View File

@ -5,6 +5,7 @@
*/ */
var bcoin = require('../../bcoin'); var bcoin = require('../../bcoin');
var bn = require('bn.js');
var utils = bcoin.utils; var utils = bcoin.utils;
var i; var i;
@ -219,3 +220,7 @@ exports.zeroHash = utils.toArray(
exports.userVersion = require('../../../package.json').version; exports.userVersion = require('../../../package.json').version;
exports.userAgent = '/bcoin:' + exports.userVersion + '/'; exports.userAgent = '/bcoin:' + exports.userVersion + '/';
exports.coin = new bn(10000000).muln(10);
exports.cent = new bn(1000000);
exports.maxMoney = new bn(21000000).mul(exports.coin);

View File

@ -357,6 +357,32 @@ Framer.prototype.merkleBlock = function merkleBlock(block) {
return this.packet('merkleblock', Framer.block(block, 'merkleblock')); return this.packet('merkleblock', Framer.block(block, 'merkleblock'));
}; };
Framer.prototype.reject = function reject(details) {
var p = [];
var off = 0;
var message = details.message || '';
var ccode = constants.reject[details.ccode] || constants.reject.malformed;
var reason = details.reason || '';
var data = details.data || [];
off += utils.writeIntv(p, message.length, off);
utils.writeAscii(p, message, off);
off += message.length;
p[off] = ccode;
off++;
off += utils.writeIntv(p, reason.length, off);
utils.writeAscii(p, reason, off);
off += reason.length;
utils.copy(data, p, off, true);
off += data.length;
return this.packet('reject', p);
};
Framer.prototype.addr = function addr(peers) { Framer.prototype.addr = function addr(peers) {
var p = []; var p = [];
var off = 0; var off = 0;

View File

@ -295,12 +295,12 @@ Parser.prototype.parseBlock = function parseBlock(p) {
off = result.off; off = result.off;
totalTX = result.r; totalTX = result.r;
if (p.length >= off + 10) { for (i = 0; i < totalTX; i++) {
for (i = 0; i < totalTX; i++) { tx = this.parseTX(p.slice(off));
tx = this.parseTX(p.slice(off)); if (!tx)
off += tx._off; return this._error('Invalid tx count for block');
txs.push(tx); off += tx._off;
} txs.push(tx);
} }
return { return {

View File

@ -686,8 +686,13 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
if (!constants.hashTypeByVal[type & 0x1f]) if (!constants.hashTypeByVal[type & 0x1f])
return false; return false;
if (!script.isValidSig(sig)) if (flags.strictder !== false) {
return false; if (!script.isValidSig(sig))
return false;
} else {
if (!script.isSig(sig))
return false;
}
subscript = script.subscript(s, lastSep); subscript = script.subscript(s, lastSep);
hash = tx.subscriptHash(index, subscript, type); hash = tx.subscriptHash(index, subscript, type);
@ -743,8 +748,13 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
if (!constants.hashTypeByVal[type & 0x1f]) if (!constants.hashTypeByVal[type & 0x1f])
return false; return false;
if (!script.isValidSig(sig)) if (flags.strictder !== false) {
return false; if (!script.isValidSig(sig))
return false;
} else {
if (!script.isSig(sig))
return false;
}
hash = tx.subscriptHash(index, subscript, type); hash = tx.subscriptHash(index, subscript, type);
@ -775,6 +785,9 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
} }
case 'checklocktimeverify': { case 'checklocktimeverify': {
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2 // OP_CHECKLOCKTIMEVERIFY = OP_NOP2
if (flags.cltv === false)
break;
if (!tx || stack.length === 0) if (!tx || stack.length === 0)
return false; return false;
@ -1298,6 +1311,16 @@ script.isCoinbase = function isCoinbase(s, block) {
return coinbase; return coinbase;
}; };
script.isSig = function isSig(sig, allowZero) {
if (!Array.isArray(sig))
return false;
if (allowZero && sig.length === 0)
return true;
return 9 <= sig.length && sig.length <= 73;
};
// https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki // https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
/** /**
* A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype> * A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>

View File

@ -838,29 +838,29 @@ TX.prototype.funds = function funds(side) {
// Used for postVerify/ContextualBlockCheck and miner isFinalTx call. // Used for postVerify/ContextualBlockCheck and miner isFinalTx call.
// BIP113 will require that time-locked transactions have nLockTime set to // BIP113 will require that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in. // less than the median time of the previous block they're contained in.
TX.prototype.isFinal = function isFinal(block, prev) { TX.prototype.isFinalBlock = function isFinalBlock(block, prev, useMedian) {
var height = prev.height + 1; var height = prev.height + 1;
var ts = this.locktimeMedian ? prev.getMedianTime() : block.ts; var ts = useMedian ? prev.getMedianTime() : block.ts;
return this._isFinal(height, ts); return this.isFinal(height, ts);
}; };
// Used in AcceptToMemoryPool // Used in AcceptToMemoryPool
TX.prototype.isFinalAccept = function isFinalAccept() { TX.prototype.isFinalMempool = function isFinalMempool(useMedian) {
var height = this.chain.height() + 1; var height = this.chain.height() + 1;
var ts = this.lockTimeMedian var ts = useMedian
? this.chain.getTip().getMedianTime() ? this.chain.getTip().getMedianTime()
: utils.now(); : utils.now();
return this._isFinalTx(height, ts); return this.isFinal(height, ts);
}; };
// Used in the original bitcoind code for AcceptBlock // Used in the original bitcoind code for AcceptBlock
TX.prototype._isFinalOriginal = function _isFinalOriginal(block) { TX.prototype.isFinalLegacy = function isFinalLegacy(block) {
var ts = block ? block.ts : utils.now(); var ts = block ? block.ts : utils.now();
var height = this.chain.height(); var height = this.chain.height();
return this._isFinalTx(height, ts); return this.isFinal(height, ts);
}; };
TX.prototype._isFinal = function _isFinal(height, ts) { TX.prototype.isFinal = function isFinal(height, ts) {
var threshold = constants.locktimeThreshold; var threshold = constants.locktimeThreshold;
var i; var i;

View File

@ -81,7 +81,7 @@ function Wallet(options, passphrase) {
this.m = 1; this.m = 1;
this.n = 1; this.n = 1;
this.prefix = 'bt/' + this.getOwnAddress() + '/'; this.prefix = 'bt/wallet/' + this.getOwnAddress() + '/';
this.multisig(options.multisig || {}); this.multisig(options.multisig || {});