Ejemplo n.º 1
0
    def ExecuteOp(self, opcode, context):
        estack = self._EvaluationStack
        istack = self._InvocationStack
        astack = self._AltStack

        if opcode > PUSH16 and opcode != RET and context.PushOnly:
            return self.VM_FAULT_and_report(VMFault.UNKNOWN1)

        if opcode >= PUSHBYTES1 and opcode <= PUSHBYTES75:
            bytestoread = context.OpReader.ReadBytes(
                int.from_bytes(opcode, 'little'))
            estack.PushT(bytestoread)
        else:

            # push values
            pushops = [
                PUSHM1, PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8,
                PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16
            ]

            if opcode == PUSH0:
                estack.PushT(bytearray(0))

            elif opcode == PUSHDATA1:
                lenngth = context.OpReader.ReadByte()
                estack.PushT(bytearray(context.OpReader.ReadBytes(lenngth)))
            elif opcode == PUSHDATA2:
                estack.PushT(
                    context.OpReader.ReadBytes(context.OpReader.ReadUInt16()))
            elif opcode == PUSHDATA4:
                estack.PushT(
                    context.OpReader.ReadBytes(context.OpReader.ReadUInt32()))
            elif opcode in pushops:
                # EvaluationStack.Push((int)opcode - (int)OpCode.PUSH1 + 1);
                topush = int.from_bytes(opcode, 'little') - int.from_bytes(
                    PUSH1, 'little') + 1
                estack.PushT(topush)

            # control
            elif opcode == NOP:
                pass
            elif opcode in [JMP, JMPIF, JMPIFNOT]:
                offset_b = context.OpReader.ReadInt16()
                offset = context.InstructionPointer + offset_b - 3

                if offset < 0 or offset > len(context.Script):
                    return self.VM_FAULT_and_report(VMFault.INVALID_JUMP)

                fValue = True
                if opcode > JMP:
                    fValue = estack.Pop().GetBoolean()
                    if opcode == JMPIFNOT:
                        fValue = not fValue
                if fValue:
                    context.SetInstructionPointer(offset)

            elif opcode == CALL:
                istack.PushT(context.Clone())
                context.SetInstructionPointer(context.InstructionPointer + 2)

                self.ExecuteOp(JMP, self.CurrentContext)

            elif opcode == RET:
                istack.Pop().Dispose()
                if istack.Count == 0:
                    self._VMState |= VMState.HALT

            elif opcode == APPCALL or opcode == TAILCALL:
                if self._Table is None:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN2)

                script_hash = context.OpReader.ReadBytes(20)

                is_normal_call = False
                for b in script_hash:
                    if b > 0:
                        is_normal_call = True

                if not is_normal_call:
                    script_hash = self.EvaluationStack.Pop().GetByteArray()

                script = self._Table.GetScript(
                    UInt160(data=script_hash).ToBytes())

                if script is None:
                    logger.error(
                        "Could not find script from script table: %s " %
                        script_hash)
                    return self.VM_FAULT_and_report(VMFault.INVALID_CONTRACT,
                                                    script_hash)

                if opcode == TAILCALL:
                    istack.Pop().Dispose()

                self.LoadScript(script)

            elif opcode == SYSCALL:
                call = context.OpReader.ReadVarBytes(252).decode('ascii')
                self.write_log(call)
                if not self._Service.Invoke(call, self):
                    return self.VM_FAULT_and_report(VMFault.SYSCALL_ERROR,
                                                    call)

            # stack operations
            elif opcode == DUPFROMALTSTACK:
                estack.PushT(astack.Peek())

            elif opcode == TOALTSTACK:
                astack.PushT(estack.Pop())

            elif opcode == FROMALTSTACK:
                estack.PushT(astack.Pop())

            elif opcode == XDROP:
                n = estack.Pop().GetBigInteger()
                if n < 0:
                    self._VMState |= VMState.FAULT
                    return
                estack.Remove(n)

            elif opcode == XSWAP:
                n = estack.Pop().GetBigInteger()

                if n < 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN3)

                # if n == 0 break, same as do x if n > 0
                if n > 0:
                    item = estack.Peek(n)
                    estack.Set(n, estack.Peek())
                    estack.Set(0, item)

            elif opcode == XTUCK:
                n = estack.Pop().GetBigInteger()

                if n <= 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN4)

                estack.Insert(n, estack.Peek())

            elif opcode == DEPTH:
                estack.PushT(estack.Count)

            elif opcode == DROP:
                estack.Pop()

            elif opcode == DUP:
                estack.PushT(estack.Peek())

            elif opcode == NIP:
                x2 = estack.Pop()
                estack.Pop()
                estack.PushT(x2)

            elif opcode == OVER:

                x2 = estack.Pop()
                x1 = estack.Peek()
                estack.PushT(x2)
                estack.PushT(x1)

            elif opcode == PICK:

                n = estack.Pop().GetBigInteger()
                if n < 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN5)

                estack.PushT(estack.Peek(n))

            elif opcode == ROLL:

                n = estack.Pop().GetBigInteger()
                if n < 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN6)

                if n > 0:
                    estack.PushT(estack.Remove(n))

            elif opcode == ROT:
                x3 = estack.Pop()
                x2 = estack.Pop()
                x1 = estack.Pop()

                estack.PushT(x2)
                estack.PushT(x3)
                estack.PushT(x1)

            elif opcode == SWAP:

                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x2)
                estack.PushT(x1)

            elif opcode == TUCK:

                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x2)
                estack.PushT(x1)
                estack.PushT(x2)

            elif opcode == CAT:

                x2 = estack.Pop().GetByteArray()
                x1 = estack.Pop().GetByteArray()
                estack.PushT(x1 + x2)

            elif opcode == SUBSTR:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    return self.VM_FAULT_and_report(
                        VMFault.SUBSTR_INVALID_LENGTH)

                index = estack.Pop().GetBigInteger()
                if index < 0:
                    return self.VM_FAULT_and_report(
                        VMFault.SUBSTR_INVALID_INDEX)

                x = estack.Pop().GetByteArray()

                estack.PushT(x[index:count + index])

            elif opcode == LEFT:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    return self.VM_FAULT_and_report(VMFault.LEFT_INVALID_COUNT)

                x = estack.Pop().GetByteArray()
                estack.PushT(x[:count])

            elif opcode == RIGHT:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    return self.VM_FAULT_and_report(
                        VMFault.RIGHT_INVALID_COUNT)

                x = estack.Pop().GetByteArray()
                if len(x) < count:
                    return self.VM_FAULT_and_report(VMFault.RIGHT_UNKNOWN)

                estack.PushT(x[-count:])

            elif opcode == SIZE:

                x = estack.Pop().GetByteArray()
                estack.PushT(len(x))

            elif opcode == INVERT:

                x = estack.Pop().GetBigInteger()
                estack.PushT(~x)

            elif opcode == AND:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()
                estack.PushT(x1 & x2)

            elif opcode == OR:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 | x2)

            elif opcode == XOR:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 ^ x2)

            elif opcode == EQUAL:
                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x1.Equals(x2))

            # numeric

            elif opcode == INC:

                x = estack.Pop().GetBigInteger()
                estack.PushT(x + 1)

            elif opcode == DEC:

                x = estack.Pop().GetBigInteger()
                estack.PushT(x - 1)

            elif opcode == SIGN:

                # Make sure to implement sign for big integer
                x = estack.Pop().GetBigInteger()
                estack.PushT(x.Sign)

            elif opcode == NEGATE:

                x = estack.Pop().GetBigInteger()
                estack.PushT(-x)

            elif opcode == ABS:

                x = estack.Pop().GetBigInteger()
                estack.PushT(abs(x))

            elif opcode == NOT:

                x = estack.Pop().GetBigInteger()
                estack.PushT(not x)

            elif opcode == NZ:

                x = estack.Pop().GetBigInteger()
                estack.PushT(x is not 0)

            elif opcode == ADD:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()
                estack.PushT(x1 + x2)

            elif opcode == SUB:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 - x2)

            elif opcode == MUL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 * x2)

            elif opcode == DIV:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 / x2)

            elif opcode == MOD:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 % x2)

            elif opcode == SHL:

                n = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(x << n)

            elif opcode == SHR:

                n = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(x >> n)

            elif opcode == BOOLAND:

                x2 = estack.Pop().GetBoolean()
                x1 = estack.Pop().GetBoolean()

                estack.PushT(x1 and x2)

            elif opcode == BOOLOR:

                x2 = estack.Pop().GetBoolean()
                x1 = estack.Pop().GetBoolean()

                estack.PushT(x1 or x2)

            elif opcode == NUMEQUAL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x2 == x1)

            elif opcode == NUMNOTEQUAL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 != x2)

            elif opcode == LT:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 < x2)

            elif opcode == GT:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 > x2)

            elif opcode == LTE:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 <= x2)

            elif opcode == GTE:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 >= x2)

            elif opcode == MIN:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()
                estack.PushT(min(x1, x2))

            elif opcode == MAX:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(max(x1, x2))

            elif opcode == WITHIN:

                b = estack.Pop().GetBigInteger()
                a = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(a <= x and x < b)

            # CRyPTO
            elif opcode == SHA1:
                h = hashlib.sha1(estack.Pop().GetByteArray())
                estack.PushT(h.digest())

            elif opcode == SHA256:
                h = hashlib.sha256(estack.Pop().GetByteArray())
                estack.PushT(h.digest())

            elif opcode == HASH160:

                estack.PushT(self.Crypto.Hash160(estack.Pop().GetByteArray()))

            elif opcode == HASH256:

                estack.PushT(self.Crypto.Hash256(estack.Pop().GetByteArray()))

            elif opcode == CHECKSIG:

                pubkey = estack.Pop().GetByteArray()
                sig = estack.Pop().GetByteArray()
                try:
                    res = self.Crypto.VerifySignature(
                        self.ScriptContainer.GetMessage(), sig, pubkey)
                    estack.PushT(res)
                except Exception as e:
                    estack.PushT(False)
                    logger.error("Could not checksig: %s " % e)

            elif opcode == VERIFY:
                pubkey = estack.Pop().GetByteArray()
                sig = estack.Pop().GetByteArray()
                message = estack.Pop().GetString()
                try:
                    res = self.Crypto.VerifySignature(message, sig, pubkey)
                    estack.PushT(res)
                except Exception as e:
                    estack.PushT(False)
                    logger.error("Could not checksig: %s " % e)

            elif opcode == CHECKMULTISIG:

                n = estack.Pop().GetBigInteger()

                if n < 1:
                    return self.VM_FAULT_and_report(
                        VMFault.CHECKMULTISIG_INVALID_PUBLICKEY_COUNT)

                pubkeys = []
                for i in range(0, n):
                    pubkeys.append(estack.Pop().GetByteArray())

                m = estack.Pop().GetBigInteger()

                if m < 1 or m > n:
                    return self.VM_FAULT_and_report(
                        VMFault.CHECKMULTISIG_SIGNATURE_ERROR, m, n)

                sigs = []

                for i in range(0, m):
                    sigs.append(estack.Pop().GetByteArray())

                message = self.ScriptContainer.GetMessage(
                ) if self.ScriptContainer else ''

                fSuccess = True

                try:

                    i = 0
                    j = 0

                    while fSuccess and i < m and j < n:

                        if self.Crypto.VerifySignature(message, sigs[i],
                                                       pubkeys[j]):
                            i += 1
                        j += 1

                        if m - i > n - j:
                            fSuccess = False

                except Exception as e:
                    fSuccess = False

                estack.PushT(fSuccess)

            # lists
            elif opcode == ARRAYSIZE:

                item = estack.Pop()

                if not item:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN7)

                if isinstance(item, CollectionMixin):
                    estack.PushT(item.Count)

                else:
                    estack.PushT(len(item.GetByteArray()))

            elif opcode == PACK:

                size = estack.Pop().GetBigInteger()

                if size < 0 or size > estack.Count:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN8)

                items = []

                for i in range(0, size):
                    topack = estack.Pop()
                    items.append(topack)

                estack.PushT(items)

            elif opcode == UNPACK:
                item = estack.Pop()

                if not isinstance(item, Array):
                    return self.VM_FAULT_and_report(
                        VMFault.UNPACK_INVALID_TYPE, item)

                items = item.GetArray()
                items.reverse()

                [estack.PushT(i) for i in items]

                estack.PushT(len(items))

            elif opcode == PICKITEM:

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    # key must be an array index or dictionary key, but not a collection
                    return self.VM_FAULT_and_report(VMFault.KEY_IS_COLLECTION,
                                                    key)

                collection = estack.Pop()

                if isinstance(collection, Array):
                    index = key.GetBigInteger()
                    if index < 0 or index >= collection.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.PICKITEM_INVALID_INDEX, index,
                            collection.Count)

                    items = collection.GetArray()
                    to_pick = items[index]
                    estack.PushT(to_pick)

                elif isinstance(collection, Map):
                    success, value = collection.TryGetValue(key)

                    if success:
                        estack.PushT(value)
                    else:
                        return self.VM_FAULT_and_report(
                            VMFault.DICT_KEY_NOT_FOUND, key, collection.Keys)

                else:
                    return self.VM_FAULT_and_report(
                        VMFault.PICKITEM_INVALID_TYPE, key, collection)

            elif opcode == SETITEM:
                value = estack.Pop()

                if isinstance(value, Struct):
                    value = value.Clone()

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    return self.VM_FAULT_and_report(VMFault.KEY_IS_COLLECTION)

                collection = estack.Pop()

                if isinstance(collection, Array):

                    index = key.GetBigInteger()

                    if index < 0 or index >= collection.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.SETITEM_INVALID_INDEX)

                    items = collection.GetArray()
                    items[index] = value

                elif isinstance(collection, Map):

                    collection.SetItem(key, value)

                else:

                    return self.VM_FAULT_and_report(
                        VMFault.SETITEM_INVALID_TYPE, key, collection)

            elif opcode == NEWARRAY:

                count = estack.Pop().GetBigInteger()
                items = [Boolean(False) for i in range(0, count)]
                estack.PushT(Array(items))

            elif opcode == NEWSTRUCT:

                count = estack.Pop().GetBigInteger()

                items = [Boolean(False) for i in range(0, count)]

                estack.PushT(Struct(items))

            elif opcode == NEWMAP:
                estack.PushT(Map())

            elif opcode == APPEND:
                newItem = estack.Pop()

                if isinstance(newItem, Struct):
                    newItem = newItem.Clone()

                arrItem = estack.Pop()

                if not isinstance(arrItem, Array):
                    return self.VM_FAULT_and_report(
                        VMFault.APPEND_INVALID_TYPE, arrItem)

                arr = arrItem.GetArray()
                arr.append(newItem)

            elif opcode == REVERSE:

                arrItem = estack.Pop()
                if not isinstance(arrItem, Array):
                    return self.VM_FAULT_and_report(
                        VMFault.REVERSE_INVALID_TYPE, arrItem)

                arrItem.Reverse()

            elif opcode == REMOVE:

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN1)

                collection = estack.Pop()

                if isinstance(collection, Array):

                    index = key.GetBigInteger()

                    if index < 0 or index >= collection.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.REMOVE_INVALID_INDEX, index,
                            collection.Count)

                    collection.RemoveAt(index)

                elif isinstance(collection, Map):

                    collection.Remove(key)

                else:

                    return self.VM_FAULT_and_report(
                        VMFault.REMOVE_INVALID_TYPE, key, collection)

            elif opcode == HASKEY:

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

                collection = estack.Pop()

                if isinstance(collection, Array):

                    index = key.GetBigInteger()

                    if index < 0:
                        return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

                    estack.PushT(index < collection.Count)

                elif isinstance(collection, Map):

                    estack.PushT(collection.ContainsKey(key))

                else:

                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

            elif opcode == KEYS:

                collection = estack.Pop()

                if isinstance(collection, Map):

                    estack.PushT(Array(collection.Keys))
                else:
                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

            elif opcode == VALUES:

                collection = estack.Pop()
                values = []

                if isinstance(collection, Map):
                    values = collection.Values

                elif isinstance(collection, Array):
                    values = collection

                else:
                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

                newArray = Array()
                for item in values:
                    if isinstance(item, Struct):
                        newArray.Add(item.Clone())
                    else:
                        newArray.Add(item)

                estack.PushT(newArray)

            elif opcode == THROW:
                return self.VM_FAULT_and_report(VMFault.THROW)

            elif opcode == THROWIFNOT:
                if not estack.Pop().GetBoolean():
                    return self.VM_FAULT_and_report(VMFault.THROWIFNOT)

            else:
                return self.VM_FAULT_and_report(VMFault.UNKNOWN_OPCODE, opcode)

        if self._VMState & VMState.FAULT == 0 and self.InvocationStack.Count > 0:
            if len(self.CurrentContext.Breakpoints):
                if self.CurrentContext.InstructionPointer in self.CurrentContext.Breakpoints:
                    self._vm_debugger = VMDebugger(self)
                    self._vm_debugger.start()
