Beispiel #1
0
    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 _convert(self, stack_item: vm.StackItem, class_type: Type[object]) -> object:
     """
     convert VM type to native
     """
     if class_type in [vm.StackItem, vm.PointerStackItem, vm.ArrayStackItem, vm.InteropStackItem]:
         return stack_item
     elif class_type == int:
         return int(stack_item.to_biginteger())
     elif class_type == vm.BigInteger:
         return stack_item.to_biginteger()
     # mypy bug? https://github.com/python/mypy/issues/9756
     elif class_type in [bytes, bytearray]:  # type: ignore
         return stack_item.to_array()
     elif class_type == bool:
         return stack_item.to_boolean()
     elif class_type == types.UInt160:
         return types.UInt160(data=stack_item.to_array())
     elif class_type == types.UInt256:
         return types.UInt256(data=stack_item.to_array())
     elif class_type == str:
         if stack_item == vm.NullStackItem():
             return ""
         return stack_item.to_array().decode()
     elif class_type == cryptography.ECPoint:
         return cryptography.ECPoint.deserialize_from_bytes(stack_item.to_array())
     elif issubclass(class_type, enum.Enum):
         if stack_item.get_type() == vm.StackItemType.INTEGER:
             stack_item = cast(vm.IntegerStackItem, stack_item)
             # mypy seems to have trouble understanding types that support __int__
             return class_type(int(stack_item))  # type: ignore
         elif stack_item.get_type() == vm.StackItemType.BYTESTRING:
             stack_item = cast(vm.ByteStringStackItem, stack_item)
             return class_type(int(stack_item.to_biginteger()))  # type: ignore
     raise ValueError(f"Unknown class type, don't know how to convert: {class_type}")
Beispiel #3
0
def contract_call(engine: contracts.ApplicationEngine,
                  contract_hash: types.UInt160, method: str,
                  call_flags: contracts.CallFlags,
                  args: vm.ArrayStackItem) -> None:
    if method.startswith("_"):
        raise ValueError("Invalid method name")

    target_contract = contracts.ManagementContract().get_contract(
        engine.snapshot, contract_hash)
    if target_contract is None:
        raise ValueError("[System.Contract.Call] Can't find target contract")

    method_descriptor = target_contract.manifest.abi.get_method(
        method, len(args))
    if method_descriptor is None:
        raise ValueError(
            f"[System.Contract.Call] Method '{method}' does not exist on target contract"
        )

    has_return_value = method_descriptor.return_type != contracts.ContractParameterType.VOID
    if not has_return_value:
        engine.current_context.evaluation_stack.push(vm.NullStackItem())

    engine._contract_call_internal2(target_contract, method_descriptor,
                                    call_flags, has_return_value, list(args))
Beispiel #4
0
 def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
     struct = vm.StructStackItem(reference_counter)
     struct.append(vm.ByteStringStackItem(self.name))
     struct.append(vm.ArrayStackItem(reference_counter,
                                     list(map(lambda g: g.to_stack_item(reference_counter), self.groups)))
                   )
     struct.append(vm.ArrayStackItem(reference_counter,
                                     list(map(lambda s: vm.ByteStringStackItem(s), self.supported_standards)))
                   )
     struct.append(self.abi.to_stack_item(reference_counter))
     struct.append(vm.ArrayStackItem(reference_counter,
                                     list(map(lambda p: p.to_stack_item(reference_counter), self.permissions)))
                   )
     if self.trusts.is_wildcard:
         struct.append(vm.NullStackItem())
     else:
         struct.append(
             vm.ArrayStackItem(reference_counter,
                               list(map(lambda t: vm.ByteStringStackItem(t.to_array()),
                                        self.trusts)))  # type: ignore
         )
     if self.extra is None:
         struct.append(vm.ByteStringStackItem("null"))
     else:
         struct.append(vm.ByteStringStackItem(json.dumps(self.extra)))
     return struct
