Skip to main content

reth_rpc_eth_api/helpers/
bal.rs

1//! Helpers for `eth_blockAccessList` RPC method.
2use 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
17/// Helper trait for `eth_blockAccessList` RPC method.
18pub trait GetBlockAccessList: Trace + LoadBlock {
19    /// Retrieves the block access list for a block identified by its hash.
20    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(&eth_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    /// Retrieves the raw RLP-encoded block access list for a block.
83    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}