Exemplo n.º 1
0
    def test_getscriptcontainer(self):
        # first test against an invalid script container (IVerifiable, but not IOperable)
        engine = test_engine()
        container = payloads.Header._serializable_init()
        engine.script_container = container

        with self.assertRaises(ValueError) as context:
            engine.invoke_syscall_by_name("System.Runtime.GetScriptContainer")
        self.assertEqual("script container is not a valid IInteroperable type",
                         str(context.exception))

        tx = test_tx(1)
        engine = test_engine()
        engine.script_container = tx

        sb = vm.ScriptBuilder()
        sb.emit_syscall(
            syscall_name_to_int("System.Runtime.GetScriptContainer"))
        engine.load_script(vm.Script(sb.to_array()))
        engine.execute()

        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack._items))
        item = engine.result_stack.pop()
        self.assertIsInstance(item, vm.ArrayStackItem)
        # we now have a Block that has been serialized, let's check the hash
        self.assertEqual(vm.ByteStringStackItem(tx.hash().to_array()), item[0])
Exemplo n.º 2
0
    def test_gasleft(self):
        engine = test_engine()
        engine.is_test_mode = True

        sb = vm.ScriptBuilder()
        sb.emit_syscall(syscall_name_to_int("System.Runtime.GasLeft"))
        data = sb.to_array()

        # test with test mode
        engine.load_script(vm.Script(data))
        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack._items))
        item = engine.result_stack.pop()
        self.assertEqual(vm.IntegerStackItem(-1), item)

        # test with actual consumption
        engine = test_engine()
        engine.is_test_mode = False
        engine.gas_amount = 500
        # we can re-use the script
        engine.load_script(vm.Script(data))
        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack._items))
        item = engine.result_stack.pop()
        # the syscall itself costs 400
        self.assertEqual(vm.IntegerStackItem(100), item)
Exemplo n.º 3
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_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(callee_contract_script))
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY)
        ]
        callee_contract = storage.ContractState(callee_contract_script,
                                                callee_manifest)

        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.NEWARRAY0)  # args (empty array)
        sb.emit_push('test_func')  # target method name
        sb.emit_push(callee_contract.script_hash().to_array())  # contract hash
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))
        caller_script = sb.to_array()
        caller_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(caller_script))
        caller_contract = storage.ContractState(caller_script, caller_manifest)

        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())
Exemplo n.º 4
0
    def invoke_syscall_by_name(self, method: str) -> Any:
        """
        Helper function to call `on_syscall` using the syscall name.

        Args:
            method: full qualified syscall name. e.g. "System.Runtime.Platform"

        Returns: the result of the syscall handler. e.g. for "System.Runtime.Platform" returns "NEO"
        """
        return self.on_syscall(contracts.syscall_name_to_int(method))
Exemplo n.º 5
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_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(callee_contract_script))
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY)
        ]
        callee_contract = storage.ContractState(callee_contract_script,
                                                callee_manifest)

        # create caller_contract script
        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.NEWARRAY0)  # args (empty array)
        sb.emit_push('test_func')  # target method name
        sb.emit_push(callee_contract.script_hash().to_array())  # contract hash
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))
        caller_script = sb.to_array()
        caller_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(caller_script))
        caller_contract = storage.ContractState(caller_script, caller_manifest)

        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(caller_contract.script_hash().to_array(),
                         item.to_array())
Exemplo n.º 6
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_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(callee_contract_script))
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY)
        ]
        callee_contract = storage.ContractState(callee_contract_script,
                                                callee_manifest)

        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.NEWARRAY0)  # args (empty array)
        sb.emit_push('test_func')  # target method name
        sb.emit_push(callee_contract.script_hash().to_array())  # contract hash
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))
        caller_script = sb.to_array()
        caller_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(caller_script))
        caller_contract = storage.ContractState(caller_script, caller_manifest)

        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))