Beispiel #5
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)
Beispiel #6
0
    def _native_to_stackitem(self, value, native_type) -> vm.StackItem:
        """
        Convert native type to VM type

        Note: order of checking matters.
        e.g. a Transaction should be treated as IInteropable, while its also ISerializable
        """
        if isinstance(value, vm.StackItem):
            return value
        elif value is None:
            return vm.NullStackItem()
        elif native_type in [int, vm.BigInteger]:
            return vm.IntegerStackItem(value)
        elif issubclass(native_type, IInteroperable):
            value_ = cast(IInteroperable, value)
            return value_.to_stack_item(self.reference_counter)
        elif issubclass(native_type, serialization.ISerializable):
            serializable_value = cast(serialization.ISerializable, value)
            return vm.ByteStringStackItem(serializable_value.to_array())
        # mypy bug? https://github.com/python/mypy/issues/9756
        elif native_type in [bytes, bytearray]:  # type: ignore
            return vm.ByteStringStackItem(value)
        elif native_type == str:
            return vm.ByteStringStackItem(bytes(value, 'utf-8'))
        elif native_type == bool:
            return vm.BooleanStackItem(value)
        elif issubclass(native_type, (enum.IntFlag, enum.IntEnum)):
            return self._native_to_stackitem(value.value, int)
        else:
            return vm.StackItem.from_interface(value)
Beispiel #7
0
    def test_with_null(self):
        n = vm.NullStackItem()
        x = contracts.BinarySerializer.serialize(n, 999)
        self.assertEqual(b'\x00', x)

        new_n = contracts.BinarySerializer.deserialize(x, 1,
                                                       self.reference_counter)
        self.assertIsInstance(new_n, vm.NullStackItem)
Beispiel #8
0
    def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
        struct = vm.StructStackItem(reference_counter)
        if self.contract.is_wildcard:
            struct.append(vm.NullStackItem())
        elif self.contract.is_hash:
            struct.append(vm.ByteStringStackItem(self.contract.contract_hash.to_array()))  # type: ignore
        else:
            struct.append(vm.ByteStringStackItem(self.contract.group.to_array()))  # type: ignore

        if self.methods.is_wildcard:
            struct.append(vm.NullStackItem())
        else:
            struct.append(
                vm.ArrayStackItem(reference_counter,
                                  list(map(lambda m: vm.ByteStringStackItem(m), self.methods)))  # type: ignore
            )
        return struct
 def test_iterator_create_invalid_type(self):
     engine = test_engine()
     item = vm.NullStackItem()
     engine.push(item)
     with self.assertRaises(ValueError) as context:
         engine.invoke_syscall_by_name("System.Iterator.Create")
     self.assertEqual(
         f"Cannot create iterator from unsupported type: {type(item)}",
         str(context.exception))
Beispiel #10
0
 def deserialize(
         json_data: JObject,
         reference_counter: vm.ReferenceCounter = None) -> vm.StackItem:
     """
     Deserialize JSON into a virtual machine stack item
     """
     t = type(json_data)
     if t == dict:
         json_data = cast(dict, json_data)
         if reference_counter is None:
             raise ValueError(
                 "Can't deserialize JSON object without reference counter")
         map_item = vm.MapStackItem(reference_counter)
         for k, v in json_data.items():
             key = vm.ByteStringStackItem(k)
             value = JSONSerializer.deserialize(v, reference_counter)
             map_item[key] = value
         return map_item
     elif t == list:
         if reference_counter is None:
             raise ValueError(
                 "Can't deserialize JSON array without reference counter")
         array_item = vm.ArrayStackItem(reference_counter)
         json_data = cast(list, json_data)
         elements = [
             JSONSerializer.deserialize(e, reference_counter)
             for e in json_data
         ]
         array_item.append(elements)
         return array_item
     elif json_data is None:
         return vm.NullStackItem()
     elif t == str:
         if json_data == "null":
             return vm.NullStackItem()
         return vm.ByteStringStackItem(json_data)  # type: ignore
     elif t == int:
         return vm.IntegerStackItem(json_data)  # type: ignore
     elif t == bool:
         json_data = cast(bool, json_data)
         return vm.BooleanStackItem(json_data)
     else:
         # should never happen or somebody ignored the type checker output
         raise ValueError()
Beispiel #11
0
 def test_serialization_array(self):
     b = vm.BooleanStackItem(True)
     bs = vm.ByteStringStackItem("test")
     i = vm.IntegerStackItem(123)
     n = vm.NullStackItem()
     ref_ctr = vm.ReferenceCounter()
     a = vm.ArrayStackItem(ref_ctr)
     a.append([b, bs, i, n])
     expected = r'[true,"test",123,null]'
     self.assertEqual(expected, contracts.JSONSerializer.serialize(a, 999))
