def test_contract_call(self):
        engine = test_engine(has_snapshot=True, default_script=False)
        # current executing contract
        fake_hash = types.UInt160.deserialize_from_bytes(b'\x01' * 20)
        contract = contracts.ContractState(0, hello_world_nef,
                                           hello_world_manifest, 0, fake_hash)
        engine.snapshot.contracts.put(contract)
        # target contract
        fake_hash2 = types.UInt160.deserialize_from_bytes(b'\x02' * 20)
        target_contract = contracts.ContractState(1, contract3_nef,
                                                  contract3_manifest, 0,
                                                  fake_hash2)
        engine.snapshot.contracts.put(target_contract)
        engine.load_script(vm.Script(contract.script))
        array = vm.ArrayStackItem(engine.reference_counter)
        array.append(vm.IntegerStackItem(3))
        engine.push(array)  # args
        engine.push(vm.IntegerStackItem(15))  # callflags
        engine.push(vm.ByteStringStackItem("test_func2"))  # method
        engine.push(vm.ByteStringStackItem(target_contract.hash.to_array()))
        engine.invoke_syscall_by_name("System.Contract.Call")
        engine.execute()

        self.assertEqual(2, len(engine.result_stack))
        main_contract_return_value = engine.result_stack.pop()
        syscall_called_contract_return_value = engine.result_stack.pop()
        self.assertEqual("hello world",
                         main_contract_return_value.to_array().decode())
        self.assertEqual(4, int(syscall_called_contract_return_value))
Esempio n. 2
0
    def test_equals(self):
        manifest = contracts.ContractManifest()
        nef = contracts.NEF()
        state = contracts.ContractState(1, nef, manifest, 0,
                                        types.UInt160.zero())
        clone = state.clone()
        self.assertEqual(state, clone)

        nef2 = contracts.NEF()
        state2 = contracts.ContractState(2, nef2, manifest, 0,
                                         types.UInt160(b'\x01' * 20))
        self.assertNotEqual(state, state2)
        self.assertNotEqual(state, None)
        self.assertNotEqual(state, object())
Esempio n. 3
0
    def test_getcallingscripthash(self):
        """
        Testing this requires 2 contracts

        1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract
        2) callee_contract: uses a System.Runtime.GetCallingScriptHash to return the calling script
        """
        sb = vm.ScriptBuilder()
        sb.emit_syscall(
            syscall_name_to_int("System.Runtime.GetCallingScriptHash"))
        callee_contract_script = sb.to_array()
        callee_nef = contracts.NEF(script=callee_contract_script)
        callee_contract_name = "callee_contract"
        callee_manifest = contracts.ContractManifest(callee_contract_name)
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY, True)
        ]
        callee_contract_hash = contract_hash(types.UInt160.zero(),
                                             callee_nef.checksum,
                                             callee_contract_name)
        callee_contract = contracts.ContractState(1, callee_nef,
                                                  callee_manifest, 0,
                                                  callee_contract_hash)

        # create caller_contract script
        sb = vm.ScriptBuilder()
        sb.emit_dynamic_call(callee_contract.hash, "test_func")
        caller_script = sb.to_array()
        caller_nef = contracts.NEF(script=caller_script)
        caller_contract_name = "caller_contract"
        caller_manifest = contracts.ContractManifest(caller_contract_name)
        caller_contract_hash = contract_hash(types.UInt160.zero(),
                                             caller_nef.checksum,
                                             caller_contract_name)
        caller_contract = contracts.ContractState(2, caller_nef,
                                                  caller_manifest, 0,
                                                  caller_contract_hash)

        engine = test_engine(has_snapshot=True, default_script=False)
        engine.snapshot.contracts.put(callee_contract)
        engine.snapshot.contracts.put(caller_contract)
        engine.load_script(vm.Script(caller_script))
        engine.execute()

        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack))
        item = engine.result_stack.pop()
        self.assertEqual(
            to_script_hash(caller_nef.script).to_array(), item.to_array())
