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