Beispiel #12
0
 def to_stack_item(self,
                   reference_counter: vm.ReferenceCounter) -> vm.StackItem:
     struct_ = super(_NeoTokenStorageState,
                     self).to_stack_item(reference_counter)
     struct_ = cast(vm.StructStackItem, struct_)
     struct_.append(vm.IntegerStackItem(self.balance_height))
     if self.vote_to.is_zero():
         struct_.append(vm.NullStackItem())
     else:
         struct_.append(vm.ByteStringStackItem(self.vote_to.to_array()))
     return struct_
Beispiel #13
0
    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))
Beispiel #14
0
    def test_transfer_negative_amount(self):
        engine = test_engine(has_snapshot=True, default_script=False)
        engine.load_script(vm.Script(contracts.GasToken().script))
        block = test_block(0)
        # set or we won't pass the native deploy call
        engine.snapshot.persisting_block = block

        gas = contracts.GasToken()

        with self.assertRaises(ValueError) as context:
            gas.transfer(engine, types.UInt160.zero(), types.UInt160.zero(),
                         vm.BigInteger(-1), vm.NullStackItem())
        self.assertEqual("Can't transfer a negative amount",
                         str(context.exception))
    def _native_to_stackitem(self, value, native_type) -> vm.StackItem:
        """
        Convert native type to VM type

        Note: order of checking matters.
        e.g. a Transaction should be treated as IInteropable, while its also ISerializable
        """
        if isinstance(value, vm.StackItem):
            return value
        elif value is None:
            return vm.NullStackItem()
        elif native_type in [int, vm.BigInteger]:
            return vm.IntegerStackItem(value)
        elif issubclass(native_type, IInteroperable):
            value_ = cast(IInteroperable, value)
            return value_.to_stack_item(self.reference_counter)
        elif issubclass(native_type, serialization.ISerializable):
            serializable_value = cast(serialization.ISerializable, value)
            return vm.ByteStringStackItem(serializable_value.to_array())
        # mypy bug? https://github.com/python/mypy/issues/9756
        elif native_type in [bytes, bytearray]:  # type: ignore
            return vm.ByteStringStackItem(value)
        elif native_type == str:
            return vm.ByteStringStackItem(bytes(value, 'utf-8'))
        elif native_type == bool:
            return vm.BooleanStackItem(value)
        elif issubclass(native_type, (enum.IntFlag, enum.IntEnum)):
            return self._native_to_stackitem(value.value, int)
        elif hasattr(native_type, '__origin__'
                     ) and native_type.__origin__ == Union:  # type: ignore
            # handle typing.Optional[type], Optional is an alias for Union[x, None]
            # only support specifying 1 type
            if len(native_type.__args__) != 2:
                raise ValueError(
                    f"Don't know how to convert native type {native_type} to stackitem"
                )
            for i in native_type.__args__:
                if i is None:
                    continue
                return self._native_to_stackitem(value, native_type)
            else:
                raise ValueError  # shouldn't be possible, but silences mypy
        else:
            return vm.StackItem.from_interface(value)
Beispiel #16
0
    def burn(self, engine: contracts.ApplicationEngine, account: types.UInt160,
             amount: vm.BigInteger) -> None:
        """
        Burn an amount of tokens from account.

        Reduces the total supply of the token.

        Raises:
            ValueError: if amount is negative
            ValueError: if the burn amount is larger than the available balance in the account
        """
        if amount.sign < 0:
            raise ValueError("Can't burn a negative amount")

        if amount == vm.BigInteger.zero():
            return

        storage_key = self.key_account + account
        storage_item = engine.snapshot.storages.get(storage_key,
                                                    read_only=False)

        state = storage_item.get(self._state)
        if state.balance < amount:
            raise ValueError(
                f"Insufficient balance. Requesting to burn {amount}, available {state.balance}"
            )

        self.on_balance_changing(engine, account, state, -amount)
        if state.balance == amount:
            engine.snapshot.storages.delete(storage_key)
        else:
            state.balance -= amount
            engine.snapshot.storages.update(storage_key, storage_item)

        storage_item = engine.snapshot.storages.get(self.key_total_supply,
                                                    read_only=False)
        old_value = vm.BigInteger(storage_item.value)
        new_value = old_value - amount
        if new_value == vm.BigInteger.zero():
            engine.snapshot.storages.delete(self.key_total_supply)
        else:
            storage_item.value = new_value.to_array()
        self._post_transfer(engine, account, types.UInt160.zero(), amount,
                            vm.NullStackItem(), False)
