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 let total_slots: usize = requests.values().map(|slots| slots.len()).sum();
119 if total_slots > DEFAULT_MAX_STORAGE_VALUES_SLOTS {
120 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(
121 format!(
122 "total slot count {total_slots} exceeds limit {DEFAULT_MAX_STORAGE_VALUES_SLOTS}",
123 ),
124 )));
125 }
126
127 self.spawn_blocking_io_fut(async move |this| {
128 let state = this.state_at_block_id_or_latest(block_id).await?;
129
130 let mut result = HashMap::with_capacity(requests.len());
131 for (address, slots) in requests {
132 let mut values = Vec::with_capacity(slots.len());
133 for slot in &slots {
134 let value = state
135 .storage(address, slot.as_b256())
136 .map_err(Self::Error::from_eth_err)?
137 .unwrap_or_default();
138 values.push(B256::new(value.to_be_bytes()));
139 }
140 result.insert(address, values);
141 }
142
143 Ok(result)
144 })
145 .await
146 }
147 }
148
149 fn get_proof(
151 &self,
152 address: Address,
153 keys: Vec<JsonStorageKey>,
154 block_id: Option<BlockId>,
155 ) -> Result<
156 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
157 Self::Error,
158 >
159 where
160 Self: EthApiSpec,
161 {
162 Ok(async move {
163 let _permit = self
164 .acquire_owned_tracing()
165 .await
166 .map_err(RethError::other)
167 .map_err(EthApiError::Internal)?;
168
169 let block_id = block_id.unwrap_or_default();
170 self.ensure_within_proof_window(block_id)?;
171
172 self.spawn_blocking_io_fut(async move |this| {
173 let state = this.state_at_block_id(block_id).await?;
174 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
175 let proof = state
176 .proof(Default::default(), address, &storage_keys)
177 .map_err(Self::Error::from_eth_err)?;
178 Ok(proof.into_eip1186_response(keys))
179 })
180 .await
181 })
182 }
183
184 fn get_account(
186 &self,
187 address: Address,
188 block_id: BlockId,
189 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send
190 where
191 Self: EthApiSpec,
192 {
193 async move {
194 self.ensure_within_proof_window(block_id)?;
195
196 self.spawn_blocking_io_fut(async move |this| {
197 let state = this.state_at_block_id(block_id).await?;
198 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
199 let Some(account) = account else { return Ok(None) };
200
201 let balance = account.balance;
202 let nonce = account.nonce;
203 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
204
205 let storage_root = state
208 .storage_root(address, Default::default())
209 .map_err(Self::Error::from_eth_err)?;
210
211 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
212 })
213 .await
214 }
215 }
216
217 fn get_account_info(
219 &self,
220 address: Address,
221 block_id: BlockId,
222 ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
223 self.spawn_blocking_io_fut(async move |this| {
224 let state = this.state_at_block_id(block_id).await?;
225 let account = state
226 .basic_account(&address)
227 .map_err(Self::Error::from_eth_err)?
228 .unwrap_or_default();
229
230 let balance = account.balance;
231 let nonce = account.nonce;
232 let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
233 Default::default()
234 } else {
235 state
236 .account_code(&address)
237 .map_err(Self::Error::from_eth_err)?
238 .unwrap_or_default()
239 .original_bytes()
240 };
241
242 Ok(AccountInfo { balance, nonce, code })
243 })
244 }
245}
246
247pub trait LoadState:
251 LoadPendingBlock
252 + EthApiTypes<
253 Error: FromEvmError<Self::Evm> + FromEthApiError,
254 RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
255 > + RpcNodeCoreExt
256{
257 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
259 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
260 }
261
262 fn state_at_block_id(
267 &self,
268 at: BlockId,
269 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
270 where
271 Self: SpawnBlocking,
272 {
273 async move {
274 if at.is_pending() &&
275 let Ok(Some(state)) = self.local_pending_state().await
276 {
277 return Ok(state)
278 }
279
280 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
281 }
282 }
283
284 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
286 self.provider().latest().map_err(Self::Error::from_eth_err)
287 }
288
289 fn state_at_block_id_or_latest(
293 &self,
294 block_id: Option<BlockId>,
295 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
296 where
297 Self: SpawnBlocking,
298 {
299 async move {
300 if let Some(block_id) = block_id {
301 self.state_at_block_id(block_id).await
302 } else {
303 Ok(self.latest_state()?)
304 }
305 }
306 }
307
308 fn evm_env_for_header(
310 &self,
311 header: &SealedHeaderFor<Self::Primitives>,
312 ) -> Result<EvmEnvFor<Self::Evm>, Self::Error> {
313 self.evm_config()
314 .evm_env(header)
315 .map_err(RethError::other)
316 .map_err(Self::Error::from_eth_err)
317 }
318
319 fn evm_env_at(
326 &self,
327 at: BlockId,
328 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
329 where
330 Self: SpawnBlocking,
331 {
332 async move {
333 if at.is_pending() {
334 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
335 Ok((evm_env, origin.state_block_id()))
336 } else {
337 let header = RpcNodeCore::provider(self)
341 .sealed_header_by_id(at)
342 .map_err(Self::Error::from_eth_err)?
343 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
344 let evm_env = self.evm_env_for_header(&header)?;
345
346 Ok((evm_env, header.hash().into()))
347 }
348 }
349 }
350
351 fn next_available_nonce_for(
357 &self,
358 request: &RpcTxReq<Self::NetworkTypes>,
359 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
360 where
361 Self: SpawnBlocking,
362 {
363 let address = request.as_ref().from;
364 self.spawn_blocking_io(move |this| {
365 let address = match address {
366 Some(address) => address,
367 None => return Err(SignError::NoAccount.into_eth_err()),
368 };
369
370 let mut next_nonce = this
372 .latest_state()?
373 .account_nonce(&address)
374 .map_err(Self::Error::from_eth_err)?
375 .unwrap_or_default();
376
377 if let Some(highest_tx) =
379 this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
380 {
381 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
383 Self::Error::from(EthApiError::InvalidTransaction(
384 RpcInvalidTransactionError::NonceMaxValue,
385 ))
386 })?;
387 }
388
389 Ok(next_nonce)
390 })
391 }
392
393 fn transaction_count(
398 &self,
399 address: Address,
400 block_id: Option<BlockId>,
401 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
402 where
403 Self: SpawnBlocking,
404 {
405 self.spawn_blocking_io_fut(async move |this| {
406 let on_chain_account_nonce = this
408 .state_at_block_id_or_latest(block_id)
409 .await?
410 .account_nonce(&address)
411 .map_err(Self::Error::from_eth_err)?
412 .unwrap_or_default();
413
414 if block_id == Some(BlockId::pending()) {
415 if let Some(highest_pool_tx) = this
417 .pool()
418 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
419 {
420 {
421 let next_tx_nonce =
424 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
425 Self::Error::from(EthApiError::InvalidTransaction(
426 RpcInvalidTransactionError::NonceMaxValue,
427 ))
428 })?;
429
430 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
432
433 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
434 return Ok(U256::from(tx_count));
435 }
436 }
437 }
438 Ok(U256::from(on_chain_account_nonce))
439 })
440 }
441
442 fn get_code(
444 &self,
445 address: Address,
446 block_id: Option<BlockId>,
447 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
448 where
449 Self: SpawnBlocking,
450 {
451 self.spawn_blocking_io_fut(async move |this| {
452 Ok(this
453 .state_at_block_id_or_latest(block_id)
454 .await?
455 .account_code(&address)
456 .map_err(Self::Error::from_eth_err)?
457 .unwrap_or_default()
458 .original_bytes())
459 })
460 }
461}