-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Document the difference between sp_io::storage and sp_io::default_child_storage #7574
Comments
Also: Why does |
It even should be documented what is the path of |
CC @cheme |
Quick first answer:
sp_io::storage only stores state in a single trie. Content can be organized by prefix: the api sp_io::default_child_storage: 'Default' kind (only this kind of child state exists) uses the same kind of trie It always store its root in a single parent trie. substrate/primitives/storage/src/lib.rs Line 173 in 368903f
sp_io::storage is used by most frame pallet by using 'decl_storage' macro, and soon the new procedural storage macro. sp_io::default_child_storage is call almost directly, there is just a very small api in front https://github.com/paritytech/substrate/blob/master/frame/support/src/storage/child.rs , but almost the same as directly call the sp_io api (especially since we got a single kind of child state/trie).
contract pallet is one of the only frame module using it: the contract variable are in a child storage (one trie per contract account), and the accounts are in the parent trie.
Almost all the chain state is using sp_io::storage with prefixes. I only know contract and crowdfund pallets to use child storage (but did not check new pallets recently).
At the time 'default' is not necessary, because we have a single kind of child trie. I wanted to put different format of trie or different states, but my PR going in this direction where a bit impacting and I did not reach a consensus, so at the time I am focusing on different problematic, but will probably go back to it at some point.
They're actually the same, only the location of their roots changes (in header or in parent trie).
storage_key is the location of the state root in the parent key, while storage stores root in the header.
But the api should use only 'storage_key' when it targets the 'default' child trie (rpc does not, iirc it uses the concatenation as parameter). |
I still don't understand why |
for the first a query is done: So you need as input 'storage_key' and 'key' to get your value (header of block is related to context or a block hash for rpc). for the second one: so you need only key.
it is a two level only structure so if you query first level you need one key, and two key for second level. For a more hierarchical child trie (n level of trie), the api should be unique, either passing a array of key or using a separtor in key like in uri. I would like it better (as stated in previous message), but the current api is two level only. Probably to avoid changing the existing api (storage) there is another one (default_child_storage). |
"For the first" - you mean for So get value at |
👍
Yeah an unbalanced trie would work as well. With current trie implementation we would need some additional api to extract root for a given prefix (there is a small subtletie related to the fact that the trie node might contain a prefix (the fact that substrate trie do not use 'extension node' makes it a bit more awkward, and I would probably want to attach the size of the prefix with the contract root). I did not find the discussion where the choice was made (somewhere on github), one of the reason for chosing child trie was Also note that it is rather similar to how ethereum account storages work. When the choice was made I wanted #5280 so the rent would work well, I still think it is the right way to go, but it did not get merge.
Yes in theory during processing you only need to access a child trie root once, but in practice, caching makes the prefix approach also fine. TLDR; the fact that you need to deal with root of the contract storage makes it rather natural: each contract got its own state trie. |
The answers to the following questions should be immediately obvious (but now they are not) after reading https://docs.rs/sp-io/2.0.0/sp_io/storage/index.html and/or https://docs.rs/sp-io/2.0.0/sp_io/default_child_storage/index.html:
What is the difference between
sp_io::storage
andsp_io::default_child_storage
? How each of them is used? Which of the two is used to store contract storage variables? What is stored in the other one? What is the "default child trie" and why at all there is a necessity to have a default child trie? How are these two storages related to each other?Please also answer the questions commenting to this issue.
The text was updated successfully, but these errors were encountered: