def _check_admin(self, engine: contracts.ApplicationEngine, state: NameState) -> bool: if engine.checkwitness(state.owner): return True if state.admin == types.UInt160.zero: return False return engine.checkwitness(state.admin)
def unregister_candidate(self, engine: contracts.ApplicationEngine, public_key: cryptography.ECPoint) -> bool: """ Remove a candidate from the consensus node candidate list. Args: engine: Application engine instance public_key: the candidate's public key Returns: True is succesfully removed. False otherwise. """ script_hash = to_script_hash( contracts.Contract.create_signature_redeemscript(public_key)) if not engine.checkwitness(script_hash): return False storage_key = self.key_candidate + public_key storage_item = engine.snapshot.storages.try_get(storage_key, read_only=False) if storage_item is None: return True else: state = storage_item.get(_CandidateState) state.registered = False if state.votes == 0: engine.snapshot.storages.delete(storage_key) self._candidates_dirty = True return True
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 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 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 refuel(self, engine: contracts.ApplicationEngine, account: types.UInt160, amount: int): if amount < 0: raise ValueError("Cannot refuel with negative amount") if not engine.checkwitness(account): raise ValueError("[refuel] check witness failed") self.burn(engine, account, vm.BigInteger(amount)) engine.refuel(amount)
def vote(self, engine: contracts.ApplicationEngine, account: types.UInt160, vote_to: cryptography.ECPoint) -> bool: """ Vote on a consensus candidate Args: engine: Application engine instance. account: source account to take voting balance from vote_to: candidate public key Returns: True is vote registered succesfully. False otherwise. """ if not engine.checkwitness(account): return False storage_key_account = self.key_account + account storage_item = engine.snapshot.storages.try_get(storage_key_account, read_only=False) if storage_item is None: return False account_state = storage_item.get(self._state) storage_key_candidate = self.key_candidate + vote_to storage_item_candidate = engine.snapshot.storages.try_get( storage_key_candidate, read_only=False) if storage_item_candidate is None: return False candidate_state = storage_item_candidate.get(_CandidateState) if not candidate_state.registered: return False if account_state.vote_to.is_zero(): si_voters_count = engine.snapshot.storages.get( self.key_voters_count, read_only=False) old_value = vm.BigInteger(si_voters_count.value) new_value = old_value + account_state.balance si_voters_count.value = new_value.to_array() self._distribute_gas(engine, account, account_state) if not account_state.vote_to.is_zero(): sk_validator = self.key_candidate + account_state.vote_to si_validator = engine.snapshot.storages.get(sk_validator, read_only=False) validator_state = si_validator.get(_CandidateState) validator_state.votes -= account_state.balance if not validator_state.registered and validator_state.votes == 0: engine.snapshot.storages.delete(sk_validator) account_state.vote_to = vote_to candidate_state.votes += account_state.balance self._candidates_dirty = True return True
def set_admin(self, engine: contracts.ApplicationEngine, name: str, admin: types.UInt160) -> None: if not self.REGEX_NAME.match(name): raise ValueError("Regex failure - name is not valid") names = name.split(".") if len(names) != 2: raise ValueError("Invalid format") if admin != types.UInt160.zero() and not engine.checkwitness(admin): raise ValueError("New admin is not valid - check witness failed") storage_item = engine.snapshot.storages.get(self.key_token + name.encode()) state = storage_item.get(NameState) if not engine.checkwitness(state.owner): raise ValueError state.admin = admin
def do_checkwitness(engine: contracts.ApplicationEngine, data: bytes) -> bool: if len(data) == 20: hash_ = types.UInt160(data) elif len(data) == 33: redeemscript = contracts.Contract.create_signature_redeemscript( cryptography.ECPoint.deserialize_from_bytes(data)) hash_ = to_script_hash(redeemscript) else: raise ValueError("Supplied CheckWitness data is not a valid hash") return engine.checkwitness(hash_)
def do_register(self, engine: contracts.ApplicationEngine, name: str, owner: types.UInt160) -> bool: if not self.is_available(engine.snapshot, name): raise ValueError( f"Registration failure - '{name}' is not available") if not engine.checkwitness(owner): raise ValueError("CheckWitness failed") engine.add_gas(self.get_price(engine.snapshot)) state = NameState( owner, name, (engine.snapshot.persisting_block.timestamp // 1000) + self.ONE_YEAR) self.mint(engine, state) engine.snapshot.storages.put( self.key_expiration + state.expiration.to_bytes(4, 'big') + name.encode(), storage.StorageItem(b'\x00')) return True
def _check_committee(self, engine: contracts.ApplicationEngine) -> bool: addr = contracts.NeoToken().get_committee_address(engine.snapshot) return engine.checkwitness(addr)