Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Fix clear prefix check to avoid erasing child trie roots. (#7848)
Browse files Browse the repository at this point in the history
* Fix clear prefix check to avoid erasing child trie roots.

* Renaming and extend existing test with check.

* last nitpicks.
  • Loading branch information
cheme authored and Bernhard Schuster committed Jan 13, 2021
1 parent 85f1fb4 commit e7ec83b
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
44 changes: 42 additions & 2 deletions primitives/state-machine/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,9 @@ where
HexDisplay::from(&prefix),
);
let _guard = guard();
if is_child_storage_key(prefix) {
warn!(target: "trie", "Refuse to directly clear prefix that is part of child storage key");

if sp_core::storage::well_known_keys::starts_with_child_storage_key(prefix) {
warn!(target: "trie", "Refuse to directly clear prefix that is part or contains of child storage key");
return;
}

Expand Down Expand Up @@ -1024,6 +1025,45 @@ mod tests {
);
}

#[test]
fn clear_prefix_cannot_delete_a_child_root() {
let child_info = ChildInfo::new_default(b"Child1");
let child_info = &child_info;
let mut cache = StorageTransactionCache::default();
let mut overlay = OverlayedChanges::default();
let mut offchain_overlay = prepare_offchain_overlay_with_changes();
let backend = Storage {
top: map![],
children_default: map![
child_info.storage_key().to_vec() => StorageChild {
data: map![
vec![30] => vec![40]
],
child_info: child_info.to_owned(),
}
],
}.into();

let ext = TestExt::new(&mut overlay, &mut offchain_overlay, &mut cache, &backend, None, None);

use sp_core::storage::well_known_keys;
let mut ext = ext;
let mut not_under_prefix = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec();
not_under_prefix[4] = 88;
not_under_prefix.extend(b"path");
ext.set_storage(not_under_prefix.clone(), vec![10]);

ext.clear_prefix(&[]);
ext.clear_prefix(&well_known_keys::CHILD_STORAGE_KEY_PREFIX[..4]);
let mut under_prefix = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec();
under_prefix.extend(b"path");
ext.clear_prefix(&well_known_keys::CHILD_STORAGE_KEY_PREFIX[..4]);
assert_eq!(ext.child_storage(child_info, &[30]), Some(vec![40]));
assert_eq!(ext.storage(not_under_prefix.as_slice()), Some(vec![10]));
ext.clear_prefix(&not_under_prefix[..5]);
assert_eq!(ext.storage(not_under_prefix.as_slice()), None);
}

#[test]
fn storage_append_works() {
let mut data = Vec::new();
Expand Down
10 changes: 10 additions & 0 deletions primitives/storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,16 @@ pub mod well_known_keys {
// Other code might depend on this, so be careful changing this.
key.starts_with(CHILD_STORAGE_KEY_PREFIX)
}

/// Returns if the given `key` starts with [`CHILD_STORAGE_KEY_PREFIX`] or collides with it.
pub fn starts_with_child_storage_key(key: &[u8]) -> bool {
if key.len() > CHILD_STORAGE_KEY_PREFIX.len() {
key.starts_with(CHILD_STORAGE_KEY_PREFIX)
} else {
CHILD_STORAGE_KEY_PREFIX.starts_with(key)
}
}

}

/// Information related to a child state.
Expand Down

0 comments on commit e7ec83b

Please sign in to comment.