polkascan / py-substrate-interface

Python Substrate Interface
https://polkascan.github.io/py-substrate-interface/
Apache License 2.0
240 stars 116 forks source link

Some runtime_call can not decode parameters #339

Closed BulatSaif closed 1 year ago

BulatSaif commented 1 year ago

I have a runtime_call, which according to documentation should work:

result = substrate.runtime_call("TransactionPaymentCallApi", "query_call_info", [call, 0])
Full script 1 ```python #!/usr/bin/env python3 from substrateinterface import SubstrateInterface, Keypair keypair = Keypair.create_from_mnemonic(Keypair.generate_mnemonic()) substrate = SubstrateInterface(url='wss://rpc.polkadot.io') call = substrate.compose_call( call_module='Balances', call_function='transfer', call_params={ 'dest': 'EaG2CRhJWPb7qmdcJvy3LiWdh26Jreu9Dx6R1rXxPmYXoDk', 'value': 3 * 10 ** 3 } ) result = substrate.runtime_call("TransactionPaymentCallApi", "query_call_info", [call, 0]) print(result) ```

But it fail with error:

$ python ./get_weight.py
Traceback (most recent call last):
  File "./get_weight.py", line 16, in <module>
    result = substrate.runtime_call("TransactionPaymentCallApi", "query_call_info", [call, 0])
  File "/home/bulat/workdir/venv/lib/python3.8/site-packages/substrateinterface/base.py", line 1258, in runtime_call
    result_obj.decode(ScaleBytes(result_data['result']))
  File "/home/bulat/workdir/venv/lib/python3.8/site-packages/scalecodec/base.py", line 874, in decode
    self.value_serialized = self.process()
  File "/home/bulat/workdir/venv/lib/python3.8/site-packages/scalecodec/types.py", line 572, in process
    field_obj = self.process_type(data_type, metadata=self.metadata)
  File "/home/bulat/workdir/venv/lib/python3.8/site-packages/scalecodec/base.py", line 978, in process_type
    obj = self.runtime_config.create_scale_object(type_string, self.data, **kwargs)
  File "/home/bulat/workdir/venv/lib/python3.8/site-packages/scalecodec/base.py", line 192, in create_scale_object
    raise NotImplementedError('Decoder class for "{}" not found'.format(type_string))
NotImplementedError: Decoder class for "DispatchClass" not found

I found very similar runtime_call in tests if I add it to my code, script runs without error:

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair, tip=1)
result = substrate.runtime_call("TransactionPaymentApi", "query_info", [extrinsic, 0])
print(result)

result = substrate.runtime_call("TransactionPaymentCallApi", "query_call_info", [call, 0])
print(result)
Full script 2 ```python #!/usr/bin/env python3 from substrateinterface import SubstrateInterface, Keypair keypair = Keypair.create_from_mnemonic(Keypair.generate_mnemonic()) substrate = SubstrateInterface(url='wss://rpc.polkadot.io') call = substrate.compose_call( call_module='Balances', call_function='transfer', call_params={ 'dest': 'EaG2CRhJWPb7qmdcJvy3LiWdh26Jreu9Dx6R1rXxPmYXoDk', 'value': 3 * 10 ** 3 } ) extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair, tip=1) result = substrate.runtime_call("TransactionPaymentApi", "query_info", [extrinsic, 0]) print(result) result = substrate.runtime_call("TransactionPaymentCallApi", "query_call_info", [call, 0]) print(result) ```

Output:

./get_weight.py 
{'weight': {'ref_time': 145691000, 'proof_size': 0}, 'class': 'Normal', 'partialFee': 11534979}
{'weight': {'ref_time': 145691000, 'proof_size': 0}, 'class': 'Normal', 'partialFee': 11534979}

Is it bug or I should run some commands to initialize state before running runtime_call?

Enviroment

Python 3.8.10
scalecodec==1.2.3
substrate-interface==1.7.0
arjanz commented 1 year ago

No you are doing everything right, it is a missing type composition for DispatchClass. Types compositions used in Runtime Calls are unfortunately not yet embedded in the metadata, but will be soon in MetadataV15: https://github.com/paritytech/substrate/pull/13302

Until then it is manual upkeep: https://github.com/polkascan/py-scale-codec/blob/34e0cc74e511251b71fbb2974a968fe1435cc3fd/scalecodec/type_registry/core.json#L3026

I will add the missing types and release this in scalecodec

arjanz commented 1 year ago

Fix released: https://github.com/polkascan/py-substrate-interface/releases/tag/v1.7.1

BulatSaif commented 1 year ago

Thanks for fast response. Just wondering, why TransactionPaymentCallApi.query_call_info start working after I run TransactionPaymentApi.query_info?

arjanz commented 1 year ago

Thanks for fast response. Just wondering, why TransactionPaymentCallApi.query_call_info start working after I run TransactionPaymentApi.query_info?

Because then the types defined for that runtime call (https://github.com/polkascan/py-scale-codec/blob/34e0cc74e511251b71fbb2974a968fe1435cc3fd/scalecodec/type_registry/core.json#L2992) are loaded in the type registry and globally available, which also defined the missing type.

I didn't want to clutter the type registry with unused types, so I chose a more on demand approach. But this also introduced some redundancy in the definitions though. Hopefully V15 is implemented soon and then this will not be an issue anymore.

BulatSaif commented 1 year ago

Because then the types defined for that runtime call (https://github.com/polkascan/py-scale-codec/blob/34e0cc74e511251b71fbb2974a968fe1435cc3fd/scalecodec/type_registry/core.json#L2992) are loaded in the type registry and globally available, which also defined the missing type.

I didn't want to clutter the type registry with unused types, so I chose a more on demand approach. But this also introduced some redundancy in the definitions though. Hopefully V15 is implemented soon and then this will not be an issue anymore.

Thanks for the explanation

Confirmed v1.7.1 do not have this error, closing the issue. Thank you!