diff --git a/Cargo.lock b/Cargo.lock index 66cd14d1e2a0..8b182f6849fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9423,6 +9423,7 @@ dependencies = [ "reth-stages-types", "reth-storage-errors", "reth-trie-common", + "reth-trie-sparse", "revm", "serde_json", "tracing", diff --git a/crates/trie/sparse/src/blinded.rs b/crates/trie/sparse/src/blinded.rs index f82bdcd95bbd..4cd88bd92a26 100644 --- a/crates/trie/sparse/src/blinded.rs +++ b/crates/trie/sparse/src/blinded.rs @@ -55,3 +55,11 @@ impl BlindedProvider for DefaultBlindedProvider { Ok(None) } } + +/// Right pad the path with 0s and return as [`B256`]. +#[inline] +pub fn pad_path_to_key(path: &Nibbles) -> B256 { + let mut padded = path.pack(); + padded.resize(32, 0); + B256::from_slice(&padded) +} diff --git a/crates/trie/sparse/src/errors.rs b/crates/trie/sparse/src/errors.rs index 20545957e1cd..46102d2d4680 100644 --- a/crates/trie/sparse/src/errors.rs +++ b/crates/trie/sparse/src/errors.rs @@ -55,4 +55,7 @@ pub enum SparseTrieError { /// RLP error. #[error(transparent)] Rlp(#[from] alloy_rlp::Error), + /// Other. + #[error(transparent)] + Other(#[from] Box), } diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index c1c3ae4dd876..011c95e6a927 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -17,6 +17,7 @@ reth-execution-errors.workspace = true reth-primitives.workspace = true reth-stages-types.workspace = true reth-storage-errors.workspace = true +reth-trie-sparse.workspace = true reth-trie-common.workspace = true revm.workspace = true diff --git a/crates/trie/trie/src/proof/blinded.rs b/crates/trie/trie/src/proof/blinded.rs new file mode 100644 index 000000000000..adcaef46b08a --- /dev/null +++ b/crates/trie/trie/src/proof/blinded.rs @@ -0,0 +1,116 @@ +use super::{Proof, StorageProof}; +use crate::{hashed_cursor::HashedCursorFactory, trie_cursor::TrieCursorFactory}; +use alloy_primitives::{ + map::{HashMap, HashSet}, + Bytes, B256, +}; +use reth_trie_common::{prefix_set::TriePrefixSetsMut, Nibbles}; +use reth_trie_sparse::{ + blinded::{pad_path_to_key, BlindedProvider, BlindedProviderFactory}, + SparseTrieError, +}; +use std::sync::Arc; + +/// Factory for instantiating providers capable of retrieving blinded trie nodes via proofs. +#[derive(Debug)] +pub struct ProofBlindedProviderFactory { + /// The cursor factory for traversing trie nodes. + trie_cursor_factory: T, + /// The factory for hashed cursors. + hashed_cursor_factory: H, + /// A set of prefix sets that have changes. + prefix_sets: Arc, +} + +impl BlindedProviderFactory for ProofBlindedProviderFactory +where + T: TrieCursorFactory + Clone, + H: HashedCursorFactory + Clone, +{ + type AccountNodeProvider = ProofBlindedAccountProvider; + type StorageNodeProvider = ProofBlindedStorageProvider; + + fn account_node_provider(&self) -> Self::AccountNodeProvider { + ProofBlindedAccountProvider { + trie_cursor_factory: self.trie_cursor_factory.clone(), + hashed_cursor_factory: self.hashed_cursor_factory.clone(), + prefix_sets: self.prefix_sets.clone(), + } + } + + fn storage_node_provider(&self, account: B256) -> Self::StorageNodeProvider { + ProofBlindedStorageProvider { + trie_cursor_factory: self.trie_cursor_factory.clone(), + hashed_cursor_factory: self.hashed_cursor_factory.clone(), + prefix_sets: self.prefix_sets.clone(), + account, + } + } +} + +/// Blinded provider for retrieving account trie nodes by path. +#[derive(Debug)] +pub struct ProofBlindedAccountProvider { + /// The cursor factory for traversing trie nodes. + trie_cursor_factory: T, + /// The factory for hashed cursors. + hashed_cursor_factory: H, + /// A set of prefix sets that have changes. + prefix_sets: Arc, +} + +impl BlindedProvider for ProofBlindedAccountProvider +where + T: TrieCursorFactory + Clone, + H: HashedCursorFactory + Clone, +{ + type Error = SparseTrieError; + + fn blinded_node(&mut self, path: Nibbles) -> Result, Self::Error> { + let targets = HashMap::from_iter([(pad_path_to_key(&path), HashSet::default())]); + let proof = + Proof::new(self.trie_cursor_factory.clone(), self.hashed_cursor_factory.clone()) + .with_prefix_sets_mut(self.prefix_sets.as_ref().clone()) + .multiproof(targets) + .map_err(|error| SparseTrieError::Other(Box::new(error)))?; + + Ok(proof.account_subtree.into_inner().remove(&path)) + } +} + +/// Blinded provider for retrieving storage trie nodes by path. +#[derive(Debug)] +pub struct ProofBlindedStorageProvider { + /// The cursor factory for traversing trie nodes. + trie_cursor_factory: T, + /// The factory for hashed cursors. + hashed_cursor_factory: H, + /// A set of prefix sets that have changes. + prefix_sets: Arc, + /// Target account. + account: B256, +} + +impl BlindedProvider for ProofBlindedStorageProvider +where + T: TrieCursorFactory + Clone, + H: HashedCursorFactory + Clone, +{ + type Error = SparseTrieError; + + fn blinded_node(&mut self, path: Nibbles) -> Result, Self::Error> { + let targets = HashSet::from_iter([pad_path_to_key(&path)]); + let storage_prefix_set = + self.prefix_sets.storage_prefix_sets.get(&self.account).cloned().unwrap_or_default(); + let proof = StorageProof::new_hashed( + self.trie_cursor_factory.clone(), + self.hashed_cursor_factory.clone(), + self.account, + ) + .with_prefix_set_mut(storage_prefix_set) + .storage_multiproof(targets) + .map_err(|error| SparseTrieError::Other(Box::new(error)))?; + + Ok(proof.subtree.into_inner().remove(&path)) + } +} diff --git a/crates/trie/trie/src/proof.rs b/crates/trie/trie/src/proof/mod.rs similarity index 99% rename from crates/trie/trie/src/proof.rs rename to crates/trie/trie/src/proof/mod.rs index 3cb0ff6f2f70..c344ec76239a 100644 --- a/crates/trie/trie/src/proof.rs +++ b/crates/trie/trie/src/proof/mod.rs @@ -17,6 +17,9 @@ use reth_trie_common::{ proof::ProofRetainer, AccountProof, MultiProof, StorageMultiProof, TrieAccount, }; +mod blinded; +pub use blinded::*; + /// A struct for generating merkle proofs. /// /// Proof generator adds the target address and slots to the prefix set, enables the proof retainer