Exemplo n.º 7
0
    def test_is_signature_contract(self):
        """
        A valid signature contract script looks as follows
        - PUSHDATA1 (0xC)
        - LEN PUBLIC KEY (33)
        - PUBLIC KEY data
        - PUSHNULL (0xB)
        - SYSCALL (0x41)
        - "Neo.Crypto.VerifyWithECDsaSecp256r1" identifier
        """

        incorrect_script_len = b'\x01' * 10
        self.assertFalse(
            contracts.Contract.is_signature_contract(incorrect_script_len))

        # first byte should be PUSHDATA1 (0xC)
        incorrect_script_start_byte = b'\x01' * 41
        self.assertFalse(
            contracts.Contract.is_signature_contract(
                incorrect_script_start_byte))

        # second byte should be 33
        incorrect_second_byte = bytearray(b'\x01' * 41)
        incorrect_second_byte[0] = int(vm.OpCode.PUSHDATA1)
        self.assertFalse(
            contracts.Contract.is_signature_contract(incorrect_second_byte))

        # index 35 should be PUSHNULL
        incorrect_idx_35 = bytearray([0xc, 33]) + b'\01' * 39
        self.assertFalse(
            contracts.Contract.is_signature_contract(incorrect_idx_35))

        # index 36 should be SYSCALL
        incorrect_idx_36 = bytearray([0xc, 33]) + b'\01' * 39
        incorrect_idx_36[35] = int(vm.OpCode.PUSHNULL)
        self.assertFalse(
            contracts.Contract.is_signature_contract(
                incorrect_idx_36))  # index 36 should be SYSCALL

        # the last 4 bytes should be the "Neo.Crypto.VerifyWithECDsaSecp256r1" SYSCALL
        incorrect_syscall_number = bytearray([0xc, 33]) + b'\01' * 39
        incorrect_syscall_number[35] = int(vm.OpCode.PUSHNULL)
        incorrect_syscall_number[36] = int(vm.OpCode.SYSCALL)
        self.assertFalse(
            contracts.Contract.is_signature_contract(incorrect_syscall_number))

        # and finally a contract that matches the correct format
        correct = bytearray([0xc, 33]) + b'\01' * 39
        correct[35] = int(vm.OpCode.PUSHNULL)
        correct[36] = int(vm.OpCode.SYSCALL)
        correct[37:41] = contracts.syscall_name_to_int(
            "Neo.Crypto.VerifyWithECDsaSecp256r1").to_bytes(4, 'little')
        self.assertTrue(contracts.Contract.is_signature_contract(correct))
Exemplo n.º 8
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())
Exemplo n.º 9
0
 def test_get_invocation_counter_fail(self):
     # current script has no invocation calls
     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"))
     engine.load_script(vm.Script(sb.to_array()))
     engine.execute()
     self.assertEqual(vm.VMState.FAULT, engine.state)
     self.assertIn(
         "Failed to get invocation counter for the current context",
         engine.exception_message)
Exemplo n.º 10
0
    def create_signature_redeemscript(
            public_key: cryptography.ECPoint) -> bytes:
        """
        Create a single signature redeem script.

        This generated script is intended to be executed by the VM to indicate that the requested action is allowed.

        Args:
            public_key: the public key to use during verification.
        """
        sb = vm.ScriptBuilder()
        sb.emit_push(public_key.encode_point(True))
        sb.emit_syscall(
            contracts.syscall_name_to_int("System.Crypto.CheckSig"))
        return sb.to_array()
Exemplo n.º 11
0
    def is_signature_contract(script: bytes) -> bool:
        """
        Test if the provided script is signature contract.

        Args:
            script: contract script.
        """
        if len(script) != 40:
            return False

        if (script[0] != vm.OpCode.PUSHDATA1 or script[1] != 33
                or script[35] != vm.OpCode.SYSCALL
                or int.from_bytes(script[36:40], 'little') !=
                contracts.syscall_name_to_int("System.Crypto.CheckSig")):
            return False
        return True
Exemplo n.º 12
0
    def test_getexecutingscripthash(self):
        engine = test_engine()
        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.PUSH1)
        sb.emit(vm.OpCode.PUSH2)
        sb.emit(vm.OpCode.PUSH3)
        sb.emit_syscall(
            syscall_name_to_int("System.Runtime.GetExecutingScriptHash"))
        data = sb.to_array()

        engine.load_script(vm.Script(data))
        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(4, len(engine.result_stack._items))
        item = engine.result_stack.pop()
        self.assertEqual(to_script_hash(data).to_array(), item.to_array())
