def _post_transfer(self, engine: contracts.ApplicationEngine, account_from: types.UInt160, account_to: types.UInt160, amount: vm.BigInteger, data: vm.StackItem, call_on_payment: bool) -> None: state = vm.ArrayStackItem(vm.ReferenceCounter()) if account_from == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_from.to_array())) if account_to == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_to.to_array())) state.append(vm.IntegerStackItem(amount)) msgrouter.interop_notify(self.hash, "Transfer", state) # wallet or smart contract if not call_on_payment \ or account_to == types.UInt160.zero() \ or contracts.ManagementContract().get_contract(engine.snapshot, account_to) is None: return if account_from == types.UInt160.zero(): from_: vm.StackItem = vm.NullStackItem() else: from_ = vm.ByteStringStackItem(account_from.to_array()) engine.call_from_native( self.hash, account_to, "onNEP17Payment", [from_, vm.IntegerStackItem(amount), data])
def _convert(self, stack_item: vm.StackItem, class_type: Type[object]) -> object: """ convert VM type to native """ if class_type in [vm.StackItem, vm.PointerStackItem, vm.ArrayStackItem, vm.InteropStackItem]: return stack_item elif class_type == int: return int(stack_item.to_biginteger()) elif class_type == vm.BigInteger: return stack_item.to_biginteger() # mypy bug? https://github.com/python/mypy/issues/9756 elif class_type in [bytes, bytearray]: # type: ignore return stack_item.to_array() elif class_type == bool: return stack_item.to_boolean() elif class_type == types.UInt160: return types.UInt160(data=stack_item.to_array()) elif class_type == types.UInt256: return types.UInt256(data=stack_item.to_array()) elif class_type == str: if stack_item == vm.NullStackItem(): return "" return stack_item.to_array().decode() elif class_type == cryptography.ECPoint: return cryptography.ECPoint.deserialize_from_bytes(stack_item.to_array()) elif issubclass(class_type, enum.Enum): if stack_item.get_type() == vm.StackItemType.INTEGER: stack_item = cast(vm.IntegerStackItem, stack_item) # mypy seems to have trouble understanding types that support __int__ return class_type(int(stack_item)) # type: ignore elif stack_item.get_type() == vm.StackItemType.BYTESTRING: stack_item = cast(vm.ByteStringStackItem, stack_item) return class_type(int(stack_item.to_biginteger())) # type: ignore raise ValueError(f"Unknown class type, don't know how to convert: {class_type}")
def contract_call(engine: contracts.ApplicationEngine, contract_hash: types.UInt160, method: str, call_flags: contracts.CallFlags, args: vm.ArrayStackItem) -> None: if method.startswith("_"): raise ValueError("Invalid method name") target_contract = contracts.ManagementContract().get_contract( engine.snapshot, contract_hash) if target_contract is None: raise ValueError("[System.Contract.Call] Can't find target contract") method_descriptor = target_contract.manifest.abi.get_method( method, len(args)) if method_descriptor is None: raise ValueError( f"[System.Contract.Call] Method '{method}' does not exist on target contract" ) has_return_value = method_descriptor.return_type != contracts.ContractParameterType.VOID if not has_return_value: engine.current_context.evaluation_stack.push(vm.NullStackItem()) engine._contract_call_internal2(target_contract, method_descriptor, call_flags, has_return_value, list(args))
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: struct = vm.StructStackItem(reference_counter) struct.append(vm.ByteStringStackItem(self.name)) struct.append(vm.ArrayStackItem(reference_counter, list(map(lambda g: g.to_stack_item(reference_counter), self.groups))) ) struct.append(vm.ArrayStackItem(reference_counter, list(map(lambda s: vm.ByteStringStackItem(s), self.supported_standards))) ) struct.append(self.abi.to_stack_item(reference_counter)) struct.append(vm.ArrayStackItem(reference_counter, list(map(lambda p: p.to_stack_item(reference_counter), self.permissions))) ) if self.trusts.is_wildcard: struct.append(vm.NullStackItem()) else: struct.append( vm.ArrayStackItem(reference_counter, list(map(lambda t: vm.ByteStringStackItem(t.to_array()), self.trusts))) # type: ignore ) if self.extra is None: struct.append(vm.ByteStringStackItem("null")) else: struct.append(vm.ByteStringStackItem(json.dumps(self.extra))) return struct
def mint(self, engine: contracts.ApplicationEngine, account: types.UInt160, amount: vm.BigInteger, call_on_payment: bool) -> None: """ Mint an amount of tokens into account. Increases the total supply of the token. """ if amount.sign < 0: raise ValueError("Can't mint a negative amount") if amount == vm.BigInteger.zero(): return storage_key = self.key_account + account storage_item = engine.snapshot.storages.try_get(storage_key, read_only=False) if storage_item is None: storage_item = storage.StorageItem(self._state().to_array()) engine.snapshot.storages.put(storage_key, storage_item) state = storage_item.get(self._state) self.on_balance_changing(engine, account, state, amount) state.balance += amount storage_item = engine.snapshot.storages.try_get(self.key_total_supply, read_only=False) if storage_item is None: storage_item = storage.StorageItem(amount.to_array()) engine.snapshot.storages.put(self.key_total_supply, storage_item) else: old_value = vm.BigInteger(storage_item.value) storage_item.value = (amount + old_value).to_array() self._post_transfer(engine, types.UInt160.zero(), account, amount, vm.NullStackItem(), call_on_payment)
def _native_to_stackitem(self, value, native_type) -> vm.StackItem: """ Convert native type to VM type Note: order of checking matters. e.g. a Transaction should be treated as IInteropable, while its also ISerializable """ if isinstance(value, vm.StackItem): return value elif value is None: return vm.NullStackItem() elif native_type in [int, vm.BigInteger]: return vm.IntegerStackItem(value) elif issubclass(native_type, IInteroperable): value_ = cast(IInteroperable, value) return value_.to_stack_item(self.reference_counter) elif issubclass(native_type, serialization.ISerializable): serializable_value = cast(serialization.ISerializable, value) return vm.ByteStringStackItem(serializable_value.to_array()) # mypy bug? https://github.com/python/mypy/issues/9756 elif native_type in [bytes, bytearray]: # type: ignore return vm.ByteStringStackItem(value) elif native_type == str: return vm.ByteStringStackItem(bytes(value, 'utf-8')) elif native_type == bool: return vm.BooleanStackItem(value) elif issubclass(native_type, (enum.IntFlag, enum.IntEnum)): return self._native_to_stackitem(value.value, int) else: return vm.StackItem.from_interface(value)
def test_with_null(self): n = vm.NullStackItem() x = contracts.BinarySerializer.serialize(n, 999) self.assertEqual(b'\x00', x) new_n = contracts.BinarySerializer.deserialize(x, 1, self.reference_counter) self.assertIsInstance(new_n, vm.NullStackItem)
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: struct = vm.StructStackItem(reference_counter) if self.contract.is_wildcard: struct.append(vm.NullStackItem()) elif self.contract.is_hash: struct.append(vm.ByteStringStackItem(self.contract.contract_hash.to_array())) # type: ignore else: struct.append(vm.ByteStringStackItem(self.contract.group.to_array())) # type: ignore if self.methods.is_wildcard: struct.append(vm.NullStackItem()) else: struct.append( vm.ArrayStackItem(reference_counter, list(map(lambda m: vm.ByteStringStackItem(m), self.methods))) # type: ignore ) return struct
def test_iterator_create_invalid_type(self): engine = test_engine() item = vm.NullStackItem() engine.push(item) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Iterator.Create") self.assertEqual( f"Cannot create iterator from unsupported type: {type(item)}", str(context.exception))
def deserialize( json_data: JObject, reference_counter: vm.ReferenceCounter = None) -> vm.StackItem: """ Deserialize JSON into a virtual machine stack item """ t = type(json_data) if t == dict: json_data = cast(dict, json_data) if reference_counter is None: raise ValueError( "Can't deserialize JSON object without reference counter") map_item = vm.MapStackItem(reference_counter) for k, v in json_data.items(): key = vm.ByteStringStackItem(k) value = JSONSerializer.deserialize(v, reference_counter) map_item[key] = value return map_item elif t == list: if reference_counter is None: raise ValueError( "Can't deserialize JSON array without reference counter") array_item = vm.ArrayStackItem(reference_counter) json_data = cast(list, json_data) elements = [ JSONSerializer.deserialize(e, reference_counter) for e in json_data ] array_item.append(elements) return array_item elif json_data is None: return vm.NullStackItem() elif t == str: if json_data == "null": return vm.NullStackItem() return vm.ByteStringStackItem(json_data) # type: ignore elif t == int: return vm.IntegerStackItem(json_data) # type: ignore elif t == bool: json_data = cast(bool, json_data) return vm.BooleanStackItem(json_data) else: # should never happen or somebody ignored the type checker output raise ValueError()
def test_serialization_array(self): b = vm.BooleanStackItem(True) bs = vm.ByteStringStackItem("test") i = vm.IntegerStackItem(123) n = vm.NullStackItem() ref_ctr = vm.ReferenceCounter() a = vm.ArrayStackItem(ref_ctr) a.append([b, bs, i, n]) expected = r'[true,"test",123,null]' self.assertEqual(expected, contracts.JSONSerializer.serialize(a, 999))
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: struct_ = super(_NeoTokenStorageState, self).to_stack_item(reference_counter) struct_ = cast(vm.StructStackItem, struct_) struct_.append(vm.IntegerStackItem(self.balance_height)) if self.vote_to.is_zero(): struct_.append(vm.NullStackItem()) else: struct_.append(vm.ByteStringStackItem(self.vote_to.to_array())) return struct_
def _post_transfer(self, engine: contracts.ApplicationEngine, account_from: types.UInt160, account_to: types.UInt160, token_id: bytes) -> None: state = vm.ArrayStackItem(engine.reference_counter) if account_from == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_from.to_array())) if account_to == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_to.to_array())) state.append(vm.IntegerStackItem(1)) state.append(vm.ByteStringStackItem(token_id)) msgrouter.interop_notify(self.hash, "Transfer", state) if account_to != types.UInt160.zero() and \ contracts.ManagementContract().get_contract(engine.snapshot, account_to) is not None: engine.call_from_native(self.hash, account_to, "onNEP17Payment", list(state))
def test_transfer_negative_amount(self): engine = test_engine(has_snapshot=True, default_script=False) engine.load_script(vm.Script(contracts.GasToken().script)) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block gas = contracts.GasToken() with self.assertRaises(ValueError) as context: gas.transfer(engine, types.UInt160.zero(), types.UInt160.zero(), vm.BigInteger(-1), vm.NullStackItem()) self.assertEqual("Can't transfer a negative amount", str(context.exception))
def _native_to_stackitem(self, value, native_type) -> vm.StackItem: """ Convert native type to VM type Note: order of checking matters. e.g. a Transaction should be treated as IInteropable, while its also ISerializable """ if isinstance(value, vm.StackItem): return value elif value is None: return vm.NullStackItem() elif native_type in [int, vm.BigInteger]: return vm.IntegerStackItem(value) elif issubclass(native_type, IInteroperable): value_ = cast(IInteroperable, value) return value_.to_stack_item(self.reference_counter) elif issubclass(native_type, serialization.ISerializable): serializable_value = cast(serialization.ISerializable, value) return vm.ByteStringStackItem(serializable_value.to_array()) # mypy bug? https://github.com/python/mypy/issues/9756 elif native_type in [bytes, bytearray]: # type: ignore return vm.ByteStringStackItem(value) elif native_type == str: return vm.ByteStringStackItem(bytes(value, 'utf-8')) elif native_type == bool: return vm.BooleanStackItem(value) elif issubclass(native_type, (enum.IntFlag, enum.IntEnum)): return self._native_to_stackitem(value.value, int) elif hasattr(native_type, '__origin__' ) and native_type.__origin__ == Union: # type: ignore # handle typing.Optional[type], Optional is an alias for Union[x, None] # only support specifying 1 type if len(native_type.__args__) != 2: raise ValueError( f"Don't know how to convert native type {native_type} to stackitem" ) for i in native_type.__args__: if i is None: continue return self._native_to_stackitem(value, native_type) else: raise ValueError # shouldn't be possible, but silences mypy else: return vm.StackItem.from_interface(value)
def burn(self, engine: contracts.ApplicationEngine, account: types.UInt160, amount: vm.BigInteger) -> None: """ Burn an amount of tokens from account. Reduces the total supply of the token. Raises: ValueError: if amount is negative ValueError: if the burn amount is larger than the available balance in the account """ if amount.sign < 0: raise ValueError("Can't burn a negative amount") if amount == vm.BigInteger.zero(): return storage_key = self.key_account + account storage_item = engine.snapshot.storages.get(storage_key, read_only=False) state = storage_item.get(self._state) if state.balance < amount: raise ValueError( f"Insufficient balance. Requesting to burn {amount}, available {state.balance}" ) self.on_balance_changing(engine, account, state, -amount) if state.balance == amount: engine.snapshot.storages.delete(storage_key) else: state.balance -= amount engine.snapshot.storages.update(storage_key, storage_item) storage_item = engine.snapshot.storages.get(self.key_total_supply, read_only=False) old_value = vm.BigInteger(storage_item.value) new_value = old_value - amount if new_value == vm.BigInteger.zero(): engine.snapshot.storages.delete(self.key_total_supply) else: storage_item.value = new_value.to_array() self._post_transfer(engine, account, types.UInt160.zero(), amount, vm.NullStackItem(), False)
def test_ripemd160_null(self): """ var tx = new Neo.Network.P2P.Payloads.Transaction { Version = 0, Nonce = 0, SystemFee = 0, NetworkFee = 0, ValidUntilBlock = 99999, Attributes = new TransactionAttribute[0], Script = new byte[0], Signers = new Signer[] { new Signer { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly}} }; using var script = new ScriptBuilder(); script.EmitSysCall(ApplicationEngine.Neo_Crypto_RIPEMD160); // Syscall var engine = ApplicationEngine.Create(TriggerType.Application, tx, null, 100_000_000, false); engine.LoadScript(script.ToArray()); engine.Push(StackItem.Null); Assert.AreEqual(engine.Execute(), VMState.HALT); Assert.AreEqual(1, engine.ResultStack.Count); var item = engine.ResultStack.Pop<ByteString>(); Console.WriteLine($"{item.GetSpan().ToHexString()}"); """ # we have to set the network magic number, because that is serialized as part of the "get_hash_data()" call settings.network.magic = 0x4F454E sb = vm.ScriptBuilder() sb.emit_syscall(syscall_name_to_int("Neo.Crypto.RIPEMD160")) engine = test_engine(has_container=True) engine.script_container.signers = [ payloads.Signer(types.UInt160.zero()) ] script = vm.Script(sb.to_array()) engine.load_script(script) engine.push(vm.NullStackItem()) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) # captured from C# expected = '0892b2402eb78d878a4c60fc799d879b672a5aa5' self.assertEqual(expected, str(engine.result_stack.pop()))
def context_unloaded(self, context: vm.ExecutionContext): # Do not use super() version, see # https://pybind11.readthedocs.io/en/master/advanced/classes.html#overriding-virtual-functions-in-python vm.ExecutionEngine.context_unloaded(self, context) if self.uncaught_exception is not None: return if len(self._invocation_states) == 0: return try: state = self._invocation_states.pop(self.current_context) except KeyError: return if state.check_return_value: eval_stack_len = len(context.evaluation_stack) if eval_stack_len == 0: self.push(vm.NullStackItem()) elif eval_stack_len > 1: raise SystemError("Invalid evaluation stack state") if state.callback is None: return
def test_notify_state_helper_basics(self): bssi = vm.ByteStringStackItem(b'\x01\x02') # 2 null = vm.NullStackItem() # 0 primitive = vm.IntegerStackItem(2) # 1 engine = test_engine() array1 = vm.ArrayStackItem(engine.reference_counter) array2 = vm.ArrayStackItem(engine.reference_counter) array2.append(primitive) # we expect a size of 3, given that our self reference should be ignored. # 5 would mean a failure of detecting a circular reference for ArrayStackItem types array1.append([bssi, null, array2, array1]) self.assertEqual(3, _validate_state_item_limits(engine, array1)) with self.assertRaises(ValueError) as context: _validate_state_item_limits(engine, vm.InteropStackItem(object())) self.assertEqual( "An item in the notification state exceeds the allowed notification size limit", str(context.exception))
def test_contract_call_exceptions(self): engine = test_engine(has_snapshot=True, default_script=False) engine.load_script(vm.Script(hello_world_nef.script)) # can't find contract with self.assertRaises(ValueError) as context: engine._contract_call_internal( types.UInt160.zero(), "valid_method", contracts.CallFlags.ALL, False, vm.ArrayStackItem(engine.reference_counter)) self.assertEqual("[System.Contract.Call] Can't find target contract", str(context.exception)) fake_contract_hash = types.UInt160(b'\x01' * 20) target_contract = contracts.ContractState(0, contract3_nef, contract3_manifest, 0, fake_contract_hash) engine.snapshot.contracts.put(target_contract) # modify the manifest of the current executing contract to only allow to call 1 specific method on other contracts new_current_manifest = deepcopy(hello_world_manifest) new_current_manifest.permissions = [ contracts.ContractPermission( contracts.ContractPermissionDescriptor( ), # allow to call any contract contracts.WildcardContainer( ['method_aaaa']) # allowing to call the listed method only ) ] fake_contract_hash2 = types.UInt160(b'\x02' * 20) new_current_contract = contracts.ContractState(1, hello_world_nef, new_current_manifest, 0, fake_contract_hash2) engine.snapshot.contracts.put(new_current_contract) with self.assertRaises(ValueError) as context: engine._contract_call_internal( target_contract.hash, "invalid_method", contracts.CallFlags.ALL, False, vm.ArrayStackItem(engine.reference_counter)) self.assertEqual( "[System.Contract.Call] Method 'invalid_method' with 0 arguments does not exist on target contract", str(context.exception)) # restore current contract to its original form and try to call a non-existing contract current_contract = contracts.ContractState(1, hello_world_nef, hello_world_manifest, 1, fake_contract_hash2) engine.snapshot.contracts.delete(new_current_contract.hash) engine.snapshot.contracts.put(current_contract) with self.assertRaises(ValueError) as context: engine._contract_call_internal( target_contract.hash, "invalid_method", contracts.CallFlags.ALL, False, vm.ArrayStackItem(engine.reference_counter)) self.assertEqual( "[System.Contract.Call] Method 'invalid_method' with 0 arguments does not exist on target contract", str(context.exception)) # call the target method with invalid number of arguments array = vm.ArrayStackItem(engine.reference_counter) array.append([vm.NullStackItem(), vm.NullStackItem()]) with self.assertRaises(ValueError) as context: engine._contract_call_internal(target_contract.hash, "test_func", contracts.CallFlags.ALL, False, array) self.assertEqual( "[System.Contract.Call] Method 'test_func' with 2 arguments does not exist on target contract", str(context.exception))
def test_contract_call_exceptions(self): engine = test_engine(has_snapshot=True, default_script=False) engine.load_script(vm.Script(hello_world_nef.script)) with self.assertRaises(ValueError) as context: contract_call_internal(engine, types.UInt160.zero(), "_invalid_method", vm.ArrayStackItem(engine.reference_counter), contracts.native.CallFlags) self.assertEqual( "[System.Contract.Call] Method not allowed to start with _", str(context.exception)) # can't find contract with self.assertRaises(ValueError) as context: contract_call_internal(engine, types.UInt160.zero(), "valid_method", vm.ArrayStackItem(engine.reference_counter), contracts.native.CallFlags) self.assertEqual("[System.Contract.Call] Can't find target contract", str(context.exception)) target_contract = storage.ContractState(contract3_nef.script, contract3_manifest) engine.snapshot.contracts.put(target_contract) # modify the manifest of the current executing contract to only allow to call 1 specific method on other contracts new_current_manifest = deepcopy(hello_world_manifest) new_current_manifest.permissions = [ contracts.ContractPermission( contracts.ContractPermissionDescriptor( ), # allow to call any contract contracts.WildcardContainer( ['method_aaaa']) # allowing to call the listed method only ) ] new_current_contract = storage.ContractState(hello_world_nef.script, new_current_manifest) engine.snapshot.contracts.put(new_current_contract) with self.assertRaises(ValueError) as context: contract_call_internal(engine, target_contract.script_hash(), "invalid_method", vm.ArrayStackItem(engine.reference_counter), contracts.native.CallFlags) self.assertEqual( "[System.Contract.Call] Not allowed to call target method 'invalid_method' according to manifest", str(context.exception)) # restore current contract to its original form and try to call a non-existing contract current_contract = storage.ContractState(hello_world_nef.script, hello_world_manifest) engine.snapshot.contracts.delete(new_current_contract.script_hash()) engine.snapshot.contracts.put(current_contract) with self.assertRaises(ValueError) as context: contract_call_internal(engine, target_contract.script_hash(), "invalid_method", vm.ArrayStackItem(engine.reference_counter), contracts.native.CallFlags) self.assertEqual( "[System.Contract.Call] requested target method 'invalid_method' does not exist on target contract", str(context.exception)) # call the target method with invalid number of arguments array = vm.ArrayStackItem(engine.reference_counter) array.append([vm.NullStackItem(), vm.NullStackItem()]) with self.assertRaises(ValueError) as context: contract_call_internal(engine, target_contract.script_hash(), "test_func", array, contracts.native.CallFlags) self.assertEqual( "[System.Contract.Call] Invalid number of contract arguments. Expected 0 actual 2", str(context.exception))
def contract_create(self, engine: contracts.ApplicationEngine, nef_file: bytes, manifest: bytes) -> contracts.ContractState: return self.contract_create_with_data(engine, nef_file, manifest, vm.NullStackItem())
def contract_update(self, engine: contracts.ApplicationEngine, nef_file: bytes, manifest: bytes) -> None: self.contract_update_with_data(engine, nef_file, manifest, vm.NullStackItem())
def deserialize(data: bytes, max_size: int, max_item_size: int, reference_counter: vm.ReferenceCounter) -> vm.StackItem: """ Deserialize data into a stack item. Args: data: byte array of a serialized stack item. max_size: data reading limit for Array, Struct and Map types. max_item_size: data reading limit for ByteString or Buffer types. reference_counter: a valid reference counter instance. Get's passed into reference stack items. """ if len(data) == 0: raise ValueError("Nothing to deserialize") deserialized: List[Union[vm.StackItem, PlaceHolder]] = [] to_deserialize = 1 with serialization.BinaryReader(data) as reader: while not to_deserialize == 0: to_deserialize -= 1 item_type = vm.StackItemType(reader.read_byte()[0]) if item_type == vm.StackItemType.ANY: deserialized.append(vm.NullStackItem()) elif item_type == vm.StackItemType.BOOLEAN: deserialized.append(vm.BooleanStackItem( reader.read_bool())) elif item_type == vm.StackItemType.INTEGER: deserialized.append( vm.IntegerStackItem( vm.BigInteger( reader.read_var_bytes( vm.IntegerStackItem.MAX_SIZE)))) elif item_type == vm.StackItemType.BYTESTRING: deserialized.append( vm.ByteStringStackItem( reader.read_var_bytes(max_item_size))) elif item_type == vm.StackItemType.BUFFER: deserialized.append( vm.BufferStackItem( reader.read_var_bytes(max_item_size))) elif item_type in [ vm.StackItemType.ARRAY, vm.StackItemType.STRUCT ]: count = reader.read_var_int(max_size) deserialized.append(PlaceHolder(item_type, count)) to_deserialize += count elif item_type == vm.StackItemType.MAP: count = reader.read_var_int(max_size) deserialized.append(PlaceHolder(item_type, count)) to_deserialize += count * 2 else: raise ValueError("Invalid format") temp: List[vm.StackItem] = [] while len(deserialized) > 0: item = deserialized.pop() if type(item) == PlaceHolder: item = cast(PlaceHolder, item) if item.type == vm.StackItemType.ARRAY: array = vm.ArrayStackItem(reference_counter) for _ in range(0, item.count): array.append(temp.pop()) temp.append(array) elif item.type == vm.StackItemType.STRUCT: struct = vm.StructStackItem(reference_counter) for _ in range(0, item.count): struct.append(temp.pop()) temp.append(struct) elif item.type == vm.StackItemType.MAP: m = vm.MapStackItem(reference_counter) for _ in range(0, item.count): k = temp.pop() k = cast(vm.PrimitiveType, k) v = temp.pop() m[k] = v temp.append(m) else: item = cast(vm.StackItem, item) temp.append(item) return temp.pop()
def test_serialize_with_exceeding_max_length(self): with self.assertRaises(ValueError) as context: n = vm.NullStackItem() contracts.BinarySerializer.serialize(n, 0) self.assertEqual("Output length exceeds max size", str(context.exception))