Exemplo n.º 1
0
    def __init__(self,
                 trigger: contracts.TriggerType,
                 container: payloads.IVerifiable,
                 snapshot: storage.Snapshot,
                 gas: int,
                 test_mode: bool = False
                 ):
        # Do not use super() version, see
        # https://pybind11.readthedocs.io/en/master/advanced/classes.html#overriding-virtual-functions-in-python
        vm.ApplicationEngineCpp.__init__(self, test_mode)
        #: A ledger snapshot to use for syscalls such as "System.Blockchain.GetHeight".
        self.snapshot = snapshot
        #: The trigger to run the engine with.
        self.trigger = trigger
        #: A flag to toggle infinite gas
        self.is_test_mode = test_mode

        self.script_container = container
        #: Gas available for consumption by the engine while executing its script.
        self.gas_amount = self.GAS_FREE + gas
        self._invocation_counter: Dict[types.UInt160, int] = {}
        #: Notifications (Notify SYSCALLs) that occured while executing the script.
        self.notifications: List[Tuple[payloads.IVerifiable, types.UInt160, bytes, vm.ArrayStackItem]] = []
        if self.snapshot is None or self.snapshot.persisting_block is None or self.snapshot.persisting_block.index == 0:
            self.exec_fee_factor = contracts.PolicyContract().DEFAULT_EXEC_FEE_FACTOR
            self.STORAGE_PRICE = contracts.PolicyContract().DEFAULT_STORAGE_PRICE
        else:
            self.exec_fee_factor = contracts.PolicyContract().get_exec_fee_factor(snapshot)
            self.STORAGE_PRICE = contracts.PolicyContract().get_storage_price(snapshot)

        from neo3.contracts import interop
        self.interop = interop
Exemplo n.º 2
0
    def invoke(self, engine: contracts.ApplicationEngine,
               version: int) -> None:
        """
        Calls a contract function

        Reads the required arguments from the engine's stack and converts them to the appropiate contract function types

        Args:
            engine: the engine executing the smart contract
            version: which version of the smart contract to load

        Raises:
             ValueError: if the request contract version is not
             ValueError: if the function to be called does not exist on the contract
             ValueError: if trying to call a function without having the correct CallFlags
        """
        if version != 0:
            raise ValueError(f"Native contract version {version} is not active"
                             )  # type: ignore

        context = engine.current_context
        flags = contracts.CallFlags(context.call_flags)
        method = self._methods.get(context.ip, None)
        if method is None:
            raise ValueError(
                f"Method at IP \"{context.ip}\" does not exist on contract {self.service_name()}"
            )
        if method.required_flags not in flags:
            raise ValueError(
                f"Method requires call flag: {method.required_flags} received: {flags}"
            )

        engine.add_gas(
            method.cpu_price *
            contracts.PolicyContract().get_exec_fee_factor(engine.snapshot) +
            method.storage_price *
            contracts.PolicyContract().get_storage_price(engine.snapshot))

        params: List[Any] = []
        if method.add_engine:
            params.append(engine)

        if method.add_snapshot:
            params.append(engine.snapshot)

        for t in method.parameter_types:
            params.append(
                engine._stackitem_to_native(context.evaluation_stack.pop(), t))

        if len(params) > 0:
            return_value = method.handler(*params)
        else:
            return_value = method.handler()
        if method.return_type is not None:
            context.evaluation_stack.push(
                engine._native_to_stackitem(return_value, type(return_value)))
