1use super::ExecutedBlock;
2use alloy_consensus::BlockHeader;
3use alloy_primitives::{keccak256, Address, BlockNumber, Bytes, StorageKey, StorageValue, B256};
4use reth_errors::ProviderResult;
5use reth_primitives_traits::{Account, Bytecode, NodePrimitives};
6use reth_storage_api::{
7 AccountReader, BlockHashReader, BytecodeReader, HashedPostStateProvider, StateProofProvider,
8 StateProvider, StateProviderBox, StateRootProvider, StorageRootProvider,
9};
10use reth_trie::{
11 updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
12 MultiProofTargets, StorageMultiProof, TrieInput,
13};
14use revm_database::BundleState;
15use std::{borrow::Cow, sync::OnceLock};
16
17#[expect(missing_debug_implementations)]
20pub struct MemoryOverlayStateProviderRef<
21 'a,
22 N: NodePrimitives = reth_ethereum_primitives::EthPrimitives,
23> {
24 pub(crate) historical: Box<dyn StateProvider + 'a>,
26 pub(crate) in_memory: Cow<'a, [ExecutedBlock<N>]>,
28 pub(crate) trie_input: OnceLock<TrieInput>,
30}
31
32impl<'a, N: NodePrimitives> MemoryOverlayStateProviderRef<'a, N> {
33 pub fn new(historical: Box<dyn StateProvider + 'a>, in_memory: Vec<ExecutedBlock<N>>) -> Self {
41 Self { historical, in_memory: Cow::Owned(in_memory), trie_input: OnceLock::new() }
42 }
43
44 pub fn boxed(self) -> Box<dyn StateProvider + 'a> {
46 Box::new(self)
47 }
48
49 fn trie_input(&self) -> &TrieInput {
51 self.trie_input.get_or_init(|| {
52 let mut input = TrieInput::default();
53 for block in self.in_memory.iter().rev() {
55 let data = block.trie_data();
56 input.nodes.extend_from_sorted(&data.trie_updates);
57 input.state.extend_from_sorted(&data.hashed_state);
58 }
59 input
60 })
61 }
62
63 fn merged_hashed_storage(&self, address: Address, storage: HashedStorage) -> HashedStorage {
64 let state = &self.trie_input().state;
65 let mut hashed = state.storages.get(&keccak256(address)).cloned().unwrap_or_default();
66 hashed.extend(&storage);
67 hashed
68 }
69}
70
71impl<N: NodePrimitives> BlockHashReader for MemoryOverlayStateProviderRef<'_, N> {
72 fn block_hash(&self, number: BlockNumber) -> ProviderResult<Option<B256>> {
73 for block in self.in_memory.iter() {
74 if block.recovered_block().number() == number {
75 return Ok(Some(block.recovered_block().hash()));
76 }
77 }
78
79 self.historical.block_hash(number)
80 }
81
82 fn canonical_hashes_range(
83 &self,
84 start: BlockNumber,
85 end: BlockNumber,
86 ) -> ProviderResult<Vec<B256>> {
87 let range = start..end;
88 let mut earliest_block_number = None;
89 let mut in_memory_hashes = Vec::with_capacity(range.size_hint().0);
90
91 for block in self.in_memory.iter() {
93 let block_num = block.recovered_block().number();
94 if range.contains(&block_num) {
95 in_memory_hashes.push(block.recovered_block().hash());
96 earliest_block_number = Some(block_num);
97 }
98 }
99
100 in_memory_hashes.reverse();
104
105 let mut hashes =
106 self.historical.canonical_hashes_range(start, earliest_block_number.unwrap_or(end))?;
107 hashes.append(&mut in_memory_hashes);
108 Ok(hashes)
109 }
110}
111
112impl<N: NodePrimitives> AccountReader for MemoryOverlayStateProviderRef<'_, N> {
113 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
114 for block in self.in_memory.iter() {
115 if let Some(account) = block.execution_output.account(address) {
116 return Ok(account);
117 }
118 }
119
120 self.historical.basic_account(address)
121 }
122}
123
124impl<N: NodePrimitives> StateRootProvider for MemoryOverlayStateProviderRef<'_, N> {
125 fn state_root(&self, state: HashedPostState) -> ProviderResult<B256> {
126 self.state_root_from_nodes(TrieInput::from_state(state))
127 }
128
129 fn state_root_from_nodes(&self, mut input: TrieInput) -> ProviderResult<B256> {
130 input.prepend_self(self.trie_input().clone());
131 self.historical.state_root_from_nodes(input)
132 }
133
134 fn state_root_with_updates(
135 &self,
136 state: HashedPostState,
137 ) -> ProviderResult<(B256, TrieUpdates)> {
138 self.state_root_from_nodes_with_updates(TrieInput::from_state(state))
139 }
140
141 fn state_root_from_nodes_with_updates(
142 &self,
143 mut input: TrieInput,
144 ) -> ProviderResult<(B256, TrieUpdates)> {
145 input.prepend_self(self.trie_input().clone());
146 self.historical.state_root_from_nodes_with_updates(input)
147 }
148}
149
150impl<N: NodePrimitives> StorageRootProvider for MemoryOverlayStateProviderRef<'_, N> {
151 fn storage_root(&self, address: Address, storage: HashedStorage) -> ProviderResult<B256> {
153 let merged = self.merged_hashed_storage(address, storage);
154 self.historical.storage_root(address, merged)
155 }
156
157 fn storage_proof(
159 &self,
160 address: Address,
161 slot: B256,
162 storage: HashedStorage,
163 ) -> ProviderResult<reth_trie::StorageProof> {
164 let merged = self.merged_hashed_storage(address, storage);
165 self.historical.storage_proof(address, slot, merged)
166 }
167
168 fn storage_multiproof(
170 &self,
171 address: Address,
172 slots: &[B256],
173 storage: HashedStorage,
174 ) -> ProviderResult<StorageMultiProof> {
175 let merged = self.merged_hashed_storage(address, storage);
176 self.historical.storage_multiproof(address, slots, merged)
177 }
178}
179
180impl<N: NodePrimitives> StateProofProvider for MemoryOverlayStateProviderRef<'_, N> {
181 fn proof(
182 &self,
183 mut input: TrieInput,
184 address: Address,
185 slots: &[B256],
186 ) -> ProviderResult<AccountProof> {
187 input.prepend_self(self.trie_input().clone());
188 self.historical.proof(input, address, slots)
189 }
190
191 fn multiproof(
192 &self,
193 mut input: TrieInput,
194 targets: MultiProofTargets,
195 ) -> ProviderResult<MultiProof> {
196 input.prepend_self(self.trie_input().clone());
197 self.historical.multiproof(input, targets)
198 }
199
200 fn witness(
201 &self,
202 mut input: TrieInput,
203 target: HashedPostState,
204 mode: reth_trie::ExecutionWitnessMode,
205 ) -> ProviderResult<Vec<Bytes>> {
206 input.prepend_self(self.trie_input().clone());
207 self.historical.witness(input, target, mode)
208 }
209}
210
211impl<N: NodePrimitives> HashedPostStateProvider for MemoryOverlayStateProviderRef<'_, N> {
212 fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState {
213 self.historical.hashed_post_state(bundle_state)
214 }
215}
216
217impl<N: NodePrimitives> StateProvider for MemoryOverlayStateProviderRef<'_, N> {
218 fn storage(
219 &self,
220 address: Address,
221 storage_key: StorageKey,
222 ) -> ProviderResult<Option<StorageValue>> {
223 for block in self.in_memory.iter() {
224 if let Some(value) = block.execution_output.storage(&address, storage_key.into()) {
225 return Ok(Some(value));
226 }
227 }
228
229 self.historical.storage(address, storage_key)
230 }
231}
232
233impl<N: NodePrimitives> BytecodeReader for MemoryOverlayStateProviderRef<'_, N> {
234 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
235 for block in self.in_memory.iter() {
236 if let Some(contract) = block.execution_output.bytecode(code_hash) {
237 return Ok(Some(contract));
238 }
239 }
240
241 self.historical.bytecode_by_hash(code_hash)
242 }
243}
244
245#[expect(missing_debug_implementations)]
248pub struct MemoryOverlayStateProvider<N: NodePrimitives = reth_ethereum_primitives::EthPrimitives> {
249 pub(crate) historical: StateProviderBox,
251 pub(crate) in_memory: Vec<ExecutedBlock<N>>,
253 pub(crate) trie_input: OnceLock<TrieInput>,
255}
256
257impl<N: NodePrimitives> MemoryOverlayStateProvider<N> {
258 pub fn new(historical: StateProviderBox, in_memory: Vec<ExecutedBlock<N>>) -> Self {
266 Self { historical, in_memory, trie_input: OnceLock::new() }
267 }
268
269 #[inline(always)]
271 fn as_ref(&self) -> MemoryOverlayStateProviderRef<'_, N> {
272 MemoryOverlayStateProviderRef {
273 historical: Box::new(self.historical.as_ref()),
274 in_memory: Cow::Borrowed(&self.in_memory),
275 trie_input: self.trie_input.clone(),
276 }
277 }
278
279 pub fn boxed(self) -> StateProviderBox {
281 Box::new(self)
282 }
283}
284
285reth_storage_api::macros::delegate_provider_impls!(MemoryOverlayStateProvider<N> where [N: NodePrimitives]);