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 transfer_helper(self, contract: contracts.NativeContract, from_account: types.UInt160, to_account: types.UInt160, amount: vm.BigInteger): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block engine.invoke_syscall_by_name("Neo.Native.Deploy") engine.invocation_stack.pop() # we no longer need the default script engine.script_container = TestIVerifiable() engine.script_container.script_hashes = [from_account] sb = vm.ScriptBuilder() sb.emit_push(amount) sb.emit_push(to_account.to_array()) sb.emit_push(from_account.to_array()) sb.emit_push(3) sb.emit(vm.OpCode.PACK) sb.emit_push(b'transfer') sb.emit_push(contract.script_hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) engine.load_script(vm.Script(sb.to_array())) engine.snapshot.contracts.put( storage.ContractState(sb.to_array(), contracts.ContractManifest())) return engine
def transfer_helper(self, contract: contracts.NativeContract, from_account: types.UInt160, to_account: types.UInt160, amount: vm.BigInteger): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block engine.invocation_stack.pop() # we no longer need the default script engine.script_container = TestIVerifiable() engine.script_container.script_hashes = [from_account] sb = vm.ScriptBuilder() sb.emit(vm.OpCode.PUSHNULL) sb.emit_push(amount) sb.emit_push(to_account.to_array()) sb.emit_push(from_account.to_array()) sb.emit_push(4) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # callflags sb.emit_push(b'transfer') sb.emit_push(contract.hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) engine.load_script(vm.Script(sb.to_array())) nef = contracts.NEF(script=sb.to_array()) manifest = contracts.ContractManifest("test_contract") contract_state = contracts.ContractState( 1, nef, manifest, 0, contract_hash(from_account, nef.checksum, manifest.name)) engine.snapshot.contracts.put(contract_state) return engine
def _internal_contract_get(self, hash: types.UInt160): contract_bytes = self._real_db.get(DBPrefixes.CONTRACTS + hash.to_array()) if contract_bytes is None: raise KeyError return contracts.ContractState.deserialize_from_bytes(contract_bytes)
def _internal_contract_delete(self, hash: types.UInt160, batch=None): if batch: db = batch else: db = self._real_db db.delete(DBPrefixes.CONTRACTS + hash.to_array())
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 contract_hash(sender: types.UInt160, checksum: int, name: str) -> types.UInt160: sb = vm.ScriptBuilder() sb.emit(vm.OpCode.ABORT) sb.emit_push(sender.to_array()) sb.emit_push(checksum) sb.emit_push(name) return to_script_hash(sb.to_array())
def tokens_of(self, snapshot: storage.Snapshot, owner: types.UInt160) -> interop.IIterator: storage_item_account = snapshot.storages.try_get(self.key_account + owner.to_array(), read_only=True) reference_counter = vm.ReferenceCounter() if storage_item_account is None: return interop.ArrayWrapper(vm.ArrayStackItem(reference_counter)) account = storage_item_account.get(NFTAccountState) tokens: List[vm.StackItem] = list(map(lambda t: vm.ByteStringStackItem(t), account.tokens)) return interop.ArrayWrapper(vm.ArrayStackItem(reference_counter, tokens))
def call_from_native(self, calling_scripthash: types.UInt160, hash_: types.UInt160, method: str, args: List[vm.StackItem]) -> None: ctx = self.current_context self._contract_call_internal(hash_, method, contracts.CallFlags.ALL, False, args) self.current_context.calling_scripthash_bytes = calling_scripthash.to_array( ) while self.current_context != ctx: self.step_out()
def script_hash_to_address(script_hash: types.UInt160) -> str: """ Converts the specified script hash to an address. Args: script_hash: script hash to convert. """ version = settings.network.account_version # this is the current Neo's protocol version data = version.to_bytes(1, 'little') + script_hash.to_array() return base58.b58encode_check(data).decode('utf-8')
def is_valid(self, contract_hash: types.UInt160) -> bool: """ Validate if the group has agreed on allowing the specific contract_hash. Args: contract_hash: """ return cryptography.verify_signature( contract_hash.to_array(), self.signature, self.public_key.encode_point(False), cryptography.ECCCurve.SECP256R1)
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 _internal_storage_find(self, contract_script_hash: types.UInt160, key_prefix: bytes): prefix = DBPrefixes.STORAGES + contract_script_hash.to_array() + key_prefix res = {} with self._real_db.iterator(prefix=prefix, include_key=True, include_value=True) as it: for key, value in it: # strip off prefix k = storage.StorageKey.deserialize_from_bytes(key[1:]) v = storage.StorageItem.deserialize_from_bytes(value) res[k] = v # yielding outside of iterator to make sure the LevelDB iterator is closed and not leaking resources for k, v in res.items(): yield k, v
def _unblock_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: return False else: engine.snapshot.storages.delete(storage_key) return True
def is_blocked(self, snapshot: storage.Snapshot, account: types.UInt160) -> bool: """ Check if the account is blocked Transaction from blocked accounts will be rejected by the consensus nodes. """ si = snapshot.storages.try_get(self.key_blocked_account + account.to_array(), read_only=True) if si is None: return False else: return True
def balance_of(self, snapshot: storage.Snapshot, owner: types.UInt160) -> vm.BigInteger: storage_item = snapshot.storages.try_get(self.key_account + owner.to_array(), read_only=True) if storage_item is None: return vm.BigInteger.zero() return NFTAccountState.deserialize_from_bytes(storage_item.value).balance