refactor. work.
This commit is contained in:
parent
42fbef82ed
commit
df420a4a8b
@ -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;
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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 || {});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user