reth_trie/proof_v2/
value.rs

1//! Generic value encoder types for proof calculation with lazy evaluation.
2
3use crate::{
4    hashed_cursor::HashedCursorFactory, proof_v2::ProofCalculator, trie_cursor::TrieCursorFactory,
5};
6use alloy_primitives::{B256, U256};
7use alloy_rlp::Encodable;
8use reth_execution_errors::trie::StateProofError;
9use reth_primitives_traits::Account;
10use reth_trie_common::Nibbles;
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(&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(&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}
88
89impl<T, H> SyncAccountValueEncoder<T, H> {
90    /// Create a new account value encoder with the given factories.
91    pub fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
92        Self {
93            trie_cursor_factory: Rc::new(trie_cursor_factory),
94            hashed_cursor_factory: Rc::new(hashed_cursor_factory),
95        }
96    }
97}
98
99/// The deferred encoder for an account value with synchronous storage root calculation.
100#[derive(Debug, Clone)]
101pub struct SyncAccountDeferredValueEncoder<T, H> {
102    trie_cursor_factory: Rc<T>,
103    hashed_cursor_factory: Rc<H>,
104    hashed_address: B256,
105    account: Account,
106}
107
108impl<T, H> DeferredValueEncoder for SyncAccountDeferredValueEncoder<T, H>
109where
110    T: TrieCursorFactory,
111    H: HashedCursorFactory,
112{
113    // Synchronously computes the storage root for this account and RLP-encodes the resulting
114    // `TrieAccount` into `buf`
115    fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError> {
116        // Create cursors for storage proof calculation
117        let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?;
118        let hashed_cursor =
119            self.hashed_cursor_factory.hashed_storage_cursor(self.hashed_address)?;
120
121        // Create storage proof calculator with StorageValueEncoder
122        let mut storage_proof_calculator = ProofCalculator::new_storage(trie_cursor, hashed_cursor);
123
124        // Compute storage root by calling storage_proof with the root path as a target.
125        // This returns just the root node of the storage trie.
126        let storage_root = storage_proof_calculator
127            .storage_proof(self.hashed_address, [Nibbles::new()])
128            .map(|nodes| {
129                // Encode the root node to RLP and hash it
130                let root_node =
131                    nodes.first().expect("storage_proof always returns at least the root");
132                root_node.node.encode(buf);
133
134                let storage_root = alloy_primitives::keccak256(buf.as_slice());
135
136                // Clear the buffer so we can re-use it to encode the TrieAccount
137                buf.clear();
138
139                storage_root
140            })?;
141
142        // Combine account with storage root to create TrieAccount
143        let trie_account = self.account.into_trie_account(storage_root);
144
145        // Encode the trie account
146        trie_account.encode(buf);
147
148        Ok(())
149    }
150}
151
152impl<T, H> LeafValueEncoder for SyncAccountValueEncoder<T, H>
153where
154    T: TrieCursorFactory,
155    H: HashedCursorFactory,
156{
157    type Value = Account;
158    type DeferredEncoder = SyncAccountDeferredValueEncoder<T, H>;
159
160    fn deferred_encoder(
161        &self,
162        hashed_address: B256,
163        account: Self::Value,
164    ) -> Self::DeferredEncoder {
165        // Return a deferred encoder that will synchronously compute the storage root when encode()
166        // is called.
167        SyncAccountDeferredValueEncoder {
168            trie_cursor_factory: self.trie_cursor_factory.clone(),
169            hashed_cursor_factory: self.hashed_cursor_factory.clone(),
170            hashed_address,
171            account,
172        }
173    }
174}