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 _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 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_deserialization_array_of_items(self): ref_ctr = vm.ReferenceCounter() array = contracts.JSONSerializer.deserialize( contracts.NEOJson.loads( r'[[true,"test1", 123, null],[false,"test2",321]]'), ref_ctr) self.assertIsInstance(array, vm.ArrayStackItem) self.assertEqual(2, len(array)) sub_array1 = array[0] self.assertIsInstance(sub_array1, vm.ArrayStackItem) self.assertEqual(4, len(sub_array1)) self.assertIsInstance(sub_array1[0], vm.BooleanStackItem) self.assertTrue(sub_array1[0]) self.assertIsInstance(sub_array1[1], vm.ByteStringStackItem) self.assertEqual(vm.ByteStringStackItem("test1"), sub_array1[1]) self.assertIsInstance(sub_array1[2], vm.IntegerStackItem) self.assertEqual(vm.BigInteger(123), sub_array1[2].to_biginteger()) self.assertIsInstance(sub_array1[3], vm.NullStackItem) sub_array2 = array[1] self.assertIsInstance(sub_array2, vm.ArrayStackItem) self.assertEqual(3, len(sub_array2)) self.assertIsInstance(sub_array2[0], vm.BooleanStackItem) self.assertFalse(sub_array2[0]) self.assertIsInstance(sub_array2[1], vm.ByteStringStackItem) self.assertEqual(vm.ByteStringStackItem("test2"), sub_array2[1]) self.assertIsInstance(sub_array2[2], vm.IntegerStackItem) self.assertEqual(vm.BigInteger(321), sub_array2[2].to_biginteger())
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 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_check_multisig_with_ECDSA_Secp256k1(self): # values taken from test_verify_secp256k1() engine = test_engine() message = vm.ByteStringStackItem(b'hello') signature = vm.ByteStringStackItem( binascii.unhexlify( b'5331be791532d157df5b5620620d938bcb622ad02c81cfc184c460efdad18e695480d77440c511e9ad02ea30d773cb54e88f8cbb069644aefa283957085f38b5' )) signatures = vm.ArrayStackItem(engine.reference_counter) signatures.append(signature) public_keys = vm.ArrayStackItem(engine.reference_counter) public_key = vm.ByteStringStackItem( binascii.unhexlify( b'03ea01cb94bdaf0cd1c01b159d474f9604f4af35a3e2196f6bdfdb33b2aa4961fa' )) public_keys.append(public_key) sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("Neo.Crypto.CheckMultisigWithECDsaSecp256k1")) script = vm.Script(sb.to_array()) engine.load_script(script) engine.push(signatures) engine.push(public_keys) engine.push(message) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) self.assertEqual(vm.BooleanStackItem(True), engine.result_stack.pop())
def value(self) -> vm.StackItem: if self._pair is None: raise ValueError( "Cannot call 'value' without having advanced the iterator at least once" ) key = self._pair[0].key value = self._pair[1].value if contracts.FindOptions.REMOVE_PREFIX in self.options: key = key[self.prefix_len:] if contracts.FindOptions.DESERIALIZE_VALUES in self.options: item: vm.StackItem = contracts.BinarySerializer.deserialize( value, 1024, self.reference_counter) else: item = vm.ByteStringStackItem(value) if contracts.FindOptions.PICK_FIELD0 in self.options: item = cast(vm.ArrayStackItem, item) item = item[0] elif contracts.FindOptions.PICK_FIELD1 in self.options: item = cast(vm.ArrayStackItem, item) item = item[1] if contracts.FindOptions.KEYS_ONLY in self.options: return vm.ByteStringStackItem(key) if contracts.FindOptions.VALUES_ONLY in self.options: return vm.ByteStringStackItem(value) return vm.StructStackItem(self.reference_counter, [ vm.ByteStringStackItem(self._pair[0].key), vm.ByteStringStackItem(self._pair[1].value) ])
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_update_exceptions6(self): # asking to update with a new script but with an invalid manifest (new manifest does not support storage, # while the old contract has existing storage) engine = test_engine(has_snapshot=True, default_script=False) contract_old = storage.ContractState(hello_world_nef.script, deepcopy(hello_world_manifest)) contract_old.manifest.features |= contracts.ContractFeatures.HAS_STORAGE engine.snapshot.contracts.put(contract_old) storage_key = storage.StorageKey(contract_old.script_hash(), b'firstkey') storage_item = storage.StorageItem(b'firstitem') engine.snapshot.storages.put(storage_key, storage_item) # we load the stored as script to properly setup "engine.current_scripthash" engine.load_script(vm.Script(contract_old.script)) # next we push the necessary items on the stack before calling the update funcztion # we take the matching manifest and change it to have no storage bad_manifest = deepcopy(bye_world_manifest) bad_manifest.features &= ~contracts.ContractFeatures.HAS_STORAGE engine.push(vm.ByteStringStackItem(str(bad_manifest).encode())) engine.push(vm.ByteStringStackItem(bye_world_nef.script)) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Contract.Update") self.assertEqual( "Error: New contract does not support storage while old contract has existing storage", str(context.exception))
def test_contract_update_ok(self): engine = test_engine(has_snapshot=True, default_script=False) # the real world setup should be # 1) deploy a smart contract with an update function that internally calls "System.Contract.Update" # 2) perform a contract call to the old contract and supply a new script + manifest as arguments # # here we will bypass deploying a contract with an update function and directly call "System.Contract.Update" on # the engine. We start by persisting the contract we want to update contract = storage.ContractState(hello_world_nef.script, hello_world_manifest) engine.snapshot.contracts.put(contract) # we load the old contract as script to properly setup "engine.current_scripthash" engine.load_script(vm.Script(contract.script)) # next we push the necessary items on the stack before calling the update function engine.push(vm.ByteStringStackItem(str(bye_world_manifest).encode())) engine.push(vm.ByteStringStackItem(bye_world_nef.script)) engine.invoke_syscall_by_name("System.Contract.Update") # test that we cannot find the old contract anymore self.assertIsNone( engine.snapshot.contracts.try_get(contract.script_hash())) new_contract = storage.ContractState(bye_world_nef.script, bye_world_manifest) # make sure the new contract is still there (and that we not just cleared the whole storage) self.assertIsNotNone( engine.snapshot.contracts.try_get(new_contract.script_hash()))
def test_get_contract(self): engine = test_engine(has_container=True, has_snapshot=True) bad_contract_hash_bytes = b'\x01' * 20 engine.push(vm.ByteStringStackItem(bad_contract_hash_bytes)) engine.invoke_syscall_by_name("System.Blockchain.GetContract") item = engine.pop() self.assertIsInstance(item, vm.NullStackItem) # now get a valid contract # first put one in storage contract = storage.ContractState(b'\x01\x02', manifest.ContractManifest()) engine.snapshot.contracts.put(contract) engine.push(vm.ByteStringStackItem(contract.script_hash().to_array())) engine.invoke_syscall_by_name("System.Blockchain.GetContract") item = engine.pop() self.assertIsInstance(item, vm.ArrayStackItem) self.assertEqual(len(item), 4) self.assertEqual(contract.script, item[0].to_array()) self.assertEqual( contract.manifest, manifest.ContractManifest.from_json(json.loads( item[1].to_array()))) self.assertEqual(contract.has_storage, item[2].to_boolean()) self.assertEqual(contract.is_payable, item[3].to_boolean())
def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem: array = vm.ArrayStackItem(reference_counter) script = vm.ByteStringStackItem(self.script) manifest = vm.ByteStringStackItem(str(self.manifest)) has_storage = vm.BooleanStackItem(self.has_storage) is_payable = vm.BooleanStackItem(self.is_payable) array.append([script, manifest, has_storage, is_payable]) return array
def test_contract_update_exceptions1(self): # asking to update a contract that is not already deployed engine = test_engine(has_snapshot=True, default_script=True) fake_manifest = b'\x01' * 10 fake_nef = b'\x01' * 10 engine.push(vm.ByteStringStackItem(fake_manifest)) engine.push(vm.ByteStringStackItem(fake_nef)) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Contract.Update") self.assertEqual("Can't find contract to update", str(context.exception))
def test_deserialization_map(self): ref_ctr = vm.ReferenceCounter() item = contracts.JSONSerializer.deserialize( contracts.NEOJson.loads(r'{"test1":123, "test2": 321}'), ref_ctr) self.assertIsInstance(item, vm.MapStackItem) self.assertEqual(2, len(item)) key1 = vm.ByteStringStackItem("test1") self.assertEqual(vm.BigInteger(123), item[key1].to_biginteger()) key2 = vm.ByteStringStackItem("test2") self.assertEqual(vm.BigInteger(321), item[key2].to_biginteger())
def test_contract_create_manifest_mismatch(self): engine = test_engine(has_snapshot=True) manifest_copy = deepcopy(hello_world_manifest) # invalidate the associated contract hash manifest_copy.abi.contract_hash = types.UInt160.zero() engine.push(vm.ByteStringStackItem(str(manifest_copy).encode())) engine.push(vm.ByteStringStackItem(hello_world_nef.script)) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Contract.Create") self.assertEqual("Error: manifest does not match with script", str(context.exception))
def test_contract_call_ex_fail(self): engine = test_engine() array = vm.ArrayStackItem(engine.reference_counter) engine.push(vm.IntegerStackItem(123)) # invalid value for CallFlags engine.push(array) # args engine.push(vm.ByteStringStackItem("test_func2")) # method engine.push(vm.ByteStringStackItem(b'\x00')) # call flags with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Contract.CallEx") self.assertIn("Failed to convert parameter stack item", str(context.exception))
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_contract_create_already_exits(self): engine = test_engine(has_snapshot=True) # store store the contract ourselves contract = storage.ContractState(hello_world_nef.script, hello_world_manifest) engine.snapshot.contracts.put(contract) # now try to create a contract engine.push(vm.ByteStringStackItem(str(hello_world_manifest).encode())) engine.push(vm.ByteStringStackItem(hello_world_nef.script)) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Contract.Create") self.assertEqual("Contract already exists", str(context.exception))
def test_iterator_create_from_array(self): engine = test_engine() array = vm.ArrayStackItem(engine.reference_counter) item1 = vm.ByteStringStackItem(b'\x01') item2 = vm.ByteStringStackItem(b'\x02') array.append(item1) array.append(item2) engine.push(array) r = engine.invoke_syscall_by_name("System.Iterator.Create") self.assertIsInstance(r, ArrayWrapper) self.assertTrue(r.next()) self.assertEqual(item1, r.value()) self.assertTrue(r.next()) self.assertEqual(item2, r.value())
def get_notifications(engine: contracts.ApplicationEngine, for_hash: types.UInt160) -> vm.ArrayStackItem: array = vm.ArrayStackItem(engine.reference_counter) for notification in engine.notifications: if notification[1] == for_hash: notification_stackitem = vm.ArrayStackItem(engine.reference_counter) notification_stackitem.append([ vm.ByteStringStackItem(notification[1].to_array()), # script_hash vm.ByteStringStackItem(notification[2]), # message notification[3].deep_copy() # state ]) array.append(notification_stackitem) if len(array) > engine.MAX_STACK_SIZE: raise ValueError("Notification count exceeds limits") return array
def test_get_block(self): engine = test_engine(has_container=True, has_snapshot=True) # test with height engine.push(vm.ByteStringStackItem(b'\x01')) engine.invoke_syscall_by_name("System.Blockchain.GetBlock") self.assertIsInstance(engine.pop(), vm.NullStackItem) # test with invalid height (-1) engine.push(vm.ByteStringStackItem(b'\xFF')) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Blockchain.GetBlock") self.assertEqual("Invalid height", str(context.exception)) # test with invalid data > 32 bytes engine.push(vm.ByteStringStackItem(b'\xFF' * 33)) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Blockchain.GetBlock") self.assertEqual("Invalid data", str(context.exception)) # test with serialized block hash (UInt256). This fake hash won't return a block engine.push(vm.ByteStringStackItem(b'\x01' * 32)) engine.invoke_syscall_by_name("System.Blockchain.GetBlock") self.assertIsInstance(engine.pop(), vm.NullStackItem) # now find an existing block # first add a block and update the snapshot # normally this would be done while persisting in Blockchain testblock = test_block() engine.snapshot.block_height = testblock.index engine.snapshot.blocks.put(testblock) engine.push(vm.ByteStringStackItem(testblock.hash().to_array())) engine.invoke_syscall_by_name("System.Blockchain.GetBlock") # # validate the right content was pushed onto the stack item = engine.pop() self.assertIsInstance(item, vm.ArrayStackItem) self.assertEqual(len(item), 8) self.assertEqual(item[0].to_array(), testblock.hash().to_array()) self.assertEqual(item[1].to_biginteger(), vm.BigInteger(testblock.version)) self.assertEqual(item[2].to_array(), testblock.prev_hash.to_array()) self.assertEqual(item[3].to_array(), testblock.merkle_root.to_array()) self.assertEqual(item[4].to_biginteger(), vm.BigInteger(testblock.timestamp)) self.assertEqual(item[5].to_biginteger(), vm.BigInteger(testblock.index)) self.assertEqual(item[6].to_array(), testblock.next_consensus.to_array()) self.assertEqual(item[7].to_biginteger(), vm.BigInteger(len(testblock.transactions)))
def test_storage_find(self): engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key1 = storage.StorageKey(self.contract.script_hash(), b'\x01') storage_item1 = storage.StorageItem(b'\x11', is_constant=False) engine.snapshot.storages.put(storage_key1, storage_item1) storage_key2 = storage.StorageKey(self.contract.script_hash(), b'\x02') storage_item2 = storage.StorageItem(b'\x22', is_constant=False) engine.snapshot.storages.put(storage_key2, storage_item2) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") 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) it.next() self.assertEqual(storage_key1.key, it.key().to_array()) self.assertEqual(storage_item1.value, it.value().to_array()) it.next() with self.assertRaises(ValueError) as context: it.key() self.assertEqual( "Cannot call 'key' without having advanced the iterator at least once", str(context.exception)) with self.assertRaises(ValueError) as context: it.value() self.assertEqual( "Cannot call 'value' without having advanced the iterator at least once", str(context.exception))
def test_contract_is_standard_fail(self): # can't find contract engine = test_engine(has_snapshot=True) engine.push(vm.ByteStringStackItem(types.UInt160.zero().to_array())) engine.invoke_syscall_by_name("System.Contract.IsStandard") engine.execute() self.assertEqual(False, engine.result_stack.pop().to_boolean())
def test_getscriptcontainer(self): # first test against an invalid script container (IVerifiable, but not IOperable) engine = test_engine() container = payloads.Header._serializable_init() engine.script_container = container with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Runtime.GetScriptContainer") self.assertEqual("script container is not a valid IInteroperable type", str(context.exception)) tx = test_tx(1) engine = test_engine() engine.script_container = tx sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetScriptContainer")) engine.load_script(vm.Script(sb.to_array())) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack._items)) item = engine.result_stack.pop() self.assertIsInstance(item, vm.ArrayStackItem) # we now have a Block that has been serialized, let's check the hash self.assertEqual(vm.ByteStringStackItem(tx.hash().to_array()), item[0])
def test_checkwitness_invalid_data(self): engine = test_engine() engine.push(vm.ByteStringStackItem(b'')) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Runtime.CheckWitness") self.assertEqual("Supplied CheckWitness data is not a valid hash", str(context.exception))
def test_multisig_verify_helper_bounds(self): engine = None message = vm.ByteStringStackItem(b'') public_keys = [object()] signatures = [] with self.assertRaises(ValueError) as context: _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1) self.assertEqual("No signatures supplied", str(context.exception)) public_keys = [] signatures = [object()] with self.assertRaises(ValueError) as context: _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1) self.assertEqual("No public keys supplied", str(context.exception)) public_keys = [object()] signatures = [object(), object()] with self.assertRaises(ValueError) as context: _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1) self.assertEqual("Verification requires 2 public keys, got only 1", str(context.exception))
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_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)