Exemplo n.º 13
0
    def test_getentryscripthash(self):
        # entry script hash is set on a engine.load_script
        sb = vm.ScriptBuilder()
        sb.emit_syscall(
            syscall_name_to_int("System.Runtime.GetEntryScriptHash"))
        raw_script = sb.to_array()

        engine = test_engine(default_script=False)
        ctx = engine.load_script(vm.Script(raw_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(raw_script).to_array(), item.to_array())
Exemplo n.º 14
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))
Exemplo n.º 15
0
    def create_multisig_redeemscript(
            m: int, public_keys: List[cryptography.ECPoint]) -> bytes:
        """
        Create a multi-signature redeem script requiring `m` signatures from the list `public_keys`.

        This generated script is intended to be executed by the VM to indicate that the requested action is allowed.

        Args:
            m: minimum number of signature required for signing. Can't be lower than 2.
            public_keys: public keys to use during verification.

        Raises:
            ValueError: if the minimum required signatures is not met.
            ValueError: if the maximum allowed signatures is exceeded.
            ValueError: if the maximum allowed public keys is exceeded.
        """
        if m < 1:
            raise ValueError(
                f"Minimum required signature count is 1, specified {m}.")

        if m > len(public_keys):
            raise ValueError(
                "Invalid public key count. "
                "Minimum required signatures is bigger than supplied public keys count."
            )

        if len(public_keys) > 1024:
            raise ValueError(
                f"Supplied public key count ({len(public_keys)}) exceeds maximum of 1024."
            )

        sb = vm.ScriptBuilder()
        sb.emit_push(m)
        public_keys.sort()

        for key in public_keys:
            sb.emit_push(key.encode_point(True))

        sb.emit_push(len(public_keys))
        sb.emit(vm.OpCode.PUSHNULL)
        sb.emit_syscall(
            contracts.syscall_name_to_int(
                "Neo.Crypto.CheckMultisigWithECDsaSecp256r1"))
        return sb.to_array()
Exemplo n.º 16
0
    def test_is_multisig_contract_256_pubkeys(self):
        # test handling of a large number of public keys
        # from 256 signatures and above he count is encoded in 2 bytes
        # for this test we manually encoded a length of 2 into 2 bytes
        script = bytearray([int(vm.OpCode.PUSHINT16), 2, 0])

        # add fake public keys
        for _ in range(0, 2):
            script += bytearray([int(vm.OpCode.PUSHDATA1)])
            script += bytearray([33])
            script += b'\xDD' * 33

        # and now mismatch the public key count value we say is present (0 here)
        script += bytearray([int(vm.OpCode.PUSHINT16), 0, 0])
        self.assertFalse(contracts.Contract.is_multisig_contract(script))

        # now we correct the public key count in the script and make it valid by adding the expected tail
        script[-2] = 2
        script += bytearray([int(vm.OpCode.SYSCALL)])
        script += contracts.syscall_name_to_int("System.Crypto.CheckMultisig").to_bytes(4, 'little')
        self.assertTrue(contracts.Contract.is_multisig_contract(script))
Exemplo n.º 17
0
    def test_gasleft(self):
        engine = test_engine()
        engine.is_test_mode = True

        sb = vm.ScriptBuilder()
        sb.emit_syscall(syscall_name_to_int("System.Runtime.GasLeft"))
        data = sb.to_array()

        # test with test mode
        engine.load_script(vm.Script(data))
        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack._items))
        item = engine.result_stack.pop()
        self.assertEqual(vm.IntegerStackItem(-1), item)
        """
        using (var engine = ApplicationEngine.Create(TriggerType.Application, null, null, gas:500))
        using (var script = new ScriptBuilder())
        {
            script.EmitSysCall(ApplicationEngine.System_Runtime_GasLeft);
            engine.LoadScript(script.ToArray());
            Assert.AreEqual(VMState.HALT, engine.Execute());
            Assert.AreEqual(engine.ResultStack.Count, 1);
            Console.WriteLine(engine.ResultStack.Pop().GetInteger());
        }
        """
        # test with actual consumption
        engine = test_engine()
        engine.is_test_mode = False
        engine.gas_amount = 500
        # we can re-use the script
        engine.load_script(vm.Script(data))
        engine.execute()
        self.assertEqual(vm.VMState.HALT, engine.state)
        self.assertEqual(1, len(engine.result_stack._items))
        item = engine.result_stack.pop()
        self.assertEqual(vm.IntegerStackItem(20), item)
