Skip to content

Commit

Permalink
feat(trie): proof blinded providers (#13085)
Browse files Browse the repository at this point in the history
  • Loading branch information
rkrasiuk authored Dec 3, 2024
1 parent ea82cbd commit ae8912f
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions crates/trie/sparse/src/blinded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
3 changes: 3 additions & 0 deletions crates/trie/sparse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,7 @@ pub enum SparseTrieError {
/// RLP error.
#[error(transparent)]
Rlp(#[from] alloy_rlp::Error),
/// Other.
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error>),
}
1 change: 1 addition & 0 deletions crates/trie/trie/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
116 changes: 116 additions & 0 deletions crates/trie/trie/src/proof/blinded.rs
Original file line number Diff line number Diff line change
@@ -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<T, H> {
/// 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<TriePrefixSetsMut>,
}

impl<T, H> BlindedProviderFactory for ProofBlindedProviderFactory<T, H>
where
T: TrieCursorFactory + Clone,
H: HashedCursorFactory + Clone,
{
type AccountNodeProvider = ProofBlindedAccountProvider<T, H>;
type StorageNodeProvider = ProofBlindedStorageProvider<T, H>;

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<T, H> {
/// 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<TriePrefixSetsMut>,
}

impl<T, H> BlindedProvider for ProofBlindedAccountProvider<T, H>
where
T: TrieCursorFactory + Clone,
H: HashedCursorFactory + Clone,
{
type Error = SparseTrieError;

fn blinded_node(&mut self, path: Nibbles) -> Result<Option<Bytes>, 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<T, H> {
/// 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<TriePrefixSetsMut>,
/// Target account.
account: B256,
}

impl<T, H> BlindedProvider for ProofBlindedStorageProvider<T, H>
where
T: TrieCursorFactory + Clone,
H: HashedCursorFactory + Clone,
{
type Error = SparseTrieError;

fn blinded_node(&mut self, path: Nibbles) -> Result<Option<Bytes>, 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))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ae8912f

Please sign in to comment.