Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/rpc/rpc-eth-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ tokio.workspace = true
# misc
auto_impl.workspace = true
dyn-clone.workspace = true
serde_json.workspace = true
tracing.workspace = true

[features]
Expand Down
34 changes: 25 additions & 9 deletions crates/rpc/rpc-eth-api/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ 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::{error::FromEthApiError, EthApiError, FillTransaction};
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use reth_storage_api::BlockIdReader;
use serde_json::Value;
use std::collections::HashMap;
use tracing::trace;

Expand Down Expand Up @@ -406,14 +408,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<Option<Bytes>>;
async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult<Option<Value>>;

/// 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<Option<Bytes>>;
) -> RpcResult<Option<Value>>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -913,17 +915,31 @@ where
}

/// Handler for: `eth_getBlockAccessListByBlockHash`
async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult<Option<Bytes>> {
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<Option<Value>> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think returning value here makes sense for now, but it has some overhead because we then need to serialize this as string again.

but lets keep it for now

trace!(target: "rpc::eth", ?block_hash, "Serving eth_getBlockAccessListByBlockHash");

let bal = self.get_block_access_list(block_hash).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<Option<Bytes>> {
) -> RpcResult<Option<Value>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockAccessListByBlockNumber");
Err(internal_rpc_err("unimplemented"))
let block_hash = self
.provider()
.block_hash_for_id(number.into())
.map_err(T::Error::from_eth_err)?
.ok_or(EthApiError::HeaderNotFound(number.into()))?;

let bal = self.get_block_access_list(block_hash).await?;
let json = serde_json::to_value(&bal)
.map_err(|e| EthApiError::Internal(reth_errors::RethError::msg(e.to_string())))?;

Ok(Some(json))
}
}
79 changes: 79 additions & 0 deletions crates/rpc/rpc-eth-api/src/helpers/bal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Helpers for `eth_blockAccessList` RPC method.
use alloy_consensus::BlockHeader;
use alloy_eips::eip7928::BlockAccessList;
use alloy_primitives::B256;
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
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::{BlockNumReader, 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_hash: B256,
) -> impl Future<Output = Result<Option<BlockAccessList>, Self::Error>> + Send {
async move {
let block = self
.recovered_block(block_hash.into())
.await?
.ok_or_else(|| EthApiError::HeaderNotFound(block_hash.into()))?;

// Check if the block has been pruned (EIP-4444)
let earliest_block = self.provider().earliest_block_number()?;
if block.header().number() < earliest_block {
return Err(EthApiError::PrunedHistoryUnavailable.into());
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this because this is now checked by recovered_block already

// Check if the block is pre-Amsterdam, as access lists are not available for those

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I'm catching up to all this BAL work, I'm guessing we have some way of pre-enabling this for development/testing?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was in the specs, i dont think there is a way to enable it ..we can just remove the check for now if you want

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will defer to @mattsse, but yeah having some way to get BALs for pre-amsterdam blocks is a requirement for big block testing. Maybe we enable that via a CLI arg or something.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Soubhik-10 lets remove this check for now, because this endpoint will come in handy for pre fork testing

// blocks
if !self.provider().chain_spec().is_amsterdam_active_at_timestamp(block.timestamp()) {
return Err(EthApiError::BlockAccessListNotAvailablePreAmsterdam.into());
}

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(&eth_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
}
}
}
11 changes: 9 additions & 2 deletions crates/rpc/rpc-eth-api/src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};
Expand All @@ -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<T> TraceExt for T where T: LoadTransaction + LoadBlock + Trace + Call {}
impl<T> TraceExt for T where T: LoadTransaction + LoadBlock + Trace + Call + GetBlockAccessList {}

/// Helper trait to unify all `eth` rpc server building block traits, for simplicity.
///
Expand All @@ -60,6 +65,7 @@ pub trait FullEthApi:
+ EthFees
+ Trace
+ LoadReceipt
+ GetBlockAccessList
{
}

Expand All @@ -73,5 +79,6 @@ impl<T> FullEthApi for T where
+ EthFees
+ Trace
+ LoadReceipt
+ GetBlockAccessList
{
}
6 changes: 6 additions & 0 deletions crates/rpc/rpc-eth-types/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn ToRpcError>),
Expand Down Expand Up @@ -345,6 +348,9 @@ impl From<EthApiError> for jsonrpsee_types::error::ErrorObject<'static> {
error.data(),
)
}
EthApiError::BlockAccessListNotAvailablePreAmsterdam => {
rpc_error_with_code(4445, error.to_string())
}
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions crates/rpc/rpc/src/eth/helpers/bal.rs
Original file line number Diff line number Diff line change
@@ -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<N, Rpc> GetBlockAccessList for EthApi<N, Rpc>
where
N: RpcNodeCore,
EthApiError: FromEvmError<N::Evm>,
Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError, Evm = N::Evm>,
{
}
1 change: 1 addition & 0 deletions crates/rpc/rpc/src/eth/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod signer;
pub mod sync_listener;
pub mod types;

mod bal;
mod block;
mod call;
mod fees;
Expand Down
Loading