Beispiel #17
0
    def test_ripemd160_null(self):
        """
        var tx = new Neo.Network.P2P.Payloads.Transaction
        {
            Version = 0,
            Nonce = 0,
            SystemFee = 0,
            NetworkFee = 0,
            ValidUntilBlock = 99999,
            Attributes = new TransactionAttribute[0],
            Script = new byte[0],
            Signers = new Signer[] { new Signer { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly}}
        };
        using var script = new ScriptBuilder();
        script.EmitSysCall(ApplicationEngine.Neo_Crypto_RIPEMD160); // Syscall
        var engine = ApplicationEngine.Create(TriggerType.Application, tx, null, 100_000_000, false);
        engine.LoadScript(script.ToArray());
        engine.Push(StackItem.Null);
        Assert.AreEqual(engine.Execute(), VMState.HALT);
        Assert.AreEqual(1, engine.ResultStack.Count);
        var item = engine.ResultStack.Pop<ByteString>();
        Console.WriteLine($"{item.GetSpan().ToHexString()}");
        """
        # we have to set the network magic number, because that is serialized as part of the "get_hash_data()" call
        settings.network.magic = 0x4F454E

        sb = vm.ScriptBuilder()
        sb.emit_syscall(syscall_name_to_int("Neo.Crypto.RIPEMD160"))

        engine = test_engine(has_container=True)
        engine.script_container.signers = [
            payloads.Signer(types.UInt160.zero())
        ]
        script = vm.Script(sb.to_array())
        engine.load_script(script)

        engine.push(vm.NullStackItem())
        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack))
        # captured from C#
        expected = '0892b2402eb78d878a4c60fc799d879b672a5aa5'
        self.assertEqual(expected, str(engine.result_stack.pop()))
Beispiel #18
0
    def context_unloaded(self, context: vm.ExecutionContext):
        # Do not use super() version, see
        # https://pybind11.readthedocs.io/en/master/advanced/classes.html#overriding-virtual-functions-in-python
        vm.ExecutionEngine.context_unloaded(self, context)
        if self.uncaught_exception is not None:
            return
        if len(self._invocation_states) == 0:
            return
        try:
            state = self._invocation_states.pop(self.current_context)
        except KeyError:
            return
        if state.check_return_value:
            eval_stack_len = len(context.evaluation_stack)
            if eval_stack_len == 0:
                self.push(vm.NullStackItem())
            elif eval_stack_len > 1:
                raise SystemError("Invalid evaluation stack state")

        if state.callback is None:
            return