Esempio n. 4
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)
Esempio n. 5
0
    def transfer_helper(self, contract: contracts.NativeContract,
                        from_account: types.UInt160, to_account: types.UInt160,
                        amount: vm.BigInteger):
        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
        engine.invocation_stack.pop()  # we no longer need the default script
        engine.script_container = TestIVerifiable()
        engine.script_container.script_hashes = [from_account]

        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.PUSHNULL)
        sb.emit_push(amount)
        sb.emit_push(to_account.to_array())
        sb.emit_push(from_account.to_array())
        sb.emit_push(4)
        sb.emit(vm.OpCode.PACK)
        sb.emit_push(15)  # callflags
        sb.emit_push(b'transfer')
        sb.emit_push(contract.hash.to_array())
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))
        engine.load_script(vm.Script(sb.to_array()))

        nef = contracts.NEF(script=sb.to_array())
        manifest = contracts.ContractManifest("test_contract")
        contract_state = contracts.ContractState(
            1, nef, manifest, 0,
            contract_hash(from_account, nef.checksum, manifest.name))
        engine.snapshot.contracts.put(contract_state)
        return engine
Esempio n. 6
0
    def test_is_allowed_based_on_group(self):
        # We test the group permissions where all methods are allowed to be called
        # if the 'groups' member is valid.

        private_key = b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
        keypair = cryptography.KeyPair(private_key)

        dummy_contract_hash = types.UInt160.from_string("01" * 20)
        contract_state = contracts.ContractState(1, contracts.NEF(),
                                                 contracts.ContractManifest(),
                                                 0, dummy_contract_hash)

        signature = cryptography.sign(contract_state.hash.to_array(),
                                      keypair.private_key)
        contract_state.manifest.groups = [
            contracts.ContractGroup(keypair.public_key, signature)
        ]

        cpd = contracts.ContractPermissionDescriptor(group=keypair.public_key)
        cp = contracts.ContractPermission(
            contract=cpd,
            methods=contracts.WildcardContainer.create_wildcard())
        self.assertTrue(cp.is_allowed(contract_state, "dummy_method"))

        # now modify the manifest to have a different `groups` attribute such that validation fails
        public_key = cryptography.ECPoint.deserialize_from_bytes(
            b'\x00')  # ECPoint.Infinity
        contract_state.manifest.groups = [
            contracts.ContractGroup(public_key, signature)
        ]
        self.assertFalse(cp.is_allowed(contract_state, "dummy_method"))
Esempio n. 7
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)
Esempio n. 8
0
    def test_storage_put_new(self):
        # see `test_storage_get_key_not_found()` for a description on why the storage is setup with a script as is

        # setup
        engine = test_engine(has_snapshot=True)
        script = vm.ScriptBuilder()
        script.emit(vm.OpCode.PUSH2)  # storage put value
        script.emit(vm.OpCode.PUSH1)  # storage put key
        script.emit_syscall(syscall_name_to_int("System.Storage.GetContext"))
        script.emit_syscall(syscall_name_to_int("System.Storage.Put"))
        engine.load_script(vm.Script(script.to_array()))

        nef = contracts.NEF(script=script.to_array())
        manifest = contracts.ContractManifest(f"contractname1")
        manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY, True)
        ]
        hash_ = to_script_hash(nef.script)

        contract = contracts.ContractState(1, nef, manifest, 0, hash_)
        engine.snapshot.contracts.put(contract)

        engine.execute()

        self.assertEqual(vm.VMState.HALT, engine.state)
        storage_key = storage.StorageKey(1, b'\x01')
        item = engine.snapshot.storages.try_get(storage_key)
        self.assertIsNotNone(item)
        self.assertEqual(b'\x02', item.value)
Esempio n. 9
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())
Esempio n. 10
0
 def test_contractstate_clone(self):
     manifest = contracts.ContractManifest()
     nef = contracts.NEF()
     state = contracts.ContractState(1, nef, manifest, 0,
                                     types.UInt160.zero())
     clone = state.clone()
     self.assertNotEqual(id(state), id(clone))
     self.assertNotEqual(id(state.manifest), id(clone.manifest))
