Skip to main content

reth_trie/proof_v2/
value.rs

1//! Generic value encoder types for proof calculation with lazy evaluation.
2
3use crate::{
4    hashed_cursor::HashedCursorFactory, prefix_set::PrefixSet, proof_v2::ProofCalculator,
5    trie_cursor::TrieCursorFactory,
6};
7use alloy_primitives::{map::B256Map, B256, U256};
8use alloy_rlp::Encodable;
9use reth_execution_errors::trie::StateProofError;
10use reth_primitives_traits::Account;
11use std::rc::Rc;
12
13/// A trait for deferred RLP-encoding of leaf values.
14pub trait DeferredValueEncoder {
15    /// RLP encodes the value into the provided buffer.
16    ///
17    /// # Arguments
18    ///
19    /// * `buf` - A mutable buffer to encode the data into
20    fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError>;
21}
22
23/// A trait for RLP-encoding values for proof calculation. This trait is designed to allow the lazy
24/// computation of leaf values in a generic way.
25///
26/// When calculating a leaf value in a storage trie the [`DeferredValueEncoder`] simply holds onto
27/// the slot value, and the `encode` method synchronously RLP-encodes it.
28///
29/// When calculating a leaf value in the accounts trie we create a [`DeferredValueEncoder`] to
30/// initiate any asynchronous computation of the account's storage root we want to do. Later we call
31/// [`DeferredValueEncoder::encode`] to obtain the result of that computation and RLP-encode it.
32pub trait LeafValueEncoder {
33    /// The type of value being encoded (e.g., U256 for storage, Account for accounts).
34    type Value;
35
36    /// The type that will compute and encode the value when needed.
37    type DeferredEncoder: DeferredValueEncoder;
38
39    /// Returns an encoder that will RLP-encode the value when its `encode` method is called.
40    ///
41    /// # Arguments
42    ///
43    /// * `key` - The key the value was stored at in the DB
44    /// * `value` - The value to encode
45    ///
46    /// The returned deferred encoder will be called as late as possible in the algorithm to
47    /// maximize the time available for parallel computation (e.g., storage root calculation).
48    fn deferred_encoder(&mut self, key: B256, value: Self::Value) -> Self::DeferredEncoder;
49}
50
51/// An encoder for storage slot values.
52///
53/// This encoder simply RLP-encodes U256 storage values directly.
54#[derive(Debug, Clone, Copy, Default)]
55pub struct StorageValueEncoder;
56
57/// The deferred encoder for a storage slot value.
58#[derive(Debug, Clone, Copy)]
59pub struct StorageDeferredValueEncoder(U256);
60
61impl DeferredValueEncoder for StorageDeferredValueEncoder {
62    fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError> {
63        self.0.encode(buf);
64        Ok(())
65    }
66}
67
68impl LeafValueEncoder for StorageValueEncoder {
69    type Value = U256;
70    type DeferredEncoder = StorageDeferredValueEncoder;
71
72    fn deferred_encoder(&mut self, _key: B256, value: Self::Value) -> Self::DeferredEncoder {
73        StorageDeferredValueEncoder(value)
74    }
75}
76
77/// An account value encoder that synchronously computes storage roots.
78///
79/// This encoder contains factories for creating trie and hashed cursors. Storage roots are
80/// computed synchronously within the deferred encoder using a `StorageProofCalculator`.
81#[derive(Debug, Clone)]
82pub struct SyncAccountValueEncoder<T, H> {
83    /// Factory for creating trie cursors.
84    trie_cursor_factory: Rc<T>,
85    /// Factory for creating hashed cursors.
86    hashed_cursor_factory: Rc<H>,
87    /// Storage prefix sets keyed by hashed address.
88    storage_prefix_sets: Rc<B256Map<PrefixSet>>,
89}
90
91impl<T, H> SyncAccountValueEncoder<T, H> {
92    /// Create a new account value encoder with the given factories.
93    pub fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
94        Self {
95            trie_cursor_factory: Rc::new(trie_cursor_factory),
96            hashed_cursor_factory: Rc::new(hashed_cursor_factory),
97            storage_prefix_sets: Rc::new(B256Map::default()),
98        }
99    }
100
101    /// Sets the storage prefix sets. When given, all cached storage trie hashes matching the
102    /// prefix sets will be invalidated during storage root calculation for the corresponding
103    /// accounts.
104    pub fn with_storage_prefix_sets(mut self, storage_prefix_sets: B256Map<PrefixSet>) -> Self {
105        self.storage_prefix_sets = Rc::new(storage_prefix_sets);
106        self
107    }
108}
109
110/// The deferred encoder for an account value with synchronous storage root calculation.
111#[derive(Debug, Clone)]
112pub struct SyncAccountDeferredValueEncoder<T, H> {
113    trie_cursor_factory: Rc<T>,
114    hashed_cursor_factory: Rc<H>,
115    storage_prefix_sets: Rc<B256Map<PrefixSet>>,
116    hashed_address: B256,
117    account: Account,
118}
119
120impl<T, H> DeferredValueEncoder for SyncAccountDeferredValueEncoder<T, H>
121where
122    T: TrieCursorFactory,
123    H: HashedCursorFactory,
124{
125    fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError> {
126        let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?;
127        let hashed_cursor =
128            self.hashed_cursor_factory.hashed_storage_cursor(self.hashed_address)?;
129
130        let mut storage_proof_calculator = ProofCalculator::new_storage(trie_cursor, hashed_cursor);
131        if let Some(prefix_set) = self.storage_prefix_sets.get(&self.hashed_address) {
132            storage_proof_calculator = storage_proof_calculator.with_prefix_set(prefix_set.clone());
133        }
134        let root_node = storage_proof_calculator.storage_root_node(self.hashed_address)?;
135        let storage_root = storage_proof_calculator
136            .compute_root_hash(&[root_node])?
137            .expect("storage_root_node returns a node at empty path");
138
139        let trie_account = self.account.into_trie_account(storage_root);
140        trie_account.encode(buf);
141
142        Ok(())
143    }
144}
145
146impl<T, H> LeafValueEncoder for SyncAccountValueEncoder<T, H>
147where
148    T: TrieCursorFactory,
149    H: HashedCursorFactory,
150{
151    type Value = Account;
152    type DeferredEncoder = SyncAccountDeferredValueEncoder<T, H>;
153
154    fn deferred_encoder(
155        &mut self,
156        hashed_address: B256,
157        account: Self::Value,
158    ) -> Self::DeferredEncoder {
159        // Return a deferred encoder that will synchronously compute the storage root when encode()
160        // is called.
161        SyncAccountDeferredValueEncoder {
162            trie_cursor_factory: Rc::clone(&self.trie_cursor_factory),
163            hashed_cursor_factory: Rc::clone(&self.hashed_cursor_factory),
164            storage_prefix_sets: Rc::clone(&self.storage_prefix_sets),
165            hashed_address,
166            account,
167        }
168    }
169}