Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
rkrasiuk committed Sep 26, 2024
1 parent f4cbfbc commit 77992e3
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 36 deletions.
5 changes: 2 additions & 3 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ alloy-dyn-abi = "0.8.0"
alloy-primitives = { version = "0.8.4", default-features = false }
alloy-rlp = "0.3.4"
alloy-sol-types = "0.8.0"
alloy-trie = { version = "0.5", default-features = false }
alloy-trie = { version = "0.6", default-features = false }

alloy-consensus = { version = "0.3.6", default-features = false }
alloy-eips = { version = "0.3.6", default-features = false }
Expand Down
3 changes: 3 additions & 0 deletions crates/evm/execution-errors/src/trie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ pub enum TrieWitnessError {
/// Missing target node.
#[display("target node missing from proof {_0:?}")]
MissingTargetNode(Nibbles),
/// Unexpected empty root.
#[display("unexpected empty root: {_0:?}")]
UnexpectedEmptyRoot(Nibbles),
}

impl From<TrieWitnessError> for ProviderError {
Expand Down
19 changes: 10 additions & 9 deletions crates/trie/common/src/proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ use alloy_primitives::{keccak256, Address, Bytes, B256, U256};
use alloy_rlp::{encode_fixed_size, Decodable};
use alloy_trie::{
nodes::TrieNode,
proof::{verify_proof, ProofVerificationError},
proof::{verify_proof, ProofNodes, ProofVerificationError},
EMPTY_ROOT_HASH,
};
use itertools::Itertools;
use reth_primitives_traits::{constants::KECCAK_EMPTY, Account};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::collections::HashMap;

/// The state multiproof of target accounts and multiproofs of their storage tries.
/// Multiproof is effectively a state subtrie that only contains the nodes
/// in the paths of target accounts.
#[derive(Clone, Default, Debug)]
pub struct MultiProof {
/// State trie multiproof for requested accounts.
pub account_subtree: BTreeMap<Nibbles, Bytes>,
pub account_subtree: ProofNodes,
/// Storage trie multiproofs.
pub storages: HashMap<B256, StorageMultiProof>,
}
Expand All @@ -36,8 +37,8 @@ impl MultiProof {
// Retrieve the account proof.
let proof = self
.account_subtree
.iter()
.filter(|(path, _)| nibbles.starts_with(path))
.matching_nodes_iter(&nibbles)
.sorted_by(|a, b| a.0.cmp(b.0))
.map(|(_, node)| node.clone())
.collect::<Vec<_>>();

Expand Down Expand Up @@ -82,12 +83,12 @@ pub struct StorageMultiProof {
/// Storage trie root.
pub root: B256,
/// Storage multiproof for requested slots.
pub subtree: BTreeMap<Nibbles, Bytes>,
pub subtree: ProofNodes,
}

impl Default for StorageMultiProof {
fn default() -> Self {
Self { root: EMPTY_ROOT_HASH, subtree: BTreeMap::default() }
Self { root: EMPTY_ROOT_HASH, subtree: Default::default() }
}
}

Expand All @@ -99,8 +100,8 @@ impl StorageMultiProof {
// Retrieve the storage proof.
let proof = self
.subtree
.iter()
.filter(|(path, _)| nibbles.starts_with(path))
.matching_nodes_iter(&nibbles)
.sorted_by(|a, b| a.0.cmp(b.0))
.map(|(_, node)| node.clone())
.collect::<Vec<_>>();

Expand Down
4 changes: 2 additions & 2 deletions crates/trie/trie/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ where
}
}
let _ = hash_builder.root();
Ok(MultiProof { account_subtree: hash_builder.take_proofs(), storages })
Ok(MultiProof { account_subtree: hash_builder.take_proof_nodes(), storages })
}

/// Generate a storage multiproof according to specified targets.
Expand Down Expand Up @@ -181,6 +181,6 @@ where
}

let root = hash_builder.root();
Ok(StorageMultiProof { root, subtree: hash_builder.take_proofs() })
Ok(StorageMultiProof { root, subtree: hash_builder.take_proof_nodes() })
}
}
56 changes: 35 additions & 21 deletions crates/trie/trie/src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use alloy_primitives::{
Bytes, B256,
};
use alloy_rlp::{BufMut, Decodable, Encodable};
use itertools::Either;
use reth_execution_errors::{StateProofError, TrieWitnessError};
use itertools::{Either, Itertools};
use reth_execution_errors::TrieWitnessError;
use reth_primitives::constants::EMPTY_ROOT_HASH;
use reth_trie_common::{
BranchNode, HashBuilder, Nibbles, TrieAccount, TrieNode, CHILD_INDEX_RANGE,
Expand Down Expand Up @@ -120,32 +120,44 @@ where
None
};
let key = Nibbles::unpack(hashed_address);
let proof = account_multiproof.account_subtree.iter().filter(|e| key.starts_with(e.0));
account_trie_nodes.extend(self.target_nodes(key.clone(), value, proof)?);
account_trie_nodes.extend(
self.target_nodes(
key.clone(),
value,
account_multiproof
.account_subtree
.matching_nodes_iter(&key)
.sorted_by(|a, b| a.0.cmp(b.0)),
)?,
);