Esempio n. 11
0
    def test_get_invocation_counter_ok(self):
        """
        We need to setup 2 contracts
        1) caller_contract: uses a System.Contract.Call to call callee_contract. This will increase the invocation counter of the callee contract
        2) callee_contract: uses a System.Runtime.GetInvocationCounter
        """
        engine = test_engine(has_snapshot=True,
                             has_container=False,
                             default_script=False)

        sb = vm.ScriptBuilder()
        sb.emit_syscall(
            syscall_name_to_int("System.Runtime.GetInvocationCounter"))
        callee_contract_script = sb.to_array()
        callee_nef = contracts.NEF(script=callee_contract_script)
        callee_manifest = contracts.ContractManifest("contract1")
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY, True)
        ]
        callee_contract = contracts.ContractState(
            1, callee_nef, callee_manifest, 0,
            contract_hash(types.UInt160.zero(), callee_nef.checksum,
                          callee_manifest.name))

        sb = vm.ScriptBuilder()
        sb.emit_dynamic_call(callee_contract.hash, "test_func")
        caller_script = sb.to_array()
        caller_nef = contracts.NEF(script=caller_script)
        caller_manifest = contracts.ContractManifest("contract2")
        caller_contract = contracts.ContractState(
            2, caller_nef, caller_manifest, 0,
            contract_hash(types.UInt160.zero(), caller_nef.checksum,
                          caller_manifest.name))

        engine.snapshot.contracts.put(callee_contract)
        engine.snapshot.contracts.put(caller_contract)
        engine.load_script(vm.Script(caller_script))
        engine.execute()

        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack))
        item = engine.result_stack.pop()
        self.assertEqual(1, int(item))
Esempio n. 12
0
    def test_checkwitness_called_by_entry(self):
        """
        We need to setup 2 contracts
        1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract
        2) callee_contract: uses a System.Runtime.CheckWitness
        """
        engine = test_engine(has_snapshot=True,
                             has_container=False,
                             default_script=False)
        tx = test_tx()
        tx.signers[0].scope = payloads.WitnessScope.CALLED_BY_ENTRY
        engine.script_container = tx

        sb = vm.ScriptBuilder()
        sb.emit_push(tx.sender.to_array())
        sb.emit_syscall(syscall_name_to_int("System.Runtime.CheckWitness"))
        callee_contract_script = sb.to_array()
        callee_nef = contracts.NEF(script=callee_contract_script)
        callee_manifest = contracts.ContractManifest()
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY, True)
        ]
        callee_contract = contracts.ContractState(
            1, callee_nef, callee_manifest, 0,
            to_script_hash(callee_contract_script))

        sb = vm.ScriptBuilder()
        sb.emit_dynamic_call(callee_contract.hash, "test_func")
        caller_script = sb.to_array()
        caller_nef = contracts.NEF(script=caller_script)
        caller_manifest = contracts.ContractManifest()
        caller_contract = contracts.ContractState(
            2, caller_nef, caller_manifest, 0, to_script_hash(caller_script))

        engine.snapshot.contracts.put(callee_contract)
        engine.snapshot.contracts.put(caller_contract)
        engine.load_script(vm.Script(caller_script))
        engine.execute()

        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack))
        item = engine.result_stack.pop()
        self.assertTrue(item.to_boolean())
Esempio n. 13
0
 def setUp(self) -> None:
     self.RET = b'\x40'
     self.manifest = contracts.ContractManifest("contract_name")
     self.nef = contracts.NEF(script=self.RET)
     self.contract_hash = to_script_hash(self.nef.script)
     self.contract = contracts.ContractState(1, self.nef, self.manifest, 0,
                                             self.contract_hash)
     self.contract.manifest.abi.methods = [
         contracts.ContractMethodDescriptor(
             "test_func", 0, [], contracts.ContractParameterType.ANY, True)
     ]
