polkascan / py-substrate-interface

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

extrinsic.extrinsic_hash.hex() 'NoneType' object has no attribute 'hex' #192

Closed BulatSaif closed 2 years ago

BulatSaif commented 2 years ago

The following valid unsigned extrinsic will fail with Error: AttributeError: 'NoneType' object has no attribute 'hex'. The extrinsic is submitted and available on-chain. Only the receipt is not returned.

call2 = substrate.compose_call(
    call_module='ParachainSystem',
    call_function='enact_authorized_upgrade',
    call_params={
        'code': '0x'+binarycontent.hex()
    }
)

extrinsic2 = substrate.create_unsigned_extrinsic(
    call=call2
)

try:
    receipt = substrate.submit_extrinsic(extrinsic2, wait_for_inclusion=True) # line 96
    print('Parachain: Extrinsic "{}" included in block "{}"'.format(receipt.extrinsic_hash, receipt.block_hash))
except SubstrateRequestException as e:
    print("Failed to send: {}".format(e))
Traceback (most recent call last):
  File "./upgrade.py", line 96, in <module>
    receipt = parachain.submit_extrinsic(extrinsic2, wait_for_inclusion=True)
  File "/home/bulat/.local/lib/python3.8/site-packages/substrateinterface/base.py", line 1782, in submit_extrinsic
    response = self.rpc_request(
  File "/home/bulat/.local/lib/python3.8/site-packages/substrateinterface/base.py", line 586, in rpc_request
    callback_result = result_handler(message, update_nr, subscription_id)
  File "/home/bulat/.local/lib/python3.8/site-packages/substrateinterface/base.py", line 1777, in result_handler
    'extrinsic_hash': '0x{}'.format(extrinsic.extrinsic_hash.hex()),
AttributeError: 'NoneType' object has no attribute 'hex'

How to reproduce:

call = relay.compose_call(
    call_module='Sudo',
    call_function='sudo_unchecked_weight',
    call_params={
        'call': payload.value,
        'weight': 1
    }
)

extrinsic = relay.create_signed_extrinsic(
    call=call,
    keypair=keypair
)

call2 = substrate.compose_call(
    call_module='ParachainSystem',
    call_function='enact_authorized_upgrade',
    call_params={
        'code': '0x'+binarycontent.hex()
    }
)

extrinsic2 = substrate.create_unsigned_extrinsic(
    call=call2
)

print('extrinsic',extrinsic.extrinsic_hash.hex())
print('extrinsic2', extrinsic2.extrinsic_hash.hex())

Current output

extrinsic 95b63d4cbfe4f808dc6ac2e3e84d37c3edb237d737cd2089913025178d94901b
Traceback (most recent call last):
  File "./upgrade.py", line 95, in <module>
    print('extrinsic2',extrinsic2.extrinsic_hash.hex())
AttributeError: 'NoneType' object has no attribute 'hex'

Desired output

extrinsic 95b63d4cbfe4f808dc6ac2e3e84d37c3edb237d737cd2089913025178d94901b
extrinsic2 <hash or None>

Versions

$ python3 --version 
Python 3.8.10
$ pip freeze | grep subs
substrate-interface==1.2.0
arjanz commented 2 years ago

At the moment no extrinsic hash is being generated for unsigned extrinsics in scalecodec, as I can remember because collisions are possible (the payload of unsigned extrinsics don't have to be unique).

But that breaks the receipt mechanism and it would be a better practice in the unique case a duplicate extrinsic is found, to raise an exception. I'll release a fix in scalecodec soon

arjanz commented 2 years ago

Latest release includes scalecodec fix: https://github.com/polkascan/py-substrate-interface/releases/tag/v1.2.1

BulatSaif commented 2 years ago

Thank you, substrate-interface-1.2.1 fixed the issue.