Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
    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)
Example #7
0
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
Example #8
0
    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)