reth_rpc_eth_api/helpers/
bal.rs1use alloy_consensus::BlockHeader;
3use alloy_eip7928::BlockAccessList;
4use alloy_primitives::Bytes;
5use alloy_rpc_types_eth::BlockId;
6use reth_errors::RethError;
7use reth_evm::{block::BlockExecutor, ConfigureEvm, Evm};
8use reth_revm::{database::StateProviderDatabase, State};
9use reth_rpc_eth_types::{
10 cache::db::StateProviderTraitObjWrapper, error::FromEthApiError, EthApiError,
11};
12use reth_storage_api::StateProviderFactory;
13
14use crate::{
15 helpers::{Call, LoadBlock, Trace},
16 RpcNodeCore, RpcNodeCoreExt,
17};
18
19pub trait GetBlockAccessList: Trace + Call + LoadBlock + RpcNodeCoreExt {
21 fn get_block_access_list(
23 &self,
24 block_id: BlockId,
25 ) -> impl Future<Output = Result<Option<BlockAccessList>, Self::Error>> + Send {
26 async move {
27 let block = self
28 .recovered_block(block_id)
29 .await?
30 .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?;
31
32 if let Some(cached_bal) =
33 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
34 {
35 return Ok(Some(cached_bal.as_bal().clone().into_alloy_bal()))
36 }
37
38 self.spawn_blocking_io(move |eth_api| {
39 let state = eth_api
40 .provider()
41 .state_by_block_id(block.parent_hash().into())
42 .map_err(Self::Error::from_eth_err)?;
43
44 let mut db = State::builder()
45 .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state)))
46 .with_bal_builder()
47 .build();
48
49 let block_txs = block.transactions_recovered();
50 let mut executor = RpcNodeCore::evm_config(ð_api)
51 .executor_for_block(&mut db, block.sealed_block())
52 .map_err(RethError::other)
53 .map_err(Self::Error::from_eth_err)?;
54
55 executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
56 executor.evm_mut().db_mut().bump_bal_index();
57
58 for block_tx in block_txs {
60 executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?;
61 executor.evm_mut().db_mut().bump_bal_index();
62 }
63
64 executor
65 .apply_post_execution_changes()
66 .map_err(|err| EthApiError::Internal(err.into()))?;
67
68 let bal = db.take_built_alloy_bal();
69 Ok(bal)
70 })
71 .await
72 }
73 }
74
75 fn get_raw_block_access_list(
77 &self,
78 block_id: BlockId,
79 ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send {
80 async move {
81 let block = self
82 .recovered_block(block_id)
83 .await?
84 .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?;
85
86 if let Some(cached_bal) =
87 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
88 {
89 return Ok(Some(cached_bal.as_raw().clone()))
90 }
91
92 Ok(self.get_block_access_list(block_id).await?.map(|bal| alloy_rlp::encode(bal).into()))
93 }
94 }
95}