Exemplo n.º 3
0
    def test_policy_block_account_and_is_blocked(self):
        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

        sb = vm.ScriptBuilder()

        # set or we won't pass the check_comittee() in the policy contract function implementations
        engine.script_container = TestIVerifiable()
        validator = settings.standby_committee[0]
        script_hash = to_script_hash(
            contracts.Contract.create_multisig_redeemscript(1, [validator]))
        engine.script_container.script_hashes = [script_hash]

        # first we setup the stack for calling `blockAccount`
        # push data to create a vm.Array holding 20 bytes for the UInt160 Account parameter of the _block_account function.
        sb.emit_push(b'\x11' * 20)
        sb.emit(vm.OpCode.PUSH1)
        sb.emit(vm.OpCode.PACK)
        sb.emit_push(15)  # call flags
        sb.emit_push("blockAccount")
        sb.emit_push(contracts.PolicyContract().hash.to_array())
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))

        # next we call `isBlocked`
        sb.emit_push(b'\x11' * 20)
        sb.emit(vm.OpCode.PUSH1)
        sb.emit(vm.OpCode.PACK)
        sb.emit_push(15)  # call flags
        sb.emit_push("isBlocked")
        sb.emit_push(contracts.PolicyContract().hash.to_array())
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))

        script = vm.Script(sb.to_array())
        engine.load_script(script)

        # storing the current script in a contract otherwise "System.Contract.Call" will fail its checks
        nef = contracts.NEF(script=sb.to_array())
        manifest = contracts.ContractManifest("test_contract")
        sender = engine.script_container.script_hashes[0]
        contract = contracts.ContractState(
            1, nef, manifest, 0,
            contract_hash(sender, nef.checksum, manifest.name))
        engine.snapshot.contracts.put(contract)

        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(2, len(engine.result_stack))
        get_is_blocked_result = engine.result_stack.pop()
        set_blocked_account_result = engine.result_stack.pop()
        self.assertTrue(set_blocked_account_result.to_boolean())
        self.assertTrue(get_is_blocked_result.to_boolean())
Exemplo n.º 4
0
    def test_policy_set_and_get_blocked_accounts(self):
        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

        sb = vm.ScriptBuilder()
        sb.emit_syscall(syscall_name_to_int("Neo.Native.Deploy"))

        # set or we won't pass the check_comittee() in the policy contract function implementations
        engine.script_container = TestIVerifiable()
        validator = settings.standby_committee[0]
        script_hash = to_script_hash(
            contracts.Contract.create_multisig_redeemscript(1, [validator]))
        engine.script_container.script_hashes = [script_hash]

        # first we setup the stack for calling `blockAccount`
        # push data to create a vm.Array holding 20 bytes for the UInt160 Account parameter of the _block_account function.
        sb.emit_push(b'\x11' * 20)
        sb.emit(vm.OpCode.PUSH1)
        sb.emit(vm.OpCode.PACK)
        sb.emit_push("blockAccount")
        sb.emit_push(contracts.PolicyContract().script_hash.to_array())
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))

        # next we call `getBlockedAccounts`
        sb.emit_contract_call(contracts.PolicyContract().script_hash,
                              "getBlockedAccounts")

        script = vm.Script(sb.to_array())
        engine.load_script(script)

        # storing the current script in a contract otherwise "System.Contract.Call" will fail its checks
        engine.snapshot.contracts.put(
            storage.ContractState(sb.to_array(), contracts.ContractManifest()))

        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(2, len(engine.result_stack))
        get_blocked_accounts_result = engine.result_stack.pop()
        set_blocked_accounts_result = engine.result_stack.pop()
        self.assertTrue(set_blocked_accounts_result.to_boolean())
        self.assertIsInstance(get_blocked_accounts_result, vm.InteropStackItem)
        stored_accounts = get_blocked_accounts_result.get_object()
        self.assertEqual(1, len(stored_accounts))

        expected_account = types.UInt160(data=b'\x11' * 20)
        self.assertEqual(expected_account, stored_accounts[0])
Exemplo n.º 5
0
    def test_policy_unblock_account(self):
        # we've tested the full round trip via "System.Contract.Call" in the test
        # test_policy_set_and_get_blocked_accounts()
        # Here we take the shortcut and test the unblock account function directly
        engine = test_engine(has_snapshot=True)
        block = test_block(0)
        engine.snapshot.persisting_block = block
        engine.invoke_syscall_by_name("Neo.Native.Deploy")

        # we must add a script_container with valid signature to pass the check_comittee() validation check
        # in the function itself
        engine.script_container = TestIVerifiable()
        validator = settings.standby_committee[0]
        script_hash = to_script_hash(
            contracts.Contract.create_multisig_redeemscript(1, [validator]))
        engine.script_container.script_hashes = [script_hash]

        policy = contracts.PolicyContract()
        account_not_found = types.UInt160(data=b'\x11' * 20)
        account = types.UInt160.zero()
        self.assertTrue(policy._block_account(engine, account))
        self.assertFalse(policy._unblock_account(engine, account_not_found))
        self.assertTrue(policy._unblock_account(engine, account))
        storage_key = storage.StorageKey(policy.script_hash,
                                         policy._PREFIX_BLOCKED_ACCOUNTS)
        storage_item = engine.snapshot.storages.try_get(storage_key)
        self.assertIsNotNone(storage_item)
        self.assertEqual(b'\x00', storage_item.value)