// Gather and record storage trie nodes for this account.
let mut storage_trie_nodes = BTreeMap::default();
let storage = state.storages.get(&hashed_address);
for hashed_slot in hashed_slots {
let slot_key = Nibbles::unpack(hashed_slot);
let slot_nibbles = Nibbles::unpack(hashed_slot);
let slot_value = storage
.and_then(|s| s.storage.get(&hashed_slot))
.filter(|v| !v.is_zero())
.map(|v| alloy_rlp::encode_fixed_size(v).to_vec());
let proof = storage_multiproof.subtree.iter().filter(|e| slot_key.starts_with(e.0));
storage_trie_nodes.extend(self.target_nodes(
slot_key.clone(),
slot_value,
proof,
)?);
storage_trie_nodes.extend(
self.target_nodes(
slot_nibbles.clone(),
slot_value,
storage_multiproof
.subtree
.matching_nodes_iter(&slot_nibbles)
.sorted_by(|a, b| a.0.cmp(b.0)),
)?,
);
}

Self::next_root_from_proofs(storage_trie_nodes, |key: Nibbles| {
// Right pad the target with 0s.
let mut padded_key = key.pack();
padded_key.resize(32, 0);
let target_key = B256::from_slice(&padded_key);
let mut proof = Proof::new(
let proof = Proof::new(
self.trie_cursor_factory.clone(),
self.hashed_cursor_factory.clone(),
)
Expand All @@ -155,29 +167,27 @@ where

// The subtree only contains the proof for a single target.
let node =
proof.subtree.remove(&key).ok_or(TrieWitnessError::MissingTargetNode(key))?;
proof.subtree.get(&key).ok_or(TrieWitnessError::MissingTargetNode(key))?;
self.witness.insert(keccak256(node.as_ref()), node.clone()); // record in witness
Ok(node)
Ok(node.clone())
})?;
}

Self::next_root_from_proofs(account_trie_nodes, |key: Nibbles| {
// Right pad the target with 0s.
let mut padded_key = key.pack();
padded_key.resize(32, 0);
let mut proof =
let proof =
Proof::new(self.trie_cursor_factory.clone(), self.hashed_cursor_factory.clone())
.with_prefix_sets_mut(self.prefix_sets.clone())
.with_target((B256::from_slice(&padded_key), HashSet::default()))
.multiproof()?;

// The subtree only contains the proof for a single target.
let node = proof
.account_subtree
.remove(&key)
.ok_or(TrieWitnessError::MissingTargetNode(key))?;
let node =
proof.account_subtree.get(&key).ok_or(TrieWitnessError::MissingTargetNode(key))?;
self.witness.insert(keccak256(node.as_ref()), node.clone()); // record in witness
Ok(node)
Ok(node.clone())
})?;

Ok(self.witness)
Expand All @@ -190,7 +200,7 @@ where
key: Nibbles,
value: Option<Vec<u8>>,
proof: impl IntoIterator<Item = (&'b Nibbles, &'b Bytes)>,
) -> Result<BTreeMap<Nibbles, Either<B256, Vec<u8>>>, StateProofError> {
) -> Result<BTreeMap<Nibbles, Either<B256, Vec<u8>>>, TrieWitnessError> {
let mut trie_nodes = BTreeMap::default();
for (path, encoded) in proof {
// Record the node in witness.
Expand All @@ -216,6 +226,7 @@ where
trie_nodes.insert(next_path.clone(), Either::Right(leaf.value.clone()));
}
}
TrieNode::EmptyRoot => return Err(TrieWitnessError::UnexpectedEmptyRoot(next_path)),
};
}

Expand Down Expand Up @@ -273,6 +284,9 @@ where
TrieNode::Extension(ext) => {
path.extend_from_slice(&ext.key);
}
TrieNode::EmptyRoot => {
return Err(TrieWitnessError::UnexpectedEmptyRoot(path))
}
}
}
}
Expand Down

0 comments on commit 77992e3

Please sign in to comment.