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::{StateProvider, StateProviderFactory};
11use std::sync::Arc;
12
13use crate::{
14 helpers::{Call, LoadBlock, Trace},
15 RpcNodeCore, RpcNodeCoreExt,
16};
17
18pub trait GetBlockAccessList: Trace + Call + LoadBlock + RpcNodeCoreExt {
20 fn get_block_access_list(
22 &self,
23 block_id: BlockId,
24 ) -> impl Future<Output = Result<Option<BlockAccessList>, Self::Error>> + Send {
25 async move {
26 if block_id.is_pending() {
27 return Ok(None)
28 }
29
30 let Some(block) = self.recovered_block(block_id).await? else {
31 return Ok(None);
32 };
33
34 if let Some(cached_bal) =
35 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
36 {
37 let (bal, _) = DecodedBal::from_rlp_bytes(cached_bal.as_raw().clone())
38 .map_err(RethError::other)
39 .map_err(Self::Error::from_eth_err)?
40 .split();
41 return Ok(Some(Vec::from(bal)))
42 }
43
44 let permit = self
45 .acquire_owned_blocking_io()
46 .await
47 .map_err(|_| EthApiError::InternalEthError)?;
48
49 self.spawn_blocking_io(move |eth_api| {
50 let _permit = permit;
51 let state = eth_api
52 .provider()
53 .state_by_block_id(block.parent_hash().into())
54 .map_err(Self::Error::from_eth_err)?;
55
56 let mut db = State::builder()
57 .with_database(StateProviderDatabase::new(state.into_evm_state_provider()))
58 .with_bal_builder()
59 .build();
60
61 let block_txs = block.transactions_recovered();
62 let mut executor = RpcNodeCore::evm_config(ð_api)
63 .executor_for_block(&mut db, block.sealed_block())
64 .map_err(RethError::other)
65 .map_err(Self::Error::from_eth_err)?;
66
67 executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
68 executor.evm_mut().db_mut().bump_bal_index();
69
70 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 revm_bal = db.take_built_bal().expect("BAL builder configured");
80 if !eth_api.eth_api_settings().cache_computed_bals {
81 return Ok(Some(revm_bal.into_alloy_bal()));
82 }
83
84 let bal = revm_bal.clone().into_alloy_bal();
85 let raw = alloy_rlp::encode(&bal).into();
86 eth_api.cache().insert_bal(block.hash(), DecodedBal::new(Arc::new(revm_bal), raw));
87 Ok(Some(bal))
88 })
89 .await
90 }
91 }
92
93 fn get_raw_block_access_list(
95 &self,
96 block_id: BlockId,
97 ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send {
98 async move {
99 let block = self
100 .recovered_block(block_id)
101 .await?
102 .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?;
103
104 if let Some(cached_bal) =
105 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
106 {
107 return Ok(Some(cached_bal.as_raw().clone()))
108 }
109
110 Ok(self.get_block_access_list(block_id).await?.map(|bal| alloy_rlp::encode(bal).into()))
111 }
112 }
113}