Ejemplo n.º 2
0
    def ExecuteOp(self, opcode, context):
        estack = self._EvaluationStack
        istack = self._InvocationStack
        astack = self._AltStack

        if opcode > PUSH16 and opcode != RET and context.PushOnly:
            self._VMState |= VMState.FAULT

        if opcode >= PUSHBYTES1 and opcode <= PUSHBYTES75:
            bytestoread = context.OpReader.ReadBytes(
                int.from_bytes(opcode, 'little'))
            estack.PushT(bytestoread)
        else:

            # push values
            pushops = [
                PUSHM1, PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8,
                PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16
            ]

            if opcode == PUSH0:
                estack.PushT(bytearray([0]))

            elif opcode == PUSHDATA1:
                lenngth = context.OpReader.ReadByte()
                estack.PushT(bytearray(context.OpReader.ReadBytes(lenngth)))
            elif opcode == PUSHDATA2:
                estack.PushT(
                    context.OpReader.ReadBytes(context.OpReader.ReadUInt16()))
            elif opcode == PUSHDATA4:
                estack.PushT(
                    context.OpReader.ReadBytes(context.OpReader.ReadUInt32()))
            elif opcode in pushops:
                # EvaluationStack.Push((int)opcode - (int)OpCode.PUSH1 + 1);
                topush = int.from_bytes(opcode, 'little') - int.from_bytes(
                    PUSH1, 'little') + 1
                estack.PushT(topush)

            # control
            elif opcode == NOP:
                pass
            elif opcode in [JMP, JMPIF, JMPIFNOT]:
                offset_b = context.OpReader.ReadInt16()
                offset = context.InstructionPointer + offset_b - 3

                if offset < 0 or offset > len(context.Script):
                    self._VMState |= VMState.FAULT
                    return

                fValue = True
                if opcode > JMP:
                    fValue = estack.Pop().GetBoolean()
                    if opcode == JMPIFNOT:
                        fValue = not fValue
                if fValue:
                    context.SetInstructionPointer(offset)

            elif opcode == CALL:
                istack.PushT(context.Clone())
                context.SetInstructionPointer(context.InstructionPointer + 2)

                self.ExecuteOp(JMP, self.CurrentContext)

            elif opcode == RET:
                istack.Pop().Dispose()
                if istack.Count == 0:
                    self._VMState |= VMState.HALT

            elif opcode == APPCALL or opcode == TAILCALL:
                if self._Table is None:
                    self._VMState |= VMState.FAULT
                    return

                script_hash = context.OpReader.ReadBytes(20)

                is_normal_call = False
                for b in script_hash:
                    if b > 0:
                        is_normal_call = True

                if not is_normal_call:
                    script_hash = self.EvaluationStack.Pop().GetByteArray()

                script = self._Table.GetScript(
                    UInt160(data=script_hash).ToBytes())

                if script is None:
                    logger.error(
                        "Could not find script from script table: %s " %
                        script_hash)
                    self._VMState |= VMState.FAULT
                    return

                if opcode == TAILCALL:
                    istack.Pop().Dispose()

                self.LoadScript(script)

            elif opcode == SYSCALL:
                call = context.OpReader.ReadVarBytes(252).decode('ascii')
                if not self._Service.Invoke(call, self):
                    self._VMState |= VMState.FAULT

            # stack operations
            elif opcode == DUPFROMALTSTACK:
                estack.PushT(astack.Peek())

            elif opcode == TOALTSTACK:
                astack.PushT(estack.Pop())

            elif opcode == FROMALTSTACK:
                estack.PushT(astack.Pop())

            elif opcode == XDROP:
                n = estack.Pop().GetBigInteger()
                if n < 0:
                    self._VMState |= VMState.FAULT
                    return
                estack.Remove(n)

            elif opcode == XSWAP:
                n = estack.Pop().GetBigInteger()

                if n < 0:
                    self._VMState |= VMState.FAULT
                    return

                # if n == 0 break, same as do x if n > 0
                if n > 0:

                    item = estack.Peek(n)
                    estack.Set(n, estack.Peek())
                    estack.Set(0, item)

            elif opcode == XTUCK:
                n = estack.Pop().GetBigInteger()

                if n <= 0:
                    self._VMState |= VMState.FAULT
                    return

                estack.Insert(n, estack.Peek())

            elif opcode == DEPTH:
                estack.PushT(estack.Count)

            elif opcode == DROP:
                estack.Pop()

            elif opcode == DUP:
                estack.PushT(estack.Peek())

            elif opcode == NIP:
                x2 = estack.Pop()
                estack.Pop()
                estack.PushT(x2)

            elif opcode == OVER:

                x2 = estack.Pop()
                x1 = estack.Peek()
                estack.PushT(x2)
                estack.PushT(x1)

            elif opcode == PICK:

                n = estack.Pop().GetBigInteger()
                if n < 0:
                    self._VMState |= VMState.FAULT
                    return

                estack.PushT(estack.Peek(n))

            elif opcode == ROLL:

                n = estack.Pop().GetBigInteger()
                if n < 0:
                    self._VMState |= VMState.FAULT
                    return

                if n > 0:
                    estack.PushT(estack.Remove(n))

            elif opcode == ROT:
                x3 = estack.Pop()
                x2 = estack.Pop()
                x1 = estack.Pop()

                estack.PushT(x2)
                estack.PushT(x3)
                estack.PushT(x1)

            elif opcode == SWAP:

                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x2)
                estack.PushT(x1)

            elif opcode == TUCK:

                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x2)
                estack.PushT(x1)
                estack.PushT(x2)

            elif opcode == CAT:

                x2 = estack.Pop().GetByteArray()
                x1 = estack.Pop().GetByteArray()
                estack.PushT(x1 + x2)

            elif opcode == SUBSTR:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    self._VMState |= VMState.FAULT
                    return

                index = estack.Pop().GetBigInteger()
                if index < 0:
                    self._VMState |= VMState.FAULT
                    return

                x = estack.Pop().GetByteArray()

                estack.PushT(x[index:count + index])

            elif opcode == LEFT:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    self._VMState |= VMState.FAULT
                    return

                x = estack.Pop().GetByteArray()
                estack.PushT(x[:count])

            elif opcode == RIGHT:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    self._VMState |= VMState.FAULT
                    return

                x = estack.Pop().GetByteArray()
                if len(x) < count:
                    self._VMState |= VMState.FAULT
                    return

                estack.PushT(x[-count:])

            elif opcode == SIZE:

                x = estack.Pop().GetByteArray()
                estack.PushT(len(x))

            elif opcode == INVERT:

                x = estack.Pop().GetBigInteger()
                estack.PushT(~x)

            elif opcode == AND:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 & x2)

            elif opcode == OR:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 | x2)

            elif opcode == XOR:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 ^ x2)

            elif opcode == EQUAL:
                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x1.Equals(x2))

            # numeric

            elif opcode == INC:

                x = estack.Pop().GetBigInteger()
                estack.PushT(x + 1)

            elif opcode == DEC:

                x = estack.Pop().GetBigInteger()
                estack.PushT(x - 1)

            elif opcode == SIGN:

                # Make sure to implement sign for big integer
                x = estack.Pop().GetBigInteger()
                estack.PushT(x.Sign)

            elif opcode == NEGATE:

                x = estack.Pop().GetBigInteger()
                estack.PushT(-x)

            elif opcode == ABS:

                x = estack.Pop().GetBigInteger()
                estack.PushT(abs(x))

            elif opcode == NOT:

                x = estack.Pop().GetBigInteger()
                estack.PushT(not x)

            elif opcode == NZ:

                x = estack.Pop().GetBigInteger()
                estack.PushT(x is not 0)

            elif opcode == ADD:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 + x2)

            elif opcode == SUB:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 - x2)

            elif opcode == MUL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 * x2)

            elif opcode == DIV:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 / x2)

            elif opcode == MOD:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 % x2)

            elif opcode == SHL:

                n = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(x << n)

            elif opcode == SHR:

                n = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(x >> n)

            elif opcode == BOOLAND:

                x2 = estack.Pop().GetBoolean()
                x1 = estack.Pop().GetBoolean()

                estack.PushT(x1 and x2)

            elif opcode == BOOLOR:

                x2 = estack.Pop().GetBoolean()
                x1 = estack.Pop().GetBoolean()

                estack.PushT(x1 or x2)

            elif opcode == NUMEQUAL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x2 == x1)

            elif opcode == NUMNOTEQUAL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 != x2)

            elif opcode == LT:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 < x2)

            elif opcode == GT:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 > x2)

            elif opcode == LTE:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 <= x2)

            elif opcode == GTE:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 >= x2)

            elif opcode == MIN:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(min(x1, x2))

            elif opcode == MAX:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(max(x1, x2))

            elif opcode == WITHIN:

                b = estack.Pop().GetBigInteger()
                a = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(a <= x and x < b)

            # CRyPTO
            elif opcode == SHA1:
                h = hashlib.sha1(estack.Pop().GetByteArray())
                estack.PushT(h.digest())

            elif opcode == SHA256:
                h = hashlib.sha256(estack.Pop().GetByteArray())
                estack.PushT(h.digest())

            elif opcode == HASH160:

                estack.PushT(self.Crypto.Hash160(estack.Pop().GetByteArray()))

            elif opcode == HASH256:

                estack.PushT(self.Crypto.Hash256(estack.Pop().GetByteArray()))

            elif opcode == CHECKSIG:

                pubkey = estack.Pop().GetByteArray()
                sig = estack.Pop().GetByteArray()

                try:

                    res = self.Crypto.VerifySignature(
                        self.ScriptContainer.GetMessage(), sig, pubkey)
                    estack.PushT(res)

                except Exception as e:
                    estack.PushT(False)
                    logger.error("Could not checksig: %s " % e)

            elif opcode == CHECKMULTISIG:

                n = estack.Pop().GetBigInteger()

                if n < 1:
                    self._VMState |= VMState.FAULT
                    return

                pubkeys = []
                for i in range(0, n):
                    pubkeys.append(estack.Pop().GetByteArray())

                m = estack.Pop().GetBigInteger()

                if m < 1 or m > n:
                    self._VMState |= VMState.FAULT
                    return

                sigs = []

                for i in range(0, m):
                    sigs.append(estack.Pop().GetByteArray())

                message = self.ScriptContainer.GetMessage(
                ) if self.ScriptContainer else ''

                fSuccess = True

                try:

                    i = 0
                    j = 0

                    while fSuccess and i < m and j < n:

                        if self.Crypto.VerifySignature(message, sigs[i],
                                                       pubkeys[j]):
                            i += 1
                        j += 1

                        if m - i > n - j:
                            fSuccess = False

                except Exception as e:
                    fSuccess = False

                estack.PushT(fSuccess)

            # lists
            elif opcode == ARRAYSIZE:

                item = estack.Pop()

                if not item:
                    self._VMState |= VMState.FAULT
                    return

                if not item.IsArray:
                    estack.PushT(len(item.GetByteArray()))

                else:
                    estack.PushT(len(item.GetArray()))

            elif opcode == PACK:

                size = estack.Pop().GetBigInteger()

                if size < 0 or size > estack.Count:
                    self._VMState |= VMState.FAULT
                    return

                items = []

                for i in range(0, size):
                    topack = estack.Pop()
                    items.append(topack)

                estack.PushT(items)

            elif opcode == UNPACK:
                item = estack.Pop()

                if not item.IsArray:
                    self._VMState |= VMState.FAULT
                    return

                items = item.GetArray()
                items.reverse()

                [estack.PushT(i) for i in items]

                estack.PushT(len(items))

            elif opcode == PICKITEM:

                index = estack.Pop().GetBigInteger()

                if index < 0:
                    self._VMState |= VMState.FAULT
                    return

                item = estack.Pop()

                if not item.IsArray:
                    self._VMState |= VMState.FAULT
                    return

                items = item.GetArray()

                if index >= len(items):
                    self._VMState |= VMState.FAULT
                    return

                to_pick = items[index]
                estack.PushT(to_pick)

            elif opcode == SETITEM:
                newItem = estack.Pop()

                if issubclass(type(newItem), StackItem) and newItem.IsStruct:
                    newItem = newItem.Clone()

                index = estack.Pop().GetBigInteger()

                arrItem = estack.Pop()

                if not issubclass(type(arrItem),
                                  StackItem) or not arrItem.IsArray:
                    self._VMState |= VMState.FAULT
                    return

                items = arrItem.GetArray()

                if index < 0 or index >= len(items):
                    self._VMState |= VMState.FAULT
                    return

                items[index] = newItem

            elif opcode == NEWARRAY:

                count = estack.Pop().GetBigInteger()
                items = [None for i in range(0, count)]
                estack.PushT(Array(items))

            elif opcode == NEWSTRUCT:

                count = estack.Pop().GetBigInteger()

                items = [None for i in range(0, count)]

                estack.PushT(Struct(items))

            elif opcode == APPEND:
                newItem = estack.Pop()

                if type(newItem) is Struct:
                    newItem = newItem.Clone()

                arrItem = estack.Pop()

                if not arrItem.IsArray:
                    self._VMState |= VMState.FAULT
                    return

                arr = arrItem.GetArray()
                arr.append(newItem)

            elif opcode == REVERSE:

                arrItem = estack.Pop()
                if not arrItem.IsArray:
                    self._VMState |= VMState.FAULT
                    return
                arrItem.GetArray().reverse()

            elif opcode == REMOVE:
                index = estack.Pop().GetBigInteger()
                arrItem = estack.Pop()
                if not arrItem.IsArray:
                    self._VMState |= VMState.FAULT
                    return
                items = arrItem.GetArray()

                if index < 0 or index >= len(items):
                    self._VMState |= VMState.FAULT
                    return
                del items[index]

            elif opcode == THROW:
                self._VMState |= VMState.FAULT
                return

            elif opcode == THROWIFNOT:
                if not estack.Pop().GetBoolean():
                    self._VMState |= VMState.FAULT
                    return

            elif opcode == DEBUG:
                pdb.set_trace()
                return

            else:

                self._VMState |= VMState.FAULT
                return

        if self._VMState & VMState.FAULT == 0 and self.InvocationStack.Count > 0:

            if self.CurrentContext.InstructionPointer in self.CurrentContext.Breakpoints:
                self._VMState |= VMState.BREAK
