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