Esempio n. 14
0
    def contract_create_with_data(
            self, engine: contracts.ApplicationEngine, nef_file: bytes,
            manifest: bytes, data: vm.StackItem) -> contracts.ContractState:
        if not isinstance(engine.script_container, payloads.Transaction):
            raise ValueError(
                "Cannot create contract without a Transaction script container"
            )

        nef_len = len(nef_file)
        manifest_len = len(manifest)
        if (nef_len == 0 or nef_len > engine.MAX_CONTRACT_LENGTH
                or manifest_len == 0
                or manifest_len > contracts.ContractManifest.MAX_LENGTH):
            raise ValueError("Invalid NEF or manifest length")

        engine.add_gas(
            max(engine.STORAGE_PRICE * (nef_len + manifest_len),
                self.get_minimum_deployment_fee(engine.snapshot)))

        nef = contracts.NEF.deserialize_from_bytes(nef_file)
        parsed_manifest = contracts.ContractManifest.from_json(
            json.loads(manifest.decode()))

        self.validate(nef.script, parsed_manifest.abi)

        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.ABORT)
        sb.emit_push(engine.script_container.sender.to_array())
        sb.emit_push(nef.checksum)
        sb.emit_push(parsed_manifest.name)
        hash_ = to_script_hash(sb.to_array())

        existing_contract = engine.snapshot.contracts.try_get(hash_)
        if existing_contract is not None:
            raise ValueError("Contract already exists")

        contract = contracts.ContractState(
            self.get_next_available_id(engine.snapshot), nef, parsed_manifest,
            0, hash_)
        if not contract.manifest.is_valid(hash_):
            raise ValueError("Error: invalid manifest")
        engine.snapshot.contracts.put(contract)

        method_descriptor = contract.manifest.abi.get_method("_deploy", 2)
        if method_descriptor is not None:
            engine.call_from_native(self.hash, hash_, method_descriptor.name,
                                    [data, vm.BooleanStackItem(False)])

        msgrouter.interop_notify(
            self.hash, "Deploy",
            vm.ArrayStackItem(engine.reference_counter,
                              vm.ByteStringStackItem(
                                  contract.hash.to_array())))
        return contract
Esempio n. 15
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())
Esempio n. 16
0
 def on_persist(self, engine: contracts.ApplicationEngine) -> None:
     # NEO implicitely expects a certain order of contract initialization
     # Native contracts have negative values for `id`, so we reverse the results
     sorted_contracts = sorted(self.registered_contracts,
                               key=lambda contract: contract.id,
                               reverse=True)
     for contract in sorted_contracts:
         if contract.active_block_index != engine.snapshot.persisting_block.index:
             continue
         engine.snapshot.contracts.put(
             contracts.ContractState(contract.id, contract.nef,
                                     contract.manifest, 0, contract.hash))
         contract._initialize(engine)
Esempio n. 17
0
    def test_transfer_from_empty_account(self):
        gas = contracts.GasToken()
        manifest = contracts.ContractManifest("test_contract2")
        nef = contracts.NEF(script=b'\x40')
        state = contracts.ContractState(
            2, nef, manifest, 0,
            contract_hash(types.UInt160.zero(), nef.checksum, manifest.name))

        engine = self.transfer_helper(gas, types.UInt160.zero(), state.hash,
                                      vm.BigInteger(1))
        engine.snapshot.contracts.put(state)
        engine.execute()
        self.assertEqual(1, len(engine.result_stack))
        result = engine.result_stack.pop()
        self.assertFalse(result)
Esempio n. 18
0
 def deploy_another_contract(self,
                             nef_path: str,
                             manifest_path: str = '') -> UInt160:
     """
     these extra contracts can be called but cannot be tested
     """
     raw_nef, raw_manifest = self.read_raw_nef_and_raw_manifest(
         nef_path, manifest_path)
     nef, manifest = self.build_nef_and_manifest_from_raw(
         raw_nef, raw_manifest)
     contract_hash = types.UInt160.deserialize_from_bytes(raw_nef[-20:])
     contract = contracts.ContractState(self.next_contract_id, nef,
                                        manifest, 0, contract_hash)
     self.previous_engine.snapshot.contracts.put(contract)
     self.deployed_contracts.append(contract)
     self.next_contract_id += 1
     return contract_hash
Esempio n. 19
0
    def test_is_allowed_invalid_method(self):
        # in the above tests we validated the 'group' and 'contract_hash' matching logic
        # now we validate 'method' matching
        dummy_contract_hash = types.UInt160.from_string("01" * 20)
        contract_state = contracts.ContractState(1, contracts.NEF(),
                                                 contracts.ContractManifest(),
                                                 0, dummy_contract_hash)

        # setup an allowed permission for a contract with UInt160.zero hash for 2 methods
        cpd = contracts.ContractPermissionDescriptor(
            contract_hash=dummy_contract_hash)
        cp = contracts.ContractPermission(
            contract=cpd,
            methods=contracts.WildcardContainer(data=['method1', 'method2']))
        self.assertTrue(cp.is_allowed(contract_state, "method1"))
        self.assertTrue(cp.is_allowed(contract_state, "method2"))
        self.assertFalse(cp.is_allowed(contract_state, "method3"))
