Assert Storage Key & Value Invariance #13037
Description
The reason for this issue is that silent changes in the scale-coding of types -- through changes in the types themselves, or unlikely, changes in the codec -- used for storage keys and values worry me more and more. Even more, since the latest migrations in Substrate mostly were triggered via OnRuntimeUpgrade
instead of hooks.
Proposal
My proposal for a solution would be the following. I have not coded this already, just checked that the traits work and the static assertion fails, but I am not sure if an auto-derive is trivial and so forth.
-
Codec provides 2 additional traits + auto-derive for
StaticEncode
#[const_trait] trait StaticEncode<const BYTES: usize> { fn zeroed_and_uninit() -> [u8; BYTES]; } #[const_trait] trait Lock<T: ~const StaticEncode<BYTES>, const BYTES: usize> { const LOCK: [u8; BYTES]; fn check_lock() { let current = T::zeroed_and_uninit(); let lock = Self::LOCK; let mut i = 0; while i < BYTES { assert!(current[i] == lock[i], "Static encoding does not match lock!"); i += 1; } } }
-
Storage items of pallets automatically implement the following impl block
Users can opt-out of this by addingpallet::without_storage_lock
// Assuming `StorageMap<T::Key, T::Value>` impl<T: Config> Pallet<T> where T: Lock<<T as Config>::Key, BYTES>, T: Lock<<T as Config>::Value, BYTES>, { const _: () = { <T as Lock<T as Config>::Key, BYTES>::check_lock(); }; const _: () = { <T as Lock<T as Config>::Value, BYTES>::check_lock(); }; }
-
Runtimes must implement
Lock<T>
for everyT
that is a key or a value
Advantages
- Compilation ensures that codec of storage relevant types has not changed
- Dependencies are also checked automatically → no silent errors here
Problems
- Getting the
BYTES
for associated types in pallets needs to be constant but runtime specific - Overhead for runtimes
- Is there a "static" representation for every codec object that can be storage key or value?
For enums it would be needed to actually encode all variants in the "static" representation in order to ensure no variant has changed its encoding.- Other relevant things to pay attention to?
Edits:
- Typos
- Changed T (i.e. the runtime) to implement the locks