Fix distance evaluation client
- Fix owner key retrieval in distance client
- I could not find how to decode the StorageMap cleanly so I used byte ranges with the help of this article. I'm not sure it can't break in the future.
- Fix modulo in evaluation result filename in distance oracle
- Fix evaluation result file deletion
- If you want to name the files using pool indices instead of a strictly increasing sequence, you run into problems (this is the reason why it was not the case, btw). It should work now, but if the node can't publish (i.e. crash or network error for this block) after the file is deleted, the evaluation result is lost.
Fixes #261 (closed)
Merge request reports
Activity
changed milestone to %client-0.9.0
requested review from @HugoTrentesaux
There is a conflict between this MR which addresses #261 (closed) and !290 (merged) which addresses #262 (closed). I'll comment only in-scope modifications (key retrieval), because others belong to the use of pool index as filename.
95 )), 96 None, 97 )? 98 .filter_map(|(raw_key, raw_data)| { 99 if &raw_key.0[40..44] == b"babe" { 100 Some(( 101 sp_core::sr25519::Public::from_raw( 102 raw_key.0[45..45 + 32].try_into().unwrap(), 103 ), 104 AccountId32::decode(&mut &raw_data.0[..]).ok()?, 105 )) 106 } else { 107 None 108 } 109 }) 110 .find(|(key, _data)| owner_keys.contains(key)) - Comment on lines +89 to +110
Here you are doing this:
- iterate over this storage map which has as many entries as validators (like 20-50):
/// The owner of a key. The key is the `KeyTypeId` + the encoded key. #[pallet::storage] pub type KeyOwner<T: Config> = StorageMap<_, Twox64Concat, (KeyTypeId, Vec<u8>), T::ValidatorId, OptionQuery>;
- decode all raw data to
sr25519::Public
andAccountId
types - for each of these, see if local owner_keys contain this public key
It seems to me that we should go the other way around:
- iterate over all local keys (like 1-2 depending on how many times
rotateKeys()
was called) - for each of this key, query the storage map at
session.keyOwner(babe, <key>)
- if it is
None
, this key is not currently in use, if it isSome
, we can stop because a node is not supposed to have multiple active owner keys locally
This way we limit the number of entries we have to iterate on and we do not have to decode manually the storage map.
Indeed I could transpose and decode fewer keys but I don't know how to get a nice typed API for the storage from the client. The getter
session.key_owner
seems accessible from the runtime only. I could not find a way to decode the StorageMap directly, as it's not a proper structure but a key prefix.Edit: If we want to write
pallet_session::Pallet::<T>::key_owner(sp_runtime::KeyTypeId(*b"babe"), key)
we needT
to implConfig
.Edited by Pascal EngélibertWhat do you mean by "accessible from the runtime only"? In this post I showed a screenshot of the call in polkadotjs, so it should be available from outside, as any storage item.
And since the key of the
StorageMap
is(KeyTypeId, Vec<u8>)
, there is no "nice typed API". The map simply expects aVec<u8>
prefixed bybabe
. The return value is an AccountId and can simply be constructed withsp_runtime::AccountId32
as you did.Not sure about the implementation details in this context. I would imagine that runtime apis would also be available client-side, but apparently not
?Yes, subxt would give us a better API but that's not an option here. (this code is called by the smith node when building a block)
By "nice typed API" I meant a getter like we have in the runtime. Outside, we have to decode since we don't have
Config
.Even the item's storage key, we would have to compute it ourselves (concatenate the item key's hash to the output of
storage_prefix
).I could not find any helpful example of requesting the storage from the client in substrate's code. There probably are, but I don't know what keyword to search for.
I guess the name is "state call" https://paritytech.github.io/polkadot-sdk/master/sc_rpc/state/trait.StateBackend.html#tymethod.call
changed this line in version 2 of the diff
Finally I computed the storage key. I find it acceptably clean, given we have no other choice than encoding something manually anyway.
State call still needs encoding the call to bytes, and it seems overkill if we just want to fetch a value from the storage. Seems it's not much used.
169 143 170 144 let evaluation_result_path = settings 171 145 .evaluation_result_dir 172 .join((current_pool_index + 1).to_string()); 146 .join(((current_pool_index + 1) % 3).to_string()); mentioned in commit f73a957d