polkascan / py-substrate-interface

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

The parchain version of the transfer ----'Transaction has a bad signature' #159

Closed yytomives closed 2 years ago

yytomives commented 2 years ago

The --dev version can transfer transactions normally, but the parchain version cannot do so

The script is as follows:

from substrateinterface import SubstrateInterface, Keypair
from substrateinterface.exceptions import SubstrateRequestException
import yaml,time
from scalecodec.base import ScaleBytes, RuntimeConfigurationObject
from scalecodec.type_registry import load_type_registry_file, load_type_registry_preset
from substrateinterface import SubstrateInterface
substrate = SubstrateInterface(
    url = "wss://apps.dico.io",
    ss58_format=42,
    type_registry_preset='default'
)
print(substrate.url,substrate.ss58_format,substrate.type_registry_preset)
keypair1 = Keypair.create_from_uri("//Alice")
call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer',
    call_params={
        'dest': "5FhEve9KvB15wDkGcnRt3eVv1ymuXYumzqrrKE4Lg5HhqPYN",
        'value': 200 * 10 ** 14
    }
)

extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair1)
try:
    receipt = substrate.submit_extrinsic(extrinsic)
    print("Extrinsic '{}' sent and included in block '{}'".format(receipt.extrinsic_hash, receipt.block_hash))
except SubstrateRequestException as e:
    print("Failed to send: {}".format(e))
time.sleep(5)

Return results: Failed to send: {'code': 1010, 'message': 'Invalid Transaction', 'data': 'Transaction has a bad signature'}

Is there a problem there?

arjanz commented 2 years ago

I found the culprit, the library doesn't check the "signed extensions" that is included in the metadata of the chain. The node you provided does not have the CheckTxVersion extensions, so the transaction_version should be excluded when the library is signing the extrinsic.

I will fix this by determining the ExtrinsicPayloadValue dynamically according to the provided "signed extensions" in the metadata, so this will work automatically. Until then you can make it work for your node by adding:

substrate = SubstrateInterface(
    url="wss://apps.dico.io",
    type_registry_preset="default",
    type_registry={
        "types": {
            "ExtrinsicPayloadValue": {
              "type": "struct",
              "type_mapping": [
                [
                  "call",
                  "CallBytes"
                ],
                [
                  "era",
                  "Era"
                ],
                [
                  "nonce",
                  "Compact<Index>"
                ],
                [
                  "tip",
                  "Compact<Balance>"
                ],
                [
                  "spec_version",
                  "u32"
                ],
                [
                  "genesis_hash",
                  "Hash"
                ],
                [
                  "block_hash",
                  "Hash"
                ]
              ]
            }
        }
    }
)
yytomives commented 2 years ago

Thank you very much for your help!

arjanz commented 2 years ago

Released signed extension support in https://github.com/polkascan/py-substrate-interface/releases/tag/v1.1.2