Exemplo n.º 6
0
 def test_policy_get_max_block_system_fee(self):
     engine = test_native_contract(contracts.PolicyContract().script_hash,
                                   "getMaxBlockSystemFee")
     engine.execute()
     self.assertEqual(vm.VMState.HALT, engine.state)
     self.assertEqual(1, len(engine.result_stack))
     item = engine.result_stack.pop()
     self.assertEqual(vm.IntegerStackItem(900000000000), item)
Exemplo n.º 7
0
 def test_policy_get_max_tx_per_block(self):
     engine = test_native_contract(contracts.PolicyContract().script_hash,
                                   "getMaxTransactionsPerBlock")
     engine.execute()
     self.assertEqual(vm.VMState.HALT, engine.state)
     self.assertEqual(1, len(engine.result_stack))
     item = engine.result_stack.pop()
     self.assertEqual(vm.IntegerStackItem(512), item)
Exemplo n.º 8
0
 def test_policy_default_get_fee_per_byte(self):
     engine = test_native_contract(contracts.PolicyContract().hash,
                                   "getFeePerByte")
     engine.execute()
     self.assertEqual(vm.VMState.HALT, engine.state)
     self.assertEqual(1, len(engine.result_stack))
     item = engine.result_stack.pop()
     self.assertEqual(vm.IntegerStackItem(1000), item)
Exemplo n.º 9
0
    def test_native_deploy_ok(self):
        engine = test_engine(has_snapshot=True)
        block = test_block(0)

        engine.snapshot.persisting_block = block
        engine.invoke_syscall_by_name("Neo.Native.Deploy")

        self.assertIn("Policy",
                      contracts.NativeContract().registered_contract_names)
        self.assertEqual(contracts.PolicyContract(),
                         contracts.NativeContract.get_contract("Policy"))
Exemplo n.º 10
0
def calculate_network_fee(tx: payloads.Transaction, snapshot: storage.Snapshot, account: wallet.Account) -> int:
    if len(tx.signers) == 0:
        raise ValueError("Cannot calculate the network fee without a sender in the transaction.")

    hashes = tx.get_script_hashes_for_verifying(snapshot)
    network_fee_size = (tx.HEADER_SIZE
                        + core_utils.get_var_size(tx.signers)  # type: ignore
                        + core_utils.get_var_size(tx.attributes)  # type: ignore
                        + core_utils.get_var_size(tx.script)  # type: ignore
                        + core_utils.get_var_size(len(hashes))  # type: ignore
                        )
    exec_fee_factor = contracts.PolicyContract().get_exec_fee_factor(snapshot)

    network_fee = 0
    for i, hash_ in enumerate(hashes):
        witness_script = None
        if hash_ == account.script_hash and account.contract and len(account.contract.script) > 0:
            witness_script = account.contract.script

        if witness_script is None and len(tx.witnesses) > 0:
            for witness in tx.witnesses:
                if witness.script_hash() == hash_:
                    witness_script = witness.verification_script
                    break

        if witness_script is None or (witness_script and len(witness_script) == 0):
            raise ValueError("Using a smart contract as a witness is not yet supported in mamba")

        elif contracts.Contract.is_signature_contract(witness_script):
            network_fee_size += 67 + core_utils.get_var_size(witness_script)  # type: ignore
            network_fee = exec_fee_factor * signature_contract_costs()
        elif contracts.Contract.is_multisig_contract(witness_script):
            _, threshold, public_keys = contracts.Contract.parse_as_multisig_contract(witness_script)
            invocation_script_size = 66 * threshold
            network_fee_size += (core_utils.get_var_size(invocation_script_size)  # type: ignore
                                 + invocation_script_size
                                 + core_utils.get_var_size(witness_script))  # type: ignore
            network_fee = exec_fee_factor * multisig_contract_costs(threshold, len(public_keys))

    network_fee += network_fee_size * contracts.PolicyContract().get_fee_per_byte(snapshot)
    return network_fee
