diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 59ff43598f..5c1b6ed88f 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 240c93233b..dfe3150194 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 b43412ebc7..e0b3642b6d 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 for Error { @@ -34,23 +30,3 @@ impl From 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 4aaed2ec7e..bd0ba27483 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, 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(PhantomData); diff --git a/substrate/primitives/trie/src/storage_proof.rs b/substrate/primitives/trie/src/storage_proof.rs index 8caae06d39..79da009ae1 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>, } -/// Storage proof in compact form. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -pub struct CompactProof { - pub encoded_nodes: Vec>, -} - impl StorageProof { /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. pub fn new(trie_nodes: Vec>) -> 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(self) -> crate::MemoryDB { 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(proofs: I) -> Self - where - I: IntoIterator, - { + pub fn merge(proofs: impl IntoIterator) -> 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( self, root: H::Out, - ) -> Result>> { + ) -> Result> { crate::encode_compact::>(self, root) } @@ -114,6 +104,22 @@ impl StorageProof { } } +impl From for crate::MemoryDB { + 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>, +} + impl CompactProof { /// Return an iterator on the compact encoded nodes. pub fn iter_compact_encoded_nodes(&self) -> impl Iterator { @@ -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( &self, expected_root: Option<&H::Out>, - ) -> Result<(StorageProof, H::Out), crate::CompactProofError>> { + ) -> Result<(StorageProof, H::Out), crate::CompactProofError> { let mut db = crate::MemoryDB::::new(&[]); let root = crate::decode_compact::, _, _>( &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( + &self, + expected_root: Option<&H::Out>, + ) -> Result<(crate::MemoryDB, H::Out), crate::CompactProofError> { + let mut db = crate::MemoryDB::::new(&[]); + let root = crate::decode_compact::, _, _>( + &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 From for crate::MemoryDB { - 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 62edc82e4c..a7f2922715 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 { - /// Verification failed due to root mismatch. - RootMismatch(TrieHash, TrieHash), - /// Missing nodes in proof. +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(thiserror::Error))] +pub enum Error { + #[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), - /// 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, Vec), - /// Errors from trie crate. - TrieError(Box>), + #[cfg_attr(feature = "std", error("Trie error: {0:?}"))] + TrieError(Box>), } -impl From>> for Error { - fn from(error: Box>) -> Self { +impl From>> for Error { + fn from(error: Box>) -> Self { Error::TrieError(error) } } -#[cfg(feature = "std")] -impl StdError for Error { - 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 fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ::fmt(&self, f) - } -} - -#[cfg(feature = "std")] -impl fmt::Display for Error { - 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>, -) -> Result, Error> +) -> Result, Error, CError>> where L: TrieConfiguration, DB: HashDBT + hash_db::HashDBRef, @@ -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(proof: StorageProof, root: TrieHash) -> Result> +pub fn encode_compact( + proof: StorageProof, + root: TrieHash, +) -> Result, CError>> where L: TrieConfiguration, {