fixes. refactor.
This commit is contained in:
parent
eb569ae12d
commit
b792976586
@ -169,7 +169,7 @@ Mempool.prototype.addBlock = function addBlock(block) {
|
||||
callback = utils.ensure(callback);
|
||||
// Remove now-mined transactions
|
||||
// XXX should batch this
|
||||
utils.forEachSerial(block.txs.slice().reverse(), function(tx, next) {
|
||||
utils.forEachSerial(block.txs, function(tx, next) {
|
||||
self.tx.remove(tx, next);
|
||||
}, callback);
|
||||
};
|
||||
@ -178,7 +178,7 @@ Mempool.prototype.removeBlock = function removeBlock(block, callback) {
|
||||
var self = this;
|
||||
callback = utils.ensure(callback);
|
||||
// XXX should batch this
|
||||
utils.forEachSerial(block.txs, function(tx, next) {
|
||||
utils.forEachSerial(block.txs.slice().reverse(), function(tx, next) {
|
||||
self.tx.add(tx, next);
|
||||
}, callback);
|
||||
};
|
||||
@ -187,7 +187,7 @@ Mempool.prototype.get =
|
||||
Mempool.prototype.getTX = function getTX(hash, callback) {
|
||||
if (hash instanceof bcoin.tx)
|
||||
hash = hash.hash('hex');
|
||||
return this.tx.getTX(hash, index, callback);
|
||||
return this.tx.getTX(hash, callback);
|
||||
};
|
||||
|
||||
Mempool.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
@ -246,15 +246,15 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
return callback(new Error('CheckTransaction failed'));
|
||||
|
||||
if (tx.isCoinbase()) {
|
||||
this.reject(peer, tx, 'coinbase', 100);
|
||||
peer.sendReject(tx, 'coinbase', 100);
|
||||
return callback(new Error('coinbase as individual tx'));
|
||||
}
|
||||
|
||||
ts = utils.now();
|
||||
height = this.chain.height + 1;
|
||||
|
||||
if (self.requireStandard && !tx.isStandard(flags, ts, height, ret)) {
|
||||
self.reject(peer, tx, ret.reason, 0);
|
||||
if (this.requireStandard && !tx.isStandard(flags, ts, height, ret)) {
|
||||
peer.sendReject(tx, ret.reason, 0);
|
||||
return callback(new Error('TX is not standard.'));
|
||||
}
|
||||
|
||||
@ -281,50 +281,50 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
return callback(new Error('TX inputs are not standard.'));
|
||||
|
||||
if (tx.getSigops(true) > constants.script.maxSigops) {
|
||||
self.reject(peer, tx, 'bad-txns-too-many-sigops', 0);
|
||||
peer.sendReject(tx, 'bad-txns-too-many-sigops', 0);
|
||||
return callback(new Error('TX has too many sigops.'));
|
||||
}
|
||||
|
||||
total = new bn(0);
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
coin = input.coin;
|
||||
coin = input.output;
|
||||
|
||||
if (coin.isCoinbase()) {
|
||||
if (self.chain.height - coin.height < constants.tx.coinbaseMaturity) {
|
||||
self.reject(peer, tx, 'bad-txns-premature-spend-of-coinbase', 0);
|
||||
peer.sendReject(tx, 'bad-txns-premature-spend-of-coinbase', 0);
|
||||
return callback(new Error('Tried to spend coinbase prematurely.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (coin.value.cmpn(0) < 0 || coin.value.cmp(constants.maxMoney) > 0)
|
||||
return self.reject(peer, tx, 'bad-txns-inputvalues-outofrange', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-inputvalues-outofrange', 100);
|
||||
|
||||
total.iadd(coin.value);
|
||||
}
|
||||
|
||||
if (total.cmpn(0) < 0 || total.cmp(constants.maxMoney) > 0)
|
||||
return self.reject(peer, tx, 'bad-txns-inputvalues-outofrange', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-inputvalues-outofrange', 100);
|
||||
|
||||
if (tx.getOutputValue().cmp(total) > 0) {
|
||||
self.reject(peer, tx, 'bad-txns-in-belowout', 100);
|
||||
peer.sendReject(tx, 'bad-txns-in-belowout', 100);
|
||||
return callback(new Error('TX is spending coins it does not have.'));
|
||||
}
|
||||
|
||||
fee = total.subn(tx.getOutputValue());
|
||||
|
||||
if (fee.cmpn(0) < 0) {
|
||||
self.reject(peer, tx, 'bad-txns-fee-negative', 100);
|
||||
peer.sendReject(tx, 'bad-txns-fee-negative', 100);
|
||||
return callback(new Error('TX has a negative fee.'));
|
||||
}
|
||||
|
||||
if (fee.cmp(constants.maxMoney) > 0) {
|
||||
return self.reject(peer, tx, 'bad-txns-fee-outofrange', 100);
|
||||
peer.sendReject(tx, 'bad-txns-fee-outofrange', 100);
|
||||
return callback(new Error('TX has a fee higher than max money.'));
|
||||
}
|
||||
|
||||
if (self.limitFree && fee.cmp(tx.getMinFee(true)) < 0) {
|
||||
self.reject(peer, tx, 'insufficient fee', 0);
|
||||
peer.sendReject(tx, 'insufficient fee', 0);
|
||||
return callback(new Error('Insufficient fee.'));
|
||||
}
|
||||
|
||||
@ -338,7 +338,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
self.lastTime = now;
|
||||
|
||||
if (self.freeCount > self.limitFreeRelay * 10 * 1000) {
|
||||
self.reject(peer, tx, 'insufficient priority', 0);
|
||||
peer.sendReject(tx, 'insufficient priority', 0);
|
||||
return callback(new Error('Too many free txs at once!'));
|
||||
}
|
||||
|
||||
@ -355,14 +355,14 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
|
||||
if (!result) {
|
||||
// Just say it's non-mandatory for now.
|
||||
self.reject(peer, tx, 'non-mandatory-script-verify-flag', 0);
|
||||
peer.sendReject(tx, 'non-mandatory-script-verify-flag', 0);
|
||||
return callback(new Error('TX did not verify.'));
|
||||
}
|
||||
|
||||
self.tx.add(tx, function(err) {
|
||||
if (err) {
|
||||
if (err.message === 'Transaction is double-spending.') {
|
||||
self.reject(peer, tx, 'bad-txns-inputs-spent', 0);
|
||||
peer.sendReject(tx, 'bad-txns-inputs-spent', 0);
|
||||
}
|
||||
return callback(err);
|
||||
}
|
||||
@ -389,17 +389,17 @@ Mempool.prototype.removeTX = function removeTX(hash, callback, force) {
|
||||
return;
|
||||
|
||||
function getTX() {
|
||||
if (hash.hash) {
|
||||
hash = hash.hash('hex');
|
||||
return self.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (!tx)
|
||||
return callback();
|
||||
return self.node.fillTX(hash, callback);
|
||||
});
|
||||
}
|
||||
return callback(null, hash);
|
||||
if (hash instanceof bcoin.tx)
|
||||
return callback(null, hash);
|
||||
|
||||
hash = hash.hash('hex');
|
||||
return self.getTX(hash, function(err, tx) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (!tx)
|
||||
return callback();
|
||||
return self.node.fillTX(hash, callback);
|
||||
});
|
||||
}
|
||||
|
||||
getTX(function(err, tx) {
|
||||
@ -421,64 +421,47 @@ Mempool.prototype.checkTX = function checkTX(tx, peer) {
|
||||
var uniq = {};
|
||||
|
||||
if (tx.inputs.length === 0)
|
||||
return this.reject(peer, tx, 'bad-txns-vin-empty', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-vin-empty', 100);
|
||||
|
||||
if (tx.outputs.length === 0)
|
||||
return this.reject(peer, tx, 'bad-txns-vout-empty', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-vout-empty', 100);
|
||||
|
||||
if (tx.getSize() > constants.block.maxSize)
|
||||
return this.reject(peer, tx, 'bad-txns-oversize', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-oversize', 100);
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
if (output.value.cmpn(0) < 0)
|
||||
return this.reject(peer, tx, 'bad-txns-vout-negative', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-vout-negative', 100);
|
||||
if (output.value.cmp(constants.maxMoney) > 0)
|
||||
return this.reject(peer, tx, 'bad-txns-vout-toolarge', 100);
|
||||
return peer.sendReject(tx, 'bad-txns-vout-toolarge', 100);
|
||||
total.iadd(output.value);
|
||||
if (total.cmpn(0) < 0 || total.cmp(constants.maxMoney))
|
||||
return this.reject(peer, tx, 'bad-txns-txouttotal-toolarge', 100);
|
||||
if (total.cmpn(0) < 0 || total.cmp(constants.maxMoney) > 0)
|
||||
return peer.sendReject(tx, 'bad-txns-txouttotal-toolarge', 100);
|
||||
}
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
if (uniq[input.out.hash])
|
||||
return this.reject(peer, tx, 'bad-txns-inputs-duplicate', 100);
|
||||
uniq[input.out.hash] = true;
|
||||
if (uniq[input.prevout.hash])
|
||||
return peer.sendReject(tx, 'bad-txns-inputs-duplicate', 100);
|
||||
uniq[input.prevout.hash] = true;
|
||||
}
|
||||
|
||||
if (tx.isCoinbase()) {
|
||||
size = bcoin.script.getSize(tx.inputs[0].script);
|
||||
if (size < 2 || size > 100)
|
||||
return this.reject(peer, tx, 'bad-cb-length', 100);
|
||||
return peer.sendReject(tx, 'bad-cb-length', 100);
|
||||
} else {
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
if (+input.out.hash === 0)
|
||||
return this.reject(peer, tx, 'bad-txns-prevout-null', 10);
|
||||
if (+input.prevout.hash === 0)
|
||||
return peer.sendReject(tx, 'bad-txns-prevout-null', 10);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Mempool.prototype.reject = function reject(peer, obj, reason, dos) {
|
||||
utils.debug('Rejecting TX %s. Reason=%s.', obj.hash('hex'), reason);
|
||||
|
||||
if (dos != null)
|
||||
this.node.pool.setMisbehavior(peer, dos);
|
||||
|
||||
if (!peer)
|
||||
return false;
|
||||
|
||||
// peer.reject({
|
||||
// reason: reason,
|
||||
// data: obj.hash ? obj.hash() : []
|
||||
// });
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -585,8 +585,8 @@ MTX.prototype.isSigned = function isSigned(m) {
|
||||
return false;
|
||||
} else if (prev.isMultisig()) {
|
||||
// Grab `m` value (number of required sigs).
|
||||
m = prev[0];
|
||||
if (Array.isArray(m))
|
||||
m = prev.code[0];
|
||||
if (Buffer.isBuffer(m))
|
||||
m = m[0] || 0;
|
||||
|
||||
// Ensure all members are signatures.
|
||||
@ -709,7 +709,7 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
|
||||
// here since it will be ignored by
|
||||
// the isMultisig clause.
|
||||
// OP_PUSHDATA2 [redeem]
|
||||
prev = this.inputs[i].getRedeem();
|
||||
prev = this.inputs[i].script.getRedeem();
|
||||
size += utils.sizeIntv(prev.getSize()) + prev.getSize();
|
||||
}
|
||||
|
||||
|
||||
@ -681,6 +681,18 @@ Peer.prototype.reject = function reject(details) {
|
||||
this._write(this.framer.reject(details));
|
||||
};
|
||||
|
||||
Peer.prototype.isMisbehaving = function isMisbehaving() {
|
||||
return this.pool.isMisbehaving(this.host);
|
||||
};
|
||||
|
||||
Peer.prototype.setMisbehavior = function setMisbehavior(dos) {
|
||||
return this.pool.setMisbehavior(this, dos);
|
||||
};
|
||||
|
||||
Peer.prototype.sendReject = function sendReject(obj, reason, dos) {
|
||||
return this.pool.reject(this, obj, reason, dos);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -172,12 +172,17 @@ Pool.prototype._init = function _init() {
|
||||
}
|
||||
|
||||
this.chain.on('block', function(block, entry, peer) {
|
||||
self.emit('block', block, peer);
|
||||
// Emit merkle txs after the fact
|
||||
if (block.type === 'merkleblock') {
|
||||
block.txs.forEach(function(tx) {
|
||||
self._handleTX(tx, peer);
|
||||
utils.forEachSerial(block.txs, function(tx, next) {
|
||||
self._handleTX(tx, peer, next);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return self.emit('error', err);
|
||||
self.emit('block', block, peer);
|
||||
});
|
||||
} else {
|
||||
self.emit('block', block, peer);
|
||||
}
|
||||
});
|
||||
|
||||
@ -384,6 +389,7 @@ Pool.prototype._startInterval = function _startInterval() {
|
||||
function load() {
|
||||
if (!self.syncing)
|
||||
return;
|
||||
|
||||
utils.debug('Stall recovery: loading again.');
|
||||
// self._load();
|
||||
}
|
||||
@ -672,11 +678,11 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer, callback) {
|
||||
Pool.prototype._handleInv = function _handleInv(hashes, peer, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
// Ignore for now if we're still syncing
|
||||
if (!this.synced)
|
||||
return;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
return callback();
|
||||
|
||||
utils.forEachSerial(hashes, function(hash, next) {
|
||||
hash = utils.toHex(hash);
|
||||
@ -823,7 +829,7 @@ Pool.prototype._createPeer = function _createPeer(options) {
|
||||
});
|
||||
|
||||
peer.on('tx', function(tx) {
|
||||
self._handleTX(tx);
|
||||
self._handleTX(tx, peer);
|
||||
});
|
||||
|
||||
peer.on('addr', function(data) {
|
||||
@ -1911,6 +1917,24 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) {
|
||||
return false;
|
||||
};
|
||||
|
||||
Pool.prototype.reject = function reject(peer, obj, reason, dos) {
|
||||
if (dos != null)
|
||||
this.setMisbehavior(peer, dos);
|
||||
|
||||
utils.debug('Rejecting %s %s: reason=%s',
|
||||
obj.type, obj.hash('hex'), reason);
|
||||
|
||||
if (!peer)
|
||||
return false;
|
||||
|
||||
// peer.reject({
|
||||
// reason: reason,
|
||||
// data: obj.hash()
|
||||
// });
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* LoadRequest
|
||||
*/
|
||||
|
||||
@ -647,6 +647,9 @@ TX.prototype._getSigops = function _getSigops(scriptHash, accurate) {
|
||||
|
||||
prev = input.script.getRedeem();
|
||||
|
||||
if (!prev)
|
||||
return;
|
||||
|
||||
total += prev.getSigops(true);
|
||||
}
|
||||
}, this);
|
||||
@ -672,7 +675,7 @@ TX.prototype.getSigops = function getSigops(scriptHash, accurate) {
|
||||
if (prev.isScripthash())
|
||||
prev = input.script.getRedeem();
|
||||
|
||||
if (prev.isWitnessScripthash()) {
|
||||
if (prev && prev.isWitnessScripthash()) {
|
||||
prev = input.witness.getRedeem();
|
||||
cost += prev.getSigops(true);
|
||||
} else {
|
||||
@ -694,6 +697,7 @@ TX.prototype.getSigops = function getSigops(scriptHash, accurate) {
|
||||
TX.prototype.isStandard = function isStandard(flags, ts, height, ret) {
|
||||
var i, input, output, type;
|
||||
var nulldata = 0;
|
||||
var maxVersion = constants.tx.version;
|
||||
|
||||
if (!ret)
|
||||
ret = { reason: null };
|
||||
@ -701,13 +705,16 @@ TX.prototype.isStandard = function isStandard(flags, ts, height, ret) {
|
||||
if (flags == null)
|
||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
|
||||
if (this.version > constants.tx.version || this.version < 1) {
|
||||
if (flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)
|
||||
maxVersion = Math.max(maxVersion, 2);
|
||||
|
||||
if (this.version < 1 || this.version > maxVersion) {
|
||||
ret.reason = 'version';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ts != null) {
|
||||
if (!tx.isFinal(ts, height)) {
|
||||
if (!this.isFinal(ts, height)) {
|
||||
ret.reason = 'non-final';
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1440,7 +1440,17 @@ TXPool.prototype.getTX = function getTX(hash, callback) {
|
||||
return callback();
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null, bcoin.tx.fromExtended(tx));
|
||||
|
||||
if (!tx)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
tx = bcoin.tx.fromExtended(tx);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
return callback(null, tx);
|
||||
});
|
||||
};
|
||||
|
||||
@ -1455,7 +1465,16 @@ TXPool.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
return callback(null, bcoin.coin.fromExtended(coin));
|
||||
if (!coin)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
coin = bcoin.coin.fromExtended(coin);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
return callback(null, coin);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user