-
Notifications
You must be signed in to change notification settings - Fork 2.7k
avoid key collision on child trie and proof on child trie #2209
Conversation
try_to backend meth (seems like proof should not work without it). Super awkward memory struct, keep this refacto for after pr (keep pr simple).
huge performance cost for wasm but need to get feedback on best/safe wasm design).
TODO wasm, then SubTrie sanitize field access (ensure no use of key without prefix), then add tests.
runtime anyway??).
`proof_recorded_and_checked_with_child` test.
srml/contract/src/account_db.rs
Outdated
@@ -62,7 +63,11 @@ pub trait AccountDb<T: Trait> { | |||
pub struct DirectAccountDb; | |||
impl<T: Trait> AccountDb<T> for DirectAccountDb { | |||
fn get_storage(&self, _account: &T::AccountId, trie_id: Option<&TrieId>, location: &StorageKey) -> Option<Vec<u8>> { | |||
trie_id.and_then(|id| child::get_raw(id, location)) | |||
// TODO pass optional SubTrie or change def to use subtrie (put the subtrie in cache (rc one of |
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 did use account_db trie_id (see other comments) as keyspace (and as subtrie parent location).
So there is a need for caching SubTrie struct. TODO issue for that ?
There is a possible optimization by putting SubTrie directly at Account_id location, this would only be possible by:
- storing account infos at the same location as subtrie (in subtrie prefix)
- changing this pr to allow storing subtrie at any location
For both point it requires implementing a way to store subtrie with different encoder (and with additional info).
@thiolliere maybe this pr (not sure it will get merged there might be better way of fixing the collision), could be of interest regarding #1882 or #1883 .
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.
So there is a need for caching SubTrie struct. TODO issue for that ?
hmm I can also think of another anwser. The trie_id: Option<&TrieId>
is already an optimisation that says: if there is a trie_id in direct_storage then you have to give me that I won't do the lookup from AccountId, so you can cache it for me.
This thoses changes you introduce we can just say: if there is a subtrie associated to the account already then give it I won't do the lookup.
Having subtrie in AccoundInfo seems cool though but not mandatory here.
@thiolliere maybe this pr (not sure it will get merged there might be better way of fixing the collision), could be of interest regarding 1882 or 1883 .
I don't know in which context this collision can happen I design things without taking this into consideration though. But interesting thanks
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.
Yes I see your optim, it is better design (that is the reason why I pinged you :)
I don't in which context this collision can happen I design things without taking this into consideration though. But interesting thanks
without this pr it happens whenever two subtries are similar and content got pruned (for contract it should happen a lot). It only requires that both subtries got same branch path (also content (same proof would be more correct)) to the deleted value.
Having subtrie in AccoundInfo seems cool though but not mandatory here.
As long as we use a trie_id as subtrie key from account_id (merging account info and trie info) there is no need to take this into consideration.
core/state-machine/src/backend.rs
Outdated
use heapsize::HeapSizeOf; | ||
use primitives::subtrie::{KeySpace, SubTrie}; | ||
|
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.
Backend struct renamed as MapTransaction and VecTransaction are really suitable with SubTrie
struct: especially the usage of Option<SubTrie>
seems awkward at some points).
…child-trie-soft-min
- use keyspace instead of storage key (situation before was an issue and gave the wrong impression). Subscription rpc for child does not exists but shall use storage_key (we may keep keyspace internally). - add children change to change set (probably break subscription rpc format).
I did merge the pr with master. Also I did not reassert the logic of using keyspace either: there might be some place where storage key should be kept. Seeing how stale this PR is, I will refer to my previous comment #2209 (comment) (see missing point) and conclude this is a wrong approach. For instance having the technical keyspace in the state will make some rather complicated specification, when an implementation using reference counted keyvalue do not need it at all. Therefore I am switching this PR to 'A4-Got issue' (could also be close (will require an issue creation first)) in favor of another approach (a bit more involved):
|
@cheme please make an issue for it and close this when done. |
initial issue is that child trie key/value stored in rocksdb are all build the same way for all child trie,
therefore two identical child trie will get all their key duplicated and the pruning will break one of the two tries (only child trie with guaranty of not having same key/value content can currently be use with pruning).
This PR solves the initial issue by prepending a unique id to the keyvalue db keys. It uses a HashDB implementation
KeySpaceDB
to prepend a unique trieid.! with current implementation it is only prepended if
PrefixedMemoryDB
is use.Long term design should move that keyspace information to the db layer (have keyvalue db that manage two level of collections: the heavy one and the light one).
Those prefix should also allow more efficient operation on child trie.
accessing all child trie keyvalue db key from rocksdb, allowing to skip what would otherwhise be a query of every nodes of the child trie for every of its states (blocks).
related to this access we can have efficient deletion.
related to this access we can export/import trie between chain (the prefix will need to be rewritten as it is only unique for a chain context).
This PR also contains a change of child trie api: do not do operation depending on
storage_key
but do operation depending onchild_trie
state.This can allow efficient child trie usage (no need to query parent trie on every operation).
Recently I tried to split this PR in two (keyspace first, api second), but this api change is needed when a child trie does not exists (having the child trie in parameter makes things easier).