Ejemplo n.º 3
0
    def ExecuteInstruction(self):
        context = self.CurrentContext
        instruction = context.CurrentInstruction
        opcode = instruction.OpCode
        estack = context._EvaluationStack
        istack = self._InvocationStack
        astack = context._AltStack

        if opcode >= PUSHBYTES1 and opcode <= PUSHDATA4:
            if not self.CheckMaxItemSize(len(instruction.Operand)):
                return False
            estack.PushT(instruction.Operand)

            if not self.CheckStackSize(True):
                return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)
        else:

            # push values
            if opcode in [
                    PUSHM1, PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7,
                    PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14,
                    PUSH15, PUSH16
            ]:

                topush = int.from_bytes(opcode, 'little') - int.from_bytes(
                    PUSH1, 'little') + 1
                estack.PushT(topush)

                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == PUSH0:
                estack.PushT(bytearray(0))
                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            # control
            elif opcode == NOP:
                pass
            elif opcode in [JMP, JMPIF, JMPIFNOT]:
                offset = context.InstructionPointer + instruction.TokenI16

                if offset < 0 or offset > context.Script.Length:
                    return self.VM_FAULT_and_report(VMFault.INVALID_JUMP)

                fValue = True
                if opcode > JMP:
                    self.CheckStackSize(False, -1)
                    fValue = estack.Pop().GetBoolean()
                    if opcode == JMPIFNOT:
                        fValue = not fValue
                if fValue:
                    context.InstructionPointer = offset
                    context.ins = context.GetInstruction(
                        context.InstructionPointer)
                else:
                    context.InstructionPointer += 3
                    context.ins = context.GetInstruction(
                        context.InstructionPointer)
                return True

            elif opcode == CALL:
                if not self.CheckMaxInvocationStack():
                    return self.VM_FAULT_and_report(
                        VMFault.CALL_EXCEED_MAX_INVOCATIONSTACK_SIZE)

                context_call = self._LoadScriptInternal(context.Script)
                context_call.InstructionPointer = context.InstructionPointer + instruction.TokenI16
                if context_call.InstructionPointer < 0 or context_call.InstructionPointer > context_call.Script.Length:
                    return False
                context.EvaluationStack.CopyTo(context_call.EvaluationStack)
                context.EvaluationStack.Clear()

            elif opcode == RET:
                context_pop: ExecutionContext = istack.Pop()
                rvcount = context_pop._RVCount

                if rvcount == -1:
                    rvcount = context_pop.EvaluationStack.Count

                if rvcount > 0:
                    if context_pop.EvaluationStack.Count < rvcount:
                        return self.VM_FAULT_and_report(VMFault.UNKNOWN1)

                    if istack.Count == 0:
                        stack_eval = self._ResultStack
                    else:
                        stack_eval = self.CurrentContext.EvaluationStack
                    context_pop.EvaluationStack.CopyTo(stack_eval, rvcount)

                if context_pop._RVCount == -1 and istack.Count > 0:
                    context_pop.AltStack.CopyTo(self.CurrentContext.AltStack)

                self.CheckStackSize(False, 0)

                if istack.Count == 0:
                    self._VMState = VMState.HALT
                return True

            elif opcode == APPCALL or opcode == TAILCALL:
                if self._Table is None:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN2)

                if opcode == APPCALL and not self.CheckMaxInvocationStack():
                    return self.VM_FAULT_and_report(
                        VMFault.APPCALL_EXCEED_MAX_INVOCATIONSTACK_SIZE)

                script_hash = instruction.Operand

                is_normal_call = False
                for b in script_hash:
                    if b > 0:
                        is_normal_call = True
                        break

                if not is_normal_call:
                    script_hash = estack.Pop().GetByteArray()

                context_new = self._LoadScriptByHash(script_hash)
                if context_new is None:
                    return self.VM_FAULT_and_report(VMFault.INVALID_CONTRACT,
                                                    script_hash)

                estack.CopyTo(context_new.EvaluationStack)

                if opcode == TAILCALL:
                    istack.Remove(1)
                else:
                    estack.Clear()

                self.CheckStackSize(False, 0)

            elif opcode == SYSCALL:
                if len(instruction.Operand) > 252:
                    return False

                if not self._Service.Invoke(instruction.Operand, self):
                    return self.VM_FAULT_and_report(VMFault.SYSCALL_ERROR,
                                                    instruction.Operand)

                if not self.CheckStackSize(False, int_MaxValue):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            # stack operations
            elif opcode == DUPFROMALTSTACK:
                estack.PushT(astack.Peek())

                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == TOALTSTACK:
                astack.PushT(estack.Pop())

            elif opcode == FROMALTSTACK:
                estack.PushT(astack.Pop())

            elif opcode == XDROP:
                n = estack.Pop().GetBigInteger()
                if n < 0:
                    self._VMState = VMState.FAULT
                    return
                estack.Remove(n)
                self.CheckStackSize(False, -2)

            elif opcode == XSWAP:
                n = estack.Pop().GetBigInteger()

                if n < 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN3)

                self.CheckStackSize(True, -1)

                # if n == 0 break, same as do x if n > 0
                if n > 0:
                    item = estack.Peek(n)
                    estack.Set(n, estack.Peek())
                    estack.Set(0, item)

            elif opcode == XTUCK:
                n = estack.Pop().GetBigInteger()

                if n <= 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN4)

                estack.Insert(n, estack.Peek())

            elif opcode == DEPTH:
                estack.PushT(estack.Count)
                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == DROP:
                estack.Pop()
                self.CheckStackSize(False, -1)

            elif opcode == DUP:
                estack.PushT(estack.Peek())
                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == NIP:
                estack.Remove(1)
                self.CheckStackSize(False, -1)

            elif opcode == OVER:
                estack.PushT(estack.Peek(1))
                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == PICK:

                n = estack.Pop().GetBigInteger()
                if n < 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN5)

                estack.PushT(estack.Peek(n))

            elif opcode == ROLL:

                n = estack.Pop().GetBigInteger()
                if n < 0:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN6)
                self.CheckStackSize(True, -1)

                if n > 0:
                    estack.PushT(estack.Remove(n))

            elif opcode == ROT:
                estack.PushT(estack.Remove(2))

            elif opcode == SWAP:
                estack.PushT(estack.Remove(1))

            elif opcode == TUCK:
                estack.Insert(2, estack.Peek())
                if not self.CheckStackSize(True):
                    return self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == CAT:

                x2 = estack.Pop().GetByteArray()
                x1 = estack.Pop().GetByteArray()
                if not self.CheckMaxItemSize(len(x1) + len(x2)):
                    return self.VM_FAULT_and_report(
                        VMFault.CAT_EXCEED_MAXITEMSIZE)
                estack.PushT(x1 + x2)
                self.CheckStackSize(True, -1)

            elif opcode == SUBSTR:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    return self.VM_FAULT_and_report(
                        VMFault.SUBSTR_INVALID_LENGTH)

                index = estack.Pop().GetBigInteger()
                if index < 0:
                    return self.VM_FAULT_and_report(
                        VMFault.SUBSTR_INVALID_INDEX)

                x = estack.Pop().GetByteArray()

                estack.PushT(x[index:count + index])
                self.CheckStackSize(True, -2)

            elif opcode == LEFT:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    return self.VM_FAULT_and_report(VMFault.LEFT_INVALID_COUNT)

                x = estack.Pop().GetByteArray()

                if count >= len(x):
                    estack.PushT(x)
                else:
                    estack.PushT(x[:count])
                self.CheckStackSize(True, -1)

            elif opcode == RIGHT:

                count = estack.Pop().GetBigInteger()
                if count < 0:
                    return self.VM_FAULT_and_report(
                        VMFault.RIGHT_INVALID_COUNT)

                x = estack.Pop().GetByteArray()
                if count > len(x):
                    return self.VM_FAULT_and_report(VMFault.RIGHT_UNKNOWN)

                if count == len(x):
                    estack.PushT(x)
                else:
                    offset = len(x) - count
                    estack.PushT(x[offset:offset + count])
                self.CheckStackSize(True, -1)

            elif opcode == SIZE:

                x = estack.Pop()
                estack.PushT(x.GetByteLength())

            elif opcode == INVERT:

                x = estack.Pop().GetBigInteger()
                estack.PushT(~x)

            elif opcode == AND:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 & x2)
                self.CheckStackSize(True, -1)

            elif opcode == OR:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 | x2)
                self.CheckStackSize(True, -1)

            elif opcode == XOR:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 ^ x2)
                self.CheckStackSize(True, -1)

            elif opcode == EQUAL:
                x2 = estack.Pop()
                x1 = estack.Pop()
                estack.PushT(x1.Equals(x2))
                self.CheckStackSize(False, -1)

            # numeric
            elif opcode == INC:

                x = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x) or not self.CheckBigInteger(x +
                                                                           1):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)
                estack.PushT(x + 1)

            elif opcode == DEC:

                x = estack.Pop().GetBigInteger()  # type: BigInteger
                if not self.CheckBigInteger(x) or (
                        x.Sign <= 0 and not self.CheckBigInteger(x - 1)):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x - 1)

            elif opcode == SIGN:

                # Make sure to implement sign for big integer
                x = estack.Pop().GetBigInteger()

                estack.PushT(x.Sign)

            elif opcode == NEGATE:

                x = estack.Pop().GetBigInteger()

                estack.PushT(-x)

            elif opcode == ABS:

                x = estack.Pop().GetBigInteger()

                estack.PushT(abs(x))

            elif opcode == NOT:

                x = estack.Pop().GetBoolean()
                estack.PushT(not x)
                self.CheckStackSize(False, 0)

            elif opcode == NZ:

                x = estack.Pop().GetBigInteger()

                estack.PushT(x is not 0)

            elif opcode == ADD:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x1) or not self.CheckBigInteger(
                        x2) or not self.CheckBigInteger(x1 + x2):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x1 + x2)
                self.CheckStackSize(True, -1)

            elif opcode == SUB:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x1) or not self.CheckBigInteger(
                        x2) or not self.CheckBigInteger(x1 - x2):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x1 - x2)
                self.CheckStackSize(True, -1)

            elif opcode == MUL:

                x2 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x2):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                x1 = estack.Pop().GetBigInteger()  # type: BigInteger
                if not self.CheckBigInteger(x1):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                result = x1 * x2
                if not self.CheckBigInteger(result):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(result)
                self.CheckStackSize(True, -1)

            elif opcode == DIV:

                x2 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x2):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                x1 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x1) or not self.CheckBigInteger(
                        x2):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x1 / x2)
                self.CheckStackSize(True, -1)

            elif opcode == MOD:

                x2 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x2):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                x1 = estack.Pop().GetBigInteger()
                if not self.CheckBigInteger(x1):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x1 % x2)
                self.CheckStackSize(True, -1)

            elif opcode == SHL:

                shift = estack.Pop().GetBigInteger()
                if not self.CheckShift(shift):
                    return self.VM_FAULT_and_report(VMFault.INVALID_SHIFT)

                x = estack.Pop().GetBigInteger()

                if not self.CheckBigInteger(x):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                x = x << shift

                if not self.CheckBigInteger(x):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x)
                self.CheckStackSize(True, -1)

            elif opcode == SHR:

                shift = estack.Pop().GetBigInteger()
                if not self.CheckShift(shift):
                    return self.VM_FAULT_and_report(VMFault.INVALID_SHIFT)

                x = estack.Pop().GetBigInteger()

                if not self.CheckBigInteger(x):
                    return self.VM_FAULT_and_report(
                        VMFault.BIGINTEGER_EXCEED_LIMIT)

                estack.PushT(x >> shift)
                self.CheckStackSize(True, -1)

            elif opcode == BOOLAND:

                x2 = estack.Pop().GetBoolean()
                x1 = estack.Pop().GetBoolean()

                estack.PushT(x1 and x2)
                self.CheckStackSize(False, -1)

            elif opcode == BOOLOR:

                x2 = estack.Pop().GetBoolean()
                x1 = estack.Pop().GetBoolean()

                estack.PushT(x1 or x2)
                self.CheckStackSize(False, -1)

            elif opcode == NUMEQUAL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x2 == x1)
                self.CheckStackSize(True, -1)

            elif opcode == NUMNOTEQUAL:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 != x2)
                self.CheckStackSize(True, -1)

            elif opcode == LT:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 < x2)
                self.CheckStackSize(True, -1)

            elif opcode == GT:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 > x2)
                self.CheckStackSize(True, -1)

            elif opcode == LTE:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 <= x2)
                self.CheckStackSize(True, -1)

            elif opcode == GTE:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(x1 >= x2)
                self.CheckStackSize(True, -1)

            elif opcode == MIN:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(min(x1, x2))
                self.CheckStackSize(True, -1)

            elif opcode == MAX:

                x2 = estack.Pop().GetBigInteger()
                x1 = estack.Pop().GetBigInteger()

                estack.PushT(max(x1, x2))
                self.CheckStackSize(True, -1)

            elif opcode == WITHIN:

                b = estack.Pop().GetBigInteger()
                a = estack.Pop().GetBigInteger()
                x = estack.Pop().GetBigInteger()

                estack.PushT(a <= x and x < b)
                self.CheckStackSize(True, -2)

            # CRyPTO
            elif opcode == SHA1:
                h = hashlib.sha1(estack.Pop().GetByteArray())
                estack.PushT(h.digest())

            elif opcode == SHA256:
                h = hashlib.sha256(estack.Pop().GetByteArray())
                estack.PushT(h.digest())

            elif opcode == HASH160:

                estack.PushT(self.Crypto.Hash160(estack.Pop().GetByteArray()))

            elif opcode == HASH256:

                estack.PushT(self.Crypto.Hash256(estack.Pop().GetByteArray()))

            elif opcode == CHECKSIG:

                pubkey = estack.Pop().GetByteArray()
                sig = estack.Pop().GetByteArray()
                container = self.ScriptContainer
                if not container:
                    logger.debug("Cannot check signature without container")
                    estack.PushT(False)
                    return
                try:
                    res = self.Crypto.VerifySignature(container.GetMessage(),
                                                      sig, pubkey)
                    estack.PushT(res)
                except Exception as e:
                    estack.PushT(False)
                    logger.debug("Could not checksig: %s " % e)
                self.CheckStackSize(True, -1)

            elif opcode == VERIFY:
                pubkey = estack.Pop().GetByteArray()
                sig = estack.Pop().GetByteArray()
                message = estack.Pop().GetByteArray()
                try:
                    res = self.Crypto.VerifySignature(message,
                                                      sig,
                                                      pubkey,
                                                      unhex=False)
                    estack.PushT(res)
                except Exception as e:
                    estack.PushT(False)
                    logger.debug("Could not verify: %s " % e)
                self.CheckStackSize(True, -2)

            elif opcode == CHECKMULTISIG:
                item = estack.Pop()
                pubkeys = []

                if isinstance(item, Array):

                    for p in item.GetArray():
                        pubkeys.append(p.GetByteArray())
                    n = len(pubkeys)
                    if n == 0:
                        return self.VM_FAULT_and_report(
                            VMFault.CHECKMULTISIG_INVALID_PUBLICKEY_COUNT)

                    self.CheckStackSize(False, -1)
                else:
                    n = item.GetBigInteger()

                    if n < 1 or n > estack.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.CHECKMULTISIG_INVALID_PUBLICKEY_COUNT)

                    for i in range(0, n):
                        pubkeys.append(estack.Pop().GetByteArray())
                    self.CheckStackSize(True, -n - 1)

                item = estack.Pop()
                sigs = []

                if isinstance(item, Array):
                    for s in item.GetArray():
                        sigs.append(s.GetByteArray())
                    m = len(sigs)

                    if m == 0 or m > n:
                        return self.VM_FAULT_and_report(
                            VMFault.CHECKMULTISIG_SIGNATURE_ERROR, m, n)
                    self.CheckStackSize(False, -1)
                else:
                    m = item.GetBigInteger()

                    if m < 1 or m > n or m > estack.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.CHECKMULTISIG_SIGNATURE_ERROR, m, n)

                    for i in range(0, m):
                        sigs.append(estack.Pop().GetByteArray())
                    self.CheckStackSize(True, -m - 1)

                message = self.ScriptContainer.GetMessage(
                ) if self.ScriptContainer else ''

                fSuccess = True

                try:

                    i = 0
                    j = 0

                    while fSuccess and i < m and j < n:

                        if self.Crypto.VerifySignature(message, sigs[i],
                                                       pubkeys[j]):
                            i += 1
                        j += 1

                        if m - i > n - j:
                            fSuccess = False

                except Exception as e:
                    fSuccess = False

                estack.PushT(fSuccess)

            # lists
            elif opcode == ARRAYSIZE:

                item = estack.Pop()

                if not item:
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN7)

                if isinstance(item, CollectionMixin):
                    estack.PushT(item.Count)
                    self.CheckStackSize(False, 0)

                else:
                    estack.PushT(len(item.GetByteArray()))
                    self.CheckStackSize(True, 0)

            elif opcode == PACK:

                size = estack.Pop().GetBigInteger()

                if size < 0 or size > estack.Count or not self.CheckArraySize(
                        size):
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN8)

                items = []

                for i in range(0, size):
                    topack = estack.Pop()
                    items.append(topack)

                estack.PushT(items)

            elif opcode == UNPACK:
                item = estack.Pop()

                if not isinstance(item, Array):
                    return self.VM_FAULT_and_report(
                        VMFault.UNPACK_INVALID_TYPE, item)

                items = item.GetArray()
                items.reverse()

                [estack.PushT(i) for i in items]

                estack.PushT(len(items))
                if not self.CheckStackSize(False, len(items)):
                    self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == PICKITEM:

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    # key must be an array index or dictionary key, but not a collection
                    return self.VM_FAULT_and_report(VMFault.KEY_IS_COLLECTION,
                                                    key)

                collection = estack.Pop()

                if isinstance(collection, Array):
                    index = key.GetBigInteger()
                    if index < 0 or index >= collection.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.PICKITEM_INVALID_INDEX, index,
                            collection.Count)

                    items = collection.GetArray()
                    to_pick = items[index]
                    estack.PushT(to_pick)

                    if not self.CheckStackSize(False, -1):
                        self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

                elif isinstance(collection, Map):
                    success, value = collection.TryGetValue(key)

                    if success:
                        estack.PushT(value)

                        if not self.CheckStackSize(False, -1):
                            self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

                    else:
                        return self.VM_FAULT_and_report(
                            VMFault.DICT_KEY_NOT_FOUND, key, collection.Keys)
                else:
                    return self.VM_FAULT_and_report(
                        VMFault.PICKITEM_INVALID_TYPE, key, collection)

            elif opcode == SETITEM:
                value = estack.Pop()

                if isinstance(value, Struct):
                    value = value.Clone()

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    return self.VM_FAULT_and_report(VMFault.KEY_IS_COLLECTION)

                collection = estack.Pop()

                if isinstance(collection, Array):

                    index = key.GetBigInteger()

                    if index < 0 or index >= collection.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.SETITEM_INVALID_INDEX)

                    items = collection.GetArray()
                    items[index] = value

                elif isinstance(collection, Map):
                    if not collection.ContainsKey(
                            key) and not self.CheckArraySize(collection.Count +
                                                             1):
                        return self.VM_FAULT_and_report(
                            VMFault.SETITEM_INVALID_MAP)

                    collection.SetItem(key, value)

                else:
                    return self.VM_FAULT_and_report(
                        VMFault.SETITEM_INVALID_TYPE, key, collection)

                if not self.CheckStackSize(False, int_MaxValue):
                    self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode in [NEWARRAY, NEWSTRUCT]:
                item = estack.Pop()
                if isinstance(item, Array):
                    result = None
                    if isinstance(item, Struct):
                        if opcode == NEWSTRUCT:
                            result = item
                    else:
                        if opcode == NEWARRAY:
                            result = item

                    if result is None:
                        result = Array(item) if opcode == NEWARRAY else Struct(
                            item)

                    estack.PushT(result)

                else:
                    count = item.GetBigInteger()
                    if count < 0:
                        return self.VM_FAULT_and_report(
                            VMFault.NEWARRAY_NEGATIVE_COUNT)

                    if not self.CheckArraySize(count):
                        return self.VM_FAULT_and_report(
                            VMFault.NEWARRAY_EXCEED_ARRAYLIMIT)

                    items = [Boolean(False) for i in range(0, count)]

                    result = Array(items) if opcode == NEWARRAY else Struct(
                        items)

                    estack.PushT(result)

                    if not self.CheckStackSize(True, count):
                        self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == NEWMAP:
                estack.PushT(Map())
                if not self.CheckStackSize(True):
                    self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == APPEND:
                newItem = estack.Pop()

                if isinstance(newItem, Struct):
                    newItem = newItem.Clone()

                arrItem = estack.Pop()

                if not isinstance(arrItem, Array):
                    return self.VM_FAULT_and_report(
                        VMFault.APPEND_INVALID_TYPE, arrItem)

                arr = arrItem.GetArray()
                if not self.CheckArraySize(len(arr) + 1):
                    return self.VM_FAULT_and_report(
                        VMFault.APPEND_EXCEED_ARRAYLIMIT)
                arr.append(newItem)

                if not self.CheckStackSize(False, int_MaxValue):
                    self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            elif opcode == REVERSE:

                arrItem = estack.Pop()
                self.CheckStackSize(False, -1)

                if not isinstance(arrItem, Array):
                    return self.VM_FAULT_and_report(
                        VMFault.REVERSE_INVALID_TYPE, arrItem)

                arrItem.Reverse()

            elif opcode == REMOVE:

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    return self.VM_FAULT_and_report(VMFault.UNKNOWN1)

                collection = estack.Pop()
                self.CheckStackSize(False, -2)

                if isinstance(collection, Array):

                    index = key.GetBigInteger()

                    if index < 0 or index >= collection.Count:
                        return self.VM_FAULT_and_report(
                            VMFault.REMOVE_INVALID_INDEX, index,
                            collection.Count)

                    collection.RemoveAt(index)

                elif isinstance(collection, Map):

                    collection.Remove(key)

                else:

                    return self.VM_FAULT_and_report(
                        VMFault.REMOVE_INVALID_TYPE, key, collection)

            elif opcode == HASKEY:

                key = estack.Pop()

                if isinstance(key, CollectionMixin):
                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

                collection = estack.Pop()

                if isinstance(collection, Array):

                    index = key.GetBigInteger()

                    if index < 0:
                        return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

                    estack.PushT(index < collection.Count)

                elif isinstance(collection, Map):

                    estack.PushT(collection.ContainsKey(key))

                else:

                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)
                self.CheckStackSize(False, -1)

            elif opcode == KEYS:

                collection = estack.Pop()

                if isinstance(collection, Map):

                    estack.PushT(Array(collection.Keys))
                    if not self.CheckStackSize(False, collection.Count):
                        self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)
                else:
                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

            elif opcode == VALUES:

                collection = estack.Pop()
                values = []

                if isinstance(collection, Map):
                    values = collection.Values

                elif isinstance(collection, Array):
                    values = collection

                else:
                    return self.VM_FAULT_and_report(VMFault.DICT_KEY_ERROR)

                newArray = Array()
                for item in values:
                    if isinstance(item, Struct):
                        newArray.Add(item.Clone())
                    else:
                        newArray.Add(item)

                estack.PushT(newArray)
                if not self.CheckStackSize(False, int_MaxValue):
                    self.VM_FAULT_and_report(VMFault.INVALID_STACKSIZE)

            # stack isolation
            elif opcode == CALL_I:
                if not self.CheckMaxInvocationStack():
                    return self.VM_FAULT_and_report(
                        VMFault.CALL__I_EXCEED_MAX_INVOCATIONSTACK_SIZE)
                rvcount = instruction.Operand[0]
                pcount = instruction.Operand[1]

                if estack.Count < pcount:
                    return self.VM_FAULT_and_report(
                        VMFault.UNKNOWN_STACKISOLATION)

                context_call = self._LoadScriptInternal(
                    context.Script, rvcount)
                context_call.InstructionPointer = context.InstructionPointer + instruction.TokenI16_1 + 2

                if context_call.InstructionPointer < 0 or context_call.InstructionPointer > context_call.Script.Length:
                    return False

                estack.CopyTo(context_call.EvaluationStack, pcount)

                for i in range(0, pcount, 1):
                    estack.Pop()

            elif opcode in [CALL_E, CALL_ED, CALL_ET, CALL_EDT]:
                if self._Table is None:
                    return self.VM_FAULT_and_report(
                        VMFault.UNKNOWN_STACKISOLATION2)

                rvcount = instruction.Operand[0]
                pcount = instruction.Operand[1]

                if estack.Count < pcount:
                    return self.VM_FAULT_and_report(
                        VMFault.UNKNOWN_STACKISOLATION)

                if opcode in [CALL_ET, CALL_EDT]:
                    if context._RVCount != rvcount:
                        return self.VM_FAULT_and_report(
                            VMFault.UNKNOWN_STACKISOLATION3)
                else:
                    if not self.CheckMaxInvocationStack():
                        return self.VM_FAULT_and_report(
                            VMFault.UNKNOWN_EXCEED_MAX_INVOCATIONSTACK_SIZE)

                if opcode in [CALL_ED, CALL_EDT]:
                    script_hash = estack.Pop().GetByteArray()
                    self.CheckStackSize(True, -1)
                else:
                    script_hash = instruction.ReadBytes(2, 20)

                context_new = self._LoadScriptByHash(script_hash, rvcount)
                if context_new is None:
                    return self.VM_FAULT_and_report(VMFault.INVALID_CONTRACT,
                                                    script_hash)

                estack.CopyTo(context_new.EvaluationStack, pcount)

                if opcode in [CALL_ET, CALL_EDT]:
                    istack.Remove(1)
                else:
                    for i in range(0, pcount, 1):
                        estack.Pop()

            elif opcode == THROW:
                return self.VM_FAULT_and_report(VMFault.THROW)

            elif opcode == THROWIFNOT:
                if not estack.Pop().GetBoolean():
                    return self.VM_FAULT_and_report(VMFault.THROWIFNOT)
                self.CheckStackSize(False, -1)

            else:
                return self.VM_FAULT_and_report(VMFault.UNKNOWN_OPCODE, opcode)
        context.MoveNext()
        return True