diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index 6b4ddc9b920bc..2345075db210a 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -54,11 +54,11 @@ fn should_return_storage() { fn should_return_child_storage() { let core = tokio::runtime::Runtime::new().unwrap(); let client = Arc::new(test_client::TestClientBuilder::new() - .add_child_storage("test", "key", vec![42_u8]) + .add_child_storage("default:test", "key", vec![42_u8]) .build()); let genesis_hash = client.genesis_hash(); let client = State::new(client, Subscriptions::new(Arc::new(core.executor()))); - let child_key = StorageKey(well_known_keys::CHILD_STORAGE_KEY_PREFIX.iter().chain(b"test").cloned().collect()); + let child_key = StorageKey(well_known_keys::CHILD_STORAGE_KEY_PREFIX.iter().chain(b"default:test").cloned().collect()); let key = StorageKey(b"key".to_vec()); diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs index 1d36a0ddad51d..a75dc01b49537 100644 --- a/core/state-machine/src/basic.rs +++ b/core/state-machine/src/basic.rs @@ -158,15 +158,12 @@ impl Externalities for BasicExternalities where H::Out: Ord { fn storage_root(&mut self) -> H::Out { let mut top = self.top.clone(); let keys: Vec<_> = self.children.keys().map(|k| k.to_vec()).collect(); - // Single child trie implementation currently allows using the same child - // empty root for all child trie. Using null storage key until multiple - // type of child trie support. - let empty_hash = default_child_trie_root::>(&[]); for storage_key in keys { let child_root = self.child_storage_root( ChildStorageKey::::from_slice(storage_key.as_slice()) .expect("Map only feed by valid keys; qed") ); + let empty_hash = default_child_trie_root::>(storage_key.as_slice()); if &empty_hash[..] == &child_root[..] { top.remove(&storage_key); } else { diff --git a/core/trie/src/child_tries/default.rs b/core/trie/src/child_tries/default.rs new file mode 100644 index 0000000000000..7e0bf2646831d --- /dev/null +++ b/core/trie/src/child_tries/default.rs @@ -0,0 +1,112 @@ +// Copyright 2015-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Default child trie declaration. That is, the child trie that uses +//! the same structure of root trie. + +use super::ChildTrie; +use crate::{TrieHash, TrieError, TrieDBMut, TrieDB}; +use rstd::boxed::Box; +use rstd::vec::Vec; +use trie_db::{TrieConfiguration, DBValue, Query, Trie, TrieMut}; +use hash_db::{HashDB, HashDBRef, PlainDB, PlainDBRef}; + +/// Child trie with the same configuration as the root trie. +pub struct DefaultChildTrie; + +impl ChildTrie for DefaultChildTrie { + fn default_root(&self) -> Vec { + L::trie_root::<_, Vec, Vec>(core::iter::empty()).as_ref().iter().cloned().collect() + } + + fn root(&self, input: I) -> Vec where + I: IntoIterator, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]> + { + L::trie_root(input).as_ref().iter().cloned().collect() + } + + fn delta_root( + &self, db: &mut DB, root_vec: Vec, delta: I + ) -> Result, Box>> where + I: IntoIterator)>, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, + DB: HashDB + PlainDB, DBValue> + { + let mut root = TrieHash::::default(); + // root is fetched from DB, not writable by runtime, so it's always valid. + root.as_mut().copy_from_slice(&root_vec); + + { + let mut trie = TrieDBMut::::from_existing(&mut *db, &mut root)?; + + for (key, change) in delta { + match change { + Some(val) => trie.insert(key.as_ref(), val.as_ref())?, + None => trie.remove(key.as_ref())?, + }; + } + } + + Ok(root.as_ref().to_vec()) + } + + fn for_keys( + &self, db: &DB, root_slice: &[u8], mut f: F + ) -> Result<(), Box>> where + DB: HashDBRef + PlainDBRef, DBValue> + { + let mut root = TrieHash::::default(); + // root is fetched from DB, not writable by runtime, so it's always valid. + root.as_mut().copy_from_slice(root_slice); + + let trie = TrieDB::::new(&*db, &root)?; + let iter = trie.iter()?; + + for x in iter { + let (key, _) = x?; + f(&key); + } + + Ok(()) + } + + fn read_value( + &self, db: &DB, root_slice: &[u8], key: &[u8] + ) -> Result>, Box>> where + DB: HashDBRef + PlainDBRef, DBValue> + { + let mut root = TrieHash::::default(); + // root is fetched from DB, not writable by runtime, so it's always valid. + root.as_mut().copy_from_slice(root_slice); + + Ok(TrieDB::::new(&*db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?) + } + + fn read_value_with, DB>( + &self, db: &DB, root_slice: &[u8], key: &[u8], query: Q + ) -> Result>, Box>> where + DB: HashDBRef + PlainDBRef, DBValue> + { + let mut root = TrieHash::::default(); + // root is fetched from DB, not writable by runtime, so it's always valid. + root.as_mut().copy_from_slice(root_slice); + + Ok(TrieDB::::new(&*db, &root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?) + } +} diff --git a/core/trie/src/child_tries/mod.rs b/core/trie/src/child_tries/mod.rs new file mode 100644 index 0000000000000..93ce6e6fb7af7 --- /dev/null +++ b/core/trie/src/child_tries/mod.rs @@ -0,0 +1,73 @@ +// Copyright 2015-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Child trie declarations. + +mod default; + +pub use self::default::DefaultChildTrie; + +use crate::{TrieHash, TrieError}; +use rstd::boxed::Box; +use rstd::vec::Vec; +use trie_db::{TrieConfiguration, DBValue, Query}; +use hash_db::{HashDB, HashDBRef, PlainDB, PlainDBRef}; + +/// Trait for a child trie configuration struct to implement. One +/// child trie should have one corresponding `ChildTrie` definition. +/// +/// To use this, add the resulting struct type into `with_child_trie` +/// macro. +pub trait ChildTrie { + /// The hash value which should be returned for an empty child trie. + /// In current Substrate's child trie implementation, empty child trie + /// value are never written into the root storage. Instead, when this + /// value is encountered, it is removed from the root trie. + fn default_root(&self) -> Vec; + + /// Given its ordered contents, closed form, calculate a child trie's root. + fn root(&self, input: I) -> Vec where + I: IntoIterator, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>; + + /// Given delta values, calculate the updated child trie root. + fn delta_root( + &self, db: &mut DB, root_vec: Vec, delta: I + ) -> Result, Box>> where + I: IntoIterator)>, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, + DB: HashDB + PlainDB, DBValue>; + + /// Call `f` for all keys in a child trie. + fn for_keys( + &self, db: &DB, root_slice: &[u8], f: F + ) -> Result<(), Box>> where + DB: HashDBRef + PlainDBRef, DBValue>; + + /// Read a value from the child trie. + fn read_value( + &self, db: &DB, root_slice: &[u8], key: &[u8] + ) -> Result>, Box>> where + DB: HashDBRef + PlainDBRef, DBValue>; + + /// Read a value from the child trie with given query. + fn read_value_with, DB>( + &self, db: &DB, root_slice: &[u8], key: &[u8], query: Q + ) -> Result>, Box>> where + DB: HashDBRef + PlainDBRef, DBValue>; +} diff --git a/core/trie/src/lib.rs b/core/trie/src/lib.rs index e526a27ebefba..07ee31901497d 100644 --- a/core/trie/src/lib.rs +++ b/core/trie/src/lib.rs @@ -22,10 +22,13 @@ mod error; mod node_header; mod node_codec; mod trie_stream; +mod child_tries; use rstd::boxed::Box; use rstd::vec::Vec; use hash_db::Hasher; +use child_tries::{ChildTrie, DefaultChildTrie}; + /// Our `NodeCodec`-specific error. pub use error::Error; /// The Substrate format implementation of `TrieStream`. @@ -41,6 +44,26 @@ pub use memory_db::prefixed_key; /// Various re-exports from the `hash-db` crate. pub use hash_db::{HashDB as HashDBT, EMPTY_PREFIX}; +macro_rules! with_child_trie { + ( $ident:ident, $storage_key:expr, $expr:expr, $default:expr ) => { + if $storage_key.starts_with(b":child_storage:default:") { + #[allow(unused_variables)] + let $ident = DefaultChildTrie; + $expr + } else { + $default + } + }; + + ( $ident:ident, $storage_key:expr, $expr:expr ) => { + with_child_trie!( + $ident, $storage_key, $expr, + panic!("all child trie operations starts by calling is_child_trie_key_valid; + is_child_trie_key checked that the key is always valid; + qed") + ) + }; +} #[derive(Default)] /// substrate trie layout @@ -173,7 +196,8 @@ pub fn read_trie_value_with< /// `child_trie_root` and `child_delta_trie_root` can panic if invalid value is provided to them. pub fn is_child_trie_key_valid(storage_key: &[u8]) -> bool { use primitives::storage::well_known_keys; - let has_right_prefix = storage_key.starts_with(b":child_storage:default:"); + let has_right_prefix = with_child_trie!(trie, storage_key, true, false); + if has_right_prefix { // This is an attempt to catch a change of `is_child_storage_key`, which // just checks if the key has prefix `:child_storage:` at the moment of writing. @@ -186,25 +210,25 @@ pub fn is_child_trie_key_valid(storage_key: &[u8]) -> bool } /// Determine the default child trie root. -pub fn default_child_trie_root(_storage_key: &[u8]) -> Vec { - L::trie_root::<_, Vec, Vec>(core::iter::empty()).as_ref().iter().cloned().collect() +pub fn default_child_trie_root(storage_key: &[u8]) -> Vec { + with_child_trie!(trie, storage_key, trie.default_root::()) } /// Determine a child trie root given its ordered contents, closed form. H is the default hasher, /// but a generic implementation may ignore this type parameter and use other hashers. -pub fn child_trie_root(_storage_key: &[u8], input: I) -> Vec +pub fn child_trie_root(storage_key: &[u8], input: I) -> Vec where I: IntoIterator, A: AsRef<[u8]> + Ord, B: AsRef<[u8]>, { - L::trie_root(input).as_ref().iter().cloned().collect() + with_child_trie!(trie, storage_key, trie.root::(input)) } /// Determine a child trie root given a hash DB and delta values. H is the default hasher, /// but a generic implementation may ignore this type parameter and use other hashers. pub fn child_delta_trie_root( - _storage_key: &[u8], + storage_key: &[u8], db: &mut DB, root_vec: Vec, delta: I @@ -216,48 +240,21 @@ pub fn child_delta_trie_root( DB: hash_db::HashDB + hash_db::PlainDB, trie_db::DBValue>, { - let mut root = TrieHash::::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - root.as_mut().copy_from_slice(&root_vec); - - { - let mut trie = TrieDBMut::::from_existing(&mut *db, &mut root)?; - - for (key, change) in delta { - match change { - Some(val) => trie.insert(key.as_ref(), val.as_ref())?, - None => trie.remove(key.as_ref())?, - }; - } - } - - Ok(root.as_ref().to_vec()) + with_child_trie!(trie, storage_key, trie.delta_root::(db, root_vec, delta)) } /// Call `f` for all keys in a child trie. pub fn for_keys_in_child_trie( - _storage_key: &[u8], + storage_key: &[u8], db: &DB, root_slice: &[u8], - mut f: F + f: F ) -> Result<(), Box>> where DB: hash_db::HashDBRef + hash_db::PlainDBRef, trie_db::DBValue>, { - let mut root = TrieHash::::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - root.as_mut().copy_from_slice(root_slice); - - let trie = TrieDB::::new(&*db, &root)?; - let iter = trie.iter()?; - - for x in iter { - let (key, _) = x?; - f(&key); - } - - Ok(()) + with_child_trie!(trie, storage_key, trie.for_keys::(db, root_slice, f)) } /// Record all keys for a given root. @@ -285,7 +282,7 @@ pub fn record_all_keys( /// Read a value from the child trie. pub fn read_child_trie_value( - _storage_key: &[u8], + storage_key: &[u8], db: &DB, root_slice: &[u8], key: &[u8] @@ -294,16 +291,12 @@ pub fn read_child_trie_value( DB: hash_db::HashDBRef + hash_db::PlainDBRef, trie_db::DBValue>, { - let mut root = TrieHash::::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - root.as_mut().copy_from_slice(root_slice); - - Ok(TrieDB::::new(&*db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?) + with_child_trie!(trie, storage_key, trie.read_value::(db, root_slice, key)) } /// Read a value from the child trie with given query. pub fn read_child_trie_value_with, DB>( - _storage_key: &[u8], + storage_key: &[u8], db: &DB, root_slice: &[u8], key: &[u8], @@ -313,11 +306,7 @@ pub fn read_child_trie_value_with + hash_db::PlainDBRef, trie_db::DBValue>, { - let mut root = TrieHash::::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - root.as_mut().copy_from_slice(root_slice); - - Ok(TrieDB::::new(&*db, &root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?) + with_child_trie!(trie, storage_key, trie.read_value_with::(db, root_slice, key, query)) } /// Constants used into trie simplification codec.