reth_rpc_eth_api/helpers/
bal.rs1use alloy_consensus::BlockHeader;
3use alloy_eip7928::{bal::DecodedBal, 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 Some(block) = self.recovered_block(block_id).await? else {
28 return Ok(None);
29 };
30
31 if let Some(cached_bal) =
32 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
33 {
34 let (bal, _) = DecodedBal::from_rlp_bytes(cached_bal.as_raw().clone())
35 .map_err(RethError::other)
36 .map_err(Self::Error::from_eth_err)?
37 .split();
38 return Ok(Some(Vec::from(bal)))
39 }
40
41 self.spawn_blocking_io(move |eth_api| {
42 let state = eth_api
43 .provider()
44 .state_by_block_id(block.parent_hash().into())
45 .map_err(Self::Error::from_eth_err)?;
46
47 let mut db = State::builder()
48 .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state)))
49 .with_bal_builder()
50 .build();
51
52 let block_txs = block.transactions_recovered();
53 let mut executor = RpcNodeCore::evm_config(ð_api)
54 .executor_for_block(&mut db, block.sealed_block())
55 .map_err(RethError::other)
56 .map_err(Self::Error::from_eth_err)?;
57
58 executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
59 executor.evm_mut().db_mut().bump_bal_index();
60
61 for block_tx in block_txs {
63 executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?;
64 executor.evm_mut().db_mut().bump_bal_index();
65 }
66
67 executor
68 .apply_post_execution_changes()
69 .map_err(|err| EthApiError::Internal(err.into()))?;
70
71 let bal = db.take_built_alloy_bal();
72 Ok(bal)
73 })
74 .await
75 }
76 }
77
78 fn get_raw_block_access_list(
80 &self,
81 block_id: BlockId,
82 ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send {
83 async move {
84 let block = self
85 .recovered_block(block_id)
86 .await?
87 .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?;
88
89 if let Some(cached_bal) =
90 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
91 {
92 return Ok(Some(cached_bal.as_raw().clone()))
93 }
94
95 Ok(self.get_block_access_list(block_id).await?.map(|bal| alloy_rlp::encode(bal).into()))
96 }
97 }
98}