-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Allow to specify some max number of values for storages in pallet macro. #8735
Conversation
4d469eb
to
0de4775
Compare
I marked a in-progress because I didn't take a last look to polish, add doc, add some more tests, and double check implementation. But the implementation should be quite good. |
@thiolliere No commands could be detected from your comment. |
max_values: #max_values, | ||
max_size: Some(max_size), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure we have the right granularity here.
The impact on the child trie for a map will be some multiple of the value size * max_values
Since max_size
encodes both the key and value, i dont think we can do the right math here to get the right PoV impact
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"child trie" ? I guess you mean the branched portion of the trie containing the Map.
The fact that max_size
encodes both key and value is correct for iterable maps I think (IIRC key is stored with value as trie node value), and not for non iterable one I think.
So from 'max_values' you can estimate the number of branches in PoV. Size of branch also could be estimate since the trie key are fix length hash.
Depending on the number of value accessed (and kind of access), you will can estimate the number of shared branch too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and not for non iterable one I think.
Ah you are right it is only the hasher which concatenate the key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we include the hash part when computing the max_size for a storage key/value ?
like if a storagemap with hashertwox64concat has only one value, then the node contains the full key and the value, so the size include the hash part. (so 8 bytes + key::max_encoded_len + value::max_encoded_len).
What do you think ?
implemented in 999640b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would share the 8bytes amongst branches size evaluation and then do (key::max_encoded_len + value::max_encoded_len) as you suggest (as if all the encoded key are in the leaf nodes (worst case scenario)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking again at what is hasertwox64, (twox64(key), key) would make unhashed part highly improbably to be in a branch so it is no really a worst case scenario.
Putting key with value seems correct. (and twox part shared amongst branches).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking again at what is hasertwox64, (twox64(key), key) would make unhashed part highly improbably to be in a branch so it is no really a worst case scenario.
Yeah I agree, I'm ok to remove the hash part, if it is considered important we can improve on it later
traits::{Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess}, | ||
traits::{ | ||
Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, StoragesInfo, | ||
ConstU32, GetDefault, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like ConstU32
isn't actually used in this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the prelude that people ususally import when declaring their pallet.
ConstU32 can be used to declare MaxValues easily:
type Foo<T> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery, GetDefault, ConstU32<100_000>>
@@ -50,7 +50,7 @@ mod misc; | |||
pub use misc::{ | |||
Len, Get, GetDefault, HandleLifetime, TryDrop, Time, UnixTime, IsType, IsSubType, ExecuteBlock, | |||
SameOrOther, OnNewAccount, OnKilledAccount, OffchainWorker, GetBacking, Backing, ExtrinsicCall, | |||
EnsureInherentsAreFirst, | |||
EnsureInherentsAreFirst, ConstU32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise, ConstU32
here appears not to be used in the rest of the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like ppl prefer to reexport everything in frame/support/src/traits instead of getting them from their own module. Though I agree we can remove this one, and it is in the pallet_prelude anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me! I have a few nits, but nothing that I think really needs to change.
I think it is more future proof. In the future some storage could make use of multiple prefix. Like one to store how much value has been inserted, etc...
e8f65d3
to
341d3f5
Compare
Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
hasher now expose `max_len` which allows to computes their maximum len. For hasher without concatenation, it is the size of the hash part, for hasher with concatenation, it is the size of the hash part + max encoded len of the key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ive been using this in my follow up PR and it is looking good.
I think it is ready to merge, and can be iterated on as we continue down the path.
Yes we should make sure the PoV benchmark is resolved before considering this API stable. |
bot merge |
Trying merge. |
…ro. (paritytech#8735) * implement max_values + storages info * some formatting + doc * rename StoragesInfo -> PalletStorageInfo * merge both StorageInfoTrait and PalletStorageInfo I think it is more future proof. In the future some storage could make use of multiple prefix. Like one to store how much value has been inserted, etc... * Update frame/support/procedural/src/storage/parse.rs Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * Update frame/support/procedural/src/storage/storage_struct.rs Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * Fix max_size using hasher information hasher now expose `max_len` which allows to computes their maximum len. For hasher without concatenation, it is the size of the hash part, for hasher with concatenation, it is the size of the hash part + max encoded len of the key. * fix tests * fix ui tests Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
fix #8729
DONE:
This PR allows to specify some max number of values for storages as a new optional generic.
And allows macros to generate storages info with an opt-in attribute.
Both macro use this information to implement a new trait on pallet: StoragesInfo:
So every storage implement
StorageInfoTrait
(on condition that value and keys implement MaxEncodedLen). Then macro calls it if the opt-in attribute is set.For decl_storage the attribute is just a
generate_storages_info
in the front.For pallet it is
#[pallet::generate_storages_info]
on top of pallet struct.For decl_storage a new attribute
max_values(..)
is available to set this new value. I might make more sense to put after themap
keyword though. I can do if requested.(EDIT: in the past I mentionned an idea to not have to opt-in but it couldn't work because storages can be private).
The runtime can get all storages info with
AllPalletWithSystem::storages_info()
.NOTE: the usage of an additional generic in storages should be ease with this PR: #8751
TODO:
Vec<StorageInfo>
, I was thinking it could have more information like frame_system could declare its usage of the:code:
key. Like we would allow 2 kind of description:but this can be done in follow-up PR
At the end I imagine we want to give this information to the client thourght Benchmarking runtime API so that client can then return the PoV worst case cost.