Exemplo n.º 18
0
 def _create_genesis_block() -> payloads.Block:
     script = vm.ScriptBuilder().emit_syscall(
         contracts.syscall_name_to_int("Neo.Native.Deploy")).to_array()
     b = payloads.Block(
         version=0,
         prev_hash=types.UInt256.zero(),
         timestamp=int(
             datetime(2016, 7, 15, 15, 8, 21, 0, timezone.utc).timestamp() *
             1000),
         index=0,
         next_consensus=Blockchain.get_consensus_address(
             settings.standby_validators),
         witness=payloads.Witness(
             invocation_script=b'',
             verification_script=b'\x11'  # (OpCode.PUSH1)
         ),
         consensus_data=payloads.ConsensusData(primary_index=0,
                                               nonce=2083236893),
         transactions=[
             payloads.Transaction(
                 version=0,
                 script=script,
                 system_fee=0,
                 network_fee=0,
                 nonce=0,
                 valid_until_block=0,
                 signers=[
                     payloads.Signer(account=to_script_hash(b'\x11'),
                                     scope=payloads.WitnessScope.FEE_ONLY)
                 ],
                 witnesses=[
                     payloads.Witness(invocation_script=b'',
                                      verification_script=b'\x11')
                 ])
         ])
     return b
Exemplo n.º 19
0
 def test_contract_create_ok(self):
     engine = test_engine(has_snapshot=True)
     sb = vm.ScriptBuilder()
     sb.emit_push(str(hello_world_manifest).encode())
     sb.emit_push(hello_world_nef.script)
     sb.emit_syscall(syscall_name_to_int("System.Contract.Create"))
     engine.load_script(vm.Script(sb.to_array()))
     engine.execute()
     self.assertEqual(vm.VMState.HALT, engine.state)
     self.assertEqual(1, len(engine.result_stack._items))
     item = engine.result_stack.pop()
     # returns a serialized contract state
     self.assertEqual(hello_world_nef.script, item[0].to_array())
     self.assertEqual(
         hello_world_manifest,
         contracts.ContractManifest.from_json(json.loads(
             item[1].to_array())))
     self.assertEqual(
         contracts.ContractFeatures.HAS_STORAGE
         in hello_world_manifest.features, item[2])
     self.assertEqual(
         contracts.ContractFeatures.PAYABLE
         in hello_world_manifest.features, item[3])
     return engine
Exemplo n.º 20
0
    def parse_as_multisig_contract(
            script: bytes) -> Tuple[bool, int, List[cryptography.ECPoint]]:
        """
        Try to parse script as multisig contract and extract related data.

        Args:
            script: array of vm byte code

        Returns:
            bool: True if the script passes as a valid multisignature contract script. False otherwise
            int: the signing threshold if validation passed. 0 otherwise
            list[ECPoint]: the public keys in the script if valiation passed. An empty array otherwise.
        """
        script = bytes(script)
        VALIDATION_FAILURE: Tuple[bool, int,
                                  List[cryptography.ECPoint]] = (False, 0, [])

        len_script = len(script)
        if len_script < 42:
            return VALIDATION_FAILURE

        # read signature length, which is encoded as variable_length
        first_byte = script[0]
        if first_byte == int(vm.OpCode.PUSHINT8):
            signature_threshold = script[1]
            i = 2
        elif first_byte == int(vm.OpCode.PUSHINT16):
            signature_threshold = int.from_bytes(script[1:3],
                                                 'little',
                                                 signed=False)
            i = 3
        elif int(vm.OpCode.PUSH1) <= first_byte <= int(vm.OpCode.PUSH16):
            signature_threshold = first_byte - int(vm.OpCode.PUSH0)
            i = 1
        else:
            return VALIDATION_FAILURE

        if signature_threshold < 1 or signature_threshold > 1024:
            return VALIDATION_FAILURE

        # try reading public keys and do a basic format validation
        pushdata1 = int(vm.OpCode.PUSHDATA1)
        public_keys = []
        while script[i] == pushdata1:
            if len_script <= i + 35:
                return VALIDATION_FAILURE
            if script[i + 1] != 33:
                return VALIDATION_FAILURE
            public_keys.append(
                cryptography.ECPoint.deserialize_from_bytes(script[i + 2:i +
                                                                   2 + 33]))
            i += 35

        public_key_count = len(public_keys)
        if public_key_count < signature_threshold or public_key_count > 1024:
            return VALIDATION_FAILURE

        # validate that the number of collected public keys match the expected count
        value = script[i]
        if value == int(vm.OpCode.PUSHINT8):
            if len_script <= i + 1 or public_key_count != script[i + 1]:
                return VALIDATION_FAILURE
            i += 2
        elif value == int(vm.OpCode.PUSHINT16):
            if len_script < i + 3 or public_key_count != int.from_bytes(
                    script[i + 1:i + 3], 'little', signed=False):
                return VALIDATION_FAILURE
            i += 3
        elif int(vm.OpCode.PUSH1) <= value <= int(vm.OpCode.PUSH16):
            if public_key_count != value - int(vm.OpCode.PUSH0):
                return VALIDATION_FAILURE
            i += 1
        else:
            return VALIDATION_FAILURE

        if len_script != i + 5:
            return VALIDATION_FAILURE

        if script[i] != int(vm.OpCode.SYSCALL):
            return VALIDATION_FAILURE
        i += 1

        syscall_num = int.from_bytes(script[i:i + 4], 'little')
        if syscall_num != contracts.syscall_name_to_int(
                "System.Crypto.CheckMultisig"):
            return VALIDATION_FAILURE
        return True, signature_threshold, public_keys
