diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 59ff43598faeda3689addd40e71b1740a8f480ef..5c1b6ed88fb4a9e8adbad59ec00e38dcc5bd39a4 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -10362,6 +10362,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-std", + "thiserror", "trie-bench", "trie-db", "trie-root", diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 240c93233bfdbf76783d40f32eaf95a78ac5a764..dfe3150194a3e39035b43976127c66010357e4b2 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -26,6 +26,7 @@ trie-db = { version = "0.23.1", default-features = false } trie-root = { version = "0.17.0", default-features = false } memory-db = { version = "0.29.0", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } +thiserror = { version = "1.0.30", optional = true } [dev-dependencies] trie-bench = "0.30.0" @@ -45,5 +46,6 @@ std = [ "trie-db/std", "trie-root/std", "sp-core/std", + "thiserror", ] memory-tracker = [] diff --git a/substrate/primitives/trie/src/error.rs b/substrate/primitives/trie/src/error.rs index b43412ebc7dc4999d33a99acd2421604296c959e..e0b3642b6db76aace38d44e7506402b3c8c66a32 100644 --- a/substrate/primitives/trie/src/error.rs +++ b/substrate/primitives/trie/src/error.rs @@ -15,18 +15,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "std")] -use std::error::Error as StdError; -#[cfg(feature = "std")] -use std::fmt; - -#[derive(Debug, PartialEq, Eq, Clone)] /// Error for trie node decoding. +#[derive(Debug, PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(thiserror::Error))] pub enum Error { - /// Bad format. + #[cfg_attr(feature = "std", error("Bad format"))] BadFormat, - /// Decoding error. - Decode(codec::Error), + #[cfg_attr(feature = "std", error("Decoding failed: {0}"))] + Decode(#[cfg_attr(feature = "std", source)] codec::Error), } impl From<codec::Error> for Error { @@ -34,23 +30,3 @@ impl From<codec::Error> for Error { Error::Decode(x) } } - -#[cfg(feature = "std")] -impl StdError for Error { - fn description(&self) -> &str { - match self { - Error::BadFormat => "Bad format error", - Error::Decode(_) => "Decoding error", - } - } -} - -#[cfg(feature = "std")] -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Decode(e) => write!(f, "Decode error: {}", e), - Error::BadFormat => write!(f, "Bad format"), - } - } -} diff --git a/substrate/primitives/trie/src/node_codec.rs b/substrate/primitives/trie/src/node_codec.rs index 4aaed2ec7e4ee062102dca483fe2a04451ec08a4..bd0ba27483e6637c181881ae270bda3ba931c120 100644 --- a/substrate/primitives/trie/src/node_codec.rs +++ b/substrate/primitives/trie/src/node_codec.rs @@ -23,7 +23,7 @@ use codec::{Compact, Decode, Encode, Input}; use hash_db::Hasher; use sp_std::{borrow::Borrow, marker::PhantomData, ops::Range, vec::Vec}; use trie_db::{ - self, nibble_ops, + nibble_ops, node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan}, ChildReference, NodeCodec as NodeCodecT, Partial, }; @@ -54,9 +54,7 @@ impl<'a> ByteSliceInput<'a> { impl<'a> Input for ByteSliceInput<'a> { fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> { - let remaining = - if self.offset <= self.data.len() { Some(self.data.len() - self.offset) } else { None }; - Ok(remaining) + Ok(Some(self.data.len().saturating_sub(self.offset))) } fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { @@ -76,7 +74,9 @@ impl<'a> Input for ByteSliceInput<'a> { } } -/// Concrete implementation of a `NodeCodec` with Parity Codec encoding, generic over the `Hasher` +/// Concrete implementation of a [`NodeCodecT`] with SCALE encoding. +/// +/// It is generic over `H` the [`Hasher`]. #[derive(Default, Clone)] pub struct NodeCodec<H>(PhantomData<H>); diff --git a/substrate/primitives/trie/src/storage_proof.rs b/substrate/primitives/trie/src/storage_proof.rs index 8caae06d390ce6400ee4b3ab1ef399c8b026045c..79da009ae151d9dc56e86f19d90daf693365aa14 100644 --- a/substrate/primitives/trie/src/storage_proof.rs +++ b/substrate/primitives/trie/src/storage_proof.rs @@ -35,12 +35,6 @@ pub struct StorageProof { trie_nodes: Vec<Vec<u8>>, } -/// Storage proof in compact form. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -pub struct CompactProof { - pub encoded_nodes: Vec<Vec<u8>>, -} - impl StorageProof { /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. pub fn new(trie_nodes: Vec<Vec<u8>>) -> Self { @@ -71,7 +65,7 @@ impl StorageProof { self.trie_nodes } - /// Creates a `MemoryDB` from `Self`. + /// Creates a [`MemoryDB`](crate::MemoryDB) from `Self`. pub fn into_memory_db<H: Hasher>(self) -> crate::MemoryDB<H> { self.into() } @@ -79,10 +73,7 @@ impl StorageProof { /// Merges multiple storage proofs covering potentially different sets of keys into one proof /// covering all keys. The merged proof output may be smaller than the aggregate size of the /// input proofs due to deduplication of trie nodes. - pub fn merge<I>(proofs: I) -> Self - where - I: IntoIterator<Item = Self>, - { + pub fn merge(proofs: impl IntoIterator<Item = Self>) -> Self { let trie_nodes = proofs .into_iter() .flat_map(|proof| proof.iter_nodes()) @@ -93,12 +84,11 @@ impl StorageProof { Self { trie_nodes } } - /// Encode as a compact proof with default - /// trie layout. + /// Encode as a compact proof with default trie layout. pub fn into_compact_proof<H: Hasher>( self, root: H::Out, - ) -> Result<CompactProof, crate::CompactProofError<Layout<H>>> { + ) -> Result<CompactProof, crate::CompactProofError<H::Out, crate::Error>> { crate::encode_compact::<Layout<H>>(self, root) } @@ -114,6 +104,22 @@ impl StorageProof { } } +impl<H: Hasher> From<StorageProof> for crate::MemoryDB<H> { + fn from(proof: StorageProof) -> Self { + let mut db = crate::MemoryDB::default(); + proof.iter_nodes().for_each(|n| { + db.insert(crate::EMPTY_PREFIX, &n); + }); + db + } +} + +/// Storage proof in compact form. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +pub struct CompactProof { + pub encoded_nodes: Vec<Vec<u8>>, +} + impl CompactProof { /// Return an iterator on the compact encoded nodes. pub fn iter_compact_encoded_nodes(&self) -> impl Iterator<Item = &[u8]> { @@ -121,13 +127,10 @@ impl CompactProof { } /// Decode to a full storage_proof. - /// - /// Method use a temporary `HashDB`, and `sp_trie::decode_compact` - /// is often better. pub fn to_storage_proof<H: Hasher>( &self, expected_root: Option<&H::Out>, - ) -> Result<(StorageProof, H::Out), crate::CompactProofError<Layout<H>>> { + ) -> Result<(StorageProof, H::Out), crate::CompactProofError<H::Out, crate::Error>> { let mut db = crate::MemoryDB::<H>::new(&[]); let root = crate::decode_compact::<Layout<H>, _, _>( &mut db, @@ -144,6 +147,25 @@ impl CompactProof { root, )) } + + /// Convert self into a [`MemoryDB`](crate::MemoryDB). + /// + /// `expected_root` is the expected root of this compact proof. + /// + /// Returns the memory db and the root of the trie. + pub fn to_memory_db<H: Hasher>( + &self, + expected_root: Option<&H::Out>, + ) -> Result<(crate::MemoryDB<H>, H::Out), crate::CompactProofError<H::Out, crate::Error>> { + let mut db = crate::MemoryDB::<H>::new(&[]); + let root = crate::decode_compact::<Layout<H>, _, _>( + &mut db, + self.iter_compact_encoded_nodes(), + expected_root, + )?; + + Ok((db, root)) + } } /// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to @@ -165,13 +187,3 @@ impl Iterator for StorageProofNodeIterator { self.inner.next() } } - -impl<H: Hasher> From<StorageProof> for crate::MemoryDB<H> { - fn from(proof: StorageProof) -> Self { - let mut db = crate::MemoryDB::default(); - for item in proof.iter_nodes() { - db.insert(crate::EMPTY_PREFIX, &item); - } - db - } -} diff --git a/substrate/primitives/trie/src/trie_codec.rs b/substrate/primitives/trie/src/trie_codec.rs index 62edc82e4c547c709272008dd4e686ab0743968e..a7f292271565f5cd749329bb561b974b1b86f961 100644 --- a/substrate/primitives/trie/src/trie_codec.rs +++ b/substrate/primitives/trie/src/trie_codec.rs @@ -20,80 +20,34 @@ //! This uses compact proof from trie crate and extends //! it to substrate specific layout and child trie system. -use crate::{ - CompactProof, HashDBT, StorageProof, TrieConfiguration, TrieError, TrieHash, EMPTY_PREFIX, -}; +use crate::{CompactProof, HashDBT, StorageProof, TrieConfiguration, TrieHash, EMPTY_PREFIX}; use sp_std::{boxed::Box, vec::Vec}; -#[cfg(feature = "std")] -use std::error::Error as StdError; -#[cfg(feature = "std")] -use std::fmt; -use trie_db::Trie; +use trie_db::{CError, Trie}; /// Error for trie node decoding. -pub enum Error<L: TrieConfiguration> { - /// Verification failed due to root mismatch. - RootMismatch(TrieHash<L>, TrieHash<L>), - /// Missing nodes in proof. +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(thiserror::Error))] +pub enum Error<H, CodecError> { + #[cfg_attr(feature = "std", error("Invalid root {0:x?}, expected {1:x?}"))] + RootMismatch(H, H), + #[cfg_attr(feature = "std", error("Missing nodes in the proof"))] IncompleteProof, - /// Compact node is not needed. + #[cfg_attr(feature = "std", error("Child node content with no root in proof"))] ExtraneousChildNode, - /// Child content with root not in proof. - ExtraneousChildProof(TrieHash<L>), - /// Bad child trie root. + #[cfg_attr(feature = "std", error("Proof of child trie {0:x?} not in parent proof"))] + ExtraneousChildProof(H), + #[cfg_attr(feature = "std", error("Invalid root {0:x?}, expected {1:x?}"))] InvalidChildRoot(Vec<u8>, Vec<u8>), - /// Errors from trie crate. - TrieError(Box<TrieError<L>>), + #[cfg_attr(feature = "std", error("Trie error: {0:?}"))] + TrieError(Box<trie_db::TrieError<H, CodecError>>), } -impl<L: TrieConfiguration> From<Box<TrieError<L>>> for Error<L> { - fn from(error: Box<TrieError<L>>) -> Self { +impl<H, CodecError> From<Box<trie_db::TrieError<H, CodecError>>> for Error<H, CodecError> { + fn from(error: Box<trie_db::TrieError<H, CodecError>>) -> Self { Error::TrieError(error) } } -#[cfg(feature = "std")] -impl<L: TrieConfiguration> StdError for Error<L> { - fn description(&self) -> &str { - match self { - Error::InvalidChildRoot(..) => "Invalid child root error", - Error::TrieError(..) => "Trie db error", - Error::RootMismatch(..) => "Trie db error", - Error::IncompleteProof => "Incomplete proof", - Error::ExtraneousChildNode => "Extraneous child node", - Error::ExtraneousChildProof(..) => "Extraneous child proof", - } - } -} - -#[cfg(feature = "std")] -impl<L: TrieConfiguration> fmt::Debug for Error<L> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - <Self as fmt::Display>::fmt(&self, f) - } -} - -#[cfg(feature = "std")] -impl<L: TrieConfiguration> fmt::Display for Error<L> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::InvalidChildRoot(k, v) => write!(f, "InvalidChildRoot at {:x?}: {:x?}", k, v), - Error::TrieError(e) => write!(f, "Trie error: {}", e), - Error::IncompleteProof => write!(f, "Incomplete proof"), - Error::ExtraneousChildNode => write!(f, "Child node content with no root in proof"), - Error::ExtraneousChildProof(root) => { - write!(f, "Proof of child trie {:x?} not in parent proof", root.as_ref()) - }, - Error::RootMismatch(root, expected) => write!( - f, - "Verification error, root is {:x?}, expected: {:x?}", - root.as_ref(), - expected.as_ref(), - ), - } - } -} - /// Decode a compact proof. /// /// Takes as input a destination `db` for decoded node and `encoded` @@ -105,7 +59,7 @@ pub fn decode_compact<'a, L, DB, I>( db: &mut DB, encoded: I, expected_root: Option<&TrieHash<L>>, -) -> Result<TrieHash<L>, Error<L>> +) -> Result<TrieHash<L>, Error<TrieHash<L>, CError<L>>> where L: TrieConfiguration, DB: HashDBT<L::Hash, trie_db::DBValue> + hash_db::HashDBRef<L::Hash, trie_db::DBValue>, @@ -195,7 +149,10 @@ where /// Then parse all child trie root and compress main trie content first /// then all child trie contents. /// Child trie are ordered by the order of their roots in the top trie. -pub fn encode_compact<L>(proof: StorageProof, root: TrieHash<L>) -> Result<CompactProof, Error<L>> +pub fn encode_compact<L>( + proof: StorageProof, + root: TrieHash<L>, +) -> Result<CompactProof, Error<TrieHash<L>, CError<L>>> where L: TrieConfiguration, {