|
@ -184,6 +184,9 @@ Interpreter.false = new Buffer([]); |
|
|
|
|
|
|
|
|
Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520; |
|
|
Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520; |
|
|
|
|
|
|
|
|
|
|
|
Interpreter.LOCKTIME_THRESHOLD = 500000000; |
|
|
|
|
|
Interpreter.LOCKTIME_THRESHOLD_BN = new BN(500000000); |
|
|
|
|
|
|
|
|
// flags taken from bitcoind
|
|
|
// flags taken from bitcoind
|
|
|
// bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
|
|
|
// bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104
|
|
|
Interpreter.SCRIPT_VERIFY_NONE = 0; |
|
|
Interpreter.SCRIPT_VERIFY_NONE = 0; |
|
@ -226,6 +229,9 @@ Interpreter.SCRIPT_VERIFY_MINIMALDATA = (1 << 6); |
|
|
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
|
|
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
|
|
Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7); |
|
|
Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7); |
|
|
|
|
|
|
|
|
|
|
|
// CLTV See BIP65 for details.
|
|
|
|
|
|
Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9); |
|
|
|
|
|
|
|
|
Interpreter.castToBool = function(buf) { |
|
|
Interpreter.castToBool = function(buf) { |
|
|
for (var i = 0; i < buf.length; i++) { |
|
|
for (var i = 0; i < buf.length; i++) { |
|
|
if (buf[i] !== 0) { |
|
|
if (buf[i] !== 0) { |
|
@ -311,6 +317,52 @@ Interpreter.prototype.evaluate = function() { |
|
|
return true; |
|
|
return true; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Checks a locktime parameter with the transaction's locktime |
|
|
|
|
|
* |
|
|
|
|
|
* @param {BN} nLockTime the locktime read from the script |
|
|
|
|
|
* @return {boolean} true if the transaction's locktime is less than or equal to |
|
|
|
|
|
* the transaction's locktime |
|
|
|
|
|
*/ |
|
|
|
|
|
Interpreter.prototype.checkLockTime = function(nLockTime) { |
|
|
|
|
|
|
|
|
|
|
|
// There are two times of nLockTime: lock-by-blockheight
|
|
|
|
|
|
// and lock-by-blocktime, distinguished by whether
|
|
|
|
|
|
// nLockTime < LOCKTIME_THRESHOLD.
|
|
|
|
|
|
//
|
|
|
|
|
|
// We want to compare apples to apples, so fail the script
|
|
|
|
|
|
// unless the type of nLockTime being tested is the same as
|
|
|
|
|
|
// the nLockTime in the transaction.
|
|
|
|
|
|
if (!( |
|
|
|
|
|
(this.tx.nLockTime < Interpreter.LOCKTIME_THRESHOLD && nLockTime.lt(Interpreter.LOCKTIME_THRESHOLD_BN)) || |
|
|
|
|
|
(this.tx.nLockTime >= Interpreter.LOCKTIME_THRESHOLD && nLockTime.gte(Interpreter.LOCKTIME_THRESHOLD_BN)) |
|
|
|
|
|
)) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Now that we know we're comparing apples-to-apples, the
|
|
|
|
|
|
// comparison is a simple numeric one.
|
|
|
|
|
|
if (nLockTime.gt(new BN(this.tx.nLockTime))) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Finally the nLockTime feature can be disabled and thus
|
|
|
|
|
|
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
|
|
|
|
|
|
// finalized by setting nSequence to maxint. The
|
|
|
|
|
|
// transaction would be allowed into the blockchain, making
|
|
|
|
|
|
// the opcode ineffective.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Testing if this vin is not final is sufficient to
|
|
|
|
|
|
// prevent this condition. Alternatively we could test all
|
|
|
|
|
|
// inputs, but testing just this input minimizes the data
|
|
|
|
|
|
// required to prove correct CHECKLOCKTIMEVERIFY execution.
|
|
|
|
|
|
if (!this.tx.inputs[this.nin].isFinal()) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Based on the inner loop of bitcoind's EvalScript function |
|
|
* Based on the inner loop of bitcoind's EvalScript function |
|
|
* bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 |
|
|
* bitcoind commit: b5d1b1092998bc95313856d535c632ea5a8f9104 |
|
@ -414,8 +466,55 @@ Interpreter.prototype.step = function() { |
|
|
case Opcode.OP_NOP: |
|
|
case Opcode.OP_NOP: |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case Opcode.OP_NOP1: |
|
|
|
|
|
case Opcode.OP_NOP2: |
|
|
case Opcode.OP_NOP2: |
|
|
|
|
|
case Opcode.OP_CHECKLOCKTIMEVERIFY: |
|
|
|
|
|
|
|
|
|
|
|
if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { |
|
|
|
|
|
// not enabled; treat as a NOP2
|
|
|
|
|
|
if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { |
|
|
|
|
|
this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'; |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.stack.length < 1) { |
|
|
|
|
|
this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'; |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Note that elsewhere numeric opcodes are limited to
|
|
|
|
|
|
// operands in the range -2**31+1 to 2**31-1, however it is
|
|
|
|
|
|
// legal for opcodes to produce results exceeding that
|
|
|
|
|
|
// range. This limitation is implemented by CScriptNum's
|
|
|
|
|
|
// default 4-byte limit.
|
|
|
|
|
|
//
|
|
|
|
|
|
// If we kept to that limit we'd have a year 2038 problem,
|
|
|
|
|
|
// even though the nLockTime field in transactions
|
|
|
|
|
|
// themselves is uint32 which only becomes meaningless
|
|
|
|
|
|
// after the year 2106.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Thus as a special case we tell CScriptNum to accept up
|
|
|
|
|
|
// to 5-byte bignums, which are good until 2**39-1, well
|
|
|
|
|
|
// beyond the 2**32-1 limit of the nLockTime field itself.
|
|
|
|
|
|
var nLockTime = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal, 5); |
|
|
|
|
|
|
|
|
|
|
|
// In the rare event that the argument may be < 0 due to
|
|
|
|
|
|
// some arithmetic being done first, you can always use
|
|
|
|
|
|
// 0 MAX CHECKLOCKTIMEVERIFY.
|
|
|
|
|
|
if (nLockTime.lt(new BN(0))) { |
|
|
|
|
|
this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'; |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Actually compare the specified lock time with the transaction.
|
|
|
|
|
|
if (!this.checkLockTime(nLockTime)) { |
|
|
|
|
|
this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'; |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case Opcode.OP_NOP1: |
|
|
case Opcode.OP_NOP3: |
|
|
case Opcode.OP_NOP3: |
|
|
case Opcode.OP_NOP4: |
|
|
case Opcode.OP_NOP4: |
|
|
case Opcode.OP_NOP5: |
|
|
case Opcode.OP_NOP5: |
|
|