polkascan / py-substrate-interface

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

Getting fees is broken in version 1.4.2 #309

Closed vtexier closed 1 year ago

vtexier commented 1 year ago

Version: 1.4.2

Requesting fees does not work anymore

I think it is since issue #277.

https://github.com/polkascan/py-substrate-interface/blob/a6adde8578f83c3cc057679443d64d0891b15190/substrateinterface/base.py#L2150

If I skip the new code in base.py at line 2150 :

if not self.supports_rpc_method('state_call'):

to run on the old code, everything works fine.

It seems to be a scale decode error (offset > length)

DEBUG:substrateinterface.base:Executing Runtime Call TransactionPaymentApi.query_info
DEBUG:substrateinterface.base:RPC request #39: "state_call"
Traceback (most recent call last):
  File "/home/vit/Documents/dev/python/tikka/tikka/slots/pyqt/entities/worker.py", line 43, in run
    self.call()
  File "/home/vit/Documents/dev/python/tikka/tikka/slots/pyqt/windows/transfer.py", line 291, in fetch_fees_from_network
    self.account, self.recipient_account.address, blockchain_value
  File "/home/vit/Documents/dev/python/tikka/tikka/domains/transfers.py", line 55, in fees
    return self.network.fees(sender_account, recipient_address, amount)
  File "/home/vit/Documents/dev/python/tikka/tikka/adapters/network/transfers.py", line 111, in fees
    call=call, keypair=sender_account_keypair
  File "/home/vit/Documents/dev/python/tikka/.venv/lib/python3.7/site-packages/substrateinterface/base.py", line 2154, in get_payment_info
    result = self.runtime_call("TransactionPaymentApi", "query_info", [extrinsic, extrinsic_len])
  File "/home/vit/Documents/dev/python/tikka/.venv/lib/python3.7/site-packages/substrateinterface/base.py", line 1599, in runtime_call
    result_obj.decode(ScaleBytes(result_data['result']))
  File "/home/vit/Documents/dev/python/tikka/.venv/lib/python3.7/site-packages/scalecodec/base.py", line 696, in decode
    self.value_serialized = self.process()
  File "/home/vit/Documents/dev/python/tikka/.venv/lib/python3.7/site-packages/scalecodec/types.py", line 526, in process
    field_obj = self.process_type(data_type, metadata=self.metadata)
  File "/home/vit/Documents/dev/python/tikka/.venv/lib/python3.7/site-packages/scalecodec/base.py", line 778, in process_type
    obj.decode(check_remaining=False)
  File "/home/vit/Documents/dev/python/tikka/.venv/lib/python3.7/site-packages/scalecodec/base.py", line 712, in decode
    f'Decoding <{self.__class__.__name__}> - No more bytes available (needed: {self.data.offset} / total: {self.data.length})'
scalecodec.exceptions.RemainingScaleBytesNotEmptyException: Decoding <U128> - No more bytes available (needed: 25 / total: 17)
python-BaseException

To help, here is the debug window with the scale value decoded.

scale_decode_error_on_fees

arjanz commented 1 year ago

Which network/runtime are you experiencing this? It seems to be a type mismatch, unfortunately runtime calls are not a part of the Substrate metadata (yet), so I have to manually update this types.

arjanz commented 1 year ago

A quick-and-dirty workaround until a fix is released (to force the library to fallback on the old RPC methods) you can add after init:

substrate.config['rpc_methods'] = substrate.rpc_request("rpc_methods", [])['result']['methods']
substrate.config['rpc_methods'].remove('state_call')
vtexier commented 1 year ago

Thanks for the quick fix! My app is currently in alpha stage so no hurry here. ;)

The blockchain project name is Duniter, and in early alpha stage too.

In polkadot.js.org I got this:

Duniter v0.3.0 api v9.10.5 apps v0.122.3-216

If you need more info on data types or substrate version, I can ask the Duniter project devs for more.

arjanz commented 1 year ago

I'm wondering if the type definition of RuntimeDispatchInfo is different than the default Substrate one: https://github.com/paritytech/substrate/blob/a1c1286d2ca6360a16d772cc8bea2190f77f4d8f/frame/transaction-payment/src/types.rs#L105

And also its components like Weight or Balance

arjanz commented 1 year ago

The unit tests for Polkadot/Kusama are passing, so I guess it's a type override. Is there a public endpoint available by any chance? That would make it easier for me to run some tests

vtexier commented 1 year ago

endpoint:

wss://gdev.p2p.legal/ws

repository:

https://git.duniter.org/nodes/rust/duniter-v2s

arjanz commented 1 year ago

Ok I found the type difference, the Balance type for Duniter is a u64 in stead of an u128 in default Substrate. Normally those type differences doesn't need any manual administration, because the embedded metadata takes care of this for calls and storage functions. But since runtime API calls are not part of the embedded metadata yet, they still need to be administered manually.

So a better solution than the earlier mentioned workaround would be (until Substrate includes runtime API calls and types into the metadata):

custom_type_registry = {
    "types": {
        "Balance": "u64"
    }
}

substrate = SubstrateInterface(
    url="wss://gdev.p2p.legal/ws",
    type_registry=custom_type_registry
)
arjanz commented 1 year ago

Ok I just found out the friendly people at Parity are working on a solution for this exact issue :)

https://github.com/paritytech/substrate/issues/12939

vtexier commented 1 year ago

Thanks for the clean config solution. Works like a charm.

On the Duniter project side, the devs are talking about the risk to break the compatibility with the ecosystem by customizing the node. It raises a real concern here. Customizing is powerful, but only possible if the ecosystem can handle the changes seamlessly.

Happy to see that this question is discussed too at Parity.