Beispiel #19
0
    def test_notify_state_helper_basics(self):
        bssi = vm.ByteStringStackItem(b'\x01\x02')  # 2
        null = vm.NullStackItem()  # 0
        primitive = vm.IntegerStackItem(2)  # 1

        engine = test_engine()
        array1 = vm.ArrayStackItem(engine.reference_counter)
        array2 = vm.ArrayStackItem(engine.reference_counter)
        array2.append(primitive)

        # we expect a size of 3, given that our self reference should be ignored.
        # 5 would mean a failure of detecting a circular reference for ArrayStackItem types
        array1.append([bssi, null, array2, array1])

        self.assertEqual(3, _validate_state_item_limits(engine, array1))

        with self.assertRaises(ValueError) as context:
            _validate_state_item_limits(engine, vm.InteropStackItem(object()))
        self.assertEqual(
            "An item in the notification state exceeds the allowed notification size limit",
            str(context.exception))
    def test_contract_call_exceptions(self):
        engine = test_engine(has_snapshot=True, default_script=False)
        engine.load_script(vm.Script(hello_world_nef.script))

        # can't find contract
        with self.assertRaises(ValueError) as context:
            engine._contract_call_internal(
                types.UInt160.zero(), "valid_method", contracts.CallFlags.ALL,
                False, vm.ArrayStackItem(engine.reference_counter))
        self.assertEqual("[System.Contract.Call] Can't find target contract",
                         str(context.exception))

        fake_contract_hash = types.UInt160(b'\x01' * 20)
        target_contract = contracts.ContractState(0, contract3_nef,
                                                  contract3_manifest, 0,
                                                  fake_contract_hash)
        engine.snapshot.contracts.put(target_contract)

        # modify the manifest of the current executing contract to only allow to call 1 specific method on other contracts
        new_current_manifest = deepcopy(hello_world_manifest)
        new_current_manifest.permissions = [
            contracts.ContractPermission(
                contracts.ContractPermissionDescriptor(
                ),  # allow to call any contract
                contracts.WildcardContainer(
                    ['method_aaaa'])  # allowing to call the listed method only
            )
        ]
        fake_contract_hash2 = types.UInt160(b'\x02' * 20)
        new_current_contract = contracts.ContractState(1, hello_world_nef,
                                                       new_current_manifest, 0,
                                                       fake_contract_hash2)
        engine.snapshot.contracts.put(new_current_contract)
        with self.assertRaises(ValueError) as context:
            engine._contract_call_internal(
                target_contract.hash, "invalid_method",
                contracts.CallFlags.ALL, False,
                vm.ArrayStackItem(engine.reference_counter))
        self.assertEqual(
            "[System.Contract.Call] Method 'invalid_method' with 0 arguments does not exist on target contract",
            str(context.exception))

        # restore current contract to its original form and try to call a non-existing contract
        current_contract = contracts.ContractState(1, hello_world_nef,
                                                   hello_world_manifest, 1,
                                                   fake_contract_hash2)
        engine.snapshot.contracts.delete(new_current_contract.hash)
        engine.snapshot.contracts.put(current_contract)

        with self.assertRaises(ValueError) as context:
            engine._contract_call_internal(
                target_contract.hash, "invalid_method",
                contracts.CallFlags.ALL, False,
                vm.ArrayStackItem(engine.reference_counter))
        self.assertEqual(
            "[System.Contract.Call] Method 'invalid_method' with 0 arguments does not exist on target contract",
            str(context.exception))

        # call the target method with invalid number of arguments
        array = vm.ArrayStackItem(engine.reference_counter)
        array.append([vm.NullStackItem(), vm.NullStackItem()])
        with self.assertRaises(ValueError) as context:
            engine._contract_call_internal(target_contract.hash, "test_func",
                                           contracts.CallFlags.ALL, False,
                                           array)
        self.assertEqual(
            "[System.Contract.Call] Method 'test_func' with 2 arguments does not exist on target contract",
            str(context.exception))
    def test_contract_call_exceptions(self):
        engine = test_engine(has_snapshot=True, default_script=False)
        engine.load_script(vm.Script(hello_world_nef.script))
        with self.assertRaises(ValueError) as context:
            contract_call_internal(engine, types.UInt160.zero(),
                                   "_invalid_method",
                                   vm.ArrayStackItem(engine.reference_counter),
                                   contracts.native.CallFlags)
        self.assertEqual(
            "[System.Contract.Call] Method not allowed to start with _",
            str(context.exception))

        # can't find contract
        with self.assertRaises(ValueError) as context:
            contract_call_internal(engine, types.UInt160.zero(),
                                   "valid_method",
                                   vm.ArrayStackItem(engine.reference_counter),
                                   contracts.native.CallFlags)
        self.assertEqual("[System.Contract.Call] Can't find target contract",
                         str(context.exception))

        target_contract = storage.ContractState(contract3_nef.script,
                                                contract3_manifest)
        engine.snapshot.contracts.put(target_contract)

        # modify the manifest of the current executing contract to only allow to call 1 specific method on other contracts
        new_current_manifest = deepcopy(hello_world_manifest)
        new_current_manifest.permissions = [
            contracts.ContractPermission(
                contracts.ContractPermissionDescriptor(
                ),  # allow to call any contract
                contracts.WildcardContainer(
                    ['method_aaaa'])  # allowing to call the listed method only
            )
        ]
        new_current_contract = storage.ContractState(hello_world_nef.script,
                                                     new_current_manifest)
        engine.snapshot.contracts.put(new_current_contract)
        with self.assertRaises(ValueError) as context:
            contract_call_internal(engine, target_contract.script_hash(),
                                   "invalid_method",
                                   vm.ArrayStackItem(engine.reference_counter),
                                   contracts.native.CallFlags)
        self.assertEqual(
            "[System.Contract.Call] Not allowed to call target method 'invalid_method' according to manifest",
            str(context.exception))

        # restore current contract to its original form and try to call a non-existing contract
        current_contract = storage.ContractState(hello_world_nef.script,
                                                 hello_world_manifest)
        engine.snapshot.contracts.delete(new_current_contract.script_hash())
        engine.snapshot.contracts.put(current_contract)

        with self.assertRaises(ValueError) as context:
            contract_call_internal(engine, target_contract.script_hash(),
                                   "invalid_method",
                                   vm.ArrayStackItem(engine.reference_counter),
                                   contracts.native.CallFlags)
        self.assertEqual(
            "[System.Contract.Call] requested target method 'invalid_method' does not exist on target contract",
            str(context.exception))

        # call the target method with invalid number of arguments
        array = vm.ArrayStackItem(engine.reference_counter)
        array.append([vm.NullStackItem(), vm.NullStackItem()])
        with self.assertRaises(ValueError) as context:
            contract_call_internal(engine, target_contract.script_hash(),
                                   "test_func", array,
                                   contracts.native.CallFlags)
        self.assertEqual(
            "[System.Contract.Call] Invalid number of contract arguments. Expected 0 actual 2",
            str(context.exception))
