-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Light friendly storage tracking: track last-modification-time entry in storage #425
Conversation
Hmm, my preference is for the "Ordered, indexed, Merklised per-block change-trie" idea rather than the prefixing idea, but happy to play in this direction to see how it goes. One particularly problematic case is there we have a huge referendum proposal (last one was 700KB) and its existence needs to be tested (this happens several times every block). In the current model, we only need to test existence of the key in the Merkle tree; if it's there we don't actually need to load the value to know that the proposal "exists". In this new model that's not enough since it might be there but in a zombie "deleted" state - we'll have to load the value (at least the first 4 bytes) to check whether it really is in the trie. That may be problematic to do efficiently without incurring the full cost of the 700KB load.
It must be since it alters the storage trie root. |
|
this.ext.set_prefix(&prefix, value); | ||
Ok(()) | ||
}, | ||
ext_save_pefix_keys(prefix_data: *const u8, prefix_len: u32, set_prefix_data: *const u8, set_prefix_len: u32) => { |
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 think there's an r
missing: ext_save_prefix_keys
it would be good to know if it's even possible to read the first few bytes of a storage item without incurring the cost of reading all from disk, since testing for existence is a pretty important thing to be able to do cheaply. |
Just for the record:
So, given what I've said, if you found another approach better than what I did here, please comment + request changes. |
Found some issues when tried to run local testnet with prefixes => gotissues for now. |
The problem ( Also: adding TODO#1.5 |
Added
|
Superceded by #628 . Reopen later if that doesn't work out (though I expect it will). |
Signed-off-by: Gregory Hill <gregorydhill@outlook.com>
This PR implements "Track last-modification-time entry in storage" section of #131 .
Brief overview:
2.1) all storage values are supposed to have prefix of ":prefix_len" (if the entry ":prefix_len" exists)
2.2) all new storage values are prepended by prefix from ":prefix" entry
2.3) both values are inserted at the genesis (see TODO below)
2.4) ":prefix" is updated (with encoded block#) when new blocks starts execution
runtime-io
functions4.1) prefix is written to the storage entry
4.2) deleted key is inserted into special
KeysSet
structure (with ":deleted" prefix)4.3) when new blocks starts execution, runtime checks if it is a good time to purge deleted values (if current_block_number % purge_interval == 0)
4.4) purge traverses
KeysSet
contents and for each deleted key checks (before purging this key):4.4.1) if it is still deleted
4.4.2) if current_block_number - deleted_at_block_number > min_age_before_purge
4.5) storage purge is not a part of consensus (i.e. there's no guarantee that old values will be purged every N blocks)
5.1) when it reads values directly from the storage (e.g. ":code")
5.2) when it abouts to delete keys with given prefix
6.6) to strip prefix, file
substrate/runtime-io/src/prefix_shared.rs
is compiled both byruntime-io
andsubstrate-state-machine
6.7) to remember keys that we need to purge (when deleting by prefix), file
substrate/runtime-io/src/keys_set.rs
is compiled both byruntime-io
andsubstrate-state-machine
TODOs (in order of importance)
1) ":prefix" or ":prefix_len" are read on every storage access bydoneruntime-io
. We need to cache these values at least for whole "CodeExecutor::call" duration. This could be done ifExt
would provide some kind of HashMap<&'static [u8], Vec>-based cache1.5) right now high-level tests for this new functionality are mostly located indemo-executor
crate. Would be good to have low-level tests insubstrate-runtime-system
crate. +also add the test for temporary values deletion (make sure they're not scheduled for the purge) - right now this is a transparent (hardcoded in state-root) part of high-level tests;2) add support (at substrate level) for runtimes to migrate storage from non-prefixed to prefixed and back forth (this would be slow since it would affect all values in the storage)
3) provide value(s) change logs to light nodes && use this to remove mined transactions/extrinsics from the pool
4) add support (at substrate level) for runtimes to change prefix length
TODOs for potential issues
1) I've found that here we only remove values from the backend, while leaving values in the overlay. Is this intended (@pepyakin ?)? Used the same strategy infixedsave_pefix_keys
, but imho it is a potential issue. UPD: paritytech/polkadot#426