From 4dc73d695af00a69f53b6f25d37616891752380b Mon Sep 17 00:00:00 2001 From: Arjan Zijderveld <5286904+arjanz@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:22:07 +0200 Subject: [PATCH] Added ink! V5 support (#395) --- examples/assets/flipper-v5.json | 463 +++++++++++++++++++++++++++ examples/assets/flipper-v5.wasm | Bin 0 -> 11756 bytes examples/create_and_exec_contract.py | 6 +- substrateinterface/contracts.py | 29 +- test/fixtures/flipper-v5.json | 463 +++++++++++++++++++++++++++ test/test_contracts.py | 54 ++++ 6 files changed, 1010 insertions(+), 5 deletions(-) create mode 100644 examples/assets/flipper-v5.json create mode 100644 examples/assets/flipper-v5.wasm create mode 100644 test/fixtures/flipper-v5.json diff --git a/examples/assets/flipper-v5.json b/examples/assets/flipper-v5.json new file mode 100644 index 0000000..73a10f1 --- /dev/null +++ b/examples/assets/flipper-v5.json @@ -0,0 +1,463 @@ +{ + "source": { + "hash": "0x04208d5b3de1808ed1ccf83d08bdb5e3974bba7c4af8d5fc1ed6d6c725155c2e", + "language": "ink! 5.0.0", + "compiler": "rustc 1.81.0-nightly", + "build_info": { + "build_mode": "Debug", + "cargo_contract_version": "4.1.1", + "rust_toolchain": "nightly-aarch64-apple-darwin", + "wasm_opt_settings": { + "keep_debug_symbols": false, + "optimization_passes": "Z" + } + } + }, + "contract": { + "name": "flipper5", + "version": "0.1.0", + "authors": [ + "[your_name] <[your_email]>" + ] + }, + "image": null, + "spec": { + "constructors": [ + { + "args": [ + { + "label": "init_value", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "default": false, + "docs": [ + "Constructor that initializes the `bool` value to the given `init_value`." + ], + "label": "new", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 2 + }, + "selector": "0x9bae9d5e" + }, + { + "args": [], + "default": false, + "docs": [ + "Constructor that initializes the `bool` value to `false`.", + "", + "Constructors can delegate to other constructors." + ], + "label": "default", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 2 + }, + "selector": "0xed4b9d1b" + } + ], + "docs": [], + "environment": { + "accountId": { + "displayName": [ + "AccountId" + ], + "type": 7 + }, + "balance": { + "displayName": [ + "Balance" + ], + "type": 9 + }, + "blockNumber": { + "displayName": [ + "BlockNumber" + ], + "type": 12 + }, + "chainExtension": { + "displayName": [ + "ChainExtension" + ], + "type": 13 + }, + "hash": { + "displayName": [ + "Hash" + ], + "type": 10 + }, + "maxEventTopics": 4, + "staticBufferSize": 16384, + "timestamp": { + "displayName": [ + "Timestamp" + ], + "type": 11 + } + }, + "events": [ + { + "args": [ + { + "docs": [], + "indexed": true, + "label": "value", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "docs": [], + "label": "Flipped", + "module_path": "flipper5::flipper5", + "signature_topic": "0x529cf346ddea0543633a1d91f021fa688fb7fe023ee1fb83ad031fe005673254" + }, + { + "args": [ + { + "docs": [], + "indexed": true, + "label": "test_value", + "type": { + "displayName": [ + "u8" + ], + "type": 6 + } + } + ], + "docs": [], + "label": "Test", + "module_path": "flipper5::flipper5", + "signature_topic": "0xc04204b5a8f12647ea7e92832f7608f4b5279fbcd2181333ff6a96906e5d555f" + } + ], + "lang_error": { + "displayName": [ + "ink", + "LangError" + ], + "type": 4 + }, + "messages": [ + { + "args": [], + "default": false, + "docs": [ + " A message that can be called on instantiated contracts.", + " This one flips the value of the stored `bool` from `true`", + " to `false` and vice versa." + ], + "label": "flip", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 2 + }, + "selector": "0x633aa551" + }, + { + "args": [], + "default": false, + "docs": [ + " Simply returns the current value of our `bool`." + ], + "label": "get", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 5 + }, + "selector": "0x2f865bd9" + } + ] + }, + "storage": { + "root": { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x00000000", + "ty": 0 + } + }, + "name": "value" + } + ], + "name": "Flipper5" + } + }, + "root_key": "0x00000000", + "ty": 1 + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "primitive": "bool" + } + } + }, + { + "id": 1, + "type": { + "def": { + "composite": { + "fields": [ + { + "name": "value", + "type": 0, + "typeName": ",>>::Type" + } + ] + } + }, + "path": [ + "flipper5", + "flipper5", + "Flipper5" + ] + } + }, + { + "id": 2, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 3 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 4 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 3 + }, + { + "name": "E", + "type": 4 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 3, + "type": { + "def": { + "tuple": [] + } + } + }, + { + "id": 4, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 1, + "name": "CouldNotReadInput" + } + ] + } + }, + "path": [ + "ink_primitives", + "LangError" + ] + } + }, + { + "id": 5, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 0 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 4 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 0 + }, + { + "name": "E", + "type": 4 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 6, + "type": { + "def": { + "primitive": "u8" + } + } + }, + { + "id": 7, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 8, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "AccountId" + ] + } + }, + { + "id": 8, + "type": { + "def": { + "array": { + "len": 32, + "type": 6 + } + } + } + }, + { + "id": 9, + "type": { + "def": { + "primitive": "u128" + } + } + }, + { + "id": 10, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 8, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "Hash" + ] + } + }, + { + "id": 11, + "type": { + "def": { + "primitive": "u64" + } + } + }, + { + "id": 12, + "type": { + "def": { + "primitive": "u32" + } + } + }, + { + "id": 13, + "type": { + "def": { + "variant": {} + }, + "path": [ + "ink_env", + "types", + "NoChainExtension" + ] + } + } + ], + "version": 5 +} \ No newline at end of file diff --git a/examples/assets/flipper-v5.wasm b/examples/assets/flipper-v5.wasm new file mode 100644 index 0000000000000000000000000000000000000000..54f1aa1a02eb2d44a71fc65756e2916a8a2dd4fa GIT binary patch literal 11756 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 boTSR)W`0^T-9Lx@f1lqz?CMs2lX?4JB3rv_ literal 0 HcmV?d00001 diff --git a/examples/create_and_exec_contract.py b/examples/create_and_exec_contract.py index 9fc0dbb..6edc837 100644 --- a/examples/create_and_exec_contract.py +++ b/examples/create_and_exec_contract.py @@ -37,15 +37,15 @@ # Create contract instance from deterministic address contract = ContractInstance.create_from_address( contract_address=contract_address, - metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v4.json'), + metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.json'), substrate=substrate ) else: # Upload WASM code code = ContractCode.create_from_contract_files( - metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v4.json'), - wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v4.wasm'), + metadata_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.json'), + wasm_file=os.path.join(os.path.dirname(__file__), 'assets', 'flipper-v5.wasm'), substrate=substrate ) diff --git a/substrateinterface/contracts.py b/substrateinterface/contracts.py index 14945d4..2ca1ab9 100644 --- a/substrateinterface/contracts.py +++ b/substrateinterface/contracts.py @@ -90,7 +90,7 @@ def __convert_to_latest_metadata(self): elif 'version' in self.metadata_dict: self.metadata_version = int(self.metadata_dict['version']) - if self.metadata_version is None or self.metadata_version > 4: + if self.metadata_version is None or self.metadata_version > 5: raise ContractMetadataParseException("Unsupported metadata version") if 1 <= self.metadata_version <= 3: @@ -126,6 +126,13 @@ def replace_name_with_label(obj): for idx, c in enumerate(self.metadata_dict['spec']['constructors']): c["payable"] = True + # V4 -> V5: new event fields: module_path and signature_topic + if self.metadata_version <= 4: + for idx, c in enumerate(self.metadata_dict['spec']['events']): + c["module_path"] = None + c["signature_topic"] = None + + def __parse_metadata(self): self.__convert_to_latest_metadata() @@ -392,6 +399,13 @@ def get_event_data(self, event_id: int) -> dict: return self.metadata_dict['spec']['events'][event_id] + def get_event_id_by_topic(self, topic: str) -> Optional[int]: + for event_id, event in enumerate(self.metadata_dict['spec']['events']): + if topic == event['signature_topic']: + return event_id + + # raise ValueError(f'Contract event for topic "{topic}" not found') + class ContractEvent(ScaleType): @@ -485,9 +499,20 @@ def process_events(self): if self.substrate.implements_scaleinfo(): if event.value['module_id'] == 'Contracts' and event.value['event_id'] == 'ContractEmitted' and event.value['attributes']['contract'] == self.contract_address: + + contract_data = event['event'][1][1]['data'].value_object + + if self.contract_metadata.metadata_version >= 5: + # Find corresponding contract event by event topic + for topic in event.value['topics']: + event_id = self.contract_metadata.get_event_id_by_topic(topic) + if event_id is not None: + event_bytes = self.substrate.create_scale_object("U8").encode(event_id).data + contract_data = event_bytes + contract_data + # Create contract event contract_event_obj = ContractEvent( - data=ScaleBytes(event['event'][1][1]['data'].value_object), + data=ScaleBytes(contract_data), runtime_config=self.substrate.runtime_config, contract_metadata=self.contract_metadata ) diff --git a/test/fixtures/flipper-v5.json b/test/fixtures/flipper-v5.json new file mode 100644 index 0000000..73a10f1 --- /dev/null +++ b/test/fixtures/flipper-v5.json @@ -0,0 +1,463 @@ +{ + "source": { + "hash": "0x04208d5b3de1808ed1ccf83d08bdb5e3974bba7c4af8d5fc1ed6d6c725155c2e", + "language": "ink! 5.0.0", + "compiler": "rustc 1.81.0-nightly", + "build_info": { + "build_mode": "Debug", + "cargo_contract_version": "4.1.1", + "rust_toolchain": "nightly-aarch64-apple-darwin", + "wasm_opt_settings": { + "keep_debug_symbols": false, + "optimization_passes": "Z" + } + } + }, + "contract": { + "name": "flipper5", + "version": "0.1.0", + "authors": [ + "[your_name] <[your_email]>" + ] + }, + "image": null, + "spec": { + "constructors": [ + { + "args": [ + { + "label": "init_value", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "default": false, + "docs": [ + "Constructor that initializes the `bool` value to the given `init_value`." + ], + "label": "new", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 2 + }, + "selector": "0x9bae9d5e" + }, + { + "args": [], + "default": false, + "docs": [ + "Constructor that initializes the `bool` value to `false`.", + "", + "Constructors can delegate to other constructors." + ], + "label": "default", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 2 + }, + "selector": "0xed4b9d1b" + } + ], + "docs": [], + "environment": { + "accountId": { + "displayName": [ + "AccountId" + ], + "type": 7 + }, + "balance": { + "displayName": [ + "Balance" + ], + "type": 9 + }, + "blockNumber": { + "displayName": [ + "BlockNumber" + ], + "type": 12 + }, + "chainExtension": { + "displayName": [ + "ChainExtension" + ], + "type": 13 + }, + "hash": { + "displayName": [ + "Hash" + ], + "type": 10 + }, + "maxEventTopics": 4, + "staticBufferSize": 16384, + "timestamp": { + "displayName": [ + "Timestamp" + ], + "type": 11 + } + }, + "events": [ + { + "args": [ + { + "docs": [], + "indexed": true, + "label": "value", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "docs": [], + "label": "Flipped", + "module_path": "flipper5::flipper5", + "signature_topic": "0x529cf346ddea0543633a1d91f021fa688fb7fe023ee1fb83ad031fe005673254" + }, + { + "args": [ + { + "docs": [], + "indexed": true, + "label": "test_value", + "type": { + "displayName": [ + "u8" + ], + "type": 6 + } + } + ], + "docs": [], + "label": "Test", + "module_path": "flipper5::flipper5", + "signature_topic": "0xc04204b5a8f12647ea7e92832f7608f4b5279fbcd2181333ff6a96906e5d555f" + } + ], + "lang_error": { + "displayName": [ + "ink", + "LangError" + ], + "type": 4 + }, + "messages": [ + { + "args": [], + "default": false, + "docs": [ + " A message that can be called on instantiated contracts.", + " This one flips the value of the stored `bool` from `true`", + " to `false` and vice versa." + ], + "label": "flip", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 2 + }, + "selector": "0x633aa551" + }, + { + "args": [], + "default": false, + "docs": [ + " Simply returns the current value of our `bool`." + ], + "label": "get", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 5 + }, + "selector": "0x2f865bd9" + } + ] + }, + "storage": { + "root": { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x00000000", + "ty": 0 + } + }, + "name": "value" + } + ], + "name": "Flipper5" + } + }, + "root_key": "0x00000000", + "ty": 1 + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "primitive": "bool" + } + } + }, + { + "id": 1, + "type": { + "def": { + "composite": { + "fields": [ + { + "name": "value", + "type": 0, + "typeName": ",>>::Type" + } + ] + } + }, + "path": [ + "flipper5", + "flipper5", + "Flipper5" + ] + } + }, + { + "id": 2, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 3 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 4 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 3 + }, + { + "name": "E", + "type": 4 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 3, + "type": { + "def": { + "tuple": [] + } + } + }, + { + "id": 4, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 1, + "name": "CouldNotReadInput" + } + ] + } + }, + "path": [ + "ink_primitives", + "LangError" + ] + } + }, + { + "id": 5, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 0 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 4 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 0 + }, + { + "name": "E", + "type": 4 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 6, + "type": { + "def": { + "primitive": "u8" + } + } + }, + { + "id": 7, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 8, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "AccountId" + ] + } + }, + { + "id": 8, + "type": { + "def": { + "array": { + "len": 32, + "type": 6 + } + } + } + }, + { + "id": 9, + "type": { + "def": { + "primitive": "u128" + } + } + }, + { + "id": 10, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 8, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "Hash" + ] + } + }, + { + "id": 11, + "type": { + "def": { + "primitive": "u64" + } + } + }, + { + "id": 12, + "type": { + "def": { + "primitive": "u32" + } + } + }, + { + "id": 13, + "type": { + "def": { + "variant": {} + }, + "path": [ + "ink_env", + "types", + "NoChainExtension" + ] + } + } + ], + "version": 5 +} \ No newline at end of file diff --git a/test/test_contracts.py b/test/test_contracts.py index 1075696..432a799 100644 --- a/test/test_contracts.py +++ b/test/test_contracts.py @@ -409,5 +409,59 @@ def setUp(self) -> None: ) +class FlipperInstanceV5TestCase(FlipperInstanceTestCase): + + @classmethod + def setUpClass(cls): + + class MockedSubstrateInterface(SubstrateInterface): + + def rpc_request(self, method, params, result_handler=None): + if method == 'state_call': + return { + 'jsonrpc': '2.0', + 'result': '0x1a987a663dbd8e5cf16786bc0100010000000000000000000000000000000000000000000008000000', + 'id': 16 + } + if method == 'contracts_call': + return { + 'jsonrpc': '2.0', + 'result': { + 'gasConsumed': 7419127834, + 'gasRequired': 74999922688, + 'storageDeposit': {'charge': '0x0'}, + 'debugMessage': '', + 'result': {'Ok': {'flags': 0, 'data': '0x0000'}} + }, + 'id': self.request_id} + + return super().rpc_request(method, params, result_handler) + + cls.substrate = MockedSubstrateInterface( + url=settings.KUSAMA_NODE_URL, type_registry_preset='canvas', type_registry={'types': {"ContractExecResult": "ContractExecResultTo269"}} + ) + + cls.keypair = Keypair.create_from_uri('//Alice') + + def setUp(self) -> None: + self.contract = ContractInstance.create_from_address( + contract_address="5DaohteAvvR9PZEhynqWvbFT8HEaHNuiiPTZV61VEUHnqsfU", + metadata_file=os.path.join(os.path.dirname(__file__), 'fixtures', 'flipper-v5.json'), + substrate=self.substrate + ) + + def test_instance_read(self): + + result = self.contract.read(self.keypair, 'get') + + self.assertEqual({'Ok': False}, result.contract_result_data.value) + + def test_instance_read_at_not_best_block(self): + parent_hash = self.substrate.get_block_header()['header']['parentHash'] + result = self.contract.read(self.keypair, 'get', block_hash=parent_hash) + + self.assertEqual({'Ok': False}, result.contract_result_data.value) + + if __name__ == '__main__': unittest.main()