more refactoring.

This commit is contained in:
Christopher Jeffrey 2016-02-16 16:13:34 -08:00
parent ab610d6fa5
commit 997f0acbb0
12 changed files with 213 additions and 397 deletions

View File

@ -299,194 +299,6 @@ Block.prototype._verify = function _verify() {
return true;
};
Block.prototype.verifyContext = function verifyContext() {
var flags = {};
var sigops = 0;
var prev, height, ts, i, j, tx, cb, input;
if (this.isGenesis())
return true;
if (!this.chain)
return true;
prev = this.chain.getBlock(this.prevBlock);
// Ensure it's not an orphan
if (!prev) {
utils.debug('Block has no previous entry: %s', this.rhash);
return false;
}
height = prev.height + 1;
// Ensure the timestamp is correct
if (this.ts <= prev.getMedianTime()) {
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.getTarget(prev, this)) {
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)) {
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)) {
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)) {
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)) {
// utils.debug('Block is outdated (v8): %s', this.rhash);
// return false;
// }
// Can't verify any further when merkleblock or headers.
if (this.subtype !== 'block')
return true;
// Make sure the height contained in the coinbase is correct.
if (this.version >= 2 && prev.isUpgraded(2)) {
cb = bcoin.script.getCoinbaseData(this.txs[0].inputs[0].script);
// Make sure the coinbase is parseable.
if (!cb) {
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) {
utils.debug('Block has bad coinbase height: %s', this.rhash);
return false;
}
}
// Signature validation is now enforced (bip66)
if (!(this.version >= 3 && prev.isUpgraded(3)))
flags.dersig = false;
// CHECKLOCKTIMEVERIFY is now usable (bip65)
if (!(this.version >= 4 && prev.isUpgraded(4)))
flags.checklocktimeverify = false;
// Use nLockTime median past (bip113)
// 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++) {
tx = this.txs[i];
// Transactions must be finalized with
// regards to nSequence and nLockTime.
if (!tx.isFinal(height, ts)) {
utils.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
// a block even though it probably should.
// if (tx.getSigops(true) > constants.script.maxTxSigops) {
// // Block 71036 abused checksig to
// // include a huge number of sigops.
// utils.debug('Block TX has too many sigops: %s', this.rhash);
// if (!(network.type === 'main' && height === 71036))
// return false;
// }
// Check for block sigops limits
// Start counting P2SH sigops once block
// timestamps reach March 31st, 2012.
if (this.ts >= constants.block.bip16time)
sigops += tx.getSigops(true);
else
sigops += tx.getSigops();
if (sigops > constants.script.maxBlockSigops) {
utils.debug('Block has too many sigops: %s', this.rhash);
return false;
}
// BIP30 - Ensure there are no duplicate txids
// this.node.hasTX(tx.hash('hex'), function(err, has) {
// if (has)
if (this.chain[tx.hash('hex')]) {
// Blocks 91842 and 91880 created duplicate
// txids by using the same exact output script
// and extraNonce.
utils.debug('Block is overwriting txids: %s', this.rhash);
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
return false;
}
// Verify the inputs of every tx (CheckInputs)
if (flags.scriptChecks !== false) {
if (tx.isCoinbase())
continue;
for (j = 0; j < tx.inputs.length; j++) {
input = tx.inputs[j];
// We need the previous output in order
// to verify the script.
if (!input.output)
continue;
// Ensure tx is not double spending an output
if (!input.output) {
utils.debug('Block is using spent inputs: %s (tx: %s, output: %s)',
this.rhash, tx.hash('hex'),
input.prevout.hash + '/' + input.prevout.index);
return false;
}
// Verify the script
if (!tx.verify(j, true, flags)) {
utils.debug('Block has invalid inputs: %s', this.rhash);
return false;
}
}
}
}
return true;
};
Block.prototype.isGenesis = function isGenesis() {
return this.hash('hex') === network.genesis.hash;
};

View File

