diff --git a/Cargo.lock b/Cargo.lock index 79e19b6c449..8bd9ced6920 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9964,6 +9964,7 @@ dependencies = [ "reth-trie-common", "revm", "revm-inspectors", + "serde_json", "tokio", "tracing", ] diff --git a/crates/rpc/rpc-eth-api/Cargo.toml b/crates/rpc/rpc-eth-api/Cargo.toml index 83ebd47ea64..559eb69e12e 100644 --- a/crates/rpc/rpc-eth-api/Cargo.toml +++ b/crates/rpc/rpc-eth-api/Cargo.toml @@ -57,6 +57,7 @@ tokio.workspace = true # misc auto_impl.workspace = true dyn-clone.workspace = true +serde_json.workspace = true tracing.workspace = true [features] diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 3ae721c0cab..e0988dba92b 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -18,8 +18,9 @@ use alloy_serde::JsonStorageKey; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth_primitives_traits::TxTy; use reth_rpc_convert::RpcTxReq; -use reth_rpc_eth_types::FillTransaction; +use reth_rpc_eth_types::{EthApiError, FillTransaction}; use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult}; +use serde_json::Value; use std::collections::HashMap; use tracing::trace; @@ -406,14 +407,14 @@ pub trait EthApi< /// Returns the EIP-7928 block access list for a block by hash. #[method(name = "getBlockAccessListByBlockHash")] - async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult>; + async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult>; /// Returns the EIP-7928 block access list for a block by number. #[method(name = "getBlockAccessListByBlockNumber")] async fn block_access_list_by_block_number( &self, number: BlockNumberOrTag, - ) -> RpcResult>; + ) -> RpcResult>; } #[async_trait::async_trait] @@ -913,17 +914,26 @@ where } /// Handler for: `eth_getBlockAccessListByBlockHash` - async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockAccessListByBlockHash"); - Err(internal_rpc_err("unimplemented")) - } + async fn block_access_list_by_block_hash(&self, block_hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?block_hash, "Serving eth_getBlockAccessListByBlockHash"); + let bal = self.get_block_access_list(block_hash.into()).await?; + let json = serde_json::to_value(&bal) + .map_err(|e| EthApiError::Internal(reth_errors::RethError::msg(e.to_string())))?; + + Ok(Some(json)) + } /// Handler for: `eth_getBlockAccessListByBlockNumber` async fn block_access_list_by_block_number( &self, number: BlockNumberOrTag, - ) -> RpcResult> { + ) -> RpcResult> { trace!(target: "rpc::eth", ?number, "Serving eth_getBlockAccessListByBlockNumber"); - Err(internal_rpc_err("unimplemented")) + + let bal = self.get_block_access_list(number.into()).await?; + let json = serde_json::to_value(&bal) + .map_err(|e| EthApiError::Internal(reth_errors::RethError::msg(e.to_string())))?; + + Ok(Some(json)) } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/bal.rs b/crates/rpc/rpc-eth-api/src/helpers/bal.rs new file mode 100644 index 00000000000..608140afe17 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/bal.rs @@ -0,0 +1,67 @@ +//! Helpers for `eth_blockAccessList` RPC method. +use alloy_consensus::BlockHeader; +use alloy_eips::eip7928::BlockAccessList; +use alloy_rpc_types_eth::BlockId; +use reth_errors::RethError; +use reth_evm::{block::BlockExecutor, ConfigureEvm, Evm}; +use reth_revm::{database::StateProviderDatabase, State}; +use reth_rpc_eth_types::{ + cache::db::StateProviderTraitObjWrapper, error::FromEthApiError, EthApiError, +}; +use reth_storage_api::StateProviderFactory; + +use crate::{ + helpers::{Call, LoadBlock, Trace}, + RpcNodeCore, +}; + +/// Helper trait for `eth_blockAccessList` RPC method. +pub trait GetBlockAccessList: Trace + Call + LoadBlock { + /// Retrieves the block access list for a block identified by its hash. + fn get_block_access_list( + &self, + block_id: BlockId, + ) -> impl Future, Self::Error>> + Send { + async move { + let block = self + .recovered_block(block_id) + .await? + .ok_or_else(|| EthApiError::HeaderNotFound(block_id))?; + + self.spawn_blocking_io(move |eth_api| { + let state = eth_api + .provider() + .state_by_block_id(block.parent_hash().into()) + .map_err(Self::Error::from_eth_err)?; + + let mut db = State::builder() + .with_database(StateProviderDatabase::new(StateProviderTraitObjWrapper(state))) + .with_bal_builder() + .build(); + + let block_txs = block.transactions_recovered(); + let mut executor = RpcNodeCore::evm_config(ð_api) + .executor_for_block(&mut db, block.sealed_block()) + .map_err(RethError::other) + .map_err(Self::Error::from_eth_err)?; + + executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?; + executor.evm_mut().db_mut().bump_bal_index(); + + // replay all transactions prior to the targeted transaction + for block_tx in block_txs { + executor.execute_transaction(block_tx).map_err(Self::Error::from_eth_err)?; + executor.evm_mut().db_mut().bump_bal_index(); + } + + executor + .apply_post_execution_changes() + .map_err(|err| EthApiError::Internal(err.into()))?; + + let bal = db.take_built_alloy_bal(); + Ok(bal) + }) + .await + } + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs index 19a72ccafb7..e04e5ec5bc5 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/mod.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -14,6 +14,7 @@ //! [`EthApiServer`](crate::EthApiServer), is implemented for any type that implements //! all the `Eth` traits, e.g. `reth_rpc::EthApi`. +pub mod bal; pub mod block; pub mod blocking_task; pub mod call; @@ -28,6 +29,7 @@ pub mod state; pub mod trace; pub mod transaction; +pub use bal::GetBlockAccessList; pub use block::{EthBlocks, LoadBlock}; pub use blocking_task::SpawnBlocking; pub use call::{Call, EthCall}; @@ -43,9 +45,12 @@ pub use transaction::{EthTransactions, LoadTransaction}; use crate::FullEthApiTypes; /// Extension trait that bundles traits needed for tracing transactions. -pub trait TraceExt: LoadTransaction + LoadBlock + SpawnBlocking + Trace + Call {} +pub trait TraceExt: + LoadTransaction + LoadBlock + SpawnBlocking + Trace + Call + GetBlockAccessList +{ +} -impl TraceExt for T where T: LoadTransaction + LoadBlock + Trace + Call {} +impl TraceExt for T where T: LoadTransaction + LoadBlock + Trace + Call + GetBlockAccessList {} /// Helper trait to unify all `eth` rpc server building block traits, for simplicity. /// @@ -60,6 +65,7 @@ pub trait FullEthApi: + EthFees + Trace + LoadReceipt + + GetBlockAccessList { } @@ -73,5 +79,6 @@ impl FullEthApi for T where + EthFees + Trace + LoadReceipt + + GetBlockAccessList { } diff --git a/crates/rpc/rpc-eth-types/src/error/mod.rs b/crates/rpc/rpc-eth-types/src/error/mod.rs index 0ea183384b7..12f0498a33a 100644 --- a/crates/rpc/rpc-eth-types/src/error/mod.rs +++ b/crates/rpc/rpc-eth-types/src/error/mod.rs @@ -207,6 +207,9 @@ pub enum EthApiError { /// The underlying error object error: jsonrpsee_types::ErrorObject<'static>, }, + /// Error thrown when trying to access block access list for blocks before Amsterdam + #[error("Block access list not available for pre-Amsterdam blocks")] + BlockAccessListNotAvailablePreAmsterdam, /// Any other error #[error("{0}")] Other(Box), @@ -345,6 +348,9 @@ impl From for jsonrpsee_types::error::ErrorObject<'static> { error.data(), ) } + EthApiError::BlockAccessListNotAvailablePreAmsterdam => { + rpc_error_with_code(4445, error.to_string()) + } } } } diff --git a/crates/rpc/rpc/src/eth/helpers/bal.rs b/crates/rpc/rpc/src/eth/helpers/bal.rs new file mode 100644 index 00000000000..39fbc20c6a9 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/bal.rs @@ -0,0 +1,15 @@ +//! Contains RPC handler implementations specific to block access lists. + +use reth_rpc_convert::RpcConvert; +use reth_rpc_eth_api::{helpers::bal::GetBlockAccessList, FromEvmError, RpcNodeCore}; +use reth_rpc_eth_types::EthApiError; + +use crate::EthApi; + +impl GetBlockAccessList for EthApi +where + N: RpcNodeCore, + EthApiError: FromEvmError, + Rpc: RpcConvert, +{ +} diff --git a/crates/rpc/rpc/src/eth/helpers/mod.rs b/crates/rpc/rpc/src/eth/helpers/mod.rs index 15fcf612d9a..2d0861461b4 100644 --- a/crates/rpc/rpc/src/eth/helpers/mod.rs +++ b/crates/rpc/rpc/src/eth/helpers/mod.rs @@ -5,6 +5,7 @@ pub mod signer; pub mod sync_listener; pub mod types; +mod bal; mod block; mod call; mod fees;