polkascan / substrate-interface-api

Substrate Interface API Application
https://documenter.getpostman.com/view/9969999/SWT5iLXH?version=latest
GNU General Public License v3.0
4 stars 13 forks source link

getting transaction has a bad signature error #1

Closed roccomuso closed 3 years ago

roccomuso commented 3 years ago

I'm trying to create a transaction using substrate-interface-api and getting a bad signature error.

Here's my steps:

  1. I use runtime_createExternalSignerPayload to create the initial payload:
    [
    "132AuLCVno4NcyEy5AWdRWKAAeYimEwsGbSaZJTF2ZcwwQ1G",
    "Balances",
    "transfer", 
    {
      "dest": "16C32b3YaXdDhCnDXn5BEEfCcsf919Hw7VNU63psWToxjXNT",
      "value": 100000
    }
    ]

That gives me this payload:

0x980500e597b100e3d58ae8c6f301f63a739585b42c5539146761bf7a1f90d059bd1560821a0600000000180000000500000091b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c391b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3

  1. I sign the raw hex payload using my private key generated with the ed25519 curve (I also verify the signature and it's valid). And returns me a signature:

    0xd18435f3971cc2adc94092f1eba811654bd5a6d086048ddc5e9d8ec85b1581ab9003d9e6e66966658279ad07c17c0cc14a40808d451519c1f93d6a049076100b

  2. I use runtime_submitExtrinsic with these params:

    [
    "132AuLCVno4NcyEy5AWdRWKAAeYimEwsGbSaZJTF2ZcwwQ1G",
    "Balances",
    "transfer", 
    {
      "dest": "16C32b3YaXdDhCnDXn5BEEfCcsf919Hw7VNU63psWToxjXNT",
      "value": 100000
    },
    "0xd18435f3971cc2adc94092f1eba811654bd5a6d086048ddc5e9d8ec85b1581ab9003d9e6e66966658279ad07c17c0cc14a40808d451519c1f93d6a049076100b"
    ]

At this point I get a bad signature error, with multiple attempts you'd result in a Transaction is temporarily banned error.

Could you help me debug the issue? Am I missing something? I don't know if this https://github.com/polkascan/substrate-interface-api/blob/master/app/resources/jsonrpc.py#L263 could possibly alterate my payload (invalidating the signature). Or if I'm missing any param.

Thanks

arjanz commented 3 years ago

I tried some examples with an ed25519 account myself and realised it's working but not very user-friendly (yet). The library cannot 'autodetect' if the signature is generated by Ed25519, Sr25519 or Ecdsa when the "signature version byte" is not supplied and therefor defaults to Sr25519.

This "signature version byte" can be supplied though to prefix the signature with 00 (for ed25519, 01 is sr25519 and 02 is ecdsa).

In this case your example would be:

[
   "132AuLCVno4NcyEy5AWdRWKAAeYimEwsGbSaZJTF2ZcwwQ1G",
   "Balances",
   "transfer", 
    {
      "dest": "16C32b3YaXdDhCnDXn5BEEfCcsf919Hw7VNU63psWToxjXNT",
      "value": 100000
    },
    "0x00d18435f3971cc2adc94092f1eba811654bd5a6d086048ddc5e9d8ec85b1581ab9003d9e6e66966658279ad07c17c0cc14a40808d451519c1f93d6a049076100b"
]

I tested this with the library https://github.com/polkascan/py-substrate-interface itself as followed:

substrate = SubstrateInterface(
    url="wss://rpc.polkadot.io",
    address_type=0,
    type_registry_preset='polkadot'
)

keypair = Keypair(ss58_address="13Rfiutv3JGWJDntux2chFcR9RuoU4MWaEKgggrMdKfsRCU1")

balance_info = substrate.get_runtime_state(
    module='System',
    storage_function='Account',
    params=[keypair.ss58_address],
).get('result')

print('Balance info', balance_info)

call = substrate.compose_call(
    call_module='Balances',
    call_function='transfer',
    call_params={
        'dest': '12nV9cr7Xr31ef3QTHmF3r4gVzAvjQZNBqi5Pk86NH7emyoN',
        'value': 100000000
    }
)

extrinsic = substrate.create_signed_extrinsic(
    call=call,
    keypair=keypair,
    signature='0x0058445b5b191645220b3a5251ecc0181b89395d5f50a6f1805798728b29267ef1327bf386f0cc74d7c6b533817a201278689afa60383a228efb38d3c615197d0d')

try:
    result = substrate.submit_extrinsic(extrinsic)

    print('Extrinsic "{}" included in block "{}"'.format(
        result['extrinsic_hash'], result.get('block_hash')
    ))

except SubstrateRequestException as e:
    print("Failed to send: {}".format(e))

Resulted in transaction: https://polkascan.io/polkadot/transaction/0x8e66bc32a7727dc46d8a33046bafdefb54c94153880068729e0689785a9367bd

This is definitely not user-friendly and we will plan some modifications to the library and substrate-api to supply which curve is being used. I guess this was not an issue yet because sr25519 is kind of the default within Substrate.

Let me know if this is working for you..

roccomuso commented 3 years ago

Thanks for the explanation! I tried prepending 0x00 but still getting a bad signature error. Then I noticed that I was basically providing a signature instead of the extrinsic to the runtime_submitExtrinsic rpc without calling first runtime_createExtrinsic.

I've now called runtime_createExtrinsic with the right ed25519 signature and got this extrinsic:

0x2d0284595d0bd94c9cb9f002399f6af8d931a275ac0bb83d7bf94a4a859aafd4fd01c600dd89bac79c3e7390bbc035697ac1f33ea02dbb033b82bd98dee02aea20404ee5a84477e0a4d7e53ea725764f41d41f57c456bb45e494d9c7dd7d79b12ce9c2040000000500e597b100e3d58ae8c6f301f63a739585b42c5539146761bf7a1f90d059bd156002093d00

Then I tried submitting this with runtime_submitExtrinsic :

[
  "132AuLCVno4NcyEy5AWdRWKAAeYimEwsGbSaZJTF2ZcwwQ1G",
  "Balances",
  "transfer", 
  {
    "dest": "16C32b3YaXdDhCnDXn5BEEfCcsf919Hw7VNU63psWToxjXNT",
    "value": 1000000
  },
  "0x2d0284595d0bd94c9cb9f002399f6af8d931a275ac0bb83d7bf94a4a859aafd4fd01c600dd89bac79c3e7390bbc035697ac1f33ea02dbb033b82bd98dee02aea20404ee5a84477e0a4d7e53ea725764f41d41f57c456bb45e494d9c7dd7d79b12ce9c2040000000500e597b100e3d58ae8c6f301f63a739585b42c5539146761bf7a1f90d059bd156002093d00"
]

and got this error: Value should start with \"0x\" and should be 64 bytes long

Sounds like an ecoding issue, maybe I gotta first encode that 1000000 when calling this rpc? This is not the case for the other rpc calls though.

arjanz commented 3 years ago

Ah I see you put the whole extrinsic payload as 4th param, but it should be the signature only (which is 64 bytes/ 128 hexbytes long)

roccomuso commented 3 years ago

To follow up on this, as discussed in chat problem was runtime_createExternalSignerPayload is just for parity signer.

In my case the right rpc call is runtime_createSignaturePayload that returns a good payload. Then after locally signing the payload, I've put 0x00 as prefix (00 for ed25519 curve) and using runtime_submitExtrinsic with the signature is enough to create and submit the extrinsic.

Worked fine!

gutenye commented 3 years ago

@roccomuso It's solved, can you close this one?