Getting KeyError: '0000' when attempting to decode events vector
Closed this issue · 2 comments
What I'm trying to do?
Decode events after making RPC call to state_getStorageAt
What's happening?
Getting KeyError: '0000'
at the time of decoding.
Something to help reproduce.
result = "0x64000000000........ ........" # This is the output of `state_getStorageAt` call, which is correct. I verified it on https://polkadot.js.org/apps/
# Loaded the necessary types before this as I learned from README
events = runtime_config.create_scale_object(
"Vec<EventRecord<Event, Hash>>", ScaleBytes(result), metadata=metadata,
)
print(events.decode())
Here's the full traceback
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/base.py:660: in decode
self.value_serialized = self.process()
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/types.py:787: in process
element = self.process_type(self.sub_type, metadata=self.metadata)
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/base.py:743: in process_type
obj.decode(check_remaining=False)
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/base.py:660: in decode
self.value_serialized = self.process()
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/types.py:2504: in process
value = super().process()
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/types.py:462: in process
field_obj = self.process_type(data_type, metadata=self.metadata)
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/base.py:743: in process_type
obj.decode(check_remaining=False)
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/base.py:660: in decode
self.value_serialized = self.process()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <GenericEvent(value=None)>
def process(self):
self.event_index = self.get_next_bytes(2).hex()
# Decode attributes
> self.event_module = self.metadata.event_index[self.event_index][0]
E KeyError: '0000'
../../../.pyenv/versions/3.8.1/envs/substrateutils/lib/python3.8/site-packages/scalecodec/types.py:2432: KeyError
The type lookup also changed with MetadataV14
. Before V14 there were string type references the libraries had to map manually in a 'type registry', like Vec<EventRecord<Event, Hash>>
. Since V14 however these reference are now integer identifiers pointed to the embedded type registry.
I will explain step for step:
First of all, you cannot rely on a fixed type string, although the type decomposition might be the same, the unique identifier can differ per runtime because of the position in the embedded type registry. So first of all you have to retrieve the System.Events
storage function from the metadata:
system_pallet = [p for p in metadata.pallets if p['name'] == 'System'][0]
event_storage_function = [s for s in system_pallet['storage']['entries'] if s['name'] == "Events"][0]
In this case you see that the return type event_storage_function['type']
is a Plain
type (no param arguments required) with id 18
.
So you will decode the data returned from the RPC with embedded type 18. The following helper function will return the type string used internally in the library (which is also backwards compatible with metadata prior to V14):
event_storage_function.get_value_type_string()
So to put this all together you can do something like:
event_data = "0x2000000000000000b0338609000000000200000001000000000080b2e60e0000000002000000020000000003be1957935299d0be2f35b8856751feab95fc7089239366b52b72ca98249b94300000020000000500be1957935299d0be2f35b8856751feab95fc7089239366b52b72ca98249b943000264d2823000000000000000000000000000200000005027a9650a6bd43f1e0b4546affb88f8c14213e1fb60512692c2b39fbfcfc56b703be1957935299d0be2f35b8856751feab95fc7089239366b52b72ca98249b943000264d2823000000000000000000000000000200000013060c4c700700000000000000000000000000000200000005047b8441d5110c178c29be709793a41d73ae8b3119a971b18fbd20945ea5d622f00313dc01000000000000000000000000000002000000000010016b0b00000000000000"
system_pallet = [p for p in metadata.pallets if p['name'] == 'System'][0]
event_storage_function = [s for s in system_pallet['storage']['entries'] if s['name'] == "Events"][0]
event = runtime_config.create_scale_object(
event_storage_function.get_value_type_string(), data=ScaleBytes(event_data), metadata=metadata
)
print(event.decode())