From a1b6cd8ef06324daf33105ee7c513360a2c12702 Mon Sep 17 00:00:00 2001 From: Arjan Zijderveld <5286904+arjanz@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:50:55 +0200 Subject: [PATCH] Updated runtime api calls handling logic --- scalecodec/type_registry/core.json | 98 +++++++++++++++++------------- scalecodec/types.py | 76 ++++++++++++++++++++++- test/test_metadata.py | 8 +++ 3 files changed, 139 insertions(+), 43 deletions(-) diff --git a/scalecodec/type_registry/core.json b/scalecodec/type_registry/core.json index a890993..3d0e8f6 100644 --- a/scalecodec/type_registry/core.json +++ b/scalecodec/type_registry/core.json @@ -1146,6 +1146,7 @@ "CustomValueMetadata15": "Bytes", "RuntimeApiMetadataV15": { "type": "struct", + "base_class": "GenericRuntimeApiMetadata", "type_mapping": [ [ "name", @@ -1163,6 +1164,7 @@ }, "RuntimeApiMethodMetadataV15": { "type": "struct", + "base_class": "GenericRuntimeApiMethodMetadata", "type_mapping": [ [ "name", @@ -1195,6 +1197,59 @@ ] ] }, + "RuntimeApiMetadataV14": { + "type": "struct", + "base_class": "LegacyRuntimeApiMetadata", + "type_mapping": [ + [ + "name", + "Text" + ], + [ + "methods", + "Vec" + ], + [ + "docs", + "Vec" + ] + ] + }, + "RuntimeApiMethodMetadataV14": { + "type": "struct", + "base_class": "LegacyRuntimeApiMethodMetadata", + "type_mapping": [ + [ + "name", + "Text" + ], + [ + "inputs", + "Vec" + ], + [ + "output", + "String" + ], + [ + "docs", + "Vec" + ] + ] + }, + "RuntimeApiMethodParamMetadataV14": { + "type": "struct", + "type_mapping": [ + [ + "name", + "Text" + ], + [ + "type", + "String" + ] + ] + }, "PalletMetadataV14": { "type": "struct", "base_class": "ScaleInfoPalletMetadata", @@ -1909,46 +1964,7 @@ ] ] }, - "ContractExecResult": "ContractExecResultTo267", - "RuntimeCallDefinition": { - "type": "struct", - "base_class": "GenericRuntimeCallDefinition", - "type_mapping": [ - [ - "api", - "String" - ], - [ - "method", - "String" - ], - [ - "description", - "String" - ], - [ - "params", - "Vec" - ], - [ - "type", - "String" - ] - ] - }, - "RuntimeCallDefinitionParam": { - "type": "struct", - "type_mapping": [ - [ - "name", - "String" - ], - [ - "type", - "String" - ] - ] - } + "ContractExecResult": "ContractExecResultTo267" }, "runtime_api": { "AccountNonceApi": { @@ -3008,8 +3024,8 @@ ["nonce", "H64"] ] }, - "EthBloom": "H2048", "H2048": "[u8; 256]", + "EthBloom": "H2048", "H64": "[u8; 8]", "Permill": "u32", "TransactionV2": { diff --git a/scalecodec/types.py b/scalecodec/types.py index 384436f..0b196d2 100644 --- a/scalecodec/types.py +++ b/scalecodec/types.py @@ -2192,6 +2192,42 @@ def get_metadata_pallet(self, name: str) -> 'GenericPalletMetadata': if pallet.value['name'] == name: return pallet + def get_runtime_apis(self): + if self.index >= 15: + return self[1]['apis'] + else: + return [self.get_runtime_api(name) for name in self.runtime_config.type_registry.get("runtime_api").keys()] + + def get_runtime_api(self, name: str) -> Optional['GenericRuntimeApiMetadata']: + + if self.index >= 15: + for runtime_api in self[1]['apis']: + if runtime_api.value['name'] == name: + return runtime_api + else: + # Legacy: Runtime APIs not included in metadata + runtime_api_data = self.runtime_config.type_registry.get("runtime_api", {}).get(name) + + if runtime_api_data: + runtime_api = self.runtime_config.create_scale_object("RuntimeApiMetadataV14") + + # Transform data + data = { + 'name': name, + 'methods': [{ + 'name': m_name, 'inputs': m_data['params'], 'output': m_data['type'], + 'docs': [m_data['description']] + } for m_name, m_data in runtime_api_data['methods'].items()], + 'docs': [] + } + + runtime_api.encode(data) + + # Add embedded types to type registry + self.runtime_config.update_type_registry_types(runtime_api_data.get("types", {})) + + return runtime_api + def process(self): value = super().process() @@ -2326,6 +2362,12 @@ def get_signed_extensions(self): return signed_extensions + def get_runtime_api(self, name: str): + return self.get_metadata().get_runtime_api(name) + + def get_runtime_apis(self): + return self.get_metadata().get_runtime_apis() + class GenericStringType(String): @property @@ -2755,7 +2797,28 @@ def get_param_info(self, max_recursion: int = TYPE_DECOMP_MAX_RECURSIVE) -> list return param_info -class GenericRuntimeCallDefinition(Struct): +class GenericRuntimeApiMetadata(Struct): + + def get_methods(self): + return list(self.value_object['methods']) + + def get_method(self, name: str) -> Optional['GenericRuntimeApiMethodMetadata']: + for method in self.value_object['methods']: + if name == method.value['name']: + return method + + +class LegacyRuntimeApiMetadata(GenericRuntimeApiMetadata): + pass + + +class GenericRuntimeApiMethodMetadata(Struct): + + def get_params(self): + return [{'name': p['name'], 'type': f'scale_info::{p["type"]}'} for p in self.value['inputs']] + + def get_return_type_string(self): + return f"scale_info::{self.value['output']}" def get_param_info(self, max_recursion: int = TYPE_DECOMP_MAX_RECURSIVE) -> list: """ @@ -2766,13 +2829,22 @@ def get_param_info(self, max_recursion: int = TYPE_DECOMP_MAX_RECURSIVE) -> list list """ param_info = [] - for param in self.value['params']: + for param in self.get_params(): scale_type = self.runtime_config.create_scale_object(param['type']) param_info.append(scale_type.generate_type_decomposition(max_recursion=max_recursion)) return param_info +class LegacyRuntimeApiMethodMetadata(GenericRuntimeApiMethodMetadata): + + def get_params(self): + return [{'name': p['name'], 'type': p["type"]} for p in self.value['inputs']] + + def get_return_type_string(self): + return self.value['output'] + + class GenericEventMetadata(Struct): @property diff --git a/test/test_metadata.py b/test/test_metadata.py index 048e361..a259d7a 100644 --- a/test/test_metadata.py +++ b/test/test_metadata.py @@ -112,6 +112,9 @@ def test_metadata_registry_decode_v14(self): self.assertGreater(len(metadata_obj.get_signed_extensions().items()), 0) + # Test runtime api + self.assertIsNotNone(metadata_obj.get_runtime_api('Core')) + def test_metadata_registry_decode_v15(self): metadata_obj = self.runtime_config.create_scale_object( "MetadataVersioned", data=ScaleBytes(self.metadata_fixture_dict['V15']) @@ -125,6 +128,11 @@ def test_metadata_registry_decode_v15(self): self.assertGreater(len(metadata_obj.get_signed_extensions().items()), 0) + self.assertIsNotNone(metadata_obj.get_runtime_api('Core')) + + method = metadata_obj.get_runtime_api('AccountNonceApi').get_method('account_nonce') + + # def test_pickle_test(self): # metadata_obj = self.runtime_config.create_scale_object( # "MetadataVersioned", data=ScaleBytes(self.metadata_fixture_dict['V14'])