Esempio n. 20
0
    def __init__(self,
                 nef_path: str,
                 manifest_path: str = '',
                 signers: List[Union[str, UInt160, payloads.Signer]] = None,
                 scope: payloads.WitnessScope = payloads.WitnessScope.GLOBAL):
        """
        Only the contract specified in __init__ can be tested. You can deploy more contracts to be called by the tested
        contract.
        """
        self.Prefix_Account_bytes = EngineResultInterpreter.int_to_bytes(
            self.Prefix_Account)
        self.raw_nef, self.raw_manifest = self.read_raw_nef_and_raw_manifest(
            nef_path, manifest_path)
        self.nef, self.manifest = self.build_nef_and_manifest_from_raw(
            self.raw_nef, self.raw_manifest)
        self.previous_engine: ApplicationEngine = self.new_engine()
        self.previous_processed_result = None
        self.contract = contracts.ContractState(
            0, self.nef, self.manifest, 0,
            types.UInt160.deserialize_from_bytes(self.raw_nef))
        self.next_contract_id = 1  # if you deploy more contracts in a same engine, the contracts must have different id
        self.previous_engine.snapshot.contracts.put(self.contract)
        self.deployed_contracts = [self.contract]
        if signers:
            signers = list(
                map(lambda signer: self.signer_auto_checker(signer, scope),
                    signers))
            self.signers = signers
        else:
            self.signers = []

        # add methods to this class for users to call contract methods
        for method in self.manifest.abi.methods:
            method_name = method.name
            method_name_with_print = method_name + '_with_print'
            if hasattr(self, method_name) or hasattr(self,
                                                     method_name_with_print):
                print(
                    f'Warning: method {method_name} or {method_name_with_print} already exists in {self}'
                )
            partial_function = partial(self.invoke_method, method_name)
            setattr(self, method_name, partial_function)
            partial_function_with_print = partial(
                self.invoke_method_with_print, method_name)
            setattr(self, method_name_with_print, partial_function_with_print)
Esempio n. 21
0
    def test_transfer_full_balance(self):
        gas = contracts.GasToken()

        manifest = contracts.ContractManifest("contract_name_to")
        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

        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 = account_from_state.balance

        engine = self.transfer_helper(gas, account_from, account_to, amount)

        # ensure the source account has balance
        engine.snapshot.storages.put(storage_key_from, storage_item_from)

        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())

        # test that the source account is no longer present in storage as the balance is zero
        self.assertIsNone(engine.snapshot.storages.try_get(storage_key_from))
Esempio n. 22
0
    def test_is_allowed_based_on_hash(self):
        # We test the group permissions where all methods are allowed to be called
        # if contract_hash is valid.
        dummy_contract_hash = types.UInt160.zero()
        contract_state = contracts.ContractState(1, contracts.NEF(),
                                                 contracts.ContractManifest(),
                                                 0, dummy_contract_hash)

        # setup an allowed permission for a contract with UInt160.zero hash for all methods
        cpd = contracts.ContractPermissionDescriptor(
            contract_hash=dummy_contract_hash)
        cp = contracts.ContractPermission(
            contract=cpd,
            methods=contracts.WildcardContainer.create_wildcard())
        self.assertTrue(cp.is_allowed(contract_state, "dummy_method"))

        # now create a different contract hash and verify it does not give permission
        contract_state.hash = types.UInt160(b'\x01' * 20)
        self.assertFalse(cp.is_allowed(contract_state, "dummy_method"))
Esempio n. 23
0
def test_native_contract(contract_hash: types.UInt160,
                         operation: str,
                         args=None):
    engine = test_engine(has_snapshot=True)
    block = test_block(0)
    # or we won't pass the native deploy call
    engine.snapshot.persisting_block = block

    sb = vm.ScriptBuilder()
    sb.emit_dynamic_call(contract_hash, operation)

    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")
    next_id = contracts.ManagementContract().get_next_available_id(
        engine.snapshot)
    contract = contracts.ContractState(next_id + 1, nef, manifest, 0,
                                       to_script_hash(nef.script))
    engine.snapshot.contracts.put(contract)

    return engine
