reth_rpc_eth_api/helpers/
state.rs1use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking};
5use crate::{EthApiTypes, FromEthApiError, RpcNodeCore, RpcNodeCoreExt};
6use alloy_consensus::constants::KECCAK_EMPTY;
7use alloy_eips::BlockId;
8use alloy_primitives::{Address, Bytes, B256, U256};
9use alloy_rpc_types_eth::{Account, AccountInfo, EIP1186AccountProofResponse};
10use alloy_serde::JsonStorageKey;
11use futures::Future;
12use reth_errors::RethError;
13use reth_evm::{ConfigureEvm, EvmEnvFor};
14use reth_primitives_traits::SealedHeaderFor;
15use reth_rpc_convert::{RpcConvert, RpcTxReq};
16use reth_rpc_eth_types::{
17 error::{FromEvmError, IntoEthApiError},
18 EthApiError, PendingBlockEnv, RpcInvalidTransactionError, SignError,
19};
20use reth_rpc_server_types::constants::DEFAULT_MAX_STORAGE_VALUES_SLOTS;
21use reth_storage_api::{
22 BlockIdReader, BlockReaderIdExt, StateProvider, StateProviderBox, StateProviderFactory,
23};
24use reth_transaction_pool::TransactionPool;
25use std::collections::HashMap;
26
27pub trait EthState: LoadState + SpawnBlocking {
29 fn max_proof_window(&self) -> u64;
31
32 fn ensure_within_proof_window(&self, block_id: BlockId) -> Result<(), Self::Error>
37 where
38 Self: EthApiSpec,
39 {
40 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
41 let block_number = self
42 .provider()
43 .block_number_for_id(block_id)
44 .map_err(Self::Error::from_eth_err)?
45 .ok_or(EthApiError::HeaderNotFound(block_id))?;
46 if chain_info.best_number.saturating_sub(block_number) > self.max_proof_window() {
47 return Err(EthApiError::ExceedsMaxProofWindow.into())
48 }
49 Ok(())
50 }
51
52 fn transaction_count(
57 &self,
58 address: Address,
59 block_id: Option<BlockId>,
60 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
61 LoadState::transaction_count(self, address, block_id)
62 }
63
64 fn get_code(
66 &self,
67 address: Address,
68 block_id: Option<BlockId>,
69 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
70 LoadState::get_code(self, address, block_id)
71 }
72
73 fn balance(
75 &self,
76 address: Address,
77 block_id: Option<BlockId>,
78 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
79 self.spawn_blocking_io_fut(async move |this| {
80 Ok(this
81 .state_at_block_id_or_latest(block_id)
82 .await?
83 .account_balance(&address)
84 .map_err(Self::Error::from_eth_err)?
85 .unwrap_or_default())
86 })
87 }
88
89 fn storage_at(
91 &self,
92 address: Address,
93 index: JsonStorageKey,
94 block_id: Option<BlockId>,
95 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
96 self.spawn_blocking_io_fut(async move |this| {
97 Ok(B256::new(
98 this.state_at_block_id_or_latest(block_id)
99 .await?
100 .storage(address, index.as_b256())
101 .map_err(Self::Error::from_eth_err)?
102 .unwrap_or_default()
103 .to_be_bytes(),
104 ))
105 })
106 }
107
108 fn storage_values(
113 &self,
114 requests: HashMap<Address, Vec<JsonStorageKey>>,
115 block_id: Option<BlockId>,
116 ) -> impl Future<Output = Result<HashMap<Address, Vec<B256>>, Self::Error>> + Send {
117 async move {
118 if requests.is_empty() {
119 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(
120 "empty request".to_string(),
121 )));
122 }
123 let total_slots: usize = requests.values().map(|slots| slots.len()).sum();
124 if total_slots > DEFAULT_MAX_STORAGE_VALUES_SLOTS {
125 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(
126 format!(
127 "total slot count {total_slots} exceeds limit {DEFAULT_MAX_STORAGE_VALUES_SLOTS}",
128 ),
129 )));
130 }
131
132 self.spawn_blocking_io_fut(async move |this| {
133 let state = this.state_at_block_id_or_latest(block_id).await?;
134
135 let mut result = HashMap::with_capacity(requests.len());
136 for (address, slots) in requests {
137 let mut values = Vec::with_capacity(slots.len());
138 for slot in &slots {
139 let value = state
140 .storage(address, slot.as_b256())
141 .map_err(Self::Error::from_eth_err)?
142 .unwrap_or_default();
143 values.push(B256::new(value.to_be_bytes()));
144 }
145 result.insert(address, values);
146 }
147
148 Ok(result)
149 })
150 .await
151 }
152 }
153
154 fn get_proof(
156 &self,
157 address: Address,
158 keys: Vec<JsonStorageKey>,
159 block_id: Option<BlockId>,
160 ) -> Result<
161 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
162 Self::Error,
163 >
164 where
165 Self: EthApiSpec,
166 {
167 Ok(async move {
168 let _permit = self
169 .acquire_owned_tracing()
170 .await
171 .map_err(RethError::other)
172 .map_err(EthApiError::Internal)?;
173
174 let block_id = block_id.unwrap_or_default();
175 self.ensure_within_proof_window(block_id)?;
176
177 self.spawn_blocking_io_fut(async move |this| {
178 let state = this.state_at_block_id(block_id).await?;
179 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
180 let proof = state
181 .proof(Default::default(), address, &storage_keys)
182 .map_err(Self::Error::from_eth_err)?;
183 Ok(proof.into_eip1186_response(keys))
184 })
185 .await
186 })
187 }
188
189 fn get_account(
191 &self,
192 address: Address,
193 block_id: BlockId,
194 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send
195 where
196 Self: EthApiSpec,
197 {
198 async move {
199 self.ensure_within_proof_window(block_id)?;
200
201 self.spawn_blocking_io_fut(async move |this| {
202 let state = this.state_at_block_id(block_id).await?;
203 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
204 let Some(account) = account else { return Ok(None) };
205
206 let balance = account.balance;
207 let nonce = account.nonce;
208 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
209
210 let storage_root = state
213 .storage_root(address, Default::default())
214 .map_err(Self::Error::from_eth_err)?;
215
216 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
217 })
218 .await
219 }
220 }
221
222 fn get_account_info(
224 &self,
225 address: Address,
226 block_id: BlockId,
227 ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
228 self.spawn_blocking_io_fut(async move |this| {
229 let state = this.state_at_block_id(block_id).await?;
230 let account = state
231 .basic_account(&address)
232 .map_err(Self::Error::from_eth_err)?
233 .unwrap_or_default();
234
235 let balance = account.balance;
236 let nonce = account.nonce;
237 let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
238 Default::default()
239 } else {
240 state
241 .account_code(&address)
242 .map_err(Self::Error::from_eth_err)?
243 .unwrap_or_default()
244 .original_bytes()
245 };
246
247 Ok(AccountInfo { balance, nonce, code })
248 })
249 }
250}
251
252pub trait LoadState:
256 LoadPendingBlock
257 + EthApiTypes<
258 Error: FromEvmError<Self::Evm> + FromEthApiError,
259 RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
260 > + RpcNodeCoreExt
261{
262 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
264 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
265 }
266
267 fn state_at_block_id(
272 &self,
273 at: BlockId,
274 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
275 where
276 Self: SpawnBlocking,
277 {
278 async move {
279 if at.is_pending() &&
280 let Ok(Some(state)) = self.local_pending_state().await
281 {
282 return Ok(state)
283 }
284
285 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
286 }
287 }
288
289 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
291 self.provider().latest().map_err(Self::Error::from_eth_err)
292 }
293
294 fn state_at_block_id_or_latest(
298 &self,
299 block_id: Option<BlockId>,
300 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
301 where
302 Self: SpawnBlocking,
303 {
304 async move {
305 if let Some(block_id) = block_id {
306 self.state_at_block_id(block_id).await
307 } else {
308 Ok(self.latest_state()?)
309 }
310 }
311 }
312
313 fn evm_env_for_header(
315 &self,
316 header: &SealedHeaderFor<Self::Primitives>,
317 ) -> Result<EvmEnvFor<Self::Evm>, Self::Error> {
318 self.evm_config()
319 .evm_env(header)
320 .map_err(RethError::other)
321 .map_err(Self::Error::from_eth_err)
322 }
323
324 fn evm_env_at(
331 &self,
332 at: BlockId,
333 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
334 where
335 Self: SpawnBlocking,
336 {
337 async move {
338 if at.is_pending() {
339 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
340 Ok((evm_env, origin.state_block_id()))
341 } else {
342 let header = RpcNodeCore::provider(self)
346 .sealed_header_by_id(at)
347 .map_err(Self::Error::from_eth_err)?
348 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
349 let evm_env = self.evm_env_for_header(&header)?;
350
351 Ok((evm_env, header.hash().into()))
352 }
353 }
354 }
355
356 fn next_available_nonce_for(
362 &self,
363 request: &RpcTxReq<Self::NetworkTypes>,
364 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
365 where
366 Self: SpawnBlocking,
367 {
368 let address = request.as_ref().from;
369 self.spawn_blocking_io(move |this| {
370 let address = match address {
371 Some(address) => address,
372 None => return Err(SignError::NoAccount.into_eth_err()),
373 };
374
375 let mut next_nonce = this
377 .latest_state()?
378 .account_nonce(&address)
379 .map_err(Self::Error::from_eth_err)?
380 .unwrap_or_default();
381
382 if let Some(highest_tx) =
384 this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
385 {
386 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
388 Self::Error::from(EthApiError::InvalidTransaction(
389 RpcInvalidTransactionError::NonceMaxValue,
390 ))
391 })?;
392 }
393
394 Ok(next_nonce)
395 })
396 }
397
398 fn transaction_count(
403 &self,
404 address: Address,
405 block_id: Option<BlockId>,
406 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
407 where
408 Self: SpawnBlocking,
409 {
410 self.spawn_blocking_io_fut(async move |this| {
411 let on_chain_account_nonce = this
413 .state_at_block_id_or_latest(block_id)
414 .await?
415 .account_nonce(&address)
416 .map_err(Self::Error::from_eth_err)?
417 .unwrap_or_default();
418
419 if block_id == Some(BlockId::pending()) {
420 if let Some(highest_pool_tx) = this
422 .pool()
423 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
424 {
425 {
426 let next_tx_nonce =
429 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
430 Self::Error::from(EthApiError::InvalidTransaction(
431 RpcInvalidTransactionError::NonceMaxValue,
432 ))
433 })?;
434
435 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
437
438 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
439 return Ok(U256::from(tx_count));
440 }
441 }
442 }
443 Ok(U256::from(on_chain_account_nonce))
444 })
445 }
446
447 fn get_code(
449 &self,
450 address: Address,
451 block_id: Option<BlockId>,
452 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
453 where
454 Self: SpawnBlocking,
455 {
456 self.spawn_blocking_io_fut(async move |this| {
457 Ok(this
458 .state_at_block_id_or_latest(block_id)
459 .await?
460 .account_code(&address)
461 .map_err(Self::Error::from_eth_err)?
462 .unwrap_or_default()
463 .original_bytes())
464 })
465 }
466}