def clams_checklocktimeverify(stack, txTo, inIdx, flags, execution_data, err_raiser): if len(stack) < 1: # We can't use scripteval.MissingOpArgumentsError here because it # uses python-bitcoinlib's OPCODE_NAMES dict. err_raiser( scripteval.EvalScriptError, 'missing arguments for CHECKLOCKTIMEVERIFY; need 1 item; but none on stack' ) if not execution_data: err_raiser( scripteval.EvalScriptError, 'CHECKLOCKTIMEVERIFY requires execution data items "block_height" and "block_time"' ) locktime = scripteval._CastToBigNum(stack[-1], err_raiser) block_height = execution_data.block_height block_time = execution_data.block_time last = '' if locktime == 0: last = 'Locktime is zero, so it passed.' else: number = block_height if locktime < 500000000 else block_time word = 'block height:' if locktime < 500000000 else 'block time:' if locktime < number: last = 'Locktime passed (%s < %s %s).' % (locktime, word, number) else: err_raiser(scripteval.EvalScriptError, 'Locktime %s is not final' % locktime) return stack, opcodes_by_name.get('OP_CHECKLOCKTIMEVERIFY'), last
def clams_checklocktimeverify(stack, txTo, inIdx, flags, execution_data, err_raiser): if len(stack) < 1: # We can't use scripteval.MissingOpArgumentsError here because it # uses python-bitcoinlib's OPCODE_NAMES dict. err_raiser(scripteval.EvalScriptError, 'missing arguments for CHECKLOCKTIMEVERIFY; need 1 item; but none on stack') if not execution_data: err_raiser(scripteval.EvalScriptError, 'CHECKLOCKTIMEVERIFY requires execution data items "block_height" and "block_time"') locktime = scripteval._CastToBigNum(stack[-1], err_raiser) block_height = execution_data.block_height block_time = execution_data.block_time last = '' if locktime == 0: last = 'Locktime is zero, so it passed.' else: number = block_height if locktime < 500000000 else block_time word = 'block height:' if locktime < 500000000 else 'block time:' if locktime < number: last = 'Locktime passed (%s < %s %s).' % (locktime, word, number) else: err_raiser(scripteval.EvalScriptError, 'Locktime %s is not final' % locktime) return stack, opcodes_by_name.get('OP_CHECKLOCKTIMEVERIFY'), last
def _UnaryOp(opcode, stack, err_raiser): if len(stack) < 1: err_raiser(MissingOpArgumentsError, opcode, stack, 1) bn = _CastToBigNum(stack[-1], err_raiser) last2 = stack.pop() last1 = '' if opcode == OP_1ADD: bn += 1 last1 = '+= 1' elif opcode == OP_1SUB: bn -= 1 last1 = '-= 1' elif opcode == OP_NEGATE: bn = -bn last1 = '*= -1' elif opcode == OP_ABS: if bn < 0: bn = -bn last1 = '= |%d|' % bn elif opcode == OP_NOT: bn = long(bn == 0) last1 = 'NOT %d' % bn elif opcode == OP_0NOTEQUAL: bn = long(bn != 0) last1 = '= %d != 0' % bn else: raise AssertionError( "Unknown unary opcode encountered; this should not happen") stack.append(bitcoin.core._bignum.bn2vch(bn)) last = '%s %s' % (last2, last1) return last
def _UnaryOp(opcode, stack, err_raiser): if len(stack) < 1: err_raiser(MissingOpArgumentsError, opcode, stack, 1) bn = _CastToBigNum(stack[-1], err_raiser) last2 = stack.pop() last1 = '' if opcode == OP_1ADD: bn += 1 last1 = '+= 1' elif opcode == OP_1SUB: bn -= 1 last1 = '-= 1' elif opcode == OP_NEGATE: bn = -bn last1 = '*= -1' elif opcode == OP_ABS: if bn < 0: bn = -bn last1 = '= |%d|' % bn elif opcode == OP_NOT: bn = long(bn == 0) last1 = 'NOT %d' % bn elif opcode == OP_0NOTEQUAL: bn = long(bn != 0) last1 = '= %d != 0' % bn else: raise AssertionError("Unknown unary opcode encountered; this should not happen") stack.append(bitcoin.core._bignum.bn2vch(bn)) last = '%s %s' % (last2, last1) return last
def _BinOp(opcode, stack, err_raiser): if len(stack) < 2: err_raiser(MissingOpArgumentsError, opcode, stack, 2) bn2 = _CastToBigNum(stack[-1], err_raiser) bn1 = _CastToBigNum(stack[-2], err_raiser) # We don't pop the stack yet so that OP_NUMEQUALVERIFY can raise # VerifyOpFailedError with a correct stack. last1 = '' if opcode == OP_ADD: bn = bn1 + bn2 last1 = '+' elif opcode == OP_SUB: bn = bn1 - bn2 last1 = '-' elif opcode == OP_BOOLAND: bn = long(bn1 != 0 and bn2 != 0) last1 = 'AND' elif opcode == OP_BOOLOR: bn = long(bn1 != 0 or bn2 != 0) last1 = 'OR' elif opcode == OP_NUMEQUAL: bn = long(bn1 == bn2) last1 = '==' elif opcode == OP_NUMEQUALVERIFY: bn = long(bn1 == bn2) if not bn: err_raiser(VerifyOpFailedError, opcode) else: # No exception, so time to pop the stack stack.pop() stack.pop() return elif opcode == OP_NUMNOTEQUAL: bn = long(bn1 != bn2) last1 = '!=' elif opcode == OP_LESSTHAN: bn = long(bn1 < bn2) last1 = '<' elif opcode == OP_GREATERTHAN: bn = long(bn1 > bn2) last1 = '>' elif opcode == OP_LESSTHANOREQUAL: bn = long(bn1 <= bn2) last1 = '<=' elif opcode == OP_GREATERTHANOREQUAL: bn = long(bn1 >= bn2) last1 = '>=' elif opcode == OP_MIN: last1 = 'MIN' if bn1 < bn2: bn = bn1 else: bn = bn2 elif opcode == OP_MAX: last1 = 'MAX' if bn1 > bn2: bn = bn1 else: bn = bn2 else: raise AssertionError("Unknown binop opcode encountered; this should not happen") last = '%s (%s %s %s) was pushed to the stack.' % (bn, bn1, last1, bn2) stack.pop() stack.pop() stack.append(bitcoin.core._bignum.bn2vch(bn)) return last
def step(self): """Generator for evaluating a script. Re-implemented _EvalScript from python-bitcoinlib for stack log. """ init_stack = self.init_stack stack = init_stack scriptIn = self.tx_script txTo = self.txTo inIdx = self.inIdx flags = self.flags if len(scriptIn) > MAX_SCRIPT_SIZE: raise EvalScriptError('script too large; got %d bytes; maximum %d bytes' % (len(scriptIn), MAX_SCRIPT_SIZE), stack=stack, scriptIn=scriptIn, txTo=txTo, inIdx=inIdx, flags=flags) altstack = [] vfExec = [] pbegincodehash = 0 nOpCount = [0] last = '' for (sop, sop_data, sop_pc) in scriptIn.raw_iter(): last = '' fExec = _CheckExec(vfExec) def err_raiser(cls, *args): """Helper function for raising EvalScriptError exceptions cls - subclass you want to raise *args - arguments Fills in the state of execution for you. """ raise cls(*args, sop=sop, sop_data=sop_data, sop_pc=sop_pc, stack=stack, scriptIn=scriptIn, txTo=txTo, inIdx=inIdx, flags=flags, altstack=altstack, vfExec=vfExec, pbegincodehash=pbegincodehash, nOpCount=nOpCount[0]) if sop in DISABLED_OPCODES: err_raiser(EvalScriptError, 'opcode %s is disabled' % OPCODE_NAMES[sop]) if sop > OP_16: nOpCount[0] += 1 if nOpCount[0] > MAX_SCRIPT_OPCODES: err_raiser(MaxOpCountError) def check_args(n): if len(stack) < n: err_raiser(MissingOpArgumentsError, sop, stack, n) if sop <= OP_PUSHDATA4: if len(sop_data) > MAX_SCRIPT_ELEMENT_SIZE: err_raiser(EvalScriptError, 'PUSHDATA of length %d; maximum allowed is %d' % (len(sop_data), MAX_SCRIPT_ELEMENT_SIZE)) elif fExec: stack.append(sop_data) # continue yield (stack, '%s was pushed to the stack.' % e(sop_data)) continue elif fExec or (OP_IF <= sop <= OP_ENDIF): if sop == OP_1NEGATE or ((sop >= OP_1) and (sop <= OP_16)): v = sop - (OP_1 - 1) stack.append(bitcoin.core._bignum.bn2vch(v)) elif sop in _ISA_BINOP: last = _BinOp(sop, stack, err_raiser) elif sop in _ISA_UNOP: last = _UnaryOp(sop, stack, err_raiser) elif sop == OP_2DROP: check_args(2) last1 = stack.pop() last2 = stack.pop() last = '%s and %s were dropped.' % e(last1, last2) elif sop == OP_2DUP: check_args(2) v1 = stack[-2] v2 = stack[-1] stack.append(v1) stack.append(v2) last = '%s and %s were copied onto the top.' % e(v1, v2) elif sop == OP_2OVER: check_args(4) v1 = stack[-4] v2 = stack[-3] stack.append(v1) stack.append(v2) last = '%s and %s were copied onto the top.' % e(v1, v2) elif sop == OP_2ROT: check_args(6) v1 = stack[-6] v2 = stack[-5] del stack[-6] del stack[-5] stack.append(v1) stack.append(v2) last = '%s and %s were moved to the top.' % e(v1, v2) elif sop == OP_2SWAP: check_args(4) tmp = stack[-4] stack[-4] = stack[-2] stack[-2] = tmp tmp = stack[-3] stack[-3] = stack[-1] stack[-1] = tmp last = '%s and %s were swapped with %s and %s' % e(*stack[-4:]) elif sop == OP_3DUP: check_args(3) v1 = stack[-3] v2 = stack[-2] v3 = stack[-1] stack.append(v1) stack.append(v2) stack.append(v3) last = '%s, %s and %s were copied onto the top.' % e(v1, v2, v3) # TODO stack log elif sop == OP_CHECKMULTISIG or sop == OP_CHECKMULTISIGVERIFY: tmpScript = CScript(scriptIn[pbegincodehash:]) _CheckMultiSig(sop, tmpScript, stack, txTo, inIdx, err_raiser, nOpCount) elif sop == OP_CHECKSIG or sop == OP_CHECKSIGVERIFY: check_args(2) vchPubKey = stack[-1] vchSig = stack[-2] tmpScript = CScript(scriptIn[pbegincodehash:]) # Drop the signature, since there's no way for a signature to sign itself # # Of course, this can only come up in very contrived cases now that # scriptSig and scriptPubKey are processed separately. tmpScript = FindAndDelete(tmpScript, CScript([vchSig])) ok = _CheckSig(vchSig, vchPubKey, tmpScript, txTo, inIdx, err_raiser) if not ok and sop == OP_CHECKSIGVERIFY: err_raiser(VerifyOpFailedError, sop) else: stack.pop() stack.pop() if ok: if sop != OP_CHECKSIGVERIFY: stack.append(b"\x01") else: stack.append(b"\x00") # TODO implement if txTo is None: err_raiser(EvalScriptError, 'CHECKSIG opcodes require a spending transaction.') else: last1 = 'After %s %s,' % ('CHECKSIG' if sop == OP_CHECKSIG else 'CHECKSIGVERIFY', 'passed' if ok else 'failed') last2 = '%s was pushed to the stack.' % e(stack[-1]) last = ' '.join([last1, last2]) elif sop == OP_CODESEPARATOR: last = '(code separator)' pbegincodehash = sop_pc elif sop == OP_DEPTH: bn = len(stack) stack.append(bitcoin.core._bignum.bn2vch(bn)) last = '%s (number of stack items) was pushed to the stack.' % e(stack[-1]) elif sop == OP_DROP: check_args(1) last1 = stack.pop() last = '%s was dropped.' % e(last1) elif sop == OP_DUP: check_args(1) v = stack[-1] stack.append(v) last = '%s was copied onto the top.' % e(v) elif sop == OP_ELSE: if len(vfExec) == 0: err_raiser(EvalScriptError, 'ELSE found without prior IF') vfExec[-1] = not vfExec[-1] elif sop == OP_ENDIF: last = 'End of IF statement.' if len(vfExec) == 0: err_raiser(EvalScriptError, 'ENDIF found without prior IF') vfExec.pop() elif sop == OP_EQUAL: check_args(2) v1 = stack.pop() v2 = stack.pop() if v1 == v2: stack.append(b"\x01") else: stack.append(b"\x00") last = '%s EQUALSIGN %s, so %s was pushed to the stack.' % e(v1, v2, stack[-1]) last = last.replace('EQUALSIGN', '==' if v1 == v2 else '!=') elif sop == OP_EQUALVERIFY: check_args(2) v1 = stack[-1] v2 = stack[-2] if v1 == v2: last1 = stack.pop() last2 = stack.pop() last = 'EQUALVERIFY passed so %s and %s were dropped.' % e(last1, last2) else: err_raiser(VerifyOpFailedError, sop) elif sop == OP_FROMALTSTACK: if len(altstack) < 1: err_raiser(MissingOpArgumentsError, sop, altstack, 1) v = altstack.pop() stack.append(v) last = '%s was pushed from the altstack to the stack.' % e(v) elif sop == OP_HASH160: check_args(1) last1 = stack.pop() stack.append(bitcoin.core.serialize.Hash160(last1)) last = '%s (HASH160 of %s) was pushed to the stack.' % e(stack[-1], last1) elif sop == OP_HASH256: check_args(1) last1 = stack.pop() stack.append(bitcoin.core.serialize.Hash(last1)) last = '%s (HASH256 of %s) was pushed to the stack.' % e(stack[-1], last1) elif sop == OP_IF or sop == OP_NOTIF: val = False if fExec: check_args(1) vch = stack.pop() val = _CastToBool(vch) if sop == OP_NOTIF: val = not val if val: last = 'Entered IF statement.' else: last = 'Skipped IF statement.' vfExec.append(val) elif sop == OP_IFDUP: check_args(1) vch = stack[-1] if _CastToBool(vch): stack.append(vch) last = 'The top stack item %s was duplicated.' % e(stack[-1]) else: last = 'The top stack item %s was not duplicated.' % e(stack[-1]) elif sop == OP_NIP: check_args(2) last1 = stack[-2] del stack[-2] last = '%s was removed.' % e(last1) elif sop == OP_NOP or (sop >= OP_NOP1 and sop <= OP_NOP10): last = '(NOP)' elif sop == OP_OVER: check_args(2) vch = stack[-2] stack.append(vch) last = '%s was copied onto the top.' % e(vch) elif sop == OP_PICK or sop == OP_ROLL: check_args(2) n = _CastToBigNum(stack.pop(), err_raiser) if n < 0 or n >= len(stack): err_raiser(EvalScriptError, "Argument for %s out of bounds" % OPCODE_NAMES[sop]) vch = stack[-n-1] rolled = False # for "last" if sop == OP_ROLL: rolled = True del stack[-n-1] stack.append(vch) if rolled: last = '%s was moved to the top.' % e(vch) else: last = '%s was copied onto the top.' % e(vch) elif sop == OP_RETURN: err_raiser(EvalScriptError, "OP_RETURN called") elif sop == OP_RIPEMD160: check_args(1) elif sop == OP_ROT: check_args(3) tmp = stack[-3] stack[-3] = stack[-2] stack[-2] = tmp tmp = stack[-2] stack[-2] = stack[-1] stack[-1] = tmp last = '%s, %s and %s were rotated to the left.' % e(stack[-1], stack[-3], stack[-2]) elif sop == OP_SIZE: check_args(1) bn = len(stack[-1]) stack.append(bitcoin.core._bignum.bn2vch(bn)) last = '%s (string length of %s) was pushed to the stack.' % e(stack[-1], stack[-2]) elif sop == OP_SHA1: check_args(1) last1 = stack.pop() stack.append(hashlib.sha1(last1).digest()) last = '%s (SHA1 of %s) was pushed to the stack.' % e(stack[-1], last1) elif sop == OP_SHA256: check_args(1) last1 = stack.pop() stack.append(hashlib.sha256(last1).digest()) last = '%s (SHA256 of %s) was pushed to the stack.' % e(stack[-1], last1) elif sop == OP_SWAP: check_args(2) tmp = stack[-2] stack[-2] = stack[-1] stack[-1] = tmp last = '%s and %s were swapped.' % e(stack[-1], stack[-2]) elif sop == OP_TOALTSTACK: check_args(1) v = stack.pop() altstack.append(v) last = '%s was pushed to the altstack.' % e(v) elif sop == OP_TUCK: check_args(2) vch = stack[-1] stack.insert(len(stack) - 2, vch) last = '%s was copied into the second-to-top position.' % e(vch) elif sop == OP_VERIFY: check_args(1) v = _CastToBool(stack[-1]) if v: last1 = stack.pop() last = '%s was dropped after VERIFY passed.' % e(last1) else: raise err_raiser(VerifyOpFailedError, sop) elif sop == OP_WITHIN: check_args(3) bn3 = _CastToBigNum(stack[-1], err_raiser) bn2 = _CastToBigNum(stack[-2], err_raiser) bn1 = _CastToBigNum(stack[-3], err_raiser) stack.pop() stack.pop() stack.pop() v = (bn2 <= bn1) and (bn1 < bn3) if v: stack.append(b"\x01") else: stack.append(b"\x00") last = '%s (the result of %s <= %s < %s) was pushed to the stack.' % e(stack[-1], bn2, bn1, bn3) else: err_raiser(EvalScriptError, 'unsupported opcode 0x%x' % sop) yield (stack, last) # size limits if len(stack) + len(altstack) > MAX_STACK_ITEMS: err_raiser(EvalScriptError, 'max stack items limit reached') # Unterminated IF/NOTIF/ELSE block if len(vfExec): raise EvalScriptError('Unterminated IF/ELSE block', stack=stack, scriptIn=scriptIn, txTo=txTo, inIdx=inIdx, flags=flags)
def _BinOp(opcode, stack, err_raiser): if len(stack) < 2: err_raiser(MissingOpArgumentsError, opcode, stack, 2) bn2 = _CastToBigNum(stack[-1], err_raiser) bn1 = _CastToBigNum(stack[-2], err_raiser) # We don't pop the stack yet so that OP_NUMEQUALVERIFY can raise # VerifyOpFailedError with a correct stack. last1 = '' if opcode == OP_ADD: bn = bn1 + bn2 last1 = '+' elif opcode == OP_SUB: bn = bn1 - bn2 last1 = '-' elif opcode == OP_BOOLAND: bn = long(bn1 != 0 and bn2 != 0) last1 = 'AND' elif opcode == OP_BOOLOR: bn = long(bn1 != 0 or bn2 != 0) last1 = 'OR' elif opcode == OP_NUMEQUAL: bn = long(bn1 == bn2) last1 = '==' elif opcode == OP_NUMEQUALVERIFY: bn = long(bn1 == bn2) if not bn: err_raiser(VerifyOpFailedError, opcode) else: # No exception, so time to pop the stack stack.pop() stack.pop() return elif opcode == OP_NUMNOTEQUAL: bn = long(bn1 != bn2) last1 = '!=' elif opcode == OP_LESSTHAN: bn = long(bn1 < bn2) last1 = '<' elif opcode == OP_GREATERTHAN: bn = long(bn1 > bn2) last1 = '>' elif opcode == OP_LESSTHANOREQUAL: bn = long(bn1 <= bn2) last1 = '<=' elif opcode == OP_GREATERTHANOREQUAL: bn = long(bn1 >= bn2) last1 = '>=' elif opcode == OP_MIN: last1 = 'MIN' if bn1 < bn2: bn = bn1 else: bn = bn2 elif opcode == OP_MAX: last1 = 'MAX' if bn1 > bn2: bn = bn1 else: bn = bn2 else: raise AssertionError( "Unknown binop opcode encountered; this should not happen") last = '%s (%s %s %s) was pushed to the stack.' % (bn, bn1, last1, bn2) stack.pop() stack.pop() stack.append(bitcoin.core._bignum.bn2vch(bn)) return last
def step(self): """Generator for evaluating a script. Re-implemented _EvalScript from python-bitcoinlib for stack log. """ stack = self.init_stack scriptIn = self.tx_script txTo = self.txTo inIdx = self.inIdx flags = self.flags execution_data = self.execution_data if len(scriptIn) > MAX_SCRIPT_SIZE: raise EvalScriptError( 'script too large; got %d bytes; maximum %d bytes' % (len(scriptIn), MAX_SCRIPT_SIZE), stack=stack, scriptIn=scriptIn, txTo=txTo, inIdx=inIdx, flags=flags) altstack = [] vfExec = [] pbegincodehash = 0 nOpCount = [0] last = '' for (sop, sop_data, sop_pc) in scriptIn.raw_iter(): last = '' fExec = _CheckExec(vfExec) def err_raiser(cls, *args): """Helper function for raising EvalScriptError exceptions cls - subclass you want to raise *args - arguments Fills in the state of execution for you. """ raise cls(*args, sop=sop, sop_data=sop_data, sop_pc=sop_pc, stack=stack, scriptIn=scriptIn, txTo=txTo, inIdx=inIdx, flags=flags, altstack=altstack, vfExec=vfExec, pbegincodehash=pbegincodehash, nOpCount=nOpCount[0]) if sop in opcodes.disabled_opcodes: err_raiser(EvalScriptError, 'opcode %s is disabled' % opcodes.opcode_names[sop]) if sop > OP_16: nOpCount[0] += 1 if nOpCount[0] > MAX_SCRIPT_OPCODES: err_raiser(MaxOpCountError) def check_args(n): if len(stack) < n: err_raiser(MissingOpArgumentsError, sop, stack, n) if sop <= OP_PUSHDATA4: if len(sop_data) > MAX_SCRIPT_ELEMENT_SIZE: err_raiser( EvalScriptError, 'PUSHDATA of length %d; maximum allowed is %d' % (len(sop_data), MAX_SCRIPT_ELEMENT_SIZE)) elif fExec: stack.append(sop_data) # continue yield (stack, sop, '%s was pushed to the stack.' % e(sop_data)) continue elif fExec or (OP_IF <= sop <= OP_ENDIF): if opcodes.is_overridden(sop): yield opcodes.override(sop, stack, txTo, inIdx, flags, execution_data, err_raiser) continue elif sop == OP_1NEGATE or ((sop >= OP_1) and (sop <= OP_16)): v = sop - (OP_1 - 1) stack.append(bitcoin.core._bignum.bn2vch(v)) last = '%s was pushed to the stack.' % e(stack[-1]) elif sop in _ISA_BINOP: last = _BinOp(sop, stack, err_raiser) elif sop in _ISA_UNOP: last = _UnaryOp(sop, stack, err_raiser) elif sop == OP_2DROP: check_args(2) last1 = stack.pop() last2 = stack.pop() last = '%s and %s were dropped.' % e(last1, last2) elif sop == OP_2DUP: check_args(2) v1 = stack[-2] v2 = stack[-1] stack.append(v1) stack.append(v2) last = '%s and %s were copied onto the top.' % e(v1, v2) elif sop == OP_2OVER: check_args(4) v1 = stack[-4] v2 = stack[-3] stack.append(v1) stack.append(v2) last = '%s and %s were copied onto the top.' % e(v1, v2) elif sop == OP_2ROT: check_args(6) v1 = stack[-6] v2 = stack[-5] del stack[-6] del stack[-5] stack.append(v1) stack.append(v2) last = '%s and %s were moved to the top.' % e(v1, v2) elif sop == OP_2SWAP: check_args(4) tmp = stack[-4] stack[-4] = stack[-2] stack[-2] = tmp tmp = stack[-3] stack[-3] = stack[-1] stack[-1] = tmp last = '%s and %s were swapped with %s and %s' % e( *stack[-4:]) elif sop == OP_3DUP: check_args(3) v1 = stack[-3] v2 = stack[-2] v3 = stack[-1] stack.append(v1) stack.append(v2) stack.append(v3) last = '%s, %s and %s were copied onto the top.' % e( v1, v2, v3) # TODO stack log elif sop == OP_CHECKMULTISIG or sop == OP_CHECKMULTISIGVERIFY: tmpScript = CScript(scriptIn[pbegincodehash:]) _CheckMultiSig(sop, tmpScript, stack, txTo, inIdx, err_raiser, nOpCount) elif sop == OP_CHECKSIG or sop == OP_CHECKSIGVERIFY: check_args(2) vchPubKey = stack[-1] vchSig = stack[-2] tmpScript = CScript(scriptIn[pbegincodehash:]) # Drop the signature, since there's no way for a signature to sign itself # # Of course, this can only come up in very contrived cases now that # scriptSig and scriptPubKey are processed separately. tmpScript = FindAndDelete(tmpScript, CScript([vchSig])) ok = _CheckSig(vchSig, vchPubKey, tmpScript, txTo, inIdx, err_raiser) if not ok and sop == OP_CHECKSIGVERIFY: err_raiser(VerifyOpFailedError, sop) else: stack.pop() stack.pop() if ok: if sop != OP_CHECKSIGVERIFY: stack.append(b"\x01") else: stack.append(b"\x00") # TODO implement if txTo is None: err_raiser( EvalScriptError, 'CHECKSIG opcodes require a spending transaction.' ) else: last1 = 'After %s %s,' % ( 'CHECKSIG' if sop == OP_CHECKSIG else 'CHECKSIGVERIFY', 'passed' if ok else 'failed') last2 = '%s was pushed to the stack.' % e( stack[-1]) last = ' '.join([last1, last2]) elif sop == OP_CODESEPARATOR: last = '(code separator)' pbegincodehash = sop_pc elif sop == OP_DEPTH: bn = len(stack) stack.append(bitcoin.core._bignum.bn2vch(bn)) last = '%s (number of stack items) was pushed to the stack.' % e( stack[-1]) elif sop == OP_DROP: check_args(1) last1 = stack.pop() last = '%s was dropped.' % e(last1) elif sop == OP_DUP: check_args(1) v = stack[-1] stack.append(v) last = '%s was copied onto the top.' % e(v) elif sop == OP_ELSE: if len(vfExec) == 0: err_raiser(EvalScriptError, 'ELSE found without prior IF') vfExec[-1] = not vfExec[-1] last = 'Skipped ELSE statement.' if vfExec[-1]: last = 'Entered ELSE statement.' elif sop == OP_ENDIF: last = 'End of IF statement.' if len(vfExec) == 0: err_raiser(EvalScriptError, 'ENDIF found without prior IF') vfExec.pop() elif sop == OP_EQUAL: check_args(2) v1 = stack.pop() v2 = stack.pop() if v1 == v2: stack.append(b"\x01") else: stack.append(b"\x00") last = '%s EQUALSIGN %s, so %s was pushed to the stack.' % e( v1, v2, stack[-1]) last = last.replace('EQUALSIGN', '==' if v1 == v2 else '!=') elif sop == OP_EQUALVERIFY: check_args(2) v1 = stack[-1] v2 = stack[-2] if v1 == v2: last1 = stack.pop() last2 = stack.pop() last = 'EQUALVERIFY passed so %s and %s were dropped.' % e( last1, last2) else: err_raiser(VerifyOpFailedError, sop) elif sop == OP_FROMALTSTACK: if len(altstack) < 1: err_raiser(MissingOpArgumentsError, sop, altstack, 1) v = altstack.pop() stack.append(v) last = '%s was pushed from the altstack to the stack.' % e( v) elif sop == OP_HASH160: check_args(1) last1 = stack.pop() stack.append(bitcoin.core.serialize.Hash160(last1)) last = '%s (HASH160 of %s) was pushed to the stack.' % e( stack[-1], last1) elif sop == OP_HASH256: check_args(1) last1 = stack.pop() stack.append(bitcoin.core.serialize.Hash(last1)) last = '%s (HASH256 of %s) was pushed to the stack.' % e( stack[-1], last1) elif sop == OP_IF or sop == OP_NOTIF: val = False if fExec: check_args(1) vch = stack.pop() val = _CastToBool(vch) if sop == OP_NOTIF: val = not val if val: last = 'Entered IF statement.' else: last = 'Skipped IF statement.' vfExec.append(val) elif sop == OP_IFDUP: check_args(1) vch = stack[-1] if _CastToBool(vch): stack.append(vch) last = 'The top stack item %s was duplicated.' % e( stack[-1]) else: last = 'The top stack item %s was not duplicated.' % e( stack[-1]) elif sop == OP_NIP: check_args(2) last1 = stack[-2] del stack[-2] last = '%s was removed.' % e(last1) elif sop == OP_NOP or (sop >= OP_NOP1 and sop <= OP_NOP10): last = '(NOP)' elif sop == OP_OVER: check_args(2) vch = stack[-2] stack.append(vch) last = '%s was copied onto the top.' % e(vch) elif sop == OP_PICK or sop == OP_ROLL: check_args(2) n = _CastToBigNum(stack.pop(), err_raiser) if n < 0 or n >= len(stack): err_raiser( EvalScriptError, "Argument for %s out of bounds" % opcodes.opcode_names[sop]) vch = stack[-n - 1] rolled = False # for "last" if sop == OP_ROLL: rolled = True del stack[-n - 1] stack.append(vch) if rolled: last = '%s was moved to the top.' % e(vch) else: last = '%s was copied onto the top.' % e(vch) elif sop == OP_RETURN: err_raiser(EvalScriptError, "OP_RETURN called") elif sop == OP_RIPEMD160: check_args(1) h = hashlib.new('ripemd160') tmp = stack.pop() h.update(tmp) stack.append(h.digest()) last = '%s (RIPEMD160 of %s) was pushed to the stack.' % e( stack[-1], tmp) elif sop == OP_ROT: check_args(3) tmp = stack[-3] stack[-3] = stack[-2] stack[-2] = tmp tmp = stack[-2] stack[-2] = stack[-1] stack[-1] = tmp last = '%s, %s and %s were rotated to the left.' % e( stack[-1], stack[-3], stack[-2]) elif sop == OP_SIZE: check_args(1) bn = len(stack[-1]) stack.append(bitcoin.core._bignum.bn2vch(bn)) last = '%s (string length of %s) was pushed to the stack.' % e( stack[-1], stack[-2]) elif sop == OP_SHA1: check_args(1) last1 = stack.pop() stack.append(hashlib.sha1(last1).digest()) last = '%s (SHA1 of %s) was pushed to the stack.' % e( stack[-1], last1) elif sop == OP_SHA256: check_args(1) last1 = stack.pop() stack.append(hashlib.sha256(last1).digest()) last = '%s (SHA256 of %s) was pushed to the stack.' % e( stack[-1], last1) elif sop == OP_SWAP: check_args(2) tmp = stack[-2] stack[-2] = stack[-1] stack[-1] = tmp last = '%s and %s were swapped.' % e(stack[-1], stack[-2]) elif sop == OP_TOALTSTACK: check_args(1) v = stack.pop() altstack.append(v) last = '%s was pushed to the altstack.' % e(v) elif sop == OP_TUCK: check_args(2) vch = stack[-1] stack.insert(len(stack) - 2, vch) last = '%s was copied into the second-to-top position.' % e( vch) elif sop == OP_VERIFY: check_args(1) v = _CastToBool(stack[-1]) if v: last1 = stack.pop() last = '%s was dropped after VERIFY passed.' % e(last1) else: raise err_raiser(VerifyOpFailedError, sop) elif sop == OP_WITHIN: check_args(3) bn3 = _CastToBigNum(stack[-1], err_raiser) bn2 = _CastToBigNum(stack[-2], err_raiser) bn1 = _CastToBigNum(stack[-3], err_raiser) l3 = stack.pop() l2 = stack.pop() l1 = stack.pop() v = (bn2 <= bn1) and (bn1 < bn3) if v: stack.append(b"\x01") else: stack.append(b"\x00") last = '%s (the result of %s <= %s < %s) was pushed to the stack.' % e( stack[-1], l2, l1, l3) else: err_raiser(EvalScriptError, 'unsupported opcode 0x%x' % sop) yield (stack, sop, last) # size limits if len(stack) + len(altstack) > MAX_STACK_ITEMS: err_raiser(EvalScriptError, 'max stack items limit reached') # Unterminated IF/NOTIF/ELSE block if len(vfExec): raise EvalScriptError('Unterminated IF/ELSE block', stack=stack, scriptIn=scriptIn, txTo=txTo, inIdx=inIdx, flags=flags)