Esempio n. 24
0
    def test_transfer_more_than_balance(self):
        gas = contracts.GasToken()
        account_from = types.UInt160.zero()
        storage_key_from = gas.key_account + account_from
        account_state = gas._state()
        account_state.balance = vm.BigInteger(123)
        storage_item_from = storage.StorageItem(account_state.to_array())

        manifest_to = contracts.ContractManifest("source_contract")
        nef_to = contracts.NEF(script=b'\x40')
        state_to = contracts.ContractState(
            1, nef_to, manifest_to, 0,
            contract_hash(types.UInt160.zero(), nef_to.checksum,
                          manifest_to.name))
        account_to = state_to.hash
        amount = account_state.balance + 1

        engine = self.transfer_helper(gas, account_from, account_to, amount)
        # ensure the source account has balance
        engine.snapshot.storages.put(storage_key_from, storage_item_from)
        engine.execute()
        self.assertEqual(1, len(engine.result_stack))
        result = engine.result_stack.pop()
        self.assertFalse(result)
    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))
Esempio n. 26
0
    def test_checkwitness_custom_groups(self):
        """
        We need to setup 2 contracts
        1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract
        2) callee_contract: uses a System.Runtime.CheckWitness
        """
        engine = test_engine(has_snapshot=True, default_script=False)
        tx = test_tx()
        engine.script_container = tx
        '''
        Create the callee contract, which does a checkwitness on its caller.
        Checkwitness shall only pass if the caller == "caller_contract" as defined by CustomGroup
        '''
        sb = vm.ScriptBuilder()
        sb.emit_syscall(
            syscall_name_to_int("System.Runtime.GetCallingScriptHash")
        )  # get script hash of "caller_contract"
        sb.emit_syscall(syscall_name_to_int("System.Runtime.CheckWitness"))
        callee_contract_script = sb.to_array()
        callee_nef = contracts.NEF(script=callee_contract_script)
        callee_contract_name = "callee_contract"
        callee_manifest = contracts.ContractManifest(callee_contract_name)
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY, True)
        ]
        callee_contract_hash = contract_hash(tx.sender, callee_nef.checksum,
                                             callee_contract_name)
        callee_contract = contracts.ContractState(1, callee_nef,
                                                  callee_manifest, 0,
                                                  callee_contract_hash)

        sb = vm.ScriptBuilder()
        sb.emit_dynamic_call(callee_contract.hash, "test_func")
        caller_script = sb.to_array()
        caller_nef = contracts.NEF(script=caller_script)
        caller_contract_name = "caller_contract"
        caller_manifest = contracts.ContractManifest(caller_contract_name)

        keypair = cryptography.KeyPair(private_key=b'\x01' * 32)
        signature = cryptography.sign(caller_script, keypair.private_key)
        caller_manifest.groups = [
            contracts.ContractGroup(public_key=keypair.public_key,
                                    signature=signature)
        ]

        caller_contract_hash = contract_hash(tx.sender, caller_nef.checksum,
                                             caller_contract_name)
        caller_contract = contracts.ContractState(2, caller_nef,
                                                  caller_manifest, 0,
                                                  caller_contract_hash)
        engine.snapshot.contracts.put(caller_contract)
        engine.snapshot.contracts.put(callee_contract)
        engine.load_script(vm.Script(caller_script))

        tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS
        tx.signers[0].allowed_groups = [keypair.public_key]

        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack))
        item = engine.result_stack.pop()
        self.assertTrue(item.to_boolean())

        # now try again but make sure it fails if the public key is not listed in the allowed groups
        engine = test_engine(has_snapshot=True, default_script=False)
        tx = test_tx()
        engine.script_container = tx

        engine.snapshot.contracts.put(caller_contract)
        engine.snapshot.contracts.put(callee_contract)
        engine.load_script(vm.Script(caller_script))

        tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS
        keypair = cryptography.KeyPair(private_key=b'\x02' * 32)
        tx.signers[0].allowed_groups = [keypair.public_key]

        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack))
        item = engine.result_stack.pop()
        self.assertFalse(item.to_boolean())