Beispiel #22
0
 def contract_create(self, engine: contracts.ApplicationEngine,
                     nef_file: bytes,
                     manifest: bytes) -> contracts.ContractState:
     return self.contract_create_with_data(engine, nef_file, manifest,
                                           vm.NullStackItem())
Beispiel #23
0
 def contract_update(self, engine: contracts.ApplicationEngine,
                     nef_file: bytes, manifest: bytes) -> None:
     self.contract_update_with_data(engine, nef_file, manifest,
                                    vm.NullStackItem())
    def deserialize(data: bytes, max_size: int, max_item_size: int,
                    reference_counter: vm.ReferenceCounter) -> vm.StackItem:
        """
        Deserialize data into a stack item.

        Args:
            data: byte array of a serialized stack item.
            max_size: data reading limit for Array, Struct and Map types.
            max_item_size: data reading limit for ByteString or Buffer types.
            reference_counter: a valid reference counter instance. Get's passed into reference stack items.
        """
        if len(data) == 0:
            raise ValueError("Nothing to deserialize")

        deserialized: List[Union[vm.StackItem, PlaceHolder]] = []
        to_deserialize = 1
        with serialization.BinaryReader(data) as reader:
            while not to_deserialize == 0:
                to_deserialize -= 1
                item_type = vm.StackItemType(reader.read_byte()[0])
                if item_type == vm.StackItemType.ANY:
                    deserialized.append(vm.NullStackItem())
                elif item_type == vm.StackItemType.BOOLEAN:
                    deserialized.append(vm.BooleanStackItem(
                        reader.read_bool()))
                elif item_type == vm.StackItemType.INTEGER:
                    deserialized.append(
                        vm.IntegerStackItem(
                            vm.BigInteger(
                                reader.read_var_bytes(
                                    vm.IntegerStackItem.MAX_SIZE))))
                elif item_type == vm.StackItemType.BYTESTRING:
                    deserialized.append(
                        vm.ByteStringStackItem(
                            reader.read_var_bytes(max_item_size)))
                elif item_type == vm.StackItemType.BUFFER:
                    deserialized.append(
                        vm.BufferStackItem(
                            reader.read_var_bytes(max_item_size)))
                elif item_type in [
                        vm.StackItemType.ARRAY, vm.StackItemType.STRUCT
                ]:
                    count = reader.read_var_int(max_size)
                    deserialized.append(PlaceHolder(item_type, count))
                    to_deserialize += count
                elif item_type == vm.StackItemType.MAP:
                    count = reader.read_var_int(max_size)
                    deserialized.append(PlaceHolder(item_type, count))
                    to_deserialize += count * 2
                else:
                    raise ValueError("Invalid format")

        temp: List[vm.StackItem] = []
        while len(deserialized) > 0:
            item = deserialized.pop()
            if type(item) == PlaceHolder:
                item = cast(PlaceHolder, item)
                if item.type == vm.StackItemType.ARRAY:
                    array = vm.ArrayStackItem(reference_counter)
                    for _ in range(0, item.count):
                        array.append(temp.pop())
                    temp.append(array)
                elif item.type == vm.StackItemType.STRUCT:
                    struct = vm.StructStackItem(reference_counter)
                    for _ in range(0, item.count):
                        struct.append(temp.pop())
                    temp.append(struct)
                elif item.type == vm.StackItemType.MAP:
                    m = vm.MapStackItem(reference_counter)
                    for _ in range(0, item.count):
                        k = temp.pop()
                        k = cast(vm.PrimitiveType, k)
                        v = temp.pop()
                        m[k] = v
                    temp.append(m)
            else:
                item = cast(vm.StackItem, item)
                temp.append(item)
        return temp.pop()
Beispiel #25
0
 def test_serialize_with_exceeding_max_length(self):
     with self.assertRaises(ValueError) as context:
         n = vm.NullStackItem()
         contracts.BinarySerializer.serialize(n, 0)
     self.assertEqual("Output length exceeds max size",
                      str(context.exception))