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::{error::FromEthApiError, EthApiError};
10use reth_storage_api::StateProviderFactory;
11
12use crate::{
13 helpers::{Call, LoadBlock, Trace},
14 RpcNodeCore, RpcNodeCoreExt,
15};
16
17pub trait GetBlockAccessList: Trace + Call + LoadBlock + RpcNodeCoreExt {
19 fn get_block_access_list(
21 &self,
22 block_id: BlockId,
23 ) -> impl Future<Output = Result<Option<BlockAccessList>, Self::Error>> + Send {
24 async move {
25 if block_id.is_pending() {
26 return Ok(None)
27 }
28
29 let Some(block) = self.recovered_block(block_id).await? else {
30 return Ok(None);
31 };
32
33 if let Some(cached_bal) =
34 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
35 {
36 let (bal, _) = DecodedBal::from_rlp_bytes(cached_bal.as_raw().clone())
37 .map_err(RethError::other)
38 .map_err(Self::Error::from_eth_err)?
39 .split();
40 return Ok(Some(Vec::from(bal)))
41 }
42
43 let permit = self
44 .acquire_owned_blocking_io()
45 .await
46 .map_err(|_| EthApiError::InternalEthError)?;
47
48 self.spawn_blocking_io(move |eth_api| {
49 let _permit = permit;
50 let state = eth_api
51 .provider()
52 .state_by_block_id(block.parent_hash().into())
53 .map_err(Self::Error::from_eth_err)?;
54
55 let mut db = State::builder()
56 .with_database(StateProviderDatabase::new(state))
57 .with_bal_builder()
58 .build();
59
60 let block_txs = block.transactions_recovered();
61 let mut executor = RpcNodeCore::evm_config(ð_api)
62 .executor_for_block(&mut db, block.sealed_block())
63 .map_err(RethError::other)
64 .map_err(Self::Error::from_eth_err)?;
65
66 executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
67 executor.evm_mut().db_mut().bump_bal_index();
68
69 for block_tx in block_txs {
71 executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?;
72 executor.evm_mut().db_mut().bump_bal_index();
73 }
74
75 executor
76 .apply_post_execution_changes()
77 .map_err(|err| EthApiError::Internal(err.into()))?;
78
79 let bal = db.take_built_alloy_bal();
80 Ok(bal)
81 })
82 .await
83 }
84 }
85
86 fn get_raw_block_access_list(
88 &self,
89 block_id: BlockId,
90 ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send {
91 async move {
92 let block = self
93 .recovered_block(block_id)
94 .await?
95 .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?;
96
97 if let Some(cached_bal) =
98 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
99 {
100 return Ok(Some(cached_bal.as_raw().clone()))
101 }
102
103 Ok(self.get_block_access_list(block_id).await?.map(|bal| alloy_rlp::encode(bal).into()))
104 }
105 }
106}