Exemplo n.º 11
0
    def init(self):
        self._methods: Dict[int, _NativeMethodMeta] = {}  # offset, meta

        self._management = contracts.ManagementContract()
        self._neo = contracts.NeoToken()
        self._gas = contracts.GasToken()
        self._policy = contracts.PolicyContract()
        self._oracle = contracts.OracleContract()
        self._ledger = contracts.LedgerContract()
        self._role = contracts.DesignationContract()
        self._crypto = contracts.CryptoContract()
        self._stdlib = contracts.StdLibContract()

        # Find all methods that have been augmented by the @register decorator
        # and turn them into methods that can be called by VM scripts
        methods_meta = []
        for pair in inspect.getmembers(self,
                                       lambda m: hasattr(m, "native_call")):
            methods_meta.append(_NativeMethodMeta(pair[1]))

        methods_meta.sort(
            key=lambda x: (x.descriptor.name, len(x.descriptor.parameters)))

        sb = vm.ScriptBuilder()
        for meta in methods_meta:
            meta.descriptor.offset = len(sb)
            sb.emit_push(0)
            self._methods.update({len(sb): meta})
            sb.emit_syscall(1736177434)  # "System.Contract.CallNative"
            sb.emit(vm.OpCode.RET)

        self._script: bytes = sb.to_array()
        self.nef = contracts.NEF("neo-core-v3.0", self._script)

        sender = types.UInt160.zero()  # OpCode.PUSH1
        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.ABORT)
        sb.emit_push(sender.to_array())
        sb.emit_push(0)
        sb.emit_push(self.service_name())
        self._hash: types.UInt160 = to_script_hash(sb.to_array())
        self._manifest: contracts.ContractManifest = contracts.ContractManifest(
        )
        self._manifest.name = self.service_name()
        self._manifest.abi.methods = list(
            map(lambda m: m.descriptor, methods_meta))

        if self._id != NativeContract._id:
            self._contracts.update({self.service_name(): self})
            self._contract_hashes.update({self._hash: self})

        self.active_block_index = settings.native_contract_activation.get(
            self.service_name, 0)
Exemplo n.º 12
0
    def test_policy_setters_fail_without_signatures(self):
        # cover set functions where check_committee fails
        policy = contracts.PolicyContract()
        engine = test_engine(has_snapshot=True)
        block = test_block(0)
        engine.snapshot.persisting_block = block
        engine.script_container = TestIVerifiable()

        with self.assertRaises(ValueError) as context:
            policy._set_fee_per_byte(engine, 0)
        self.assertEqual("Check committee failed", str(context.exception))

        self.assertFalse(policy._block_account(engine, None))
        self.assertFalse(policy._unblock_account(engine, None))
Exemplo n.º 13
0
    def test_policy_setters_fail_without_signatures(self):
        # cover set functions where check_committee fails
        policy = contracts.PolicyContract()
        engine = test_engine(has_snapshot=True)
        block = test_block(0)
        engine.snapshot.persisting_block = block
        engine.invoke_syscall_by_name("Neo.Native.Deploy")
        engine.script_container = TestIVerifiable()

        self.assertFalse(policy._set_max_block_size(engine, None))
        self.assertFalse(policy._set_max_transactions_per_block(engine, None))
        self.assertFalse(policy._set_max_block_system_fee(engine, None))
        self.assertFalse(policy._set_fee_per_byte(engine, None))
        self.assertFalse(policy._block_account(engine, None))
        self.assertFalse(policy._unblock_account(engine, None))
Exemplo n.º 14
0
    def test_native_call(self):
        engine = test_engine(has_snapshot=True, default_script=True)
        block = test_block(0)

        engine.snapshot.persisting_block = block
        # need to create and store a contract matching the current_context.script
        # otherwise system.contract.call checks will fail
        engine.snapshot.contracts.put(
            storage.ContractState(b'\x40', contracts.ContractManifest()))
        engine.invoke_syscall_by_name("Neo.Native.Deploy")
        engine.push(vm.ArrayStackItem(
            engine.reference_counter))  # empty array for no arguments
        engine.push(vm.ByteStringStackItem(b'getMaxTransactionsPerBlock'))
        policy_contract_hash = vm.ByteStringStackItem(
            contracts.PolicyContract().script_hash.to_array())
        engine.push(policy_contract_hash)
        engine.invoke_syscall_by_name("System.Contract.Call")
