polkascan / py-substrate-interface

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

get_block_metadata function returns a dictionary and scalecodec __init__ raises error #74

Open lana-shanghai opened 3 years ago

lana-shanghai commented 3 years ago

Hey Arjan,

There is a little issue happening when I'm running a python simulation and sending transactions to the substrate node. At some point I get the traceback below, do you think there is a workaround here to re-try getting the correct metadata result?

The error: https://github.com/polkascan/py-scale-codec/blob/master/scalecodec/base.py#L243

The function where this error drags from: https://github.com/polkascan/py-substrate-interface/blob/master/substrateinterface/base.py#L744

The traceback:

track_trade_event: {5c7f2e} [origin: H2 PV -> H1 Storage2] [IAA House 2 -> IAA House 1] 0.011199999999999998 kWh @ 0.176 15.71428571 888af532-09f7-4114-9ebe-6b5613052896 [fee: 0.0 cts.]
data:  {'apis': [['0xdf6acb689907609b', 3], ['0x37e397fc7c91f5e4', 1], ['0x40fe3ad401f8959a', 4], ['0xd2bc9897eed08f15', 2], ['0xf78b278be53f454c', 2], ['0xdd718d5cc53262d4', 1], ['0xab3c0572291feb8b', 1], ['0xed99c5acb25eedf5', 2], ['0xbc9d89904f5b923f', 1], ['0x37c8bb1350a9a2a8', 1], ['0x68b66ba122c93fa7', 1]], 'authoringVersion': 1, 'implName': 'canvas', 'implVersion': 0, 'specName': 'canvas', 'specVersion': 8, 'transactionVersion': 1}
Traceback (most recent call last):
  File "/Users/admin/Envs/d3a/bin/d3a", line 33, in <module>
    sys.exit(load_entry_point('d3a', 'console_scripts', 'd3a')())
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/d3a_core/cli.py", line 151, in run
    run_simulation(setup_module_name, simulation_config, None, None, None,
  File "/Users/admin/github/d3a/src/d3a/d3a_core/simulation.py", line 618, in run_simulation
    simulation.run()
  File "/Users/admin/github/d3a/src/d3a/d3a_core/simulation.py", line 234, in run
    self._run_cli_execute_cycle(initial_slot, tick_resume) \
  File "/Users/admin/github/d3a/src/d3a/d3a_core/simulation.py", line 246, in _run_cli_execute_cycle
    self._execute_simulation(slot_resume, tick_resume, console)
  File "/Users/admin/github/d3a/src/d3a/d3a_core/simulation.py", line 363, in _execute_simulation
    self.area.tick_and_dispatch()
  File "/Users/admin/github/d3a/src/d3a/models/area/__init__.py", line 400, in tick_and_dispatch
    self.dispatcher.broadcast_tick()
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 63, in broadcast_tick
    return self._broadcast_notification(AreaEvent.TICK, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 81, in _broadcast_notification
    child.dispatcher.event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 113, in event_listener
    self.area.tick_and_dispatch()
  File "/Users/admin/github/d3a/src/d3a/models/area/__init__.py", line 400, in tick_and_dispatch
    self.dispatcher.broadcast_tick()
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 63, in broadcast_tick
    return self._broadcast_notification(AreaEvent.TICK, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 91, in _broadcast_notification
    agents[area_name].event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 402, in event_listener
    super().event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/events/__init__.py", line 58, in event_listener
    self._event_mapping(event_type)(**kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/area_agents/one_sided_agent.py", line 59, in event_tick
    engine.tick(area=area)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/area_agents/one_sided_engine.py", line 97, in tick
    self.propagate_offer(area.current_tick)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/area_agents/one_sided_engine.py", line 132, in propagate_offer
    forwarded_offer = self._forward_offer(offer)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/area_agents/one_sided_engine.py", line 86, in _forward_offer
    self.markets.target.dispatch_market_offer_event(forwarded_offer)
  File "/Users/admin/github/d3a/src/d3a/models/market/one_sided.py", line 107, in dispatch_market_offer_event
    self._notify_listeners(MarketEvent.OFFER, offer=offer)
  File "/Users/admin/github/d3a/src/d3a/models/market/__init__.py", line 145, in _notify_listeners
    listener(event, market_id=self.id, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 81, in _broadcast_notification
    child.dispatcher.event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 120, in event_listener
    self.area.strategy.event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 402, in event_listener
    super().event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/events/__init__.py", line 58, in event_listener
    self._event_mapping(event_type)(**kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/storage.py", line 598, in event_offer
    self.buy_energy(market, offer)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/storage.py", line 517, in buy_energy
    self._try_to_buy_offer(offer, market, max_affordable_offer_rate)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/storage.py", line 498, in _try_to_buy_offer
    self.accept_offer(market, offer, energy=max_energy,
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 314, in accept_offer
    trade = self._accept_offer(market_or_id, offer, buyer, energy, trade_rate, already_tracked,
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 341, in _accept_offer
    return market_or_id.accept_offer(offer_or_id=offer, buyer=buyer, energy=energy,
  File "/Users/admin/github/d3a/src/d3a/models/market/__init__.py", line 57, in wrapper
    return function(self, *args, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/market/one_sided.py", line 277, in accept_offer
    self._notify_listeners(MarketEvent.TRADE, trade=trade)
  File "/Users/admin/github/d3a/src/d3a/models/market/__init__.py", line 145, in _notify_listeners
    listener(event, market_id=self.id, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/area/event_dispatcher.py", line 91, in _broadcast_notification
    agents[area_name].event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 402, in event_listener
    super().event_listener(event_type, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/events/__init__.py", line 58, in event_listener
    self._event_mapping(event_type)(**kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/area_agents/one_sided_agent.py", line 63, in event_trade
    engine.event_trade(trade=trade)
  File "/Users/admin/github/d3a/src/d3a/models/strategy/area_agents/one_sided_engine.py", line 162, in event_trade
    trade_source = self.owner.accept_offer(
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 314, in accept_offer
    trade = self._accept_offer(market_or_id, offer, buyer, energy, trade_rate, already_tracked,
  File "/Users/admin/github/d3a/src/d3a/models/strategy/__init__.py", line 341, in _accept_offer
    return market_or_id.accept_offer(offer_or_id=offer, buyer=buyer, energy=energy,
  File "/Users/admin/github/d3a/src/d3a/models/market/__init__.py", line 57, in wrapper
    return function(self, *args, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/market/one_sided.py", line 268, in accept_offer
    self.bc_interface.track_trade_event(self.simulation_id, self.market_id,
  File "/Users/admin/github/d3a/src/d3a/d3a_core/util.py", line 382, in wrapped
    return recursive_retry(f, 0, max_retries, *args, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/d3a_core/util.py", line 389, in recursive_retry
    return functor(*args, **kwargs)
  File "/Users/admin/github/d3a/src/d3a/models/market/blockchain_interface.py", line 113, in track_trade_event
    call = self.substrate.compose_call(
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/substrateinterface/base.py", line 1349, in compose_call
    self.init_runtime(block_hash=block_hash)
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/substrateinterface/base.py", line 1089, in init_runtime
    self.metadata_decoder = self.get_block_metadata(block_hash=runtime_block_hash, decode=True)
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/substrateinterface/base.py", line 785, in get_block_metadata
    metadata_decoder = MetadataDecoder(ScaleBytes(response.get('result')))
  File "/Users/admin/Envs/d3a/lib/python3.8/site-packages/scalecodec/base.py", line 225, in __init__
    raise ValueError("Provided data is not in supported format: provided '{}'".format(type(data)))
ValueError: Provided data is not in supported format: provided '<class 'dict'>'
arjanz commented 3 years ago

The get_block_metadata function depends on the state_getMetadata RPC call and that the results directly contains the hex-bytes (0x...). It seems for some reason that is not the case (apparently a dict), is that something that has changed in the runtime? What exactly does state_getMetadata return in your case?.

Also, are you using the latest version? It could also be an error is present in the RPC call result and at some point I added better error handling:

https://github.com/polkascan/py-substrate-interface/blob/7da12f022947d59d34b89b14b944e5d6796119fe/substrateinterface/base.py#L766

lana-shanghai commented 3 years ago

The get_block_metadata function depends on the state_getMetadata RPC call and that the results directly contains the hex-bytes (0x...). It seems for some reason that is not the case (apparently a dict), is that something that has changed in the runtime? What exactly does state_getMetadata return in your case?.

Also, are you using the latest version? It could also be an error is present in the RPC call result and at some point I added better error handling:

https://github.com/polkascan/py-substrate-interface/blob/7da12f022947d59d34b89b14b944e5d6796119fe/substrateinterface/base.py#L766

so the dictionary I get looks like so:

data:  {'apis': [['0xdf6acb689907609b', 3], ['0x37e397fc7c91f5e4', 1], ['0x40fe3ad401f8959a', 4], ['0xd2bc9897eed08f15', 2], ['0xf78b278be53f454c', 2], ['0xdd718d5cc53262d4', 1], ['0xab3c0572291feb8b', 1], ['0xed99c5acb25eedf5', 2], ['0xbc9d89904f5b923f', 1], ['0x37c8bb1350a9a2a8', 1], ['0x68b66ba122c93fa7', 1]], 'authoringVersion': 1, 'implName': 'canvas', 'implVersion': 0, 'specName': 'canvas', 'specVersion': 8, 'transactionVersion': 1}

The substrate interface version in 0.11.15 - the latest I think :)

lana-shanghai commented 3 years ago

@arjanz do you think adding a check to the type of the data variable would help? It tries to get the block hash, so maybe adding a re-try would help? E.g. somewhere around here? https://github.com/polkascan/py-substrate-interface/blob/7da12f022947d59d34b89b14b944e5d6796119fe/substrateinterface/base.py#L748

arjanz commented 3 years ago

Do you have a way for me to reproduce this error you are getting? Otherwise it will be very difficult for me to analyse this or give you pointers in the right direction..

lana-shanghai commented 3 years ago

Do you have a way for me to reproduce this error you are getting? Otherwise it will be very difficult for me to analyse this or give you pointers in the right direction..

I'm getting this error when running our d3a simulation with a node. The process is described in our wiki https://gridsingularity.github.io/d3a/blockchain/ It sends transactions to a substrate node we have in the cluster. It fails about mid-way through the 96 transactions in the basic test scenario (I posted the traceback above). Somehow at some point it returns the result of {"id":1, "jsonrpc":"2.0", "method": "state_getRuntimeVersion"} instead of {"id":1, "jsonrpc":"2.0", "method": "state_getMetadata"} and I can't figure out in the interface, where this could happen. The RPC call is here https://github.com/polkascan/py-substrate-interface/blob/7da12f022947d59d34b89b14b944e5d6796119fe/substrateinterface/base.py#L764