more block verification.
This commit is contained in:
parent
e1ec89fe7d
commit
8d120a4fd6
@ -271,79 +271,171 @@ Block.prototype._verify = function _verify() {
|
||||
};
|
||||
|
||||
Block.prototype.postVerify = function postVerify() {
|
||||
var prev, i, tx, cb, sigops;
|
||||
var flags = {};
|
||||
var bip16time = 1333238400;
|
||||
var strictp2sh = this.ts >= bip16time;
|
||||
var prev, height, i, j, tx, cb, sigops, input;
|
||||
|
||||
if (this.subtype !== 'block')
|
||||
return true;
|
||||
|
||||
if (this.isGenesis())
|
||||
return true;
|
||||
|
||||
if (!this.chain)
|
||||
return true;
|
||||
|
||||
prev = this.chain.getBlock(this.prevBlock);
|
||||
height = prev.height + 1;
|
||||
|
||||
// Ensure it's not an orphan
|
||||
if (!prev)
|
||||
if (!prev) {
|
||||
console.log('NO PREV: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the timestamp is correct
|
||||
if (this.ts <= prev.getMedianTime())
|
||||
if (this.ts <= prev.getMedianTime()) {
|
||||
console.log('BAD TIME: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test all txs
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
tx = this.txs[i];
|
||||
|
||||
// TXs must be finalized with regards to seq and locktime
|
||||
if (!tx.isFinal(this, prev))
|
||||
if (!tx.isFinal(this, prev)) {
|
||||
console.log('IS NOT FINAL: %s', height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.bits !== this.chain.target(prev, this))
|
||||
// Ensure the miner's target is equal to what we expect
|
||||
if (this.bits !== this.chain.target(prev, this)) {
|
||||
console.log('BAD TARGET: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.version < 2 && prev.isOutdated(2))
|
||||
// Only allow version 2 blocks (coinbase height)
|
||||
// once the majority of blocks are using it.
|
||||
if (this.version < 2 && prev.isOutdated(2)) {
|
||||
console.log('OUTDATED 2: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.version < 3 && prev.isOutdated(3))
|
||||
// Only allow version 3 blocks (sig validation)
|
||||
// once the majority of blocks are using it.
|
||||
if (this.version < 3 && prev.isOutdated(3)) {
|
||||
console.log('OUTDATED 3: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.version < 4 && prev.isOutdated(4))
|
||||
// Only allow version 4 blocks (checklocktimeverify)
|
||||
// once the majority of blocks are using it.
|
||||
if (this.version < 4 && prev.isOutdated(4)) {
|
||||
console.log('OUTDATED 4: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enforce height in coinbase
|
||||
if (this.version >= 2 && prev.needsUpgrade(2)) {
|
||||
// Make sure the height contained in the
|
||||
// coinbase is correct.
|
||||
if (this.version >= 2 && prev.isUpgraded(2)) {
|
||||
cb = bcoin.script.isCoinbase(this.txs[0].inputs[0].script, this);
|
||||
|
||||
if (!cb)
|
||||
if (!cb) {
|
||||
console.log('BAD COINBASE: %s', height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cb.height !== prev.height + 1)
|
||||
if (cb.height !== height) {
|
||||
console.log('BAD COINBASE HEIGHT: %s', height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// sig validation (bip66)
|
||||
if (this.version >= 3 && prev.needsUpgrade(3))
|
||||
// Signature validation is now enforced (bip66)
|
||||
if (this.version >= 3 && prev.isUpgraded(3))
|
||||
flags.strictder = true;
|
||||
|
||||
// checklocktimeverify (bip65)
|
||||
if (this.version >= 4 && prev.needsUpgrade(4))
|
||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
||||
if (this.version >= 4 && prev.isUpgraded(4))
|
||||
flags.cltv = true;
|
||||
|
||||
// Check for sigops limits
|
||||
sigops = 0;
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
if (tx.sigops(true) > constants.script.maxTxSigops)
|
||||
return false;
|
||||
sigops += tx.sigops(strictp2sh);
|
||||
if (sigops > constants.script.maxBlockSigops)
|
||||
tx = this.txs[i];
|
||||
|
||||
// Bitcoind does not check for this when accepting
|
||||
// a block even though it probably should.
|
||||
// if (tx.sigops(true) > constants.script.maxTxSigops) {
|
||||
// // Block 71036 abused checksig to
|
||||
// // include a huge number of sigops.
|
||||
// if (!(network.type === 'main' && height === 71036))
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// Start counting P2SH sigops once block
|
||||
// timestamps reach March 31st, 2012.
|
||||
if (this.ts >= constants.block.bip16time)
|
||||
sigops += tx.sigops(true);
|
||||
else
|
||||
sigops += tx.sigops();
|
||||
|
||||
if (sigops > constants.script.maxBlockSigops) {
|
||||
console.log('BAD SIGOPS: %s', height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// BIP30 - Ensure there are no duplicate txids
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
tx = this.txs[i];
|
||||
if (this.chain.index[tx.hash('hex')]) {
|
||||
// Blocks 91842 and 91880 created duplicate
|
||||
// txids by carefully crafting the coinbases.
|
||||
if (!(network.type === 'main' && height === 91842 && height === 91880))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are an ancestor of a checkpoint,
|
||||
// we can skip the input verification.
|
||||
if (height < network.checkpoints.lastHeight && !network.checkpoints[height])
|
||||
flags.noScriptChecks = true;
|
||||
|
||||
// Verify the inputs of every tx (CheckInputs)
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
tx = this.txs[i];
|
||||
|
||||
if (tx.isCoinbase())
|
||||
continue;
|
||||
|
||||
if (flags.noScriptChecks)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
|
||||
if (!input.out.tx)
|
||||
continue;
|
||||
|
||||
assert(input.out.tx);
|
||||
|
||||
if (!tx.verify(j, true, flags))
|
||||
return false;
|
||||
|
||||
// if (this.chain.isSpent(input.out.hash, input.out.index))
|
||||
// return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Block.prototype.isGenesis = function isGenesis() {
|
||||
return this.hash('hex') === utils.toHex(network.genesis._hash);
|
||||
};
|
||||
|
||||
Block.prototype.getHeight = function getHeight() {
|
||||
if (!this.chain)
|
||||
return -1;
|
||||
|
||||
@ -600,16 +600,17 @@ Chain.prototype.height = function height() {
|
||||
return this.getTip().height;
|
||||
};
|
||||
|
||||
// /home/chjj/bitcoin/src/pow.cpp
|
||||
Chain.prototype.target = function target(last, block) {
|
||||
var powLimit = utils.toCompact(network.powLimit);
|
||||
var interval = network.powTargetTimespan / network.powTargetSpacing | 0;
|
||||
var first, ts;
|
||||
var ts, first, i;
|
||||
|
||||
// Genesis
|
||||
if (!last)
|
||||
last = this.getTip();
|
||||
return powLimit;
|
||||
|
||||
// Do not retarget
|
||||
if ((last.height + 1) % interval) {
|
||||
if ((last.height + 1) % network.powDiffInterval !== 0) {
|
||||
if (network.powAllowMinDifficultyBlocks) {
|
||||
// Special behavior for testnet:
|
||||
ts = block ? (block.ts || block) : utils.now();
|
||||
@ -617,7 +618,7 @@ Chain.prototype.target = function target(last, block) {
|
||||
return powLimit;
|
||||
|
||||
while (last.prev
|
||||
&& last.height % interval !== 0
|
||||
&& last.height % network.powDiffInterval !== 0
|
||||
&& last.bits !== powLimit) {
|
||||
last = last.prev;
|
||||
}
|
||||
@ -628,34 +629,39 @@ Chain.prototype.target = function target(last, block) {
|
||||
}
|
||||
|
||||
// Back 2 weeks
|
||||
first = this.index.entries[last.height - (interval - 1)];
|
||||
// first = last;
|
||||
// for (i = 0; first && i < network.powDiffInterval - 1; i++)
|
||||
// first = first.prev;
|
||||
|
||||
if (!first)
|
||||
return 0;
|
||||
// Back 2 weeks
|
||||
first = this.index.entries[last.height - (network.powDiffInterval - 1)];
|
||||
|
||||
assert(first);
|
||||
|
||||
return this.retarget(last, first);
|
||||
};
|
||||
|
||||
Chain.prototype.retarget = function retarget(last, first) {
|
||||
var powTargetTimespan = new bn(network.powTargetTimespan);
|
||||
var actualTimespan, powLimit, target;
|
||||
var actualTimespan, target;
|
||||
|
||||
if (network.powNoRetargeting)
|
||||
return last.bits;
|
||||
|
||||
actualTimespan = new bn(last.ts).subn(first.ts);
|
||||
actualTimespan = new bn(last.ts - first.ts);
|
||||
target = utils.fromCompact(last.bits);
|
||||
|
||||
if (actualTimespan.cmp(powTargetTimespan.divn(4)) < 0)
|
||||
actualTimespan = powTargetTimespan.divn(4);
|
||||
|
||||
if (actualTimespan.cmp(powTargetTimespan.muln(4)) > 0)
|
||||
actualTimespan = powTargetTimespan.muln(4);
|
||||
|
||||
powLimit = network.powLimit;
|
||||
target = utils.fromCompact(last.bits);
|
||||
target.imul(actualTimespan);
|
||||
target = target.div(powTargetTimespan);
|
||||
if (target.cmp(powLimit) > 0)
|
||||
target = powLimit.clone();
|
||||
|
||||
if (target.cmp(network.powLimit) > 0)
|
||||
target = network.powLimit.clone();
|
||||
|
||||
return utils.toCompact(target);
|
||||
};
|
||||
@ -832,13 +838,11 @@ ChainBlock.prototype.getMedianTime = function() {
|
||||
};
|
||||
|
||||
ChainBlock.prototype.isOutdated = function(version) {
|
||||
return this.isSuperMajority(version,
|
||||
network.block.majorityRejectBlockOutdated);
|
||||
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
|
||||
};
|
||||
|
||||
ChainBlock.prototype.needsUpgrade = function(version) {
|
||||
return this.isSuperMajority(version,
|
||||
network.block.majorityEnforceBlockUpgrade);
|
||||
ChainBlock.prototype.isUpgraded = function(version) {
|
||||
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
|
||||
};
|
||||
|
||||
ChainBlock.prototype.isSuperMajority = function(version, required) {
|
||||
|
||||
@ -100,6 +100,10 @@ Input.prototype.__defineGetter__('addrs', function() {
|
||||
return this.data.addrs || [];
|
||||
});
|
||||
|
||||
Input.prototype.__defineGetter__('scriptaddr', function() {
|
||||
return this.data.scriptaddr;
|
||||
});
|
||||
|
||||
Input.prototype.__defineGetter__('m', function() {
|
||||
return this.data.m || 1;
|
||||
});
|
||||
|
||||
@ -84,6 +84,10 @@ Output.prototype.__defineGetter__('addrs', function() {
|
||||
return this.data.addrs || [];
|
||||
});
|
||||
|
||||
Output.prototype.__defineGetter__('scriptaddr', function() {
|
||||
return this.data.scriptaddr;
|
||||
});
|
||||
|
||||
Output.prototype.__defineGetter__('m', function() {
|
||||
return this.data.m || 1;
|
||||
});
|
||||
|
||||
@ -467,6 +467,10 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
|
||||
Pool.prototype._handleInv = function _handleInv(hashes, peer) {
|
||||
var i, hash;
|
||||
|
||||
// Ignore for now if we're still syncing
|
||||
if (!this.chain.isFull())
|
||||
return;
|
||||
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = utils.toHex(hashes[i]);
|
||||
if (!this.chain.has(hash)) {
|
||||
|
||||
@ -156,7 +156,15 @@ exports.block = {
|
||||
maxSize: 1000000,
|
||||
maxSigops: 1000000 / 50,
|
||||
maxOrphanTx: 1000000 / 100,
|
||||
medianTimeSpan: 11
|
||||
medianTimeSpan: 11,
|
||||
bip16time: 1333238400
|
||||
};
|
||||
|
||||
exports.tx = {
|
||||
maxSize: 100000,
|
||||
fee: 10000,
|
||||
dust: 5460,
|
||||
bareMultisig: true
|
||||
};
|
||||
|
||||
exports.script = {
|
||||
@ -167,7 +175,9 @@ exports.script = {
|
||||
maxPubkeysPerMultisig: 20,
|
||||
maxBlockSigops: exports.block.maxSize / 50,
|
||||
maxScripthashSigops: 15,
|
||||
maxTxSigops: exports.block.maxSize / 50 / 5
|
||||
maxTxSigops: exports.block.maxSize / 50 / 5,
|
||||
maxOpReturnBytes: 83,
|
||||
maxOpReturn: 80
|
||||
};
|
||||
|
||||
exports.reject = {
|
||||
|
||||
@ -80,6 +80,7 @@ main.checkpoints = main.checkpoints.reduce(function(out, block) {
|
||||
main.checkpoints.tsLastCheckpoint = 1397080064;
|
||||
main.checkpoints.txsLastCheckpoint = 36544669;
|
||||
main.checkpoints.txsPerDay = 60000.0;
|
||||
main.checkpoints.lastHeight = Object.keys(main.checkpoints).sort().pop();
|
||||
|
||||
main.halvingInterval = 210000;
|
||||
|
||||
@ -137,12 +138,13 @@ main.powLimit = new bn(
|
||||
);
|
||||
main.powTargetTimespan = 14 * 24 * 60 * 60; // two weeks
|
||||
main.powTargetSpacing = 10 * 60;
|
||||
main.powDiffInterval = main.powTargetTimespan / main.powTargetSpacing | 0;
|
||||
main.powAllowMinDifficultyBlocks = false;
|
||||
main.powNoRetargeting = false;
|
||||
|
||||
main.block = {
|
||||
majorityEnforceBlockUpgrade: 750,
|
||||
majorityRejectBlockOutdated: 950,
|
||||
majorityEnforceUpgrade: 750,
|
||||
majorityRejectOutdated: 950,
|
||||
majorityWindow: 1000
|
||||
};
|
||||
|
||||
@ -193,6 +195,7 @@ testnet.checkpoints = testnet.checkpoints.reduce(function(out, block) {
|
||||
testnet.checkpoints.tsLastCheckpoint = 1338180505;
|
||||
testnet.checkpoints.txsLastCheckpoint = 16341;
|
||||
testnet.checkpoints.txsPerDay = 300;
|
||||
testnet.checkpoints.lastHeight = Object.keys(testnet.checkpoints).sort().pop();
|
||||
|
||||
testnet.halvingInterval = 210000;
|
||||
|
||||
@ -241,11 +244,12 @@ testnet.powLimit = new bn(
|
||||
);
|
||||
testnet.powTargetTimespan = 14 * 24 * 60 * 60; // two weeks
|
||||
testnet.powTargetSpacing = 10 * 60;
|
||||
testnet.powDiffInterval = testnet.powTargetTimespan / testnet.powTargetSpacing | 0;
|
||||
testnet.powAllowMinDifficultyBlocks = true;
|
||||
testnet.powNoRetargeting = false;
|
||||
|
||||
testnet.block = {
|
||||
majorityEnforceBlockUpgrade: 51,
|
||||
majorityRejectBlockOutdated: 75,
|
||||
majorityEnforceUpgrade: 51,
|
||||
majorityRejectOutdated: 75,
|
||||
majorityWindow: 100
|
||||
};
|
||||
|
||||
@ -232,9 +232,12 @@ script._next = function _next(to, s, pc) {
|
||||
return -1;
|
||||
};
|
||||
|
||||
script.execute = function execute(s, stack, tx, index, recurse) {
|
||||
script.execute = function execute(s, stack, tx, index, flags, recurse) {
|
||||
s = s.slice();
|
||||
|
||||
if (!flags)
|
||||
flags = {};
|
||||
|
||||
if (s.length > constants.script.maxOps)
|
||||
return false;
|
||||
|
||||
@ -806,7 +809,7 @@ script.execute = function execute(s, stack, tx, index, recurse) {
|
||||
}
|
||||
case 'eval_': {
|
||||
// OP_EVAL = OP_NOP1
|
||||
if (!script.allowEval)
|
||||
if (!flags.allowEval)
|
||||
break;
|
||||
|
||||
recurse = recurse || 0;
|
||||
@ -828,7 +831,7 @@ script.execute = function execute(s, stack, tx, index, recurse) {
|
||||
if (res)
|
||||
return false;
|
||||
|
||||
res = script.execute(evalScript, stack, tx, index, recurse);
|
||||
res = script.execute(evalScript, stack, tx, index, flags, recurse);
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
@ -847,13 +850,13 @@ script.execute = function execute(s, stack, tx, index, recurse) {
|
||||
return true;
|
||||
};
|
||||
|
||||
script.exec = function exec(input, output, tx, i, recurse) {
|
||||
script.exec = function exec(input, output, tx, i, flags) {
|
||||
var stack = [];
|
||||
var res;
|
||||
|
||||
script.execute(input, stack, tx, i, recurse);
|
||||
script.execute(input, stack, tx, i, flags);
|
||||
|
||||
res = script.execute(output, stack, tx, i, recurse);
|
||||
res = script.execute(output, stack, tx, i, flags);
|
||||
|
||||
if (!res || stack.length === 0 || new bn(stack.pop()).cmpn(0) === 0)
|
||||
return false;
|
||||
@ -888,6 +891,34 @@ script.standard = function standard(s) {
|
||||
|| null;
|
||||
};
|
||||
|
||||
script.isStandard = function isStandard(s) {
|
||||
var m, n;
|
||||
var type = script.standard(s);
|
||||
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
if (type === 'multisig') {
|
||||
m = new bn(s[0]).toNumber();
|
||||
n = new bn(s[s.length - 2]).toNumber();
|
||||
if (n < 1 || n > 3)
|
||||
return false;
|
||||
if (m < 1 || m > n)
|
||||
return false;
|
||||
} else if (type === 'colored') {
|
||||
if (script.size(s) > constants.script.maxOpReturnBytes)
|
||||
return false;
|
||||
}
|
||||
|
||||
return type != null;
|
||||
};
|
||||
|
||||
script.size = function size(s) {
|
||||
if (s._raw)
|
||||
return s._raw.length;
|
||||
return bcoin.script.encode(s).length;
|
||||
};
|
||||
|
||||
script.lockTime = function lockTime(s) {
|
||||
var lock = s[0];
|
||||
var res = s.length > 3
|
||||
@ -1053,7 +1084,7 @@ script.isColored = function isColored(s) {
|
||||
|
||||
return s[0] === 'ret'
|
||||
&& Array.isArray(s[1])
|
||||
&& s[1].length <= 40;
|
||||
&& s[1].length <= constants.script.maxOpReturn;
|
||||
};
|
||||
|
||||
script.colored = function colored(s) {
|
||||
@ -1411,6 +1442,8 @@ script.pushOnly = function pushOnly(s) {
|
||||
op = s[i];
|
||||
if (Array.isArray(op) || (op >= 1 && op <= 16))
|
||||
continue;
|
||||
if (constants.opcodes[op] == null)
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1425,6 +1458,8 @@ script.sigops = function sigops(s, accurate) {
|
||||
op = s[i];
|
||||
if (Array.isArray(op))
|
||||
continue;
|
||||
if (constants.opcodes[op] == null)
|
||||
return 0;
|
||||
if (op === 'checksig' || op === 'checksigverify') {
|
||||
n++;
|
||||
} else if (op === 'checkmultisig' || op === 'checkmultisigverify') {
|
||||
@ -1435,14 +1470,12 @@ script.sigops = function sigops(s, accurate) {
|
||||
}
|
||||
}
|
||||
lastOp = op;
|
||||
if (lastOp === null)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
script.sigopsScripthash = function sigopsScripthash(s, accurate) {
|
||||
script.sigopsScripthash = function sigopsScripthash(s) {
|
||||
if (!script.isScripthashInput(s))
|
||||
return 0;
|
||||
|
||||
@ -1451,5 +1484,40 @@ script.sigopsScripthash = function sigopsScripthash(s, accurate) {
|
||||
|
||||
s = script.decode(input[input.length - 1]);
|
||||
|
||||
return script.sigops(s, accurate);
|
||||
return script.sigops(s, true);
|
||||
};
|
||||
|
||||
script.args = function args(s) {
|
||||
var type, pubs, m;
|
||||
|
||||
s = bcoin.script.subscript(s);
|
||||
|
||||
if (script.lockTime(s))
|
||||
s = s.slice(3);
|
||||
|
||||
type = script.standard(s);
|
||||
|
||||
if (type === 'pubkey')
|
||||
return 1;
|
||||
|
||||
if (type === 'pubkeyhash')
|
||||
return 2;
|
||||
|
||||
if (type === 'multisig') {
|
||||
pubs = bcoin.script.isMultisig(s);
|
||||
if (!pub)
|
||||
return -1;
|
||||
m = new bn(s[0]).toNumber();
|
||||
if (pubs.length < 1 || m < 1)
|
||||
return -1;
|
||||
return m + 1;
|
||||
}
|
||||
|
||||
if (this.type === 'scripthash')
|
||||
return 1;
|
||||
|
||||
if (this.type === 'colored')
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
131
lib/bcoin/tx.js
131
lib/bcoin/tx.js
@ -67,8 +67,8 @@ function TX(data, block) {
|
||||
this.ps = this.ts === 0 ? utils.now() : 0;
|
||||
}
|
||||
|
||||
TX.fee = 10000;
|
||||
TX.dust = 5460;
|
||||
TX.fee = constants.tx.fee;
|
||||
TX.dust = constants.tx.dust;
|
||||
|
||||
TX.prototype.clone = function clone() {
|
||||
return new TX(this);
|
||||
@ -514,7 +514,7 @@ TX.prototype.subscriptHash = function subscriptHash(index, s, type) {
|
||||
return hash;
|
||||
};
|
||||
|
||||
TX.prototype.verify = function verify(index, force) {
|
||||
TX.prototype.verify = function verify(index, force, flags) {
|
||||
// Valid if included in block
|
||||
if (!force && this.ts !== 0)
|
||||
return true;
|
||||
@ -543,8 +543,8 @@ TX.prototype.verify = function verify(index, force) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bcoin.script.execute(input.script, stack, this, i);
|
||||
res = bcoin.script.execute(prev, stack, this, i);
|
||||
bcoin.script.execute(input.script, stack, this, i, flags);
|
||||
res = bcoin.script.execute(prev, stack, this, i, flags);
|
||||
|
||||
if (!res || stack.length === 0 || new bn(stack.pop()).cmpn(0) === 0)
|
||||
return false;
|
||||
@ -554,7 +554,7 @@ TX.prototype.verify = function verify(index, force) {
|
||||
if (!Array.isArray(redeem))
|
||||
return false;
|
||||
redeem = bcoin.script.decode(redeem);
|
||||
res = bcoin.script.execute(redeem, stack, this, i);
|
||||
res = bcoin.script.execute(redeem, stack, this, i, flags);
|
||||
if (!res || stack.length === 0 || new bn(stack.pop()).cmpn(0) === 0)
|
||||
return false;
|
||||
}
|
||||
@ -881,19 +881,126 @@ TX.prototype._isFinal = function _isFinal(height, ts) {
|
||||
return true;
|
||||
};
|
||||
|
||||
TX.prototype.sigops = function sigops(scripthash) {
|
||||
TX.prototype.sigops = function sigops(scripthash, accurate) {
|
||||
var n = 0;
|
||||
this.inputs.forEach(function(input) {
|
||||
n += bcoin.script.sigops(input.script);
|
||||
if (scripthash)
|
||||
n += bcoin.script.sigops(input.script, accurate);
|
||||
if (scripthash && !this.isCoinbase())
|
||||
n += bcoin.script.sigopsScripthash(input.script);
|
||||
});
|
||||
}, true);
|
||||
this.outputs.forEach(function(output) {
|
||||
n += bcoin.script.sigops(output.script);
|
||||
});
|
||||
n += bcoin.script.sigops(output.script, accurate);
|
||||
}, this);
|
||||
return n;
|
||||
};
|
||||
|
||||
TX.prototype.isStandard = function isStandard() {
|
||||
var i, input, output, type;
|
||||
var colored = 0;
|
||||
|
||||
if (this.version > constants.tx.version || this.version < 1)
|
||||
return false;
|
||||
|
||||
if (this.size() > constants.tx.maxSize)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
|
||||
if (script.size(input.script) > 1650)
|
||||
return false;
|
||||
|
||||
if (!bcoin.script.pushOnly(input.script))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.outputs.length; i++) {
|
||||
output = this.outputs[i];
|
||||
type = bcoin.script.standard(output.script);
|
||||
|
||||
if (!bcoin.script.isStandard(output.script))
|
||||
return false;
|
||||
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
if (type === 'colored') {
|
||||
colored++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type === 'multisig' && !constants.tx.bareMultisig)
|
||||
return false;
|
||||
|
||||
if (output.value.cmpn(constants.tx.dust) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (colored > 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
TX.prototype.isStandardInputs = function isStandardInputs(flags) {
|
||||
var i, input, prev, args, stack, res, s, targs;
|
||||
|
||||
if (this.isCoinbase())
|
||||
return true;
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
|
||||
if (!input.out.tx)
|
||||
return false;
|
||||
|
||||
prev = input.out.tx[input.out.index];
|
||||
|
||||
if (!prev)
|
||||
return false;
|
||||
|
||||
args = bcoin.script.args(prev.script);
|
||||
|
||||
if (args < 0)
|
||||
return false;
|
||||
|
||||
stack = [];
|
||||
|
||||
res = bcoin.script.execute(input.script, stack, this, i, flags);
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
if (bcoin.script.isScripthash(prev.script)) {
|
||||
if (stack.length === 0)
|
||||
return false;
|
||||
|
||||
s = stack[stack.length - 1];
|
||||
|
||||
if (!Array.isArray(s))
|
||||
return false;
|
||||
|
||||
s = bcoin.script.decode(s);
|
||||
|
||||
if (bcoin.script.standard(s)) {
|
||||
targs = bcoin.script.args(s);
|
||||
if (targs < 0)
|
||||
return false;
|
||||
args += targs;
|
||||
} else {
|
||||
// Bitcoind returns here whether true
|
||||
// or false... strange behavior (bug?)
|
||||
return script.sigops(s, true) <= constants.script.maxScripthashSigops;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.length !== args)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
TX.prototype.getHeight = function getHeight() {
|
||||
if (!this.chain)
|
||||
return -1;
|
||||
|
||||
@ -787,6 +787,10 @@ utils.fromCompact = function fromCompact(compact) {
|
||||
if (negative)
|
||||
num.ineg();
|
||||
|
||||
// var overflow = mantissa !== 0 && ((exponent > 34)
|
||||
// || (mantissa > 0xff && exponent > 33)
|
||||
// || (mantissa > 0xffff && exponent > 32));
|
||||
|
||||
return num;
|
||||
};
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ var pool = bcoin.pool({
|
||||
redundancy: 1,
|
||||
parallel: 4000,
|
||||
loadWindow: 750,
|
||||
createConnection: function() {
|
||||
createConnection_: function() {
|
||||
console.log('connecting...');
|
||||
return net.connect(8333, addrs[(Math.random() * addrs.length) | 0]);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user