Exemplo n.º 15
0
    def test_policy_unblock_account(self):
        engine = test_engine(has_snapshot=True)
        block = test_block(0)
        engine.snapshot.persisting_block = block

        # we must add a script_container with valid signature to pass the check_comittee() validation check
        # in the function itself
        engine.script_container = TestIVerifiable()
        validator = settings.standby_committee[0]
        script_hash = to_script_hash(
            contracts.Contract.create_multisig_redeemscript(1, [validator]))
        engine.script_container.script_hashes = [script_hash]

        policy = contracts.PolicyContract()
        account_not_found = types.UInt160(data=b'\x11' * 20)
        account = types.UInt160.zero()
        self.assertTrue(policy._block_account(engine, account))
        self.assertFalse(policy._unblock_account(engine, account_not_found))
        self.assertTrue(policy._unblock_account(engine, account))
        storage_key = policy.key_blocked_account + account
        storage_item = engine.snapshot.storages.try_get(storage_key)
        self.assertIsNone(storage_item)
Exemplo n.º 16
0
    def test_policy_limit_setters(self):
        policy = contracts.PolicyContract()
        D = namedtuple(
            'D', ['test_func', 'value', 'expected_return', 'storage_prefix'])
        testdata = [
            D(policy._set_max_block_size, message.Message.PAYLOAD_MAX_SIZE,
              False, policy._PREFIX_MAX_BLOCK_SIZE),
            D(policy._set_max_block_size, 123, True,
              policy._PREFIX_MAX_BLOCK_SIZE),
            D(policy._set_max_transactions_per_block, 123, True,
              policy._PREFIX_MAX_TRANSACTIONS_PER_BLOCK),
            D(policy._set_max_block_system_fee, 123, False,
              policy._PREFIX_MAX_BLOCK_SYSTEM_FEE),
            # value is lower than magic number
            D(policy._set_max_block_system_fee, 5_000_000, True,
              policy._PREFIX_MAX_BLOCK_SYSTEM_FEE),
            D(policy._set_fee_per_byte, 123, True, policy._PREFIX_FEE_PER_BYTE)
        ]

        engine = test_engine(has_snapshot=True)
        block = test_block(0)
        engine.snapshot.persisting_block = block
        engine.invoke_syscall_by_name("Neo.Native.Deploy")

        # set or we won't pass the check_comittee() in the policy contract function implementations
        engine.script_container = TestIVerifiable()
        validator = settings.standby_committee[0]
        script_hash = to_script_hash(
            contracts.Contract.create_multisig_redeemscript(1, [validator]))
        engine.script_container.script_hashes = [script_hash]

        for d in testdata:
            self.assertEqual(d.expected_return, d.test_func(engine, d.value))
            if d.expected_return is True:
                item = engine.snapshot.storages.try_get(
                    storage.StorageKey(policy.script_hash, d.storage_prefix))
                self.assertIsNotNone(item)
                self.assertEqual(d.value, int.from_bytes(item.value, 'little'))
Exemplo n.º 17
0
 def test_various(self):
     native = contracts.NativeContract()
     known_contracts = native.registered_contracts
     self.assertIn(contracts.GasToken(), known_contracts)
     self.assertIn(contracts.NeoToken(), known_contracts)
     self.assertIn(contracts.PolicyContract(), known_contracts)
Exemplo n.º 18
0
 def test_basics(self):
     policy = contracts.PolicyContract()
     self.assertEqual(-3, policy.id)
     self.assertEqual("Policy", contracts.PolicyContract.service_name())
     self.assertEqual([], policy.supported_standards())
Exemplo n.º 19
0
 def test_basics(self):
     policy = contracts.PolicyContract()
     self.assertEqual(-7, policy.id)
     self.assertEqual("PolicyContract",
                      contracts.PolicyContract().service_name())