polkascan / py-substrate-interface

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

batch call interface is not intuitive #180

Closed brenzi closed 2 years ago

brenzi commented 2 years ago

If I try to do a batch call, I'd expect to supply a list of GenericCall, and this worked previously (before the metadata V14 change, I believe)

So, I'd expect this to work

from substrateinterface import SubstrateInterface
from substrateinterface.utils.ss58 import is_valid_ss58_address, ss58_decode, ss58_encode

substrate = SubstrateInterface(
    url="wss://api.solo.integritee.io"
)

calls = []

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer',
    call_params={
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1 * 10**15
    }
)

calls.append(call)

batch_call = substrate.compose_call(
    call_module='Utility',
    call_function='batch',
    call_params={
        'calls': calls
    }
)

But as I understand from https://github.com/polkascan/py-substrate-interface/issues/125#issuecomment-887488443 this is no longer supported, but I'll have to supply a dict instead:

from substrateinterface import SubstrateInterface
from substrateinterface.utils.ss58 import is_valid_ss58_address, ss58_decode, ss58_encode

substrate = SubstrateInterface(
    url="wss://api.solo.integritee.io"
)

calls = []

call = {
    'call_module': 'Balances',
    'call_function': 'transfer',
    'call_args': {
        'dest': '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
        'value': 1 * 10**15
    }
}

calls.append(call)

batch_call = substrate.compose_call(
    call_module='Utility',
    call_function='batch',
    call_params={
        'calls': calls
    }
)

which replaces the field name call_params with call_args which seems inconsistent to me

brenzi commented 2 years ago

oh, and worse: The above doesn't produce a legit batch call with a single balance transfer. It takes two calls to work. (or is that a js/apps issue when I use Developer-> Extrinsics-> Decode?

arjanz commented 2 years ago

If I try to do a batch call, I'd expect to supply a list of GenericCall, and this worked previously (before the metadata V14 change, I believe)

I ran a few tests as this was indeed lost since the MetadataV14 upgrade of the library, as it didn't check if the value was a subclass of GenericCall which is also valid. I fixed this in https://github.com/polkascan/py-scale-codec/commit/34a2fa5e35993aaa9f146be0bf37a2192fa37bd0 and will be available in next release.

Until that is released this will also work:

batch_call = substrate.compose_call(
    call_module='Utility',
    call_function='batch',
    call_params={
        'calls': [call.value for call in calls]
    }
)

which replaces the field name call_params with call_args which seems inconsistent to me

Yes I agree.. This was one many things that changed along the development in parallel with the changes of Substrate over the years, but it needs some more refactor attention to make it more consistent. I'll make a separate issue for this.

oh, and worse: The above doesn't produce a legit batch call with a single balance transfer. It takes two calls to work. (or is that a js/apps issue when I use Developer-> Extrinsics-> Decode?

I couldn't reproduce this, I submitted an Utility.batch extrinsic (with a list containing one call) to a local substrate-node-template and was received successful. Which Substrate implementation were you using?

Side note is that for substrate-node-template you probably need to instantiate with:

substrate = SubstrateInterface(
        url="ws://127.0.0.1:9944",
        type_registry_preset="substrate-node-template"
    )

Because the default LookupSource type there is not a MultiAddress

Hope this helps and thanks for reporting!