Exemplo n.º 1
0
    def test_can_call(self):
        # create a default contract, which is allowed to call any other contract and any other method
        cm = contracts.ContractManifest()
        target_manifest = contracts.ContractManifest()
        target_manifest.abi.contract_hash = types.UInt160.from_string("11" *
                                                                      20)
        self.assertTrue(cm.can_call(target_manifest, "some_method"))

        # now add a permission that allows all methods, but for a different contract hash
        contract_hash = types.UInt160.from_string("22" * 20)
        cpd = contracts.ContractPermissionDescriptor(
            contract_hash=contract_hash)
        cp = contracts.ContractPermission(
            contract=cpd,
            methods=contracts.WildcardContainer.create_wildcard())
        cm.permissions = [cp]
        self.assertFalse(cm.can_call(target_manifest, "some_method"))

        # now change the permissions (specifically the contract_hash) to allow calling
        new_contract_hash = types.UInt160.zero()
        cpd = contracts.ContractPermissionDescriptor(
            contract_hash=new_contract_hash)
        cp = contracts.ContractPermission(
            contract=cpd,
            methods=contracts.WildcardContainer.create_wildcard())
        cm.permissions = [cp]
        self.assertTrue(cm.can_call(target_manifest, "some_method"))
Exemplo n.º 2
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"))
Exemplo n.º 3
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
        mock_manifest = mock.MagicMock()
        mock_manifest.contract_hash = types.UInt160.zero()

        # setup an allowed permission for a contract with UInt160.zero hash for 2 methods
        cpd = contracts.ContractPermissionDescriptor(
            contract_hash=types.UInt160.zero())
        cp = contracts.ContractPermission(
            contract=cpd,
            methods=contracts.WildcardContainer(data=['method1', 'method2']))
        self.assertTrue(cp.is_allowed(mock_manifest, "method1"))
        self.assertTrue(cp.is_allowed(mock_manifest, "method2"))
        self.assertFalse(cp.is_allowed(mock_manifest, "method3"))
Exemplo n.º 4
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"))
Exemplo n.º 5
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.
        mock_manifest = mock.MagicMock()
        mock_manifest.contract_hash = types.UInt160.zero()

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

        # now create a different contract hash and verify it does not give permission
        mock_manifest.contract_hash = types.UInt160.from_string("01" * 20)
        self.assertFalse(cp.is_allowed(mock_manifest, "dummy_method"))
Exemplo n.º 6
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"))
Exemplo n.º 7
0
    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))
Exemplo n.º 8
0
    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))