reth_rpc_eth_api/helpers/
state.rs1use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking};
4use crate::{EthApiTypes, FromEthApiError, RpcNodeCore, RpcNodeCoreExt};
5use alloy_consensus::{constants::KECCAK_EMPTY, BlockHeader};
6use alloy_eips::BlockId;
7use alloy_primitives::{Address, Bytes, B256, U256};
8use alloy_rpc_types_eth::{Account, EIP1186AccountProofResponse};
9use alloy_serde::JsonStorageKey;
10use futures::Future;
11use reth_chainspec::{EthChainSpec, EthereumHardforks};
12use reth_errors::RethError;
13use reth_evm::ConfigureEvmEnv;
14use reth_provider::{
15 BlockIdReader, BlockNumReader, ChainSpecProvider, EvmEnvProvider as _, ProviderHeader,
16 StateProvider, StateProviderBox, StateProviderFactory,
17};
18use reth_rpc_eth_types::{EthApiError, PendingBlockEnv, RpcInvalidTransactionError};
19use reth_transaction_pool::TransactionPool;
20use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId};
21
22pub trait EthState: LoadState + SpawnBlocking {
24 fn max_proof_window(&self) -> u64;
26
27 fn transaction_count(
32 &self,
33 address: Address,
34 block_id: Option<BlockId>,
35 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
36 LoadState::transaction_count(self, address, block_id)
37 }
38
39 fn get_code(
41 &self,
42 address: Address,
43 block_id: Option<BlockId>,
44 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
45 LoadState::get_code(self, address, block_id)
46 }
47
48 fn balance(
50 &self,
51 address: Address,
52 block_id: Option<BlockId>,
53 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
54 self.spawn_blocking_io(move |this| {
55 Ok(this
56 .state_at_block_id_or_latest(block_id)?
57 .account_balance(address)
58 .map_err(Self::Error::from_eth_err)?
59 .unwrap_or_default())
60 })
61 }
62
63 fn storage_at(
65 &self,
66 address: Address,
67 index: JsonStorageKey,
68 block_id: Option<BlockId>,
69 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
70 self.spawn_blocking_io(move |this| {
71 let storage_value = this
72 .state_at_block_id_or_latest(block_id)?
73 .storage(address, index.as_b256())
74 .map_err(Self::Error::from_eth_err)?
75 .unwrap_or_default();
76 match storage_value.is_public() {
77 true => Ok(B256::new(storage_value.value.to_be_bytes())),
78 false => Ok(B256::ZERO),
79 }
80 })
81 }
82
83 fn get_proof(
85 &self,
86 address: Address,
87 keys: Vec<JsonStorageKey>,
88 block_id: Option<BlockId>,
89 ) -> Result<
90 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
91 Self::Error,
92 >
93 where
94 Self: EthApiSpec,
95 {
96 Ok(async move {
97 let _permit = self
98 .acquire_owned()
99 .await
100 .map_err(RethError::other)
101 .map_err(EthApiError::Internal)?;
102
103 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
104 let block_id = block_id.unwrap_or_default();
105
106 let block_number = self
108 .provider()
109 .block_number_for_id(block_id)
110 .map_err(Self::Error::from_eth_err)?
111 .ok_or(EthApiError::HeaderNotFound(block_id))?;
112 let max_window = self.max_proof_window();
113 if chain_info.best_number.saturating_sub(block_number) > max_window {
114 return Err(EthApiError::ExceedsMaxProofWindow.into())
115 }
116
117 self.spawn_blocking_io(move |this| {
118 let state = this.state_at_block_id(block_id)?;
119 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
120 let proof = state
121 .proof(Default::default(), address, &storage_keys)
122 .map_err(Self::Error::from_eth_err)?;
123 Ok(proof.into_eip1186_response(keys))
124 })
125 .await
126 })
127 }
128
129 fn get_account(
131 &self,
132 address: Address,
133 block_id: BlockId,
134 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send {
135 self.spawn_blocking_io(move |this| {
136 let state = this.state_at_block_id(block_id)?;
137 let account = state.basic_account(address).map_err(Self::Error::from_eth_err)?;
138 let Some(account) = account else { return Ok(None) };
139
140 let chain_info = this.provider().chain_info().map_err(Self::Error::from_eth_err)?;
142 let block_number = this
143 .provider()
144 .block_number_for_id(block_id)
145 .map_err(Self::Error::from_eth_err)?
146 .ok_or(EthApiError::HeaderNotFound(block_id))?;
147 let max_window = this.max_proof_window();
148 if chain_info.best_number.saturating_sub(block_number) > max_window {
149 return Err(EthApiError::ExceedsMaxProofWindow.into())
150 }
151
152 let balance = account.balance;
153 let nonce = account.nonce;
154 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
155
156 let storage_root = state
159 .storage_root(address, Default::default())
160 .map_err(Self::Error::from_eth_err)?;
161
162 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
163 })
164 }
165}
166
167pub trait LoadState:
171 EthApiTypes
172 + RpcNodeCoreExt<
173 Provider: StateProviderFactory
174 + ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>,
175 Pool: TransactionPool,
176 >
177{
178 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
180 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
181 }
182
183 fn state_at_block_id(&self, at: BlockId) -> Result<StateProviderBox, Self::Error> {
188 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
189 }
190
191 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
193 self.provider().latest().map_err(Self::Error::from_eth_err)
194 }
195
196 fn state_at_block_id_or_latest(
200 &self,
201 block_id: Option<BlockId>,
202 ) -> Result<StateProviderBox, Self::Error> {
203 if let Some(block_id) = block_id {
204 self.state_at_block_id(block_id)
205 } else {
206 Ok(self.latest_state()?)
207 }
208 }
209
210 fn evm_env_at(
217 &self,
218 at: BlockId,
219 ) -> impl Future<Output = Result<(CfgEnvWithHandlerCfg, BlockEnv, BlockId), Self::Error>> + Send
220 where
221 Self: LoadPendingBlock + SpawnBlocking,
222 {
223 async move {
224 if at.is_pending() {
225 let PendingBlockEnv { cfg, block_env, origin } =
226 self.pending_block_env_and_cfg()?;
227 Ok((cfg, block_env, origin.state_block_id()))
228 } else {
229 let block_hash = RpcNodeCore::provider(self)
231 .block_hash_for_id(at)
232 .map_err(Self::Error::from_eth_err)?
233 .ok_or(EthApiError::HeaderNotFound(at))?;
234
235 let header =
236 self.cache().get_header(block_hash).await.map_err(Self::Error::from_eth_err)?;
237 let evm_config = self.evm_config().clone();
238 let (cfg, block_env) = self
239 .provider()
240 .env_with_header(&header, evm_config)
241 .map_err(Self::Error::from_eth_err)?;
242 Ok((cfg, block_env, block_hash.into()))
243 }
244 }
245 }
246
247 fn evm_env_for_raw_block(
251 &self,
252 header: &ProviderHeader<Self::Provider>,
253 ) -> impl Future<Output = Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error>> + Send
254 where
255 Self: LoadPendingBlock + SpawnBlocking,
256 {
257 async move {
258 let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash().into()).await?;
260
261 let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE;
262 self.evm_config().fill_block_env(&mut block_env, header, after_merge);
263
264 Ok((cfg, block_env))
265 }
266 }
267
268 fn next_available_nonce(
272 &self,
273 address: Address,
274 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
275 where
276 Self: SpawnBlocking,
277 {
278 self.spawn_blocking_io(move |this| {
279 let on_chain_account_nonce = this
281 .latest_state()?
282 .account_nonce(address)
283 .map_err(Self::Error::from_eth_err)?
284 .unwrap_or_default();
285
286 let mut next_nonce = on_chain_account_nonce;
287 if let Some(highest_tx) = this
289 .pool()
290 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
291 {
292 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
294 Self::Error::from(EthApiError::InvalidTransaction(
295 RpcInvalidTransactionError::NonceMaxValue,
296 ))
297 })?;
298 }
299
300 Ok(next_nonce)
301 })
302 }
303
304 fn transaction_count(
309 &self,
310 address: Address,
311 block_id: Option<BlockId>,
312 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
313 where
314 Self: SpawnBlocking,
315 {
316 self.spawn_blocking_io(move |this| {
317 let on_chain_account_nonce = this
319 .state_at_block_id_or_latest(block_id)?
320 .account_nonce(address)
321 .map_err(Self::Error::from_eth_err)?
322 .unwrap_or_default();
323
324 if block_id == Some(BlockId::pending()) {
325 if let Some(highest_pool_tx) =
327 this.pool().get_highest_transaction_by_sender(address)
328 {
329 {
330 let next_tx_nonce =
333 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
334 Self::Error::from(EthApiError::InvalidTransaction(
335 RpcInvalidTransactionError::NonceMaxValue,
336 ))
337 })?;
338
339 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
341
342 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
343 return Ok(U256::from(tx_count));
344 }
345 }
346 }
347 Ok(U256::from(on_chain_account_nonce))
348 })
349 }
350
351 fn get_code(
353 &self,
354 address: Address,
355 block_id: Option<BlockId>,
356 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
357 where
358 Self: SpawnBlocking,
359 {
360 self.spawn_blocking_io(move |this| {
361 Ok(this
362 .state_at_block_id_or_latest(block_id)?
363 .account_code(address)
364 .map_err(Self::Error::from_eth_err)?
365 .unwrap_or_default()
366 .original_bytes())
367 })
368 }
369}