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::{database::StateProviderDatabase, BlockExecutor, ConfigureEvm};
8use reth_rpc_eth_types::{error::FromEthApiError, EthApiError};
9use reth_storage_api::{StateProvider, StateProviderFactory};
10use std::sync::Arc;
11
12use crate::{
13 helpers::{LoadBlock, Trace},
14 RpcNodeCore,
15};
16
17pub trait GetBlockAccessList: Trace + LoadBlock {
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 db = StateProviderDatabase::new(state.into_evm_state_provider());
56 let mut executor = RpcNodeCore::evm_config(ð_api)
57 .executor_for_block(db, block.sealed_block())
58 .map_err(RethError::other)
59 .map_err(Self::Error::from_eth_err)?;
60 executor.enable_block_access_list_builder();
61 executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
62 for block_tx in block.transactions_recovered() {
63 executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?;
64 }
65 let (_, bal) = executor
66 .finish_with_prepared_block_access_list()
67 .map_err(Self::Error::from_eth_err)?;
68 let Some(bal) = bal else { return Ok(None) };
69 if !eth_api.eth_api_settings().cache_computed_bals {
70 return Ok(Some(BlockAccessList::from(bal)))
71 }
72
73 let alloy_bal = BlockAccessList::from(&bal);
74 let raw = alloy_rlp::encode(&alloy_bal).into();
75 eth_api.cache().insert_bal(block.hash(), DecodedBal::new(Arc::new(bal), raw));
76 Ok(Some(alloy_bal))
77 })
78 .await
79 }
80 }
81
82 fn get_raw_block_access_list(
84 &self,
85 block_id: BlockId,
86 ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send {
87 async move {
88 let block = self
89 .recovered_block(block_id)
90 .await?
91 .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?;
92
93 if let Some(cached_bal) =
94 self.cache().get_bal(block.hash()).await.map_err(Self::Error::from_eth_err)?
95 {
96 return Ok(Some(cached_bal.as_raw().clone()))
97 }
98
99 Ok(self.get_block_access_list(block_id).await?.map(|bal| alloy_rlp::encode(bal).into()))
100 }
101 }
102}