def test_with_array(self): """ var a = new Neo.VM.Types.Array(); var i = new Integer(new BigInteger(1)); var i2 = new Integer(new BigInteger(2)); a.Add(i); a.Add(i2); """ # Console.WriteLine($"b'\\x{BitConverter.ToString(BinarySerializer.Serialize(a, 999)).Replace("-", @"\x")}'"); # moved outside of multiline comment because pycharm is broken: https://youtrack.jetbrains.com/issue/PY-43117 i = vm.IntegerStackItem(vm.BigInteger(1)) i2 = vm.IntegerStackItem(vm.BigInteger(2)) a = vm.ArrayStackItem(self.reference_counter) a.append(i) a.append(i2) expected = b'\x40\x02\x21\x01\x01\x21\x01\x02' out = contracts.BinarySerializer.serialize(a, 999) self.assertEqual(expected, out) # now we add a reference to ourselves. with self.assertRaises(ValueError) as context: a.append(a) contracts.BinarySerializer.serialize(a, 999) self.assertEqual("Item already exists", str(context.exception)) # now test deserialization # first remove the reference to self a.remove(len(a) - 1) new_a = contracts.BinarySerializer.deserialize(out, 2048, self.reference_counter) self.assertIsInstance(a, vm.ArrayStackItem) self.assertEqual(a._items, new_a._items)
def test_contract_call_ex(self): # code is the same as "test_contract_call" except for the interop engine = test_engine(has_snapshot=True, default_script=False) # current executing contract contract = storage.ContractState(hello_world_nef.script, hello_world_manifest) engine.snapshot.contracts.put(contract) # target contract target_contract = storage.ContractState(contract3_nef.script, contract3_manifest) engine.snapshot.contracts.put(target_contract) engine.load_script(vm.Script(contract.script)) engine.push(vm.IntegerStackItem(15)) # call flags array = vm.ArrayStackItem(engine.reference_counter) array.append(vm.IntegerStackItem(3)) engine.push(array) # args engine.push(vm.ByteStringStackItem("test_func2")) # method engine.push( vm.ByteStringStackItem(target_contract.script_hash().to_array())) engine.invoke_syscall_by_name("System.Contract.CallEx") engine.execute() self.assertEqual(2, len(engine.result_stack)) main_contract_return_value = engine.result_stack.pop() syscall_called_contract_return_value = engine.result_stack.pop() self.assertEqual("hello world", main_contract_return_value.to_array().decode()) self.assertEqual(4, int(syscall_called_contract_return_value))
def test_contract_call(self): engine = test_engine(has_snapshot=True, default_script=False) # current executing contract fake_hash = types.UInt160.deserialize_from_bytes(b'\x01' * 20) contract = contracts.ContractState(0, hello_world_nef, hello_world_manifest, 0, fake_hash) engine.snapshot.contracts.put(contract) # target contract fake_hash2 = types.UInt160.deserialize_from_bytes(b'\x02' * 20) target_contract = contracts.ContractState(1, contract3_nef, contract3_manifest, 0, fake_hash2) engine.snapshot.contracts.put(target_contract) engine.load_script(vm.Script(contract.script)) array = vm.ArrayStackItem(engine.reference_counter) array.append(vm.IntegerStackItem(3)) engine.push(array) # args engine.push(vm.IntegerStackItem(15)) # callflags engine.push(vm.ByteStringStackItem("test_func2")) # method engine.push(vm.ByteStringStackItem(target_contract.hash.to_array())) engine.invoke_syscall_by_name("System.Contract.Call") engine.execute() self.assertEqual(2, len(engine.result_stack)) main_contract_return_value = engine.result_stack.pop() syscall_called_contract_return_value = engine.result_stack.pop() self.assertEqual("hello world", main_contract_return_value.to_array().decode()) self.assertEqual(4, int(syscall_called_contract_return_value))
def test_iterator_create_from_map(self): engine = test_engine() map_item = vm.MapStackItem(engine.reference_counter) key1 = vm.IntegerStackItem(1) key2 = vm.IntegerStackItem(3) item1 = vm.IntegerStackItem(2) item2 = vm.IntegerStackItem(4) map_item[key1] = item1 map_item[key2] = item2 engine.push(map_item) r = engine.invoke_syscall_by_name("System.Iterator.Create") self.assertIsInstance(r, MapWrapper) self.assertTrue(r.next()) value = r.value() self.assertIsInstance(value, vm.StructStackItem) self.assertEqual(2, len(value)) self.assertEqual(key1, value[0]) self.assertEqual(item1, value[1]) self.assertTrue(r.next()) value = r.value() self.assertIsInstance(value, vm.StructStackItem) self.assertEqual(2, len(value)) self.assertEqual(key2, value[0]) self.assertEqual(item2, value[1]) # exhausted the iterator self.assertFalse(r.next()) with self.assertRaises(ValueError) as context: r.value() self.assertEqual( "Cannot call 'value' without having advanced the iterator at least once", str(context.exception))
def designate_as_role(self, engine: contracts.ApplicationEngine, role: DesignateRole, nodes: List[cryptography.ECPoint]) -> None: if len(nodes) == 0: raise ValueError( "[DesignateContract] Cannot designate empty nodes list") if len(nodes) > 32: raise ValueError( "[DesignateContract] Cannot designate a nodes list larger than 32" ) if not self._check_committee(engine): raise ValueError("[DesignateContract] check committee failed") if engine.snapshot.persisting_block is None: raise ValueError nodes.sort() index = engine.snapshot.persisting_block.index + 1 storage_key = self.create_key( role.to_bytes(1, 'little') + self._to_uint32(index)) with serialization.BinaryWriter() as writer: writer.write_serializable_list(nodes) storage_item = storage.StorageItem(writer.to_array()) engine.snapshot.storages.update(storage_key, storage_item) state = vm.ArrayStackItem(engine.reference_counter) state.append(vm.IntegerStackItem(role.value)) state.append( vm.IntegerStackItem(engine.snapshot.persisting_block.index)) msgrouter.interop_notify(self.hash, "Designation", state)
def test_gasleft(self): engine = test_engine() engine.is_test_mode = True sb = vm.ScriptBuilder() sb.emit_syscall(syscall_name_to_int("System.Runtime.GasLeft")) data = sb.to_array() # test with test mode engine.load_script(vm.Script(data)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack._items)) item = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(-1), item) # test with actual consumption engine = test_engine() engine.is_test_mode = False engine.gas_amount = 500 # we can re-use the script engine.load_script(vm.Script(data)) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack._items)) item = engine.result_stack.pop() # the syscall itself costs 400 self.assertEqual(vm.IntegerStackItem(100), item)
def finish(self, engine: contracts.ApplicationEngine) -> None: tx = engine.script_container tx = cast(payloads.Transaction, tx) response = tx.try_get_attribute(payloads.OracleResponse) if response is None: raise ValueError("Oracle response not found") request = self.get_request(engine.snapshot, response.id) if request is None: raise ValueError("Oracle request not found") state = vm.ArrayStackItem( engine.reference_counter, [vm.IntegerStackItem(response.id), vm.ByteStringStackItem(request.original_tx_id.to_array()) ] ) msgrouter.interop_notify(self.hash, "OracleResponse", state) user_data = contracts.BinarySerializer.deserialize(request.user_data, engine.MAX_STACK_SIZE, engine.reference_counter) args: List[vm.StackItem] = [vm.ByteStringStackItem(request.url.encode()), user_data, vm.IntegerStackItem(int(response.code)), vm.ByteStringStackItem(response.result)] engine.call_from_native(self.hash, request.callback_contract, request.callback_method, args)
def test_atoi(self): engine = test_engine(has_snapshot=True) original_item = b'100' base = 10 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "atoi", [original_item, base]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) item = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(100), item) engine = test_engine(has_snapshot=True) original_item = b'64' base = 16 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "atoi", [original_item, base]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) item = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(100), item) engine = test_engine(has_snapshot=True) invalid_base = 2 sb = vm.ScriptBuilder() sb.emit_dynamic_call_with_args(contracts.StdLibContract().hash, "atoi", [original_item, invalid_base]) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.FAULT, engine.state) self.assertIn("Invalid base specified", engine.exception_message)
def test_with_map(self): """ var m = new Map(new ReferenceCounter()); var i = new Integer(new BigInteger(1)); var i2 = new Integer(new BigInteger(2)); var b = new Neo.VM.Types.Boolean(true); m[i] = b; m[i2] = b; """ # moved outside of multiline comment because pycharm is broken: https://youtrack.jetbrains.com/issue/PY-43117 #Console.WriteLine($"b'\\x{BitConverter.ToString(BinarySerializer.Serialize(m, 999)).Replace("-", @"\x")}'"); m = vm.MapStackItem(self.reference_counter) i = vm.IntegerStackItem(vm.BigInteger(1)) i2 = vm.IntegerStackItem(vm.BigInteger(2)) b = vm.BooleanStackItem(True) m[i] = b m[i2] = b expected = b'\x48\x02\x21\x01\x01\x20\x01\x21\x01\x02\x20\x01' out = contracts.BinarySerializer.serialize(m, 999) self.assertEqual(expected, out) # now we add a reference to ourselves. with self.assertRaises(ValueError) as context: m[i] = m contracts.BinarySerializer.serialize(m, 999) self.assertEqual("Item already exists", str(context.exception)) # now test deserialization m[i] = b # restore m[i] to original content new_m = contracts.BinarySerializer.deserialize(out, 2048, self.reference_counter) self.assertEqual(len(m), len(new_m)) self.assertEqual(m.keys(), new_m.keys()) self.assertEqual(m.values(), new_m.values())
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 test_iterator_concat(self): engine = test_engine() array1 = vm.ArrayStackItem(engine.reference_counter) item1 = vm.IntegerStackItem(123) array1.append(item1) array2 = vm.ArrayStackItem(engine.reference_counter) item2 = vm.IntegerStackItem(456) array2.append(item2) script = vm.ScriptBuilder() # initialize 1 slot to store the iterator in script.emit(vm.OpCode.INITSLOT) script.emit_raw(b'\x01\x00') # stack state at this point is # * array2 # * array1 script.emit_syscall(syscall_name_to_int("System.Iterator.Create")) # Iterator.create removed array2 and places an iterator on the stack, we store this in a variables slot script.emit(vm.OpCode.STLOC0) # so we can call iterator.create again, with array1 as argument script.emit_syscall(syscall_name_to_int("System.Iterator.Create")) # we restore the iterator of array2 script.emit(vm.OpCode.LDLOC0) # we concat and get [array2, array1] script.emit_syscall(syscall_name_to_int("System.Iterator.Concat")) script.emit(vm.OpCode.STLOC0) # have just 1 value per iterator, so we call next and value just 2 times for _ in range(2): script.emit(vm.OpCode.LDLOC0) script.emit_syscall(syscall_name_to_int("System.Enumerator.Next")) script.emit(vm.OpCode.DROP) script.emit(vm.OpCode.LDLOC0) script.emit_syscall(syscall_name_to_int("System.Enumerator.Value")) # we add a call to key for coverage script.emit(vm.OpCode.LDLOC0) script.emit_syscall(syscall_name_to_int("System.Iterator.Key")) engine.load_script(vm.Script(script.to_array())) engine.push(array1) engine.push(array2) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) # we expect 3 values on there, 1 key/array index and 2 array values self.assertEqual(len(engine.result_stack), 3) key_from_engine = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(0), key_from_engine) item1_from_engine = engine.result_stack.pop() self.assertEqual(item1, item1_from_engine) # item2 was put on last, comes of first item2_from_engine = engine.result_stack.pop() self.assertEqual(item2, item2_from_engine)
def test_serialization_map_with_integer_key(self): i = vm.IntegerStackItem(123) v = vm.IntegerStackItem(321) ref_ctr = vm.ReferenceCounter() m = vm.MapStackItem(ref_ctr) m[i] = v expected = r'{"123":321}' s = contracts.JSONSerializer.serialize(m, 999) self.assertEqual(expected, s)
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: struct = cast( vm.StructStackItem, super(ContractMethodDescriptor, self).to_stack_item(reference_counter)) struct.append(vm.IntegerStackItem(self.return_type.value)) struct.append(vm.IntegerStackItem(self.offset)) struct.append(vm.BooleanStackItem(self.safe)) return struct
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: array = vm.ArrayStackItem(reference_counter) id_ = vm.IntegerStackItem(self.id) nef = vm.ByteStringStackItem(self.nef.to_array()) update_counter = vm.IntegerStackItem(self.update_counter) hash_ = vm.ByteStringStackItem(self.hash.to_array()) array.append([ id_, update_counter, hash_, nef, self.manifest.to_stack_item(reference_counter) ]) return array
def test_base64(self): engine = test_engine() original_item = vm.IntegerStackItem(100) engine.push(original_item) engine.invoke_syscall_by_name("System.Binary.Base64Encode") item = engine.pop() self.assertEqual('ZA==', item.to_array().decode()) engine.push(item) engine.invoke_syscall_by_name("System.Binary.Base64Decode") item = engine.pop() self.assertEqual(original_item, vm.IntegerStackItem(item.to_array()))
def test_iterator_create_from_primitive_type(self): engine = test_engine() buffer = vm.ByteStringStackItem(b'\x03\x04') engine.push(buffer) r = engine.invoke_syscall_by_name("System.Iterator.Create") self.assertIsInstance(r, ByteArrayWrapper) self.assertTrue(r.next()) self.assertEqual(vm.IntegerStackItem(3), r.value()) self.assertTrue(r.next()) self.assertEqual(vm.IntegerStackItem(4), r.value()) self.assertFalse(r.next()) self.assertEqual(vm.IntegerStackItem(4), r.value())
def test_serialization_basics(self): ref = vm.ReferenceCounter() m = vm.MapStackItem(ref) s = contracts.JSONSerializer.serialize(m, 999) self.assertEqual("{}", s) a = vm.ArrayStackItem(ref) s = contracts.JSONSerializer.serialize(a, 999) self.assertEqual(r'[]', s) i1 = vm.IntegerStackItem(1) i2 = vm.IntegerStackItem(9007199254740992) a.append([i1, i2]) s = contracts.JSONSerializer.serialize(a, 999) self.assertEqual(r'[1,"9007199254740992"]', s)
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 key(self) -> vm.PrimitiveType: if self.index < 0: raise ValueError( "Cannot call 'key' without having advanced the iterator at least once" ) return vm.IntegerStackItem(self.index)
def test_gettrigger(self): engine = test_engine() engine.invoke_syscall_by_name("System.Runtime.GetTrigger") item = engine.pop() self.assertIsInstance(item, vm.IntegerStackItem) self.assertEqual( vm.IntegerStackItem(contracts.TriggerType.APPLICATION.value), item)
def test_storage_find(self): # settings.storage.default_provider = 'leveldb' engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key1 = storage.StorageKey(self.contract.id, b'\x01') storage_item1 = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key1, storage_item1) storage_key2 = storage.StorageKey(self.contract.id, b'\x02') storage_item2 = storage.StorageItem(b'\x22') engine.snapshot.storages.put(storage_key2, storage_item2) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") engine.push(vm.IntegerStackItem(contracts.FindOptions.NONE)) engine.push(vm.ByteStringStackItem(storage_key1.key)) engine.push(vm.StackItem.from_interface(ctx)) it = engine.invoke_syscall_by_name("System.Storage.Find") self.assertIsInstance(it, interop.StorageIterator) with self.assertRaises(ValueError) as context: it.value() self.assertEqual( "Cannot call 'value' without having advanced the iterator at least once", str(context.exception)) self.assertTrue(it.next()) struct = it.value() # 0 key, 1 value self.assertEqual(storage_item1.value, struct[1].to_array())
def get_candidates(self, engine: contracts.ApplicationEngine) -> None: array = vm.ArrayStackItem(engine.reference_counter) for k, v in self._get_candidates(engine.snapshot): struct = vm.StructStackItem(engine.reference_counter) struct.append(vm.ByteStringStackItem(k.to_array())) struct.append(vm.IntegerStackItem(v)) array.append(struct) engine.push(array)
def test_policy_get_max_block_system_fee(self): engine = test_native_contract(contracts.PolicyContract().script_hash, "getMaxBlockSystemFee") engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(900000000000), item)
def test_gettime(self): engine = test_engine(has_container=False, has_snapshot=True) b = test_block() engine.snapshot.persisting_block = b engine.invoke_syscall_by_name("System.Runtime.GetTime") item = engine.pop() self.assertIsInstance(item, vm.IntegerStackItem) self.assertEqual(vm.IntegerStackItem(b.timestamp), item)
def test_enumerator_create_from_primitive(self): engine = test_engine() item1 = vm.IntegerStackItem(123) engine.push(item1) r = engine.invoke_syscall_by_name("System.Enumerator.Create") self.assertIsInstance(r, ByteArrayWrapper) self.assertTrue(r.next()) self.assertEqual(item1, r.value())
def test_notify_state_helper_struct(self): bssi = vm.ByteStringStackItem(b'\x01\x02') # 2 primitive = vm.IntegerStackItem(2) # 1 engine = test_engine() struct = vm.StructStackItem(engine.reference_counter) struct.append([bssi, primitive]) self.assertEqual(3, _validate_state_item_limits(engine, struct))
def test_policy_get_max_tx_per_block(self): engine = test_native_contract(contracts.PolicyContract().script_hash, "getMaxTransactionsPerBlock") engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(512), item)
def test_serialization_map(self): ref = vm.ReferenceCounter() key1 = vm.ByteStringStackItem("test1") key2 = vm.ByteStringStackItem("test2") key3 = vm.ByteStringStackItem("test3") v1 = vm.IntegerStackItem(1) v2 = vm.IntegerStackItem(2) v3 = vm.IntegerStackItem(3) m = vm.MapStackItem(ref) m[key1] = v1 m[key3] = v3 m[key2] = v2 s = contracts.JSONSerializer.serialize(m, 999) # this is a known deviation. NEO preserved key order, we don't # but shouldn't matter as it gets deserialized to a map stackitem expected = r'{"test1":1,"test2":2,"test3":3}' self.assertEqual(expected, s)
def test_policy_default_get_fee_per_byte(self): engine = test_native_contract(contracts.PolicyContract().hash, "getFeePerByte") engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(vm.IntegerStackItem(1000), item)
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: """ Convert self to a VM stack item. Args: reference_counter: ExecutionEngine reference counter """ array = vm.ArrayStackItem(reference_counter) tx_hash = vm.ByteStringStackItem(self.hash().to_array()) version = vm.IntegerStackItem(self.version) nonce = vm.IntegerStackItem(self.nonce) sender = vm.ByteStringStackItem(self.sender.to_array()) system_fee = vm.IntegerStackItem(self.system_fee) network_fee = vm.IntegerStackItem(self.network_fee) valid_until = vm.IntegerStackItem(self.valid_until_block) script = vm.ByteStringStackItem(self.script) array.append([tx_hash, version, nonce, sender, system_fee, network_fee, valid_until, script]) return array