reject packets. pool refactor.

This commit is contained in:
Christopher Jeffrey 2016-03-23 15:11:58 -07:00
parent 5023c7efe4
commit 6d5e277629
7 changed files with 150 additions and 190 deletions

View File

@ -65,22 +65,29 @@ AbstractBlock.prototype.getSize = function getSize() {
return this._size || this.render().length;
};
AbstractBlock.prototype.verify = function verify() {
AbstractBlock.prototype.verify = function verify(ret) {
if (this.valid == null)
this.valid = this._verify();
this.valid = this._verify(ret);
return this.valid;
};
AbstractBlock.prototype.verifyHeaders = function verifyHeaders() {
AbstractBlock.prototype.verifyHeaders = function verifyHeaders(ret) {
if (!ret)
ret = {};
// Check proof of work
if (!utils.testTarget(this.bits, this.hash())) {
utils.debug('Block failed POW test: %s', this.rhash);
ret.reason = 'high-hash';
ret.score = 50;
return false;
}
// Check timestamp against now + 2 hours
if (this.ts > utils.now() + 2 * 60 * 60) {
utils.debug('Block timestamp is too high: %s', this.rhash);
ret.reason = 'time-too-new';
ret.score = 0;
return false;
}

View File

@ -168,23 +168,30 @@ Block.prototype.__defineGetter__('commitmentHash', function() {
return this._commitmentHash;
});
Block.prototype._verify = function _verify() {
Block.prototype._verify = function _verify(ret) {
var uniq = {};
var i, tx, hash;
if (!this.verifyHeaders())
if (!ret)
ret = {};
if (!this.verifyHeaders(ret))
return false;
// Size can't be bigger than MAX_BLOCK_SIZE
if (this.txs.length > constants.block.maxSize
|| this.getVirtualSize() > constants.block.maxSize) {
utils.debug('Block is too large: %s', this.rhash);
ret.reason = 'bad-blk-length';
ret.score = 100;
return false;
}
// First TX must be a coinbase
if (!this.txs.length || !this.txs[0].isCoinbase()) {
utils.debug('Block has no coinbase: %s', this.rhash);
ret.reason = 'bad-cb-missing';
ret.score = 100;
return false;
}
@ -195,6 +202,8 @@ Block.prototype._verify = function _verify() {
// The rest of the txs must not be coinbases
if (i > 0 && tx.isCoinbase()) {
utils.debug('Block more than one coinbase: %s', this.rhash);
ret.reason = 'bad-cb-multiple';
ret.score = 100;
return false;
}
@ -202,6 +211,8 @@ Block.prototype._verify = function _verify() {
hash = tx.hash('hex');
if (uniq[hash]) {
utils.debug('Block has duplicate txids: %s', this.rhash);
ret.reason = 'bad-txns-duplicate';
ret.score = 100;
return false;
}
uniq[hash] = true;
@ -210,6 +221,8 @@ Block.prototype._verify = function _verify() {
// Check merkle root
if (this.getMerkleRoot() !== this.merkleRoot) {
utils.debug('Block failed merkleroot test: %s', this.rhash);
ret.reason = 'bad-txnmrkleroot';
ret.score = 100;
return false;
}

View File

@ -331,24 +331,24 @@ Chain.prototype._preload = function _preload(callback) {
});
};
Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) {
Chain.prototype._verifyContext = function _verifyContext(block, prev, peer, callback) {
var self = this;
this._verify(block, prev, function(err, flags) {
this._verify(block, prev, peer, function(err, flags) {
if (err)
return callback(err);
if (flags === false)
return callback(null, false);
self._checkDuplicates(block, prev, function(err, result) {
self._checkDuplicates(block, prev, peer, function(err, result) {
if (err)
return callback(err);
if (!result)
return callback(null, false);
self._checkInputs(block, prev, flags, function(err, result) {
self._checkInputs(block, prev, flags, peer, function(err, result) {
if (err)
return callback(err);
@ -361,19 +361,22 @@ Chain.prototype._verifyContext = function _verifyContext(block, prev, callback)
});
};
Chain.prototype._verify = function _verify(block, prev, callback) {
Chain.prototype._verify = function _verify(block, prev, peer, callback) {
var self = this;
var flags = constants.flags.MANDATORY_VERIFY_FLAGS;
var height, ts, i, tx, coinbaseHeight;
var medianTime, locktimeMedian, segwit;
var ret = {};
function done(err, result) {
prev.free();
callback(err, result);
}
if (!block.verify())
if (!block.verify(ret)) {
self.emit('verify-error', block, ret.reason, ret.score, peer);
return done(null, false);
}
// Skip the genesis block
if (block.isGenesis())
@ -395,11 +398,13 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
// Ensure the timestamp is correct
if (block.ts <= medianTime) {
utils.debug('Block time is lower than median: %s', block.rhash);
self.emit('verify-error', block, 'time-too-old', 0, peer);
return done(null, false);
}
if (block.bits !== self.getTarget(prev, block)) {
utils.debug('Block is using wrong target: %s', block.rhash);
self.emit('verify-error', block, 'bad-diffbits', 100, peer);
return done(null, false);
}
@ -418,6 +423,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
// once the majority of blocks are using it.
if (block.version < 2 && prev.isOutdated(2)) {
utils.debug('Block is outdated (v2): %s', block.rhash);
self.emit('verify-error', block, 'bad-version', 0, peer);
return done(null, false);
}
@ -425,6 +431,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
// once the majority of blocks are using it.
if (block.version < 3 && prev.isOutdated(3)) {
utils.debug('Block is outdated (v3): %s', block.rhash);
self.emit('verify-error', block, 'bad-version', 0, peer);
return done(null, false);
}
@ -432,6 +439,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
// once the majority of blocks are using it.
if (block.version < 4 && prev.isOutdated(4)) {
utils.debug('Block is outdated (v4): %s', block.rhash);
self.emit('verify-error', block, 'bad-version', 0, peer);
return done(null, false);
}
@ -440,6 +448,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
if (block.version < 5 && prev.isOutdated(5)) {
utils.debug('Block is outdated (v5): %s', block.rhash);
self.emit('verify-error', block, 'bad-version', 0, peer);
return done(null, false);
}
}
@ -481,6 +490,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
if (coinbaseHeight) {
if (block.getCoinbaseHeight() !== height) {
utils.debug('Block has bad coinbase height: %s', block.rhash);
self.emit('verify-error', block, 'bad-cb-height', 100, peer);
return done(null, false);
}
}
@ -488,11 +498,13 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
if (block.version >= 5 && segwit) {
if (block.commitmentHash !== block.getCommitmentHash()) {
utils.debug('Block failed witnessroot test: %s', block.rhash);
self.emit('verify-error', block, 'bad-blk-wit-length', 100, peer);
return done(null, false);
}
} else {
if (block.hasWitness()) {
utils.debug('Unexpected witness data found: %s', block.rhash);
self.emit('verify-error', block, 'unexpected-witness', 100, peer);
return done(null, false);
}
}
@ -508,6 +520,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
// regards to nSequence and nLockTime.
if (!tx.isFinal(height, ts)) {
utils.debug('TX is not final: %s (%s)', block.rhash, i);
self.emit('verify-error', block, 'bad-txns-nonfinal', 10, peer);
return done(null, false);
}
}
@ -516,7 +529,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
});
};
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, peer, callback) {
var self = this;
var height = prev.height + 1;
@ -540,8 +553,10 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
// and extraNonce.
if (result) {
utils.debug('Block is overwriting txids: %s', block.rhash);
if (!(network.type === 'main' && (height === 91842 || height === 91880)))
if (!(network.type === 'main' && (height === 91842 || height === 91880))) {
self.emit('verify-error', block, 'bad-txns-BIP30', 100, peer);
return next(null, false);
}
}
next(null, true);
@ -549,7 +564,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
}, callback);
};
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, peer, callback) {
var height = prev.height + 1;
var scriptCheck = true;
@ -588,6 +603,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
if (sigops > constants.script.maxBlockSigops) {
utils.debug('Block has too many sigops: %s', block.rhash);
self.emit('verify-error', block, 'bad-blk-sigops', 100, peer);
return callback(null, false);
}
@ -610,6 +626,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
utils.revHex(input.prevout.hash) + '/' + input.prevout.index);
if (height < network.checkpoints.lastHeight)
throw new Error('BUG: Spent inputs in historical data!');
self.emit('verify-error', block, 'bad-txns-inputs-missingorspent', 100, peer);
return callback(null, false);
}
@ -661,8 +678,10 @@ Chain.prototype._checkReward = function _checkReward(block) {
for (i = 1; i < block.txs.length; i++)
actual.iadd(block.txs[i].getFee());
if (claimed.cmp(actual) > 0)
if (claimed.cmp(actual) > 0) {
self.emit('verify-error', block, 'bad-cb-amount', 100, peer);
return false;
}
return true;
};
@ -910,6 +929,7 @@ Chain.prototype.onFlush = function onFlush(callback) {
Chain.prototype.add = function add(initial, peer, callback, force) {
var self = this;
var total = 0;
var ret = {};
assert(this.loaded);
@ -951,6 +971,7 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
chain: !!self.invalid[prevHash]
}, peer);
self.invalid[hash] = true;
self.emit('verify-error', block, 'duplicate', 0, peer);
return done();
}
@ -958,7 +979,7 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
// This is only necessary for new
// blocks coming in, not the resolving
// orphans.
if (block === initial && !block.verify()) {
if (block === initial && !block.verify(ret)) {
self.invalid[hash] = true;
self.emit('invalid', block, {
height: height,
@ -966,6 +987,7 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
seen: false,
chain: false
}, peer);
self.emit('verify-error', block, ret.reason, ret.score, peer);
return done();
}
@ -999,6 +1021,9 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
seen: true
}, peer);
if (self.options.headers)
self.emit('verify-error', block, 'bad-prevblk', 0, peer);
return done();
}
@ -1021,6 +1046,8 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
hash: hash,
seen: false
}, peer);
if (self.options.headers)
self.emit('verify-error', block, 'bad-prevblk', 0, peer);
return done();
}
@ -1050,6 +1077,8 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
checkpoint: true
}, peer);
self.emit('verify-error', block, 'checkpoint mismatch', 100, peer);
return done();
}
}
@ -1087,7 +1116,7 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
// Do "contextual" verification on our block
// now that we're certain its previous
// block is in the chain.
self._verifyContext(block, prev, function(err, verified) {
self._verifyContext(block, prev, peer, function(err, verified) {
var entry;
// Couldn't verify block.

View File

@ -30,8 +30,8 @@ function CompactBlock(data) {
utils.inherits(CompactBlock, bcoin.abstractblock);
CompactBlock.prototype._verify = function _verify() {
return this.verifyHeaders();
CompactBlock.prototype._verify = function _verify(ret) {
return this.verifyHeaders(ret);
};
CompactBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {

View File

@ -54,6 +54,7 @@ function Mempool(node, options) {
this.pendingTX = {};
this.pendingSize = 0;
this.pendingLimit = 20 << 20;
this.locker = new bcoin.locker(this, this.add, this.pendingLimit);
this.freeCount = 0;
this.lastTime = 0;
@ -74,79 +75,11 @@ Mempool.flags = constants.flags.STANDARD_VERIFY_FLAGS;
Mempool.mandatory = constants.flags.MANDATORY_VERIFY_FLAGS;
Mempool.prototype._lock = function _lock(func, args, force) {
var self = this;
var tx, called;
if (force) {
assert(this.busy);
return function unlock() {
assert(!called);
called = true;
};
}
if (this.busy) {
if (func === Mempool.prototype.add) {
tx = args[0];
this.pending.push(tx);
this.pendingTX[tx.hash('hex')] = true;
this.pendingSize += tx.getSize();
if (this.pendingSize > this.pendingLimit) {
this.purgePending();
return;
}
}
this.jobs.push([func, args]);
return;
}
this.busy = true;
return function unlock() {
var item, tx;
assert(!called);
called = true;
self.busy = false;
if (func === Mempool.prototype.add) {
if (self.pending.length === 0)
self.emit('flush');
}
if (self.jobs.length === 0)
return;
item = self.jobs.shift();
if (item[0] === Mempool.prototype.add) {
tx = item[1][0];
assert(tx === self.pending.shift());
delete self.pendingTX[tx.hash('hex')];
self.pendingSize -= tx.getSize();
}
item[0].apply(self, item[1]);
};
return this.locker.lock(func, args, force);
};
Mempool.prototype.purgePending = function purgePending() {
var self = this;
utils.debug('Warning: %dmb of pending txs. Purging.',
utils.mb(this.pendingSize));
this.pending.forEach(function(tx) {
delete self.pendingTX[tx.hash('hex')];
});
this.pending.length = 0;
this.pendingSize = 0;
this.jobs = this.jobs.filter(function(item) {
return item[0] !== Mempool.prototype.add;
});
return this.locker.purgePending();
};
Mempool.prototype._init = function _init() {
@ -488,10 +421,9 @@ Mempool.prototype.resolveOrphans = function resolveOrphans(tx, callback, force)
var hashes = [];
var resolved = [];
var batch = this.db.batch();
var p;
this.db.get('d/' + hash, function(err, buf) {
var p;
if (err && err.type !== 'NotFoundError')
return callback(err);
@ -600,6 +532,10 @@ Mempool.prototype.removeTX = function removeTX(hash, callback, force) {
};
Mempool.prototype.checkTX = function checkTX(tx, peer) {
return Mempool.checkTX(tx, peer);
};
Mempool.checkTX = function checkTX(tx, peer) {
var i, input, output, size;
var total = new bn(0);
var uniq = {};

View File

@ -99,13 +99,18 @@ MerkleBlock.prototype._verifyPartial = function _verifyPartial() {
return true;
};
MerkleBlock.prototype._verify = function _verify() {
if (!this.verifyHeaders())
MerkleBlock.prototype._verify = function _verify(ret) {
if (!ret)
ret = {};
if (!this.verifyHeaders(ret))
return false;
// Verify the partial merkle tree if we are a merkleblock.
if (!this._verifyPartial()) {
utils.debug('Block failed merkle test: %s', this.rhash);
ret.reason = 'bad-txnmrklroot';
ret.score = 100;
return false;
}

View File

@ -186,43 +186,24 @@ Pool.prototype._init = function _init() {
}
});
this.chain.on('verify-error', function(block, reason, score, peer) {
peer.sendReject(block, reason, score);
});
this.chain.on('fork', function(block, data, peer) {
self.emit('fork', data, peer);
if (!peer)
return;
// If we failed a checkpoint, peer is misbehaving.
if (data.checkpoint) {
self.setMisbehavior(peer, 100);
return;
}
});
this.chain.on('invalid', function(block, data, peer) {
if (!peer)
return;
self.setMisbehavior(peer, 100);
self.emit('invalid', data, peer);
});
this.chain.on('exists', function(block, data, peer) {
if (!peer)
return;
// self.setMisbehavior(peer, 1);
self.emit('exists', data, peer);
});
this.chain.on('orphan', function(block, data, peer) {
if (!peer)
return;
// Increase banscore by 10 if we're using getheaders.
if (self.options.headers) {
// self.setMisbehavior(peer, 10);
return;
}
self.emit('orphan', data, peer);
// Resolve orphan chain
self.resolveOrphan(self.peers.load, null, data.hash);
});
@ -520,9 +501,6 @@ Pool.prototype._addLoader = function _addLoader() {
};
Pool.prototype.startSync = function startSync() {
if (!this.loaded)
return this.once('open', this.startSync.bind(this));
this.syncing = true;
this._startInterval();
@ -567,7 +545,7 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer, callback)
peer.host);
if (headers.length > 2000) {
this.setMisbehavior(peer, 100);
peer.setMisbehavior(100);
return callback();
}
@ -627,7 +605,7 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer, callback) {
// Normally this is 500, but with older
// versions locator.GetDistanceBack() is called.
// if (hashes.length > 500) {
// this.setMisbehavior(peer, 100);
// peer.setMisbehavior(100);
// return;
// }
@ -1140,29 +1118,19 @@ Pool.prototype.watch = function watch(id) {
if (id) {
hid = utils.toHex(id);
if (this.watchMap[hid])
if (this.watchMap[hid]) {
this.watchMap[hid]++;
else
this.watchMap[hid] = 1;
return;
}
this.watchMap[hid] = 1;
this.bloom.add(id);
}
// Send it to peers
if (this._pendingWatch)
return;
this._pendingWatch = true;
utils.nextTick(function() {
self._pendingWatch = false;
if (self.peers.load)
self.peers.load.updateWatch();
for (i = 0; i < self.peers.regular.length; i++)
self.peers.regular[i].updateWatch();
});
this.updateWatch();
};
Pool.prototype.unwatch = function unwatch(id) {
@ -1171,9 +1139,6 @@ Pool.prototype.unwatch = function unwatch(id) {
id = utils.toHex(id);
if (!this.bloom.test(id, 'hex'))
return;
if (!this.watchMap[id] || --this.watchMap[id] !== 0)
return;
@ -1182,10 +1147,16 @@ Pool.prototype.unwatch = function unwatch(id) {
// Reset bloom filter
this.bloom.reset();
Object.keys(this.watchMap).forEach(function(id) {
this.bloom.add(id, 'hex');
this.bloom.add(id);
}, this);
// Resend it to peers
this.updateWatch();
};
Pool.prototype.updateWatch = function updateWatch() {
var self = this;
if (this._pendingWatch)
return;
@ -1205,13 +1176,13 @@ Pool.prototype.unwatch = function unwatch(id) {
// See "Filter matching algorithm":
// https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki
Pool.prototype.isWatched = function(tx, bloom) {
var i, prev, input, output;
var i, input, output;
if (!bloom)
bloom = this.bloom;
function testScript(script) {
return script.some(function(chunk) {
function testScript(code) {
return code.some(function(chunk) {
if (!Buffer.isBuffer(chunk) || chunk.length === 0)
return false;
return bloom.test(chunk);
@ -1227,7 +1198,7 @@ Pool.prototype.isWatched = function(tx, bloom) {
for (i = 0; i < tx.outputs.length; i++) {
output = tx.outputs[i];
// Test the output script
if (testScript(output.script))
if (testScript(output.script.code))
return true;
}
@ -1235,23 +1206,23 @@ Pool.prototype.isWatched = function(tx, bloom) {
// 4. Test data elements in input scripts
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
prev = input.prevout.hash;
if (typeof prev === 'string')
prev = new Buffer(prev, 'hex');
// Test the prev_out tx hash
if (bloom.test(prev))
if (bloom.test(input.prevout.hash, 'hex'))
return true;
// Test the prev_out script
if (input.output) {
if (testScript(input.output.script))
if (testScript(input.output.script.code))
return true;
}
// Test the input script
if (testScript(input.script))
if (testScript(input.script.code))
return true;
// Test the witness
if (testScript(input.witness.items))
return true;
}
@ -1262,9 +1233,6 @@ Pool.prototype.isWatched = function(tx, bloom) {
Pool.prototype.addWallet = function addWallet(wallet, callback) {
var self = this;
if (!this.loaded)
return this.once('open', this.addWallet.bind(this, wallet, callback));
callback = utils.asyncify(callback);
if (this.options.spv)
@ -1295,13 +1263,13 @@ Pool.prototype.removeWallet = function removeWallet(wallet) {
};
Pool.prototype.watchAddress = function watchAddress(address) {
address = bcoin.address.parse(address);
this.watch(address.hash);
var hash = bcoin.address.parse(address).hash;
this.watch(hash);
};
Pool.prototype.unwatchAddress = function unwatchAddress(address) {
address = bcoin.address.parse(address);
this.unwatch(address.hash);
var hash = bcoin.address.parse(address).hash;
this.unwatch(hash);
};
Pool.prototype.watchWallet = function watchWallet(wallet) {
@ -1464,13 +1432,9 @@ Pool.prototype.getData = function getData(peer, type, hash, options, callback) {
if (exists)
return callback();
if (self.request.map[hash]) {
// if (callback)
// self.request.map[hash].callback.push(callback);
if (self.request.map[hash])
return callback();
}
// item = new LoadRequest(self, peer, type, hash, callback);
item = new LoadRequest(self, peer, type, hash);
if (options.noQueue)
@ -1503,7 +1467,9 @@ Pool.prototype.getData = function getData(peer, type, hash, options, callback) {
if (!options.force && type !== self.tx.type)
return self.chain.has(hash, done);
return done(null, false);
return utils.nextTick(function() {
return done(null, false);
});
};
Pool.prototype.scheduleRequests = function scheduleRequests(peer) {
@ -1587,15 +1553,15 @@ Pool.prototype.getBlock = function getBlock(hash, callback) {
if (!this.peers.load)
return setTimeout(this.getBlock.bind(this, hash, callback), 1000);
this.getData(this.peers.load, 'block', hash, { force: true }, function(block) {
this.getData(this.peers.load, this.block.type, hash, { force: true }, function(block) {
callback(null, block);
});
this.scheduleRequests(this.peers.load);
};
Pool.prototype.sendBlock = function sendBlock(block) {
return this.broadcast(block);
Pool.prototype.sendBlock = function sendBlock(block, callback) {
return this.broadcast(block, callback);
};
Pool.prototype.getTX = function getTX(hash, range, callback) {
@ -1668,27 +1634,22 @@ Pool.prototype.getTX = function getTX(hash, range, callback) {
})();
};
Pool.prototype.sendTX = function sendTX(tx) {
var flags = constants.flags.STANDARD_VERIFY_FLAGS;
// This is to avoid getting banned by
// bitcoind nodes. Possibly check
// sigops. Call isStandard and/or
// isStandardInputs as well.
if (tx.hasPrevout()) {
if (!tx.verify(null, true, flags)) {
utils.debug(
'Could not relay TX (%s). It does not verify.',
tx.rhash);
return;
}
}
return this.broadcast(tx);
Pool.prototype.sendTX = function sendTX(tx, callback) {
callback = utils.asyncify(callback);
// Failsafe to avoid getting banned by bitcoind nodes.
if (!bcoin.mempool.checkTX(tx))
return callback(new Error('CheckTransaction failed.'));
return this.broadcast(tx, callback);
};
Pool.prototype.broadcast = function broadcast(msg) {
Pool.prototype.broadcast = function broadcast(msg, callback) {
var self = this;
var e = new EventEmitter();
callback = utils.once(callback);
var entry = {
msg: msg,
e: e,
@ -1696,6 +1657,7 @@ Pool.prototype.broadcast = function broadcast(msg) {
var i = self.inv.list.indexOf(entry);
if (i !== -1)
self.inv.list.splice(i, 1);
callback(new Error('Timed out.'));
}, this.inv.timeout)
};
@ -1703,9 +1665,17 @@ Pool.prototype.broadcast = function broadcast(msg) {
this.peers.regular.forEach(function(peer) {
var result = peer.broadcast(msg);
if (!result) return;
if (!result)
return;
result[0].once('request', function() {
e.emit('ack', peer);
callback();
});
result[0].once('reject', function(payload) {
e.emit('reject', payload, peer);
callback(new Error('TX was rejected: ' + payload.reason));
});
});
@ -1916,7 +1886,7 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) {
Pool.prototype.reject = function reject(peer, obj, reason, dos) {
if (dos != null)
this.setMisbehavior(peer, dos);
peer.setMisbehavior(dos);
utils.debug('Rejecting %s %s: reason=%s',
obj.type, obj.hash('hex'), reason);