예제 #1
0
    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)
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
 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)
예제 #7
0
    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
예제 #8
0
    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
예제 #9
0
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_)
예제 #10
0
    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
예제 #11
0
 def _check_committee(self, engine: contracts.ApplicationEngine) -> bool:
     addr = contracts.NeoToken().get_committee_address(engine.snapshot)
     return engine.checkwitness(addr)