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 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 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 _initialize(self, engine: contracts.ApplicationEngine) -> None: super(NameService, self)._initialize(engine) engine.snapshot.storages.put( self.key_domain_price, storage.StorageItem(vm.BigInteger(1000000000).to_array())) engine.snapshot.storages.put(self.key_roots, storage.StorageItem(b'\x00'))
def _initialize(self, engine: contracts.ApplicationEngine) -> None: engine.snapshot.storages.put( self.key_request_id, storage.StorageItem(vm.BigInteger.zero().to_array())) engine.snapshot.storages.put( self.key_price, storage.StorageItem(vm.BigInteger(50000000).to_array()))
def test_transfer_partial_balance_to_account_with_balance(self): gas = contracts.GasToken() manifest = contracts.ContractManifest("contract_name") nef = contracts.NEF(script=b'\x40') state_to = contracts.ContractState( 1, nef, manifest, 0, contract_hash(types.UInt160.zero(), nef.checksum, manifest.name)) account_to = state_to.hash storage_key_to = gas.key_account + account_to account_to_state = gas._state() account_to_state.balance = vm.BigInteger(100) storage_item_to = storage.StorageItem(account_to_state.to_array()) account_from = types.UInt160(b'\x01' * 20) storage_key_from = gas.key_account + account_from account_from_state = gas._state() account_from_state.balance = vm.BigInteger(123) storage_item_from = storage.StorageItem(account_from_state.to_array()) amount = vm.BigInteger(50) engine = self.transfer_helper(gas, account_from, account_to, amount) # ensure the source and destination account have balances engine.snapshot.storages.put(storage_key_from, storage_item_from) engine.snapshot.storages.put(storage_key_to, storage_item_to) transfer_event = () def notify_listener(contract_script_hash, event, state): nonlocal transfer_event transfer_event = (contract_script_hash, event, state) msgrouter.interop_notify += notify_listener engine.execute() self.assertEqual(1, len(engine.result_stack)) result = engine.result_stack.pop() self.assertTrue(result) self.assertEqual(gas.hash, transfer_event[0]) self.assertEqual("Transfer", transfer_event[1]) state_items = list(transfer_event[2]) self.assertEqual(account_from, types.UInt160(state_items[0].to_array())) self.assertEqual(account_to, types.UInt160(state_items[1].to_array())) self.assertEqual(amount, state_items[2].to_biginteger()) # validate from account is deducted by `amount` new_storage_account_from = engine.snapshot.storages.get( storage_key_from) new_account_state_from = gas._state.deserialize_from_bytes( new_storage_account_from.value) self.assertEqual(account_from_state.balance - amount, new_account_state_from.balance) # validate to account is credited with `amount` new_storage_account_to = engine.snapshot.storages.get(storage_key_to) new_account_state_to = gas._state.deserialize_from_bytes( new_storage_account_to.value) self.assertEqual(account_to_state.balance + amount, new_account_state_to.balance)
def test_clone_from_replica(self): si_data = b'\x01\x02\x03' si = storage.StorageItem(si_data) clone = si.clone() self.assertEqual(si, clone) self.assertNotEqual(id(si), id(clone)) si2 = storage.StorageItem(bytearray()) si2.from_replica(si) self.assertEqual(si, si2)
def _initialize(self, engine: contracts.ApplicationEngine) -> None: # NEO's native contract initialize. Is called upon contract deploy self._committee_state = _CommitteeState(engine.snapshot, dict.fromkeys(settings.standby_validators, vm.BigInteger(0))) engine.snapshot.storages.put(self.key_voters_count, storage.StorageItem(b'\x00')) gas_bonus_state = GasBonusState(_GasRecord(0, GasToken().factor * 5)) engine.snapshot.storages.put(self.key_gas_per_block, storage.StorageItem(gas_bonus_state.to_array())) engine.snapshot.storages.put(self.key_register_price, storage.StorageItem((GasToken().factor * 1000).to_array())) self.mint(engine, contracts.Contract.get_consensus_address(settings.standby_validators), self.total_amount, False)
def test_storage_put_overwrite(self): # test with new data being shorter than the old data engine = test_engine(has_snapshot=True) key = b'\x01' storage_key = storage.StorageKey(types.UInt160.zero(), key) storage_item = storage.StorageItem(b'\x11\x22\x33', is_constant=False) engine.snapshot.storages.put(storage_key, storage_item) ctx = storage.StorageContext(types.UInt160.zero(), is_read_only=False) new_item_value = b'\x11\x22' contracts.interop._storage_put_internal(engine, ctx, key, new_item_value, storage.StorageFlags.NONE) item = engine.snapshot.storages.get(storage_key) self.assertIsNotNone(item) self.assertEqual(new_item_value, item.value) # now test with data being longer than before longer_item_value = b'\x11\x22\x33\x44' contracts.interop._storage_put_internal(engine, ctx, key, longer_item_value, storage.StorageFlags.NONE) item = engine.snapshot.storages.get(storage_key) self.assertIsNotNone(item) self.assertEqual(longer_item_value, item.value)
def set_record(self, engine: contracts.ApplicationEngine, name: str, record_type: RecordType, data: str) -> None: if not self.REGEX_NAME.match(name): raise ValueError("Regex failure - name is not valid") if record_type == RecordType.A: # we only validate if the data is a valid IPv4 address ipaddress.IPv4Address(data) elif record_type == RecordType.CNAME: if not self.REGEX_NAME.match(data): raise ValueError("Invalid CNAME") elif record_type == RecordType.TXT: if len(data) > 255: raise ValueError("TXT data exceeds maximum length of 255") elif record_type == RecordType.AAAA: # we only validate if the data is a valid IPv6 address ipaddress.IPv6Address(data) domain = '.'.join(name.split('.')[2:]) storage_item = engine.snapshot.storages.get(self.key_token + domain.encode()) state = storage_item.get(NameState) if not self._check_admin(engine, state): raise ValueError("Admin check failed") storage_key_record = self.key_record + domain.encode() + name.encode( ) + record_type.to_bytes(1, 'little') engine.snapshot.storages.update(storage_key_record, storage.StorageItem(data.encode()))
def transfer(self, engine: contracts.ApplicationEngine, account_to: types.UInt160, token_id: bytes) -> bool: if account_to == types.UInt160.zero(): raise ValueError("To account can't be zero") key_token = self.key_token + token_id storage_item = engine.snapshot.storages.try_get(key_token, read_only=True) if storage_item is None: raise ValueError("Token state not found") token_state = NFTState.deserialize_from_bytes(storage_item.value) if token_state.owner != engine.calling_scripthash and engine.checkwitness(token_state.owner): return False if token_state.owner != account_to: token = NFTState.from_stack_item(engine.snapshot.storages.get(key_token, read_only=False)) key_from = self.key_account + token_state.owner.to_array account_state = engine.snapshot.storages.get(key_from).get(NFTAccountState) account_state.remove(token_id) if account_state.balance == 0: engine.snapshot.storages.delete(key_from) token.owner = account_to key_to = self.key_account + account_to.to_array() storage_item = engine.snapshot.storages.try_get(key_to, read_only=False) if storage_item is None: storage_item = storage.StorageItem(NFTAccountState().to_array()) engine.snapshot.storages.put(key_to, storage_item) storage_item.get(NFTAccountState).add(token_id) self.on_transferred(engine, token.owner, token) self._post_transfer(engine, token_state.owner, account_to, token_id) return True
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 storage_put(engine: contracts.ApplicationEngine, context: storage.StorageContext, key: bytes, value: bytes) -> None: if len(key) > MAX_STORAGE_KEY_SIZE: raise ValueError( f"Storage key length exceeds maximum of {MAX_STORAGE_KEY_SIZE}") if len(value) > MAX_STORAGE_VALUE_SIZE: raise ValueError( f"Storage value length exceeds maximum of {MAX_STORAGE_VALUE_SIZE}" ) if context.is_read_only: raise ValueError("Cannot persist to read-only storage context") storage_key = storage.StorageKey(context.id, key) item = engine.snapshot.storages.try_get(storage_key, read_only=False) if item is None: new_data_len = len(key) + len(value) item = storage.StorageItem(b'') engine.snapshot.storages.put(storage_key, item) else: if len(value) == 0: new_data_len = 0 elif len(value) <= len(item.value): new_data_len = (len(value) - 1) // 4 + 1 elif len(item.value) == 0: new_data_len = len(value) else: new_data_len = (len(item.value) - 1) // 4 + 1 + len(value) - len( item.value) engine.add_gas(new_data_len * engine.STORAGE_PRICE) item.value = value
def test_storage_get_key_not_found(self): engine = test_engine(has_snapshot=True) script = vm.ScriptBuilder() # key parameter for the `Get` syscall script.emit(vm.OpCode.PUSH2) script.emit_syscall(syscall_name_to_int("System.Storage.GetContext")) # at this point our stack looks like follows # * storage context # * key script.emit_syscall(syscall_name_to_int("System.Storage.Get")) engine.load_script(vm.Script(script.to_array())) # we set the script parameter of the ContractState to our script # which ensures that `engine.current_scripthash` matches the script we manually build above # this basically means the engine thinks it is running a smart contract that we can find in our storage # which in turns enables us to call the `System.Storage.GetContext` syscall contract = storage.ContractState(script=script.to_array(), _manifest=self.manifest) engine.snapshot.contracts.put(contract) storage_key = storage.StorageKey(contract.script_hash(), b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertIsInstance(item, vm.NullStackItem)
def register_candidate(self, engine: contracts.ApplicationEngine, public_key: cryptography.ECPoint) -> bool: """ Register a candidate for consensus node election. Args: engine: Application engine instance public_key: the candidate's public key Returns: True is succesfully registered. False otherwise. """ script_hash = to_script_hash( contracts.Contract.create_signature_redeemscript(public_key)) if not engine.checkwitness(script_hash): return False engine.add_gas(self.get_register_price(engine.snapshot)) storage_key = self.key_candidate + public_key storage_item = engine.snapshot.storages.try_get(storage_key, read_only=False) if storage_item is None: state = _CandidateState() state.registered = True storage_item = storage.StorageItem(state.to_array()) engine.snapshot.storages.put(storage_key, storage_item) else: state = storage_item.get(_CandidateState) state.registered = True self._candidates_dirty = True return True
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_storage_get_ok2(self): # this is basically the same as `test_storage_get_ok` # but performed by executing a script # it exists to validate that the `Optional[bytes]` return value is converted properly engine = test_engine(has_snapshot=True) script = vm.ScriptBuilder() script.emit(vm.OpCode.PUSH1) script.emit_syscall(syscall_name_to_int("System.Storage.GetContext")) script.emit_syscall(syscall_name_to_int("System.Storage.Get")) engine.load_script(vm.Script(script.to_array())) nef = contracts.NEF(script=script.to_array()) contract_hash = to_script_hash(nef.script) contract = contracts.ContractState(1, nef, self.manifest, 0, contract_hash) engine.snapshot.contracts.put(contract) storage_key = storage.StorageKey(contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertEqual(storage_item.value, item.to_array())
def post_persist(self, engine: contracts.ApplicationEngine): super(NeoToken, self).post_persist(engine) # distribute GAS for committee m = len(settings.standby_committee) n = settings.network.validators_count index = engine.snapshot.persisting_block.index % m gas_per_block = self.get_gas_per_block(engine.snapshot) committee = self.get_committee_from_cache(engine.snapshot) pubkey = committee[index] account = to_script_hash(contracts.Contract.create_signature_redeemscript(pubkey)) GasToken().mint(engine, account, gas_per_block * self._COMMITTEE_REWARD_RATIO / 100, False) if self._should_refresh_committee(engine.snapshot.persisting_block.index): voter_reward_of_each_committee = gas_per_block * self._VOTER_REWARD_RATIO * 100000000 * m / (m + n) / 100 for i, member in enumerate(committee): factor = 2 if i < n else 1 member_votes = self._committee_state[member] if member_votes > 0: voter_sum_reward_per_neo = voter_reward_of_each_committee * factor / member_votes voter_reward_key = (self.key_voter_reward_per_committee + member + self._to_uint32(engine.snapshot.persisting_block.index + 1) ) border = (self.key_voter_reward_per_committee + member).to_array() try: pair = next(engine.snapshot.storages.find_range(voter_reward_key.to_array(), border, "reverse")) result = vm.BigInteger(pair[1].value) except StopIteration: result = vm.BigInteger.zero() voter_sum_reward_per_neo += result engine.snapshot.storages.put(voter_reward_key, storage.StorageItem(voter_sum_reward_per_neo.to_array()))
def _storage_put_internal(engine: contracts.ApplicationEngine, context: storage.StorageContext, key: bytes, value: bytes, flags: storage.StorageFlags) -> None: if len(key) > MAX_STORAGE_KEY_SIZE: raise ValueError( f"Storage key length exceeds maximum of {MAX_STORAGE_KEY_SIZE}") if len(value) > MAX_STORAGE_VALUE_SIZE: raise ValueError( f"Storage value length exceeds maximum of {MAX_STORAGE_VALUE_SIZE}" ) if context.is_read_only: raise ValueError("Cannot persist to read-only storage context") storage_key = storage.StorageKey(context.script_hash, key) item = engine.snapshot.storages.try_get(storage_key, read_only=False) is_constant = storage.StorageFlags.CONSTANT in flags if item is None: new_data_len = len(key) + len(value) item = storage.StorageItem(b'', is_constant) engine.snapshot.storages.put(storage_key, item) else: if item.is_constant: raise ValueError("StorageItem is marked as constant") if len(value) <= len(item.value): new_data_len = 1 else: new_data_len = len(value) - len(item.value) engine.add_gas(new_data_len * STORAGE_PRICE) item.value = value item.is_constant = is_constant
def test_storage_get_key_not_found(self): engine = test_engine(has_snapshot=True, has_container=True) script = vm.ScriptBuilder() # key parameter for the `Storage.Get` syscall script.emit(vm.OpCode.PUSH2) script.emit_syscall(syscall_name_to_int("System.Storage.GetContext")) # at this point our stack looks like follows # * storage context # * key script.emit_syscall(syscall_name_to_int("System.Storage.Get")) engine.load_script(vm.Script(script.to_array())) # we have to store our contract or some sanity checks will fail (like getting a StorageContext nef = contracts.NEF(script=script.to_array()) contract = contracts.ContractState(1, nef, self.manifest, 0, to_script_hash(nef.script)) engine.snapshot.contracts.put(contract) storage_key = storage.StorageKey(contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertIsInstance(item, vm.NullStackItem)
def transfer(self, engine: contracts.ApplicationEngine, account_from: types.UInt160, account_to: types.UInt160, amount: vm.BigInteger, data: vm.StackItem ) -> bool: """ Transfer tokens from one account to another. Raises: ValueError: if the requested amount is negative. Returns: True on success. False otherwise. """ if amount.sign < 0: raise ValueError("Can't transfer a negative amount") # transfer from an account not owned by the smart contract that is requesting the transfer # and there is no signature that approves we are allowed todo so if account_from != engine.calling_scripthash and not engine.checkwitness(account_from): return False storage_key_from = self.key_account + account_from storage_item_from = engine.snapshot.storages.try_get(storage_key_from, read_only=False) if storage_item_from is None: return False state_from = storage_item_from.get(self._state) if amount == vm.BigInteger.zero(): self.on_balance_changing(engine, account_from, state_from, amount) else: if state_from.balance < amount: return False if account_from == account_to: self.on_balance_changing(engine, account_from, state_from, vm.BigInteger.zero()) else: self.on_balance_changing(engine, account_from, state_from, -amount) if state_from.balance == amount: engine.snapshot.storages.delete(storage_key_from) else: state_from.balance -= amount storage_key_to = self.key_account + account_to storage_item_to = engine.snapshot.storages.try_get(storage_key_to, read_only=False) if storage_item_to is None: storage_item_to = storage.StorageItem(self._state().to_array()) engine.snapshot.storages.put(storage_key_to, storage_item_to) state_to = storage_item_to.get(self._state) self.on_balance_changing(engine, account_to, state_to, amount) state_to.balance += amount self._post_transfer(engine, account_from, account_to, amount, data, True) return True
def mint(self, engine: contracts.ApplicationEngine, token: NFTState) -> None: engine.snapshot.storages.put(self.key_token + token.id, storage.StorageItem(token.to_array())) sk_account = self.key_account + token.id si_account = engine.snapshot.storages.try_get(sk_account, read_only=False) if si_account is None: si_account = storage.StorageItem(NFTAccountState().to_array()) engine.snapshot.storages.put(sk_account, si_account) account = si_account.get(NFTAccountState) account.add(token.id) si_total_supply = engine.snapshot.storages.get(self.key_total_suppply, read_only=False) new_value = vm.BigInteger(si_total_supply.value) + 1 si_total_supply.value = new_value.to_array() self._post_transfer(engine, types.UInt160.zero(), token.owner, token.id)
def _set_minimum_deployment_fee(self, engine: contracts.ApplicationEngine, value: int) -> None: if value < 0: raise ValueError("Can't set deployment fee to a negative value") if not self._check_committee(engine): raise ValueError engine.snapshot.storages.update( self.key_min_deploy_fee, storage.StorageItem(vm.BigInteger(value).to_array()))
def test_serialization(self): si_data = b'\x01\x02\x03' si = storage.StorageItem(si_data, False) length_indicator = b'\x03' bool_false = b'\x00' self.assertEqual(length_indicator + si_data + bool_false, si.to_array()) self.assertEqual( si, storage.StorageItem.deserialize_from_bytes(length_indicator + si_data + bool_false))
def test_getting_serializable(self): raw_value = b'\x01\x01' si = storage.StorageItem(raw_value) obj = si.get(TestSerializable) self.assertEqual(str(vm.BigInteger(1)), str(obj.value)) self.assertEqual(raw_value, si.value) new_raw_value = b'\x01\x02' obj.value += 1 obj2 = si.get(TestSerializable) self.assertEqual(id(obj), id(obj2)) self.assertEqual(vm.BigInteger(2), obj2.value) self.assertEqual(new_raw_value, si.value)
def test_storage_get_ok(self): engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key = storage.StorageKey(self.contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") engine.push(vm.ByteStringStackItem(storage_key.key)) engine.push(vm.StackItem.from_interface(ctx)) returned_value = engine.invoke_syscall_by_name("System.Storage.Get") self.assertEqual(storage_item.value, returned_value)
def post_persist(self, engine: contracts.ApplicationEngine) -> None: super(OracleContract, self).post_persist(engine) nodes = [] for tx in engine.snapshot.persisting_block.transactions: response = tx.try_get_attribute(payloads.OracleResponse) if response is None: continue # remove request from storage sk_request = self.key_request + response.id.to_bytes(8, 'little') si_request = engine.snapshot.storages.try_get(sk_request) if si_request is None: continue request = OracleRequest.deserialize_from_bytes(si_request.value) engine.snapshot.storages.delete(sk_request) # remove id from id list sk_id_list = self.key_id_list + self._get_url_hash(request.url) si_id_list = engine.snapshot.storages.try_get(sk_id_list, read_only=False) if si_id_list is None: si_id_list = storage.StorageItem(b'\x00') id_list = si_id_list.get(_IdList) id_list.remove(response.id) if len(id_list) == 0: engine.snapshot.storages.delete(sk_id_list) # mint gas for oracle nodes nodes_public_keys = contracts.DesignationContract( ).get_designated_by_role(engine.snapshot, contracts.DesignateRole.ORACLE, engine.snapshot.persisting_block.index) for public_key in nodes_public_keys: nodes.append([ to_script_hash( contracts.Contract.create_signature_redeemscript( public_key)), vm.BigInteger.zero() ]) if len(nodes) > 0: idx = response.id % len(nodes) # mypy can't figure out that the second item is a BigInteger nodes[idx][1] += self.get_price( engine.snapshot) # type: ignore for pair in nodes: if pair[1].sign > 0: # type: ignore self._gas.mint(engine, pair[0], pair[1], False)
def test_delete_ok(self): engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key = storage.StorageKey(self.contract.id, b'\x01') storage_item = storage.StorageItem(b'\x11') engine.snapshot.storages.put(storage_key, storage_item) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") engine.push(vm.ByteStringStackItem(storage_key.key)) engine.push(vm.StackItem.from_interface(ctx)) engine.invoke_syscall_by_name("System.Storage.Delete") self.assertIsNone(engine.snapshot.storages.try_get(storage_key))
def _block_account(self, engine: contracts.ApplicationEngine, account: types.UInt160) -> bool: """ Should only be called through syscalls """ if not self._check_committee(engine): return False storage_key = self.key_blocked_account + account.to_array() storage_item = engine.snapshot.storages.try_get(storage_key, read_only=False) if storage_item is None: storage_item = storage.StorageItem(b'\x00') engine.snapshot.storages.update(storage_key, storage_item) else: return False return True
def test_storage_delete_constant_item(self): engine = test_engine(has_snapshot=True) engine.snapshot.contracts.put(self.contract) storage_key = storage.StorageKey(self.contract.script_hash(), b'\x01') storage_item = storage.StorageItem(b'\x11', is_constant=True) engine.snapshot.storages.put(storage_key, storage_item) ctx = engine.invoke_syscall_by_name("System.Storage.GetContext") engine.push(vm.ByteStringStackItem(storage_key.key)) engine.push(vm.StackItem.from_interface(ctx)) with self.assertRaises(ValueError) as context: engine.invoke_syscall_by_name("System.Storage.Delete") self.assertEqual( "Cannot delete a storage item that is marked constant", str(context.exception))