Exemple #1
0
    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())
Exemple #2
0
    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))
Exemple #3
0
    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)
Exemple #4
0
 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'))
Exemple #5
0
 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()))
Exemple #6
0
    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)
Exemple #7
0
    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)
Exemple #8
0
    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)
Exemple #9
0
    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)
Exemple #10
0
    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()))
Exemple #11
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
    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))
Exemple #13
0
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
Exemple #14
0
    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)
Exemple #15
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
Exemple #16
0
    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)
Exemple #17
0
    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())
Exemple #18
0
    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()))
Exemple #19
0
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
Exemple #20
0
    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)
Exemple #21
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
Exemple #22
0
    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)
Exemple #23
0
 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()))
Exemple #24
0
    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)
Exemple #26
0
    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)
Exemple #27
0
    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)
Exemple #28
0
    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))
Exemple #29
0
    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
Exemple #30
0
    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))