Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
4 changes: 2 additions & 2 deletions core/rpc/src/state/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());


Expand Down
5 changes: 1 addition & 4 deletions core/state-machine/src/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,12 @@ impl<H: Hasher> Externalities<H> 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::<Layout<H>>(&[]);
for storage_key in keys {
let child_root = self.child_storage_root(
ChildStorageKey::<H>::from_slice(storage_key.as_slice())
.expect("Map only feed by valid keys; qed")
);
let empty_hash = default_child_trie_root::<Layout<H>>(storage_key.as_slice());
if &empty_hash[..] == &child_root[..] {
top.remove(&storage_key);
} else {
Expand Down
112 changes: 112 additions & 0 deletions core/trie/src/child_tries/default.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

//! 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<L: TrieConfiguration>(&self) -> Vec<u8> {
L::trie_root::<_, Vec<u8>, Vec<u8>>(core::iter::empty()).as_ref().iter().cloned().collect()
}

fn root<L: TrieConfiguration, I, A, B>(&self, input: I) -> Vec<u8> where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>
{
L::trie_root(input).as_ref().iter().cloned().collect()
}

fn delta_root<L: TrieConfiguration, I, A, B, DB>(
&self, db: &mut DB, root_vec: Vec<u8>, delta: I
) -> Result<Vec<u8>, Box<TrieError<L>>> where
I: IntoIterator<Item = (A, Option<B>)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
DB: HashDB<L::Hash, DBValue> + PlainDB<TrieHash<L>, DBValue>
{
let mut root = TrieHash::<L>::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::<L>::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<L: TrieConfiguration, F: FnMut(&[u8]), DB>(
&self, db: &DB, root_slice: &[u8], mut f: F
) -> Result<(), Box<TrieError<L>>> where
DB: HashDBRef<L::Hash, DBValue> + PlainDBRef<TrieHash<L>, DBValue>
{
let mut root = TrieHash::<L>::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::<L>::new(&*db, &root)?;
let iter = trie.iter()?;

for x in iter {
let (key, _) = x?;
f(&key);
}

Ok(())
}

fn read_value<L: TrieConfiguration, DB>(
&self, db: &DB, root_slice: &[u8], key: &[u8]
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>> where
DB: HashDBRef<L::Hash, DBValue> + PlainDBRef<TrieHash<L>, DBValue>
{
let mut root = TrieHash::<L>::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::<L>::new(&*db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?)
}

fn read_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=DBValue>, DB>(
&self, db: &DB, root_slice: &[u8], key: &[u8], query: Q
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>> where
DB: HashDBRef<L::Hash, DBValue> + PlainDBRef<TrieHash<L>, DBValue>
{
let mut root = TrieHash::<L>::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::<L>::new(&*db, &root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?)
}
}
73 changes: 73 additions & 0 deletions core/trie/src/child_tries/mod.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

//! 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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we may rename ChildTrie with something a bit more generic, I would say ChildState but that is not really related to the following methods either, so here to me KeyValueState is what makes the more sense.
Similarily we can remove the 'child' info here: there is nothing related to the child nature.
Still If we add method or associated const such as

  /// ChildTrie storage key defines its type. eg: the default child trie is using
  /// well_known_keys:: CHILD_STORAGE_KEY_PREFIX followed by ':' then
  // 'default', default being this associated const.
  const TYPE_PREFIX: &'static[u8] =  b"default:";

or

 get_type_prefix() -> &'static[u8];

/// 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<L: TrieConfiguration>(&self) -> Vec<u8>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for all those function I would consider removing type parameter L, and pushing it into the struct

struct DefaultTrie<'a, L, DB, Query>{
  root: &'a[u8],
  _ph: PhantomData<(L, DB, Query)>
}

instead of

struct DefaultChildTrie;

Actually this comes with some constraint (probably associated type for prover and and memorydb), so it may not be worth it at this point.


/// Given its ordered contents, closed form, calculate a child trie's root.
fn root<L: TrieConfiguration, I, A, B>(&self, input: I) -> Vec<u8> where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>;

/// Given delta values, calculate the updated child trie root.
fn delta_root<L: TrieConfiguration, I, A, B, DB>(
&self, db: &mut DB, root_vec: Vec<u8>, delta: I
) -> Result<Vec<u8>, Box<TrieError<L>>> where
I: IntoIterator<Item = (A, Option<B>)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
DB: HashDB<L::Hash, DBValue> + PlainDB<TrieHash<L>, DBValue>;

/// Call `f` for all keys in a child trie.
fn for_keys<L: TrieConfiguration, F: FnMut(&[u8]), DB>(
&self, db: &DB, root_slice: &[u8], f: F
) -> Result<(), Box<TrieError<L>>> where
DB: HashDBRef<L::Hash, DBValue> + PlainDBRef<TrieHash<L>, DBValue>;

/// Read a value from the child trie.
fn read_value<L: TrieConfiguration, DB>(
&self, db: &DB, root_slice: &[u8], key: &[u8]
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>> where
DB: HashDBRef<L::Hash, DBValue> + PlainDBRef<TrieHash<L>, DBValue>;

/// Read a value from the child trie with given query.
fn read_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=DBValue>, DB>(
&self, db: &DB, root_slice: &[u8], key: &[u8], query: Q
) -> Result<Option<Vec<u8>>, Box<TrieError<L>>> where
DB: HashDBRef<L::Hash, DBValue> + PlainDBRef<TrieHash<L>, DBValue>;
}
87 changes: 38 additions & 49 deletions core/trie/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that it will be good to have a constant reference instead of b"child_storage:default:" and if we put a function/constant in ChildTrie trait to define its type prefix, it should also be use.

( $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
Expand Down Expand Up @@ -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<L: TrieConfiguration>(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.
Expand All @@ -186,25 +210,25 @@ pub fn is_child_trie_key_valid<L: TrieConfiguration>(storage_key: &[u8]) -> bool
}

/// Determine the default child trie root.
pub fn default_child_trie_root<L: TrieConfiguration>(_storage_key: &[u8]) -> Vec<u8> {
L::trie_root::<_, Vec<u8>, Vec<u8>>(core::iter::empty()).as_ref().iter().cloned().collect()
pub fn default_child_trie_root<L: TrieConfiguration>(storage_key: &[u8]) -> Vec<u8> {
with_child_trie!(trie, storage_key, trie.default_root::<L>())
}

/// 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<L: TrieConfiguration, I, A, B>(_storage_key: &[u8], input: I) -> Vec<u8>
pub fn child_trie_root<L: TrieConfiguration, I, A, B>(storage_key: &[u8], input: I) -> Vec<u8>
where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
{
L::trie_root(input).as_ref().iter().cloned().collect()
with_child_trie!(trie, storage_key, trie.root::<L, _, _, _>(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<L: TrieConfiguration, I, A, B, DB>(
_storage_key: &[u8],
storage_key: &[u8],
db: &mut DB,
root_vec: Vec<u8>,
delta: I
Expand All @@ -216,48 +240,21 @@ pub fn child_delta_trie_root<L: TrieConfiguration, I, A, B, DB>(
DB: hash_db::HashDB<L::Hash, trie_db::DBValue>
+ hash_db::PlainDB<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::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::<L>::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::<L, _, _, _, _>(db, root_vec, delta))
}

/// Call `f` for all keys in a child trie.
pub fn for_keys_in_child_trie<L: TrieConfiguration, F: FnMut(&[u8]), DB>(
_storage_key: &[u8],
storage_key: &[u8],
db: &DB,
root_slice: &[u8],
mut f: F
f: F
) -> Result<(), Box<TrieError<L>>>
where
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>
+ hash_db::PlainDBRef<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::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::<L>::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::<L, _, _>(db, root_slice, f))
}

/// Record all keys for a given root.
Expand Down Expand Up @@ -285,7 +282,7 @@ pub fn record_all_keys<L: TrieConfiguration, DB>(

/// Read a value from the child trie.
pub fn read_child_trie_value<L: TrieConfiguration, DB>(
_storage_key: &[u8],
storage_key: &[u8],
db: &DB,
root_slice: &[u8],
key: &[u8]
Expand All @@ -294,16 +291,12 @@ pub fn read_child_trie_value<L: TrieConfiguration, DB>(
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>
+ hash_db::PlainDBRef<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::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::<L>::new(&*db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?)
with_child_trie!(trie, storage_key, trie.read_value::<L, _>(db, root_slice, key))
}

/// Read a value from the child trie with given query.
pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=DBValue>, DB>(
_storage_key: &[u8],
storage_key: &[u8],
db: &DB,
root_slice: &[u8],
key: &[u8],
Expand All @@ -313,11 +306,7 @@ pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=D
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>
+ hash_db::PlainDBRef<TrieHash<L>, trie_db::DBValue>,
{
let mut root = TrieHash::<L>::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::<L>::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::<L, _, _>(db, root_slice, key, query))
}

/// Constants used into trie simplification codec.
Expand Down