def test_to_parameter(self): stack_item = Integer(BigInteger(14)) cp1 = ContractParameter.AsParameterType(ContractParameterType.Integer, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'Integer', 'value': 14}) cp1 = ContractParameter.AsParameterType(ContractParameterType.Boolean, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'Boolean', 'value': True}) cp1 = ContractParameter.AsParameterType(ContractParameterType.ByteArray, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'ByteArray', 'value': '0e'}) with self.assertRaises(Exception) as ctx: cp1 = ContractParameter.AsParameterType(ContractParameterType.Array, stack_item) cp1 = ContractParameter.AsParameterType(ContractParameterType.String, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'String', 'value': '14'}) cp1 = ContractParameter.AsParameterType(ContractParameterType.InteropInterface, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'InteropInterface'}) stack_item = Boolean(False) cp1 = ContractParameter.AsParameterType(ContractParameterType.Integer, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'Integer', 'value': 0}) cp1 = ContractParameter.AsParameterType(ContractParameterType.Boolean, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'Boolean', 'value': False}) cp1 = ContractParameter.AsParameterType(ContractParameterType.ByteArray, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'ByteArray', 'value': ''}) with self.assertRaises(Exception) as ctx: cp1 = ContractParameter.AsParameterType(ContractParameterType.Array, stack_item) cp1 = ContractParameter.AsParameterType(ContractParameterType.String, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'String', 'value': 'False'}) cp1 = ContractParameter.AsParameterType(ContractParameterType.InteropInterface, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'InteropInterface'}) stack_item = ByteArray(bytearray(b'\xe0\x02')) cp1 = ContractParameter.AsParameterType(ContractParameterType.Integer, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'Integer', 'value': 736}) cp1 = ContractParameter.AsParameterType(ContractParameterType.Boolean, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'Boolean', 'value': True}) cp1 = ContractParameter.AsParameterType(ContractParameterType.ByteArray, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'ByteArray', 'value': 'e002'}) with self.assertRaises(Exception) as ctx: cp1 = ContractParameter.AsParameterType(ContractParameterType.Array, stack_item) cp1 = ContractParameter.AsParameterType(ContractParameterType.String, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'String', 'value': 'e002'}) cp1 = ContractParameter.AsParameterType(ContractParameterType.InteropInterface, stack_item) self.assertEqual(cp1.ToJson(), {'type': 'InteropInterface'})
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()
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