@ -39,6 +39,8 @@ function Chain(options) {
this.request = new utils.RequestCache();
this.loading = false;
this.tip = null;
this.mempool = options.mempool;
this.blockdb = options.blockdb;
this.orphan = {
map: {},
@ -261,16 +263,16 @@ Chain.prototype._preload = function _preload(callback) {
Chain.prototype._saveBlock = function _saveBlock(block, callback) {
var self = this;
var node = bcoin.node.global;
if (!node)
if (!this.blockdb)
return callback();
node.block.saveBlock(block, function(err) {
this.blockdb.block.saveBlock(block, function(err) {
if (err)
return callback(err);
node.mempool.addBlock(block);
if (self.mempool)
self.mempool.addBlock(block);
return callback();
});
@ -278,19 +280,19 @@ Chain.prototype._saveBlock = function _saveBlock(block, callback) {
Chain.prototype._removeBlock = function _removeBlock(tip, callback) {
var self = this;
var node = bcoin.node.global;
if (!node)
if (!this.blockdb)
return callback();
node.block.removeBlock(tip, function(err, block) {
this.blockdb.removeBlock(tip, function(err, block) {
if (err)
return callback(err);
if (!block)
return callback();
node.mempool.removeBlock(block);
if (self.mempool)
self.mempool.removeBlock(block);
self.emit('reorg block', block.hash('hex'));
@ -331,10 +333,9 @@ Chain.prototype._verifyContext = function _verifyContext(block, prev, callback)
};
Chain.prototype._verify = function _verify(block, prev) {
// var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
var flags = {};
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
var sigops = 0;
var height, ts, i, tx, cb, coinbaseHeight;
var height, ts, i, tx, cb, coinbaseHeight, medianTime, locktimeMedian;
// Skip the genesis block
if (block.isGenesis())
@ -347,9 +348,10 @@ Chain.prototype._verify = function _verify(block, prev) {
}
height = prev.height + 1;
medianTime = prev.getMedianTime();
// Ensure the timestamp is correct
if (block.ts <= prev.getMedianTime()) {
if (block.ts <= medianTime) {
utils.debug('Block time is lower than median: %s', block.rhash);
return false;
}
@ -393,12 +395,12 @@ Chain.prototype._verify = function _verify(block, prev) {
coinbaseHeight = true;
// Signature validation is now enforced (bip66)
if (!(block.version >= 3 && prev.isUpgraded(3)))
flags.dersig = false;
if (block.version >= 3 && prev.isUpgraded(3))
flags |= constants.flags.VERIFY_DERSIG;
// CHECKLOCKTIMEVERIFY is now usable (bip65)
if (!(block.version >= 4 && prev.isUpgraded(4)))
flags.checklocktimeverify = false;
if (block.version >= 4 && prev.isUpgraded(4))
flags |= constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
// Use nLockTime median past (bip113)
// https://github.com/btcdrak/bips/blob/d4c9a236ecb947866c61aefb868b284498489c2b/bip-0113.mediawiki
@ -406,7 +408,7 @@ Chain.prototype._verify = function _verify(block, prev) {
// https://gist.github.com/sipa/bf69659f43e763540550
// http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html
// if (block.version >= 8 && prev.isUpgraded(8))
// flags.locktimeMedian = true;
// locktimeMedian = true;
// Can't verify any further when merkleblock or headers.
if (block.subtype !== 'block')
@ -430,9 +432,7 @@ Chain.prototype._verify = function _verify(block, prev) {
}
// Get timestamp for tx.isFinal().
ts = flags.locktimeMedian
? prev.getMedianTime()
: block.ts;
ts = locktimeMedian ? medianTime : block.ts;
// Check all transactions
for (i = 0; i < block.txs.length; i++) {
@ -474,12 +474,11 @@ Chain.prototype._verify = function _verify(block, prev) {
};
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
var node = bcoin.node.global;
var height = prev.height + 1;
var pending = block.txs.length;
var called;
if (!node || block.subtype !== 'block')
if (!this.blockdb || block.subtype !== 'block')
return callback(null, true);
if (block.isGenesis())
@ -499,7 +498,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
var hash = tx.hash('hex');
// BIP30 - Ensure there are no duplicate txids
node.block.hasTX(hash, function(err, result) {
self.blockdb.hasTX(hash, function(err, result) {
if (called)
return;
@ -522,10 +521,9 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
};
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
var node = bcoin.node.global;
var height = prev.height + 1;
if (!node || block.subtype !== 'block')
if (!this.blockdb || block.subtype !== 'block')
return callback(null, true);
if (block.isGenesis())
@ -536,7 +534,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
return callback(null, true);
node.block.fillCoins(block.txs, function(err) {
this.blockdb.fillCoins(block.txs, function(err) {
var i, j, input, hash;
if (err)

View File

@ -52,12 +52,16 @@ ChainBlock.prototype.getProof = function getProof() {
return new bn(1).ushln(256).div(target.addn(1));
};
ChainBlock.prototype.getChainwork = function() {
ChainBlock.prototype.getChainwork = function getChainwork() {
var prev = this.prev;
return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
};
ChainBlock.prototype.getMedianTime = function() {
ChainBlock.prototype.isGenesis = function isGenesis(version) {
return this.hash === network.genesis.hash;
};
ChainBlock.prototype.getMedianTime = function getMedianTime() {
var entry = this;
var median = [];
var timeSpan = constants.block.medianTimespan;
@ -71,15 +75,15 @@ ChainBlock.prototype.getMedianTime = function() {
return median[median.length / 2 | 0];
};
ChainBlock.prototype.isOutdated = function(version) {
ChainBlock.prototype.isOutdated = function isOutdated(version) {
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
};
ChainBlock.prototype.isUpgraded = function(version) {
ChainBlock.prototype.isUpgraded = function isUpgraded(version) {
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
};
ChainBlock.prototype.isSuperMajority = function(version, required) {
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required) {
var entry = this;
var found = 0;
var majorityWindow = network.block.majorityWindow;
@ -94,7 +98,7 @@ ChainBlock.prototype.isSuperMajority = function(version, required) {
return found >= required;
};
ChainBlock.prototype.toJSON = function() {
ChainBlock.prototype.toJSON = function toJSON() {
return {
hash: this.hash,
version: this.version,
@ -107,7 +111,7 @@ ChainBlock.prototype.toJSON = function() {
};
};
ChainBlock.fromJSON = function(chain, json) {
ChainBlock.fromJSON = function fromJSON(chain, json) {
return new ChainBlock(chain, json);
};

View File

@ -1213,9 +1213,13 @@ function pbkdf2(key, salt, iterations, dkLen) {
if (typeof key === 'string')
key = new Buffer(key, 'ascii');
else if (Array.isArray(key))
key = new Buffer(key);
if (typeof salt === 'string')
salt = new Buffer(salt, 'ascii');
else if (Array.isArray(key))
salt = new Buffer(salt);
var DK = new Buffer(dkLen);
var U = new Buffer(hLen);

View File

@ -19,7 +19,7 @@ var fs = bcoin.fs;
* Mempool
*/
function Mempool(node, options) {
function Mempool(pool, options) {
if (!(this instanceof Mempool))
return new Mempool(pool, options);
@ -27,9 +27,8 @@ function Mempool(node, options) {
options = {};
this.options = options;
this.node = node;
this.pool = node.pool;
this.block = node.block;
this.pool = pool;
this.blockdb = pool.blockdb;
this.txs = {};
this.spent = {};
@ -38,6 +37,8 @@ function Mempool(node, options) {
this.count = 0;
this.locked = false;
Mempool.global = this;
this._init();
}
@ -178,6 +179,7 @@ Mempool.prototype.hasTX = function hasTX(hash) {
Mempool.prototype.add =
Mempool.prototype.addTX = function addTX(tx, peer, callback) {
var self = this;
var flags = constants.flags.STANDARD_VERIFY_FLAGS;
var hash = tx.hash('hex');
assert(tx.ts === 0);
@ -201,7 +203,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
this._lockTX(tx);
this.block.fillCoin(tx, function(err) {
this.blockdb.fillCoin(tx, function(err) {
var i, input, dup, height, ts, priority;
self._unlockTX(tx);
@ -294,7 +296,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
}
}
if (!tx.verify(null, true)) {
if (!tx.verify(null, true, flags)) {
return callback(new Error('TX did not verify.'));
peer.reject({
data: tx.hash(),
@ -340,6 +342,8 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
self.txs[hash] = tx;
self.count++;
self.size += tx.getSize();
self.emit('tx', tx);
});
};
@ -425,6 +429,7 @@ Mempool.prototype.removeTX = function removeTX(hash, callback) {
delete this.txs[hash];
this.count--;
this.size -= tx.getSize();
this.emit('remove tx', tx);
};
// Need to lock the mempool when

View File

@ -137,46 +137,47 @@ Miner.prototype.addBlock = function addBlock(block) {
};
Miner.prototype.addTX = function addTX(tx) {
var full, ts;
var flags, height, ts;
full = this.index.inputs.every(function(input) {
return !!input.output;
});
flags = constants.flags.MANDATORY_VERIFY_FLAGS
| constants.flags.VERIFY_DERSIG
| constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
// Cannot calculate fee if we don't have the prev_out.
// Could possibly just burn some coins.
if (this.options.burn === false) {
if (!full)
return;
if (!tx.hasPrevout())
return false;
}
// Ignore if it's already in a block
if (tx.height !== -1)
return;
return false;
if (!tx.verify(null, true))
return;
if (!tx.verify(null, true, flags))
return false;
if (tx.isCoinbase())
return;
return false;
// Get timestamp for tx.isFinal() - bip113
ts = this.block.version === 8
height = this.last.height + 1;
ts = this.block.version >= 8
? this.last.getMedianTime()
: this.block.ts;
if (!tx.isFinal(this.last.height + 1, ts))
return;
if (!tx.isFinal(height, ts))
return false;
// Deliver me from the block size debate, please
if (this.block.getSize() + tx.getSize() > constants.blocks.maxSize)
return;
return false;
// Add the tx to our block
this.block.txs.push(tx);
// Calculate our new reward fee
if (full)
if (tx.hasPrevout())
this.fee.iadd(tx.getFee());
// Update coinbase value

View File

@ -35,7 +35,7 @@ function Node(options) {
if (this.options.network)
network.set(this.options.network);
this.block = null;
this.blockdb = null;
this.mempool = null;
this.pool = null;
this.chain = null;
@ -50,80 +50,27 @@ inherits(Node, EventEmitter);
Node.prototype._init = function _init() {
var self = this;
this.blockdb = new bcoin.blockdb(this.options.blockdb);
this.mempool = new bcoin.mempool(this, this.options.mempool);
if (!this.options.pool)
this.options.pool = {};
this.options.pool.type = 'full';
this.options.pool.spv = false;
this.options.pool.blockdb = this.blockdb;
this.options.pool.mempool = this.mempool;
this.block = new bcoin.blockdb(this.options.block);
this.mempool = new bcoin.mempool(this, this.options.mempool);
this.pool = new bcoin.pool(this.options.pool);
this.chain = this.pool.chain;
if (0)
this.pool.on('block', function(block, peer) {
self.mempool.addBlock(block);
});
if (0)
this.pool.on('block', function(block, peer) {
self.block.saveBlock(block, function(err) {
if (err)
throw err;
self.mempool.addBlock(block);
if (0)
var hash = block.txs[0].hash('hex');
if (0)
self.block.getTX(hash, function(err, tx) {
if (err) throw err;
utils.print(tx);
});
if (0)
self.block.getCoin(hash, 0, function(err, tx) {
if (err) throw err;
utils.print(tx);
});
});
});
this.mempool.on('error', function(err) {
self.emit('error', err);
});
this.chain.on('error', function(err) {
self.emit('error', err);
});
this.pool.on('error', function(err) {
self.emit('error', err);
});
this.pool.on('fork', function(data) {
if (data.block)
self.mempool.removeBlock(block);
});
if (0)
this.pool.on('fork', function(a, b) {
[a, b].forEach(function(hash) {
self.block.removeBlock(hash, function(err, block) {
if (err)
throw err;
if (!block)
return;
self.mempool.removeBlock(block);
});
});
});
this.pool.on('tx', function(tx, peer) {
assert(tx.ts === 0);
self.mempool.addTX(tx, peer);
});
this.pool.startSync();
};
@ -140,12 +87,12 @@ Node.prototype.getCoin = function getCoin(hash, index, callback) {
if (this.mempool.isSpent(hash, index))
return callback(null, null);
this.block.getCoin(hash, index, function(err, coin) {
this.blockdb.getCoin(hash, index, function(err, coin) {
if (err)
return callback(err);
if (!coin)
return;
return callback();
return callback(null, coin);
});
@ -159,7 +106,7 @@ Node.prototype.getCoinByAddress = function getCoinsByAddress(addresses, callback
mempool = this.mempool.getCoinsByAddress(addresses);
this.block.getCoinsByAddress(addresses, function(err, coins) {
this.blockdb.getCoinsByAddress(addresses, function(err, coins) {
if (err)
return callback(err);
@ -181,10 +128,13 @@ Node.prototype.getTX = function getTX(hash, callback) {
if (tx)
return callback(null, tx);
this.block.getTX(hash, function(err, tx) {
this.blockdb.getTX(hash, function(err, tx) {
if (err)
return callback(err);
if (!tx)
return callback();
return callback(null, tx);
});
};
@ -197,7 +147,7 @@ Node.prototype.isSpent = function isSpent(hash, index, callback) {
if (this.mempool.isSpent(hash, index))
return callback(null, true);
this.block.isSpent(hash, index, callback);
this.blockdb.isSpent(hash, index, callback);
};
Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
@ -208,7 +158,7 @@ Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
mempool = this.mempool.getTXByAddress(addresses);
this.block.getTXByAddress(addresses, function(err, txs) {
this.blockdb.getTXByAddress(addresses, function(err, txs) {
if (err)
return callback(err);
@ -218,16 +168,20 @@ Node.prototype.getTXByAddress = function getTXByAddress(addresses, callback) {
Node.prototype.fillCoin = function fillCoin(tx, callback) {
callback = utils.asyncify(callback);
if (this.mempool.fillCoin(tx))
return callback();
this.block.fillCoin(tx, callback);
this.blockdb.fillCoin(tx, callback);
};
Node.prototype.fillTX = function fillTX(tx, callback) {
callback = utils.asyncify(callback);
if (this.mempool.fillTX(tx))
return callback();
this.block.fillTX(tx, callback);
this.blockdb.fillTX(tx, callback);
};
/**

View File

@ -144,13 +144,11 @@ Peer.prototype._init = function init() {
self.pool.setMisbehavior(self, 100);
});
if (this.pool.options.fullNode) {
this.once('version', function() {
utils.debug(
'Sent version (%s): height=%s',
self.host, this.pool.chain.height());
});
}
this.once('version', function() {
utils.debug(
'Sent version (%s): height=%s',
self.host, this.pool.chain.height());
});
this._ping.timer = setInterval(function() {
self.challenge = utils.nonce();
@ -269,7 +267,7 @@ Peer.prototype.broadcast = function broadcast(items) {
};
Peer.prototype.updateWatch = function updateWatch() {
if (this.pool.options.fullNode)
if (!this.pool.options.spv)
return;
if (this.ack)

View File

@ -32,24 +32,24 @@ function Pool(options) {
this.options = options;
if (this.options.debug)
if (options.debug)
bcoin.debug = this.options.debug;
if (this.options.network)
network.set(this.options.network);
if (options.network)
network.set(options.network);
this.options.fullNode = !!this.options.fullNode;
options.spv = options.spv !== false;
if (options.type === 'spv')
this.options.fullNode = false;
options.spv = true;
else if (options.type === 'full')
this.options.fullNode = true;
options.spv = false;
this.options.headers = this.options.headers;
this.options.multiplePeers = this.options.multiplePeers;
this.options.relay = this.options.relay == null
? (this.options.fullNode ? true : false)
: this.options.relay;
options.headers = options.headers;
options.multiplePeers = options.multiplePeers;
options.relay = options.relay == null
? (!options.spv ? true : false)
: options.relay;
this.originalSeeds = (options.seeds || network.seeds).map(utils.parseHost);
this.setSeeds([]);
@ -58,20 +58,23 @@ function Pool(options) {
this.destroyed = false;
this.size = options.size || 32;
if (!this.options.fullNode) {
if (this.options.headers == null)
this.options.headers = true;
if (this.options.multiplePeers == null)
this.options.multiplePeers = true;
this.blockdb = options.blockdb;
this.mempool = options.mempool;
if (options.spv) {
if (options.headers == null)
options.headers = true;
if (options.multiplePeers == null)
options.multiplePeers = true;
} else {
if (this.options.headers == null)
this.options.headers = false;
if (this.options.multiplePeers == null)
this.options.multiplePeers = false;
if (options.headers == null)
options.headers = false;
if (options.multiplePeers == null)
options.multiplePeers = false;
}
if (!this.options.headers)
this.options.multiplePeers = false;
if (!options.headers)
options.multiplePeers = false;
this.syncing = false;
this.synced = false;
@ -84,9 +87,11 @@ function Pool(options) {
this.requestTimeout = options.requestTimeout || 600000;
this.chain = new bcoin.chain({
fullNode: this.options.fullNode,
multiplePeers: this.options.multiplePeers,
preload: this.options.preload
spv: options.spv,
multiplePeers: options.multiplePeers,
preload: options.preload,
blockdb: options.blockdb,
mempool: options.mempool
});
this.watchMap = {};
@ -115,7 +120,7 @@ function Pool(options) {
this.block = {
bestHeight: 0,
bestHash: null,
type: this.options.fullNode ? 'block' : 'filtered',
type: !options.spv ? 'block' : 'filtered',
invalid: {}
};
@ -133,10 +138,6 @@ function Pool(options) {
this.validate = {
// 5 days scan delta for obtaining TXs
delta: 5 * 24 * 3600,
// Minimum verification depth
minDepth: options.minValidateDepth || 0,
// getTX map
map: {}
};
@ -148,7 +149,7 @@ function Pool(options) {
};
// Added and watched wallets
this.options.wallets = this.options.wallets || [];
options.wallets = options.wallets || [];
this.wallets = [];
Pool.global = this;
@ -615,7 +616,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer, callback) {
requested = self._response(block);
// Emulate BIP37: emit all the filtered transactions.
if (self.options.fullNode && self.listeners('watched').length > 0) {
if (!self.options.spv && self.listeners('watched').length > 0) {
block.txs.forEach(function(tx) {
if (self.isWatched(tx))
self.emit('watched', tx, peer);
@ -857,22 +858,35 @@ Pool.prototype._handleTX = function _handleTX(tx, peer, callback) {
callback = utils.asyncify(callback);
this._prehandleTX(tx, peer, function(err) {
var requested, added;
function addMempool(tx, peer, callback) {
if (!self.mempool)
return callback();
if (tx.ts !== 0)
return callback();
self.mempool.addTX(tx, peer, callback);
}
this._prehandleTX(tx, peer, function(err) {
if (err)
return callback(err);
requested = self._response(tx);
added = self._addTX(tx, 1);
addMempool(tx, peer, function(err) {
var requested, added;
if (added || tx.block)
self.emit('tx', tx, peer);
if (err)
utils.debug('Mempool error: %s', err.message);
if (!self.options.fullNode && tx.block)
self.emit('watched', tx, peer);
requested = self._response(tx);
added = self._addTX(tx, 1);
return callback();
if (added || tx.block)
self.emit('tx', tx, peer);
if (self.options.spv && tx.block)
self.emit('watched', tx, peer);
return callback();
});
});
};
@ -1232,7 +1246,7 @@ Pool.prototype.addWallet = function addWallet(w) {
self.sendTX(tx);
});
if (self.options.fullNode)
if (!self.options.spv)
return;
if (self._pendingSearch)
@ -1323,7 +1337,7 @@ Pool.prototype.searchWallet = function(w, h) {
assert(!this.loading);
if (this.options.fullNode)
if (!this.options.spv)
return;
if (w == null) {
@ -1393,7 +1407,7 @@ Pool.prototype.search = function search(id, range, e) {
assert(!this.loading);
if (this.options.fullNode)
if (!this.options.spv)
return;
if (typeof e === 'function') {
@ -1570,7 +1584,7 @@ Pool.prototype.getTX = function getTX(hash, range, cb) {
if (!this.peers.load)
return setTimeout(this.getBlock.bind(this, hash, cb), 1000);
if (this.options.fullNode)
if (!this.options.spv)
return cb(new Error('Cannot get tx with full node'));
hash = utils.toHex(hash);

View File

@ -272,3 +272,33 @@ exports.userAgent = '/bcoin:' + exports.userVersion + '/';
exports.banTime = 24 * 60 * 60;
exports.banScore = 100;
// Script and locktime flags
exports.flags = {
VERIFY_NONE: 0,
VERIFY_P2SH: (1 << 0),
VERIFY_STRICTENC: (1 << 1),
VERIFY_DERSIG: (1 << 2),
VERIFY_LOW_S: (1 << 3),
VERIFY_NULLDUMMY: (1 << 4),
VERIFY_SIGPUSHONLY: (1 << 5),
VERIFY_MINIMALDATA: (1 << 6),
VERIFY_DISCOURAGE_UPGRADABLE_NOPS: (1 << 7),
VERIFY_CLEANSTACK: (1 << 8),
VERIFY_CHECKLOCKTIMEVERIFY: (1 << 9)
};
// Block validation
exports.flags.MANDATORY_VERIFY_FLAGS = exports.flags.VERIFY_P2SH;
// Mempool validation
exports.flags.STANDARD_VERIFY_FLAGS =
exports.flags.MANDATORY_VERIFY_FLAGS
| exports.flags.VERIFY_DERSIG
| exports.flags.VERIFY_STRICTENC
| exports.flags.VERIFY_MINIMALDATA
| exports.flags.VERIFY_NULLDUMMY
| exports.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS
| exports.flags.VERIFY_CLEANSTACK
| exports.flags.VERIFY_CHECKLOCKTIMEVERIFY
| exports.flags.VERIFY_LOW_S;

View File

@ -198,10 +198,10 @@ script.verify = function verify(input, output, tx, i, flags) {
var copy, res, redeem;
var stack = [];
if (!flags)
flags = {};
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (flags.sigpushonly !== false) {
if (flags & constants.flags.VERIFY_SIGPUSHONLY) {
if (!script.isPushOnly(input))
return false;
}
@ -210,7 +210,7 @@ script.verify = function verify(input, output, tx, i, flags) {
script.execute(input, stack, tx, i, flags);
// Copy the stack for P2SH
if (flags.verifyp2sh !== false)
if (flags & constants.flags.VERIFY_P2SH)
copy = stack.slice();
// Execute the previous output script
@ -221,7 +221,7 @@ script.verify = function verify(input, output, tx, i, flags) {
return false;
// If the script is P2SH, execute the real output script
if (flags.verifyp2sh !== false && script.isScripthash(output)) {
if ((flags & constants.flags.VERIFY_P2SH) && script.isScripthash(output)) {
// P2SH can only have push ops in the scriptSig
if (!script.isPushOnly(input))
return false;
@ -250,7 +250,7 @@ script.verify = function verify(input, output, tx, i, flags) {
}
// Ensure there is nothing left on the stack
if (flags.cleanstack !== false) {
if (flags & constants.flags.VERIFY_CLEANSTACK) {
if (stack.length !== 0)
return false;
}
@ -370,8 +370,8 @@ script._next = function _next(to, s, pc) {
script.execute = function execute(data, stack, tx, index, flags, recurse) {
var s = data.slice();
if (!flags)
flags = {};
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (s.length > constants.script.maxOps)
return false;
@ -418,7 +418,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
case 'nop8':
case 'nop9':
case 'nop10': {
if (flags.discourage_nops !== false)
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
return false;
break;
}
@ -908,7 +908,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
val = stack.pop();
if (flags.verifynulldummy !== false) {
if (flags & constants.flags.VERIFY_NULLDUMMY) {
if (!script.isDummy(val))
return false;
}
@ -925,8 +925,8 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
}
case 'checklocktimeverify': {
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
if (flags.checklocktimeverify === false) {
if (flags.discourage_nops !== false)
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
return false;
break;
}
@ -965,8 +965,8 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
}
case 'nop1': {
// OP_EVAL = OP_NOP1
if (flags['eval'] !== true) {
if (flags.discourage_nops !== false)
if (!script.allowEval) {
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
return false;
break;
}
@ -1126,10 +1126,13 @@ script.removeData = function removeData(s, data) {
};
script.checkPush = function checkPush(op, value, flags) {
if (!flags)
flags = {};
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (flags.minimaldata === false)
// Disabled for now.
return true;
if (!(flags & constants.flags.VERIFY_MINIMALDATA))
return true;
if (!op.pushdata)
@ -2038,13 +2041,13 @@ script.isData = function isData(data) {
};
script.isValidKey = function isValidKey(key, flags) {
if (!flags)
flags = {};
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (!utils.isBuffer(key))
return false;
if (flags.strictenc !== false) {
if (flags & constants.flags.VERIFY_STRICTENC) {
if (!script.isKeyEncoding(key))
return false;
}
@ -2073,8 +2076,8 @@ script.isKeyEncoding = function isKeyEncoding(key) {
};
script.isValidSignature = function isValidSignature(sig, flags) {
if (!flags)
flags = {};
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (!utils.isBuffer(sig))
return false;
@ -2083,19 +2086,19 @@ script.isValidSignature = function isValidSignature(sig, flags) {
if (sig.length === 0)
return true;
if (flags.dersig !== false
|| flags.low_s !== false
|| flags.strictenc !== false) {
if ((flags & constants.flags.VERIFY_DERSIG)
|| (flags & constants.flags.VERIFY_LOW_S)
|| (flags & constants.flags.VERIFY_STRICTENC)) {
if (!script.isSignatureEncoding(sig))
return false;
}
if (flags.low_s !== false) {
if (flags & constants.flags.VERIFY_LOW_S) {
if (!script.isLowDER(sig))
return false;
}
if (flags.strictenc !== false) {
if (flags & constants.flags.VERIFY_STRICTENC) {
if (!script.isHashType(sig))
return false;
}

View File

@ -809,13 +809,6 @@ TX.prototype.signatureHash = function signatureHash(index, s, type) {
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
if (!Array.isArray(s)) {
type = s;
s = this.inputs[index].output.script;
if (bcoin.script.isScripthash(s))
s = bcoin.script.getRedeem(this.inputs[index].script);
}
if (typeof type === 'string')
type = constants.hashType[type];