refactoring.
This commit is contained in:
parent
359cef93a0
commit
d2767e4e34
@ -7,6 +7,7 @@
|
||||
var bcoin = require('../bcoin');
|
||||
var utils = require('./utils');
|
||||
var assert = utils.assert;
|
||||
var constants = bcoin.protocol.constants;
|
||||
var BufferReader = require('./reader');
|
||||
var BufferWriter = require('./writer');
|
||||
|
||||
@ -133,7 +134,7 @@ Input.prototype.isFinal = function isFinal() {
|
||||
};
|
||||
|
||||
Input.prototype.isCoinbase = function isCoinbase() {
|
||||
return +this.prevout.hash === 0;
|
||||
return this.prevout.hash === constants.nullHash;
|
||||
};
|
||||
|
||||
Input.prototype.test = function test(addressMap) {
|
||||
|
||||
@ -286,6 +286,7 @@ Mempool.prototype.add =
|
||||
Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
var self = this;
|
||||
var hash, ts, height, now;
|
||||
var flags = Mempool.flags;
|
||||
var ret = {};
|
||||
|
||||
var unlock = this._lock(addTX, [tx, peer, callback], force);
|
||||
@ -300,6 +301,11 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
if (!peer)
|
||||
peer = DUMMY_PEER;
|
||||
|
||||
if (this.chain.segwitActive) {
|
||||
flags |= constants.flags.VERIFY_WITNESS;
|
||||
flags |= constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
|
||||
}
|
||||
|
||||
hash = tx.hash('hex');
|
||||
|
||||
assert(tx.ts === 0);
|
||||
@ -308,24 +314,29 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback, force) {
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (!this.chain.segwitActive) {
|
||||
if (tx.hasWitness())
|
||||
if (tx.hasWitness()) {
|
||||
peer.sendReject(tx, 'nonstandard', 'no-witness-yet', 0);
|
||||
return callback(new VerifyError('nonstandard', 'no-witness-yet', 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.checkTX(tx, peer))
|
||||
return callback(new VerifyError('invalid', 'CheckTransaction failed', -1));
|
||||
if (!tx.isSane(ret)) {
|
||||
peer.sendReject(tx, 'invalid', ret.reason, ret.score);
|
||||
return callback(new VerifyError('invalid', ret.reason, ret.score));
|
||||
}
|
||||
|
||||
if (tx.isCoinbase()) {
|
||||
peer.sendReject(tx, 'invalid', 'coinbase', 100);
|
||||
return callback(new VerifyError('invalid', 'coinbase', 100));
|
||||
}
|
||||
|
||||
ts = utils.now();
|
||||
height = this.chain.height + 1;
|
||||
|
||||
if (this.requireStandard && !tx.isStandard(Mempool.flags, ts, height, ret)) {
|
||||
peer.sendReject(tx, 'nonstandard', ret.reason, 0);
|
||||
return callback(new VerifyError(ret.reason, 0));
|
||||
if (this.requireStandard) {
|
||||
ts = utils.now();
|
||||
height = this.chain.height + 1;
|
||||
if (!tx.isStandard(flags, ts, height, ret)) {
|
||||
peer.sendReject(tx, 'nonstandard', ret.reason, 0);
|
||||
return callback(new VerifyError(ret.reason, 0));
|
||||
}
|
||||
}
|
||||
|
||||
this._hasTX(tx, function(err, exists) {
|
||||
@ -441,6 +452,7 @@ Mempool.prototype.verify = function verify(tx, callback) {
|
||||
|
||||
if (this.chain.segwitActive) {
|
||||
flags |= constants.flags.VERIFY_WITNESS;
|
||||
flags |= constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
|
||||
mandatory |= constants.flags.VERIFY_WITNESS;
|
||||
}
|
||||
|
||||
@ -455,7 +467,7 @@ Mempool.prototype.verify = function verify(tx, callback) {
|
||||
0));
|
||||
}
|
||||
|
||||
if (self.requireStandard && !tx.isStandardInputs(flags)) {
|
||||
if (self.requireStandard && !tx.hasStandardInputs(flags)) {
|
||||
return callback(new VerifyError(
|
||||
'nonstandard',
|
||||
'bad-txns-nonstandard-inputs',
|
||||
@ -794,68 +806,6 @@ Mempool.prototype.getSnapshot = function getSnapshot(callback) {
|
||||
return this.tx.getAllHashes(callback);
|
||||
};
|
||||
|
||||
Mempool.prototype.checkTX = function checkTX(tx, peer) {
|
||||
return Mempool.checkTX(tx, peer);
|
||||
};
|
||||
|
||||
Mempool.checkTX = function checkTX(tx, peer) {
|
||||
var uniq = {};
|
||||
var total = new bn(0);
|
||||
var i, input, output, size;
|
||||
|
||||
if (!peer)
|
||||
peer = DUMMY_PEER;
|
||||
|
||||
if (tx.inputs.length === 0)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-vin-empty', 100);
|
||||
|
||||
if (tx.outputs.length === 0)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-vout-empty', 100);
|
||||
|
||||
if (tx.getVirtualSize() > constants.block.maxSize)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-oversize', 100);
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
|
||||
if (output.value.cmpn(0) < 0)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-vout-negative', 100);
|
||||
|
||||
if (output.value.cmp(constants.maxMoney) > 0)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-vout-toolarge', 100);
|
||||
|
||||
total.iadd(output.value);
|
||||
|
||||
if (total.cmpn(0) < 0 || total.cmp(constants.maxMoney) > 0) {
|
||||
return peer.sendReject(tx,
|
||||
'invalid',
|
||||
'bad-txns-txouttotal-toolarge',
|
||||
100);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
if (uniq[input.prevout.hash])
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-inputs-duplicate', 100);
|
||||
uniq[input.prevout.hash] = true;
|
||||
}
|
||||
|
||||
if (tx.isCoinbase()) {
|
||||
size = tx.inputs[0].script.getSize();
|
||||
if (size < 2 || size > 100)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-cb-length', 100);
|
||||
} else {
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
if (+input.prevout.hash === 0)
|
||||
return peer.sendReject(tx, 'invalid', 'bad-txns-prevout-null', 10);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Mempool.prototype.getLocks = function getLocks(tx, flags, entry, callback) {
|
||||
var self = this;
|
||||
var mask = constants.sequenceLocktimeMask
|
||||
|
||||
@ -522,13 +522,13 @@ Peer.prototype._handleVersion = function handleVersion(payload) {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.witness) {
|
||||
if (!payload.witness) {
|
||||
// this._error('Peer does not support segregated witness service.');
|
||||
// this.setMisbehavior(100);
|
||||
// return;
|
||||
}
|
||||
}
|
||||
// if (this.options.witness) {
|
||||
// if (!payload.witness) {
|
||||
// this._error('Peer does not support segregated witness service.');
|
||||
// this.setMisbehavior(100);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (payload.witness)
|
||||
this.haveWitness = true;
|
||||
@ -712,8 +712,19 @@ Peer.prototype._handleReject = function handleReject(payload) {
|
||||
entry.e.emit('reject', payload);
|
||||
};
|
||||
|
||||
Peer.prototype._handleAlert = function handleAlert(payload) {
|
||||
this.emit('alert', payload);
|
||||
Peer.prototype._handleAlert = function handleAlert(details) {
|
||||
var hash = utils.dsha256(details.payload);
|
||||
var signature = details.signature;
|
||||
|
||||
if (!bcoin.ec.verify(hash, signature, network.alertKey)) {
|
||||
utils.debug('Peer %s sent a phony alert packet.', this.host);
|
||||
// Let's look at it because why not?
|
||||
utils.debug(details);
|
||||
this.setMisbehavior(100);
|
||||
return;
|
||||
}
|
||||
|
||||
this.emit('alert', details);
|
||||
};
|
||||
|
||||
Peer.prototype.getHeaders = function getHeaders(hashes, stop) {
|
||||
|
||||
@ -798,10 +798,13 @@ Pool.prototype._createPeer = function _createPeer(options) {
|
||||
});
|
||||
|
||||
peer.on('reject', function(payload) {
|
||||
var data = payload.data ? utils.revHex(utils.toHex(payload.data)) : null;
|
||||
var data = payload.data
|
||||
? utils.revHex(utils.toHex(payload.data))
|
||||
: null;
|
||||
|
||||
utils.debug(
|
||||
'Reject: msg=%s ccode=%s reason=%s data=%s',
|
||||
'Reject (%s): msg=%s ccode=%s reason=%s data=%s',
|
||||
peer.host,
|
||||
payload.message,
|
||||
payload.ccode,
|
||||
payload.reason,
|
||||
@ -1663,7 +1666,7 @@ Pool.prototype.getTX = function getTX(hash, range, callback) {
|
||||
|
||||
Pool.prototype.sendTX = function sendTX(tx, callback) {
|
||||
// Failsafe to avoid getting banned by bitcoind nodes.
|
||||
if (!bcoin.mempool.checkTX(tx))
|
||||
if (!tx.isSane())
|
||||
return utils.asyncify(callback)(new Error('CheckTransaction failed.'));
|
||||
|
||||
return this.broadcast(tx, callback);
|
||||
|
||||
@ -269,6 +269,9 @@ exports.zeroHash = new Buffer(
|
||||
'hex'
|
||||
);
|
||||
|
||||
exports.nullHash =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
|
||||
exports.userVersion = require('../../../package.json').version;
|
||||
exports.userAgent = '/bcoin:' + exports.userVersion + '/';
|
||||
|
||||
|
||||
@ -736,10 +736,6 @@ Parser.parseAlert = function parseAlert(p) {
|
||||
signature = p.readVarBytes();
|
||||
size = p.end();
|
||||
|
||||
assert(
|
||||
bcoin.ec.verify(utils.dsha256(payload), signature, network.alertKey),
|
||||
'Alert does not verify.');
|
||||
|
||||
p = new BufferReader(payload);
|
||||
p.start();
|
||||
version = p.read32();
|
||||
|
||||
@ -175,11 +175,14 @@ Stack.prototype.__defineSetter__('length', function(value) {
|
||||
return this.items.length = value;
|
||||
});
|
||||
|
||||
Stack.prototype.getRedeem = function getRedeem() {
|
||||
Stack.prototype.getRedeem = function getRedeem(pop) {
|
||||
var redeem = Script.getRedeem(this.items);
|
||||
if (!redeem)
|
||||
return;
|
||||
this.pop();
|
||||
|
||||
if (pop !== false)
|
||||
this.pop();
|
||||
|
||||
return redeem;
|
||||
};
|
||||
|
||||
@ -1399,6 +1402,10 @@ Script.prototype.getType = function getType() {
|
||||
|| 'unknown';
|
||||
};
|
||||
|
||||
Script.prototype.isUnknown = function isUnknown() {
|
||||
return this.getType() === 'unknown';
|
||||
};
|
||||
|
||||
Script.prototype.isStandard = function isStandard() {
|
||||
var type = this.getType();
|
||||
var m, n;
|
||||
@ -1420,6 +1427,41 @@ Script.prototype.isStandard = function isStandard() {
|
||||
return type !== 'unknown';
|
||||
};
|
||||
|
||||
Script.prototype.isStandardProgram = function isStandardProgram(witness, flags) {
|
||||
var program, witnessScript, i;
|
||||
|
||||
assert((flags & constants.flags.VERIFY_WITNESS) !== 0);
|
||||
assert(this.isWitnessProgram());
|
||||
|
||||
program = this.getWitnessProgram();
|
||||
|
||||
if (!program.type)
|
||||
return false;
|
||||
|
||||
if (program.version > 0) {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (program.type === 'witnesspubkeyhash') {
|
||||
if (witness.items.length !== 2)
|
||||
return false;
|
||||
} else if (program.type === 'witnessscripthash') {
|
||||
if (witness.items.length === 0)
|
||||
return false;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
for (i = 0; i < witness.items.length; i++) {
|
||||
if (witness.items[i].length > constants.script.maxSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Script.prototype.getSize = function getSize() {
|
||||
return this.encode().length;
|
||||
};
|
||||
@ -1745,6 +1787,10 @@ Script.getInputType = function getInputType(code, prev, isWitness) {
|
||||
return type;
|
||||
};
|
||||
|
||||
Script.prototype.isInputUnknown = function isInputUnknown() {
|
||||
return this.getInputType() === 'unknown';
|
||||
};
|
||||
|
||||
Script.createOutputScript = function(options) {
|
||||
var script, keys, m, n, hash, flags, address, redeem;
|
||||
|
||||
|
||||
254
lib/bcoin/tx.js
254
lib/bcoin/tx.js
@ -12,6 +12,7 @@ var assert = utils.assert;
|
||||
var constants = bcoin.protocol.constants;
|
||||
var network = bcoin.protocol.network;
|
||||
var Script = bcoin.script;
|
||||
var Stack = bcoin.script.stack;
|
||||
var BufferReader = require('./reader');
|
||||
var BufferWriter = require('./writer');
|
||||
|
||||
@ -243,7 +244,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
type = constants.hashType[type];
|
||||
|
||||
assert(index >= 0 && index < this.inputs.length);
|
||||
assert(prev instanceof bcoin.script);
|
||||
assert(prev instanceof Script);
|
||||
|
||||
// Clone the transaction.
|
||||
copy = {
|
||||
@ -333,7 +334,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
type = constants.hashType[type];
|
||||
|
||||
assert(index >= 0 && index < this.inputs.length);
|
||||
assert(prev instanceof bcoin.script);
|
||||
assert(prev instanceof Script);
|
||||
|
||||
if (!(type & constants.hashType.anyonecanpay)) {
|
||||
hashPrevouts = new BufferWriter();
|
||||
@ -412,7 +413,7 @@ TX.prototype.verify = function verify(index, force, flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bcoin.script.verify(
|
||||
return Script.verify(
|
||||
input.script,
|
||||
input.witness,
|
||||
input.coin.script,
|
||||
@ -437,7 +438,8 @@ TX.prototype.verifyAsync = function verifyAsync(index, force, flags, callback) {
|
||||
};
|
||||
|
||||
TX.prototype.isCoinbase = function isCoinbase() {
|
||||
return this.inputs.length === 1 && +this.inputs[0].prevout.hash === 0;
|
||||
return this.inputs.length === 1
|
||||
&& this.inputs[0].prevout.hash === constants.nullHash;
|
||||
};
|
||||
|
||||
TX.prototype.getFee = function getFee() {
|
||||
@ -719,6 +721,88 @@ TX.prototype.getSigops = function getSigops(scriptHash, accurate) {
|
||||
return (cost + 3) / 4 | 0;
|
||||
};
|
||||
|
||||
// CheckTransaction
|
||||
TX.prototype.isSane = function isSane(ret) {
|
||||
var uniq = {};
|
||||
var total = new bn(0);
|
||||
var i, input, output, size;
|
||||
|
||||
if (!ret)
|
||||
ret = {};
|
||||
|
||||
if (this.inputs.length === 0) {
|
||||
ret.reason = 'bad-txns-vin-empty';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.outputs.length === 0) {
|
||||
ret.reason = 'bad-txns-vout-empty';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.getVirtualSize() > constants.block.maxSize) {
|
||||
ret.reason = 'bad-txns-oversize';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.outputs.length; i++) {
|
||||
output = this.outputs[i];
|
||||
|
||||
if (output.value.cmpn(0) < 0) {
|
||||
ret.reason = 'bad-txns-vout-negative';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (output.value.cmp(constants.maxMoney) > 0) {
|
||||
ret.reason = 'bad-txns-vout-toolarge';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
|
||||
total.iadd(output.value);
|
||||
|
||||
if (total.cmpn(0) < 0 || total.cmp(constants.maxMoney) > 0) {
|
||||
ret.reason = 'bad-txns-txouttotal-toolarge';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
if (uniq[input.prevout.hash]) {
|
||||
ret.reason = 'bad-txns-inputs-duplicate';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
uniq[input.prevout.hash] = true;
|
||||
}
|
||||
|
||||
if (this.isCoinbase()) {
|
||||
size = this.inputs[0].script.getSize();
|
||||
if (size < 2 || size > 100) {
|
||||
ret.reason = 'bad-cb-length';
|
||||
ret.score = 100;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
if (input.prevout.hash === constants.nullHash) {
|
||||
ret.reason = 'bad-txns-prevout-null';
|
||||
ret.score = 10;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// IsStandardTx
|
||||
TX.prototype.isStandard = function isStandard(flags, ts, height, ret) {
|
||||
var i, input, output, type;
|
||||
@ -805,9 +889,9 @@ TX.prototype.isStandard = function isStandard(flags, ts, height, ret) {
|
||||
};
|
||||
|
||||
// AreInputsStandard
|
||||
TX.prototype.isStandardInputs = function isStandardInputs(flags) {
|
||||
var i, input, args, stack, res, redeem, targs, hadWitness;
|
||||
TX.prototype.hasStandardInputs = function hasStandardInputs(flags) {
|
||||
var maxSigops = constants.script.maxScripthashSigops;
|
||||
var i, input, args, stack, res, redeem, targs;
|
||||
|
||||
if (flags == null)
|
||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
@ -821,67 +905,49 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
|
||||
if (!input.coin)
|
||||
return false;
|
||||
|
||||
if ((flags & constants.flags.VERIFY_WITNESS)
|
||||
&& input.coin.script.isWitnessProgram()) {
|
||||
// Input script must be empty.
|
||||
if (input.script.code.length !== 0)
|
||||
return false;
|
||||
|
||||
// Verify the program in the output script
|
||||
if (!input.coin.script.isStandardProgram(input.witness, flags))
|
||||
return false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
args = input.coin.script.getArgs();
|
||||
|
||||
if (args < 0)
|
||||
return false;
|
||||
|
||||
stack = new bcoin.script.stack([]);
|
||||
|
||||
// XXX Not accurate:
|
||||
// Not accurate:
|
||||
// Failsafe to avoid getting dos'd in case we ever
|
||||
// call isStandardInputs before isStandard.
|
||||
// call hasStandardInputs before isStandard.
|
||||
if (!input.script.isPushOnly())
|
||||
return false;
|
||||
|
||||
stack = new Stack([]);
|
||||
|
||||
res = input.script.execute(stack, flags, this, i, 0);
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
if ((flags & constants.flags.VERIFY_WITNESS)
|
||||
&& input.coin.script.isWitnessProgram()) {
|
||||
hadWitness = true;
|
||||
|
||||
// Input script must be empty.
|
||||
if (input.script.code.length !== 0)
|
||||
return false;
|
||||
|
||||
// Verify the program in the output script
|
||||
if (!this.isStandardProgram(input.witness, input.coin.script, flags))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & constants.flags.VERIFY_P2SH)
|
||||
&& input.coin.script.isScripthash()) {
|
||||
if (stack.length === 0)
|
||||
return false;
|
||||
|
||||
redeem = bcoin.script.getRedeem(stack);
|
||||
redeem = stack.getRedeem(false);
|
||||
|
||||
if (!redeem)
|
||||
return false;
|
||||
|
||||
// Not accurate?
|
||||
if (redeem.getSize() > 520)
|
||||
return false;
|
||||
|
||||
// Also consider scripthash "unknown"?
|
||||
if (redeem.getType() === 'unknown') {
|
||||
if (redeem.getSigops(true) > maxSigops)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
targs = redeem.getArgs();
|
||||
if (targs < 0)
|
||||
return false;
|
||||
args += targs;
|
||||
|
||||
if ((flags & constants.flags.VERIFY_WITNESS)
|
||||
&& redeem.isWitnessProgram()) {
|
||||
hasWitness = true;
|
||||
|
||||
// Input script must be exactly one push of the redeem script.
|
||||
if (!(input.script.code.length === 1
|
||||
&& utils.isEqual(input.script.code[0], redeem.raw))) {
|
||||
@ -889,13 +955,25 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
|
||||
}
|
||||
|
||||
// Verify the program in the redeem script
|
||||
if (!this.isStandardProgram(input.witness, redeem, flags))
|
||||
if (!redeem.isStandardProgram(input.witness, flags))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hadWitness)
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (redeem.isUnknown()) {
|
||||
if (redeem.getSigops(true) > maxSigops)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
targs = redeem.getArgs();
|
||||
|
||||
if (targs < 0)
|
||||
return false;
|
||||
|
||||
args += targs;
|
||||
}
|
||||
|
||||
if (stack.length !== args)
|
||||
return false;
|
||||
@ -904,36 +982,49 @@ TX.prototype.isStandardInputs = function isStandardInputs(flags) {
|
||||
return true;
|
||||
};
|
||||
|
||||
TX.prototype.isStandardProgram = function isStandardProgram(witness, output, flags) {
|
||||
var program, witnessScript, j;
|
||||
// AreInputsStandard (segwit branch)
|
||||
TX.prototype.hasStandardInputsWitness = function hasStandardInputsWitness(flags) {
|
||||
var maxSigops = constants.script.maxScripthashSigops;
|
||||
var i, input, stack, res, redeem;
|
||||
|
||||
assert((flags & constants.flags.VERIFY_WITNESS) !== 0);
|
||||
assert(output.isWitnessProgram());
|
||||
if (flags == null)
|
||||
flags = constants.flags.STANDARD_VERIFY_FLAGS;
|
||||
|
||||
program = output.getWitnessProgram();
|
||||
|
||||
if (!program.type)
|
||||
return false;
|
||||
|
||||
if (program.version > 0) {
|
||||
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
||||
return false;
|
||||
if (this.isCoinbase())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (program.type === 'witnesspubkeyhash') {
|
||||
if (witness.items.length !== 2)
|
||||
return false;
|
||||
} else if (program.type === 'witnessscripthash') {
|
||||
if (witness.items.length === 0)
|
||||
return false;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
|
||||
for (j = 0; j < witness.items.length; j++) {
|
||||
if (witness.items[j].length > constants.script.maxSize)
|
||||
if (!input.coin)
|
||||
return false;
|
||||
|
||||
if ((flags & constants.flags.VERIFY_P2SH)
|
||||
&& input.coin.script.isScripthash()) {
|
||||
// Not accurate:
|
||||
// Failsafe to avoid getting dos'd in case we ever
|
||||
// call hasStandardInputs before isStandard.
|
||||
if (!input.script.isPushOnly())
|
||||
return false;
|
||||
|
||||
stack = new Stack([]);
|
||||
|
||||
res = input.script.execute(stack, flags, this, i, 0);
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
if (stack.length === 0)
|
||||
return false;
|
||||
|
||||
redeem = stack.getRedeem(false);
|
||||
|
||||
if (!redeem)
|
||||
return false;
|
||||
|
||||
if (redeem.getSigops(true) > maxSigops)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -962,18 +1053,7 @@ TX.prototype.getPriority = function getPriority(height, size) {
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
|
||||
if (!input.coin)
|
||||
return new bn(0);
|
||||
|
||||
age = input.coin.getConfirmations(height);
|
||||
|
||||
if (age === -1)
|
||||
age = 0;
|
||||
|
||||
if (age !== 0)
|
||||
age += 1;
|
||||
|
||||
age = input.coin.getAge(height);
|
||||
sum.iadd(input.coin.value.muln(age));
|
||||
}
|
||||
|
||||
@ -1011,7 +1091,7 @@ TX.prototype.getMinFee = function getMinFee(size) {
|
||||
|
||||
fee = new bn(constants.tx.minFee).muln(size).divn(1000);
|
||||
|
||||
if (fee.cmpn(0) === 0 && constants.tx.minFee.cmpn(0) > 0)
|
||||
if (fee.cmpn(0) === 0 && constants.tx.minFee > 0)
|
||||
fee = new bn(constants.tx.minFee);
|
||||
|
||||
return fee;
|
||||
@ -1060,6 +1140,10 @@ TX.prototype.__defineGetter__('rhash', function() {
|
||||
return utils.revHex(this.hash('hex'));
|
||||
});
|
||||
|
||||
TX.prototype.__defineGetter__('rwhash', function() {
|
||||
return utils.revHex(this.witnessHash('hex'));
|
||||
});
|
||||
|
||||
TX.prototype.__defineGetter__('fee', function() {
|
||||
return this.getFee();
|
||||
});
|
||||
@ -1233,7 +1317,7 @@ TX._fromExtended = function _fromExtended(buf, saveCoins) {
|
||||
tx.ps = p.readU32();
|
||||
// tx.changeIndex = p.readU32();
|
||||
|
||||
if (+tx.block === 0)
|
||||
if (tx.block === constants.nullHash)
|
||||
tx.block = null;
|
||||
|
||||
if (tx.height === 0x7fffffff)
|
||||
|
||||
@ -1751,6 +1751,19 @@ utils.mb = function mb(size) {
|
||||
};
|
||||
|
||||
utils.inherits = function inherits(obj, from) {
|
||||
var f;
|
||||
|
||||
obj.super_ = from;
|
||||
|
||||
if (Object.setPrototypeOf) {
|
||||
Object.setPrototypeOf(obj.prototype, from.prototype);
|
||||
Object.defineProperty(obj.prototype, 'constructor', {
|
||||
value: obj,
|
||||
enumerable: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object.create) {
|
||||
obj.prototype = Object.create(from.prototype, {
|
||||
constructor: {
|
||||
@ -1760,9 +1773,11 @@ utils.inherits = function inherits(obj, from) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
var f = function() {};
|
||||
|
||||
f = function() {};
|
||||
f.prototype = from.prototype;
|
||||
obj.prototype = new f;
|
||||
obj.prototype.constructor = obj;
|
||||
};
|
||||
|
||||
utils.once = function once(callback) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user