Exemplo n.º 21
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

        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_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(callee_contract_script))
        callee_manifest.abi.methods = [
            contracts.ContractMethodDescriptor(
                "test_func", 0, [], contracts.ContractParameterType.ANY)
        ]
        callee_contract = storage.ContractState(callee_contract_script,
                                                callee_manifest)

        sb = vm.ScriptBuilder()
        sb.emit(vm.OpCode.NEWARRAY0)  # args (empty array)
        sb.emit_push('test_func')  # target method name
        sb.emit_push(callee_contract.script_hash().to_array())  # contract hash
        sb.emit_syscall(syscall_name_to_int("System.Contract.Call"))
        caller_script = sb.to_array()

        caller_manifest = contracts.ContractManifest(
            contract_hash=to_script_hash(caller_script))
        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 = storage.ContractState(caller_script, caller_manifest)
        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())
Exemplo n.º 22
0
    def is_multisig_contract(script: bytes) -> bool:
        """
        Test if the provided script is multi-signature contract.

        Args:
            script: contract script.
        """

        len_script = len(script)
        if len_script < 43:
            return False

        # read signature length, which is encoded as variable_length
        first_byte = script[0]
        if first_byte == int(vm.OpCode.PUSHINT8):
            signature_count = script[1]
            i = 2
        elif first_byte == int(vm.OpCode.PUSHINT16):
            signature_count = int.from_bytes(script[1:3],
                                             'little',
                                             signed=False)
            i = 3
        elif int(vm.OpCode.PUSH1) <= first_byte <= int(vm.OpCode.PUSH16):
            signature_count = first_byte - int(vm.OpCode.PUSH0)
            i = 1
        else:
            return False

        if signature_count < 1 or signature_count > 1024:
            return False

        # try reading public keys and do a basic format validation
        pushdata1 = int(vm.OpCode.PUSHDATA1)
        public_key_count = 0
        while script[i] == pushdata1:
            if len_script <= i + 35:
                return False
            if script[i + 1] != 33:
                return False
            i += 35
            public_key_count += 1

        if public_key_count < signature_count or public_key_count > 1024:
            return False

        # validate that the number of collected public keys match the expected count
        value = script[i]
        if value == int(vm.OpCode.PUSHINT8):
            if len_script <= i + 1 or public_key_count != script[i + 1]:
                return False
            i += 2
        elif value == int(vm.OpCode.PUSHINT16):
            if len_script < i + 3 or public_key_count != int.from_bytes(
                    script[i + 1:i + 3], 'little', signed=False):
                return False
            i += 3
        elif int(vm.OpCode.PUSH1) <= value <= int(vm.OpCode.PUSH16):
            if public_key_count != value - int(vm.OpCode.PUSH0):
                return False
            i += 1
        else:
            return False

        if len_script != i + 6:
            return False

        if script[i] != int(vm.OpCode.PUSHNULL):
            return False
        if script[i + 1] != int(vm.OpCode.SYSCALL):
            return False
        i += 2

        syscall_num = int.from_bytes(script[i:i + 4], 'little')
        if syscall_num != contracts.syscall_name_to_int(
                "Neo.Crypto.CheckMultisigWithECDsaSecp256r1"):
            return False
        return True
Exemplo n.º 23
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())