From cf2a6a1ee8e8375b107627e7525a726405a5053f Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 6 Dec 2024 16:30:50 +0400 Subject: [PATCH] feat: EthApi traits abstraction (#13170) --- Cargo.lock | 2 + crates/e2e-test-utils/src/node.rs | 4 +- crates/e2e-test-utils/src/rpc.rs | 5 +- crates/node/builder/src/launch/common.rs | 1 + crates/node/builder/src/rpc.rs | 24 ++- crates/optimism/rpc/src/eth/block.rs | 21 ++- crates/optimism/rpc/src/eth/call.rs | 4 +- crates/optimism/rpc/src/eth/mod.rs | 17 +- crates/optimism/rpc/src/eth/pending_block.rs | 116 +++++++++--- crates/optimism/rpc/src/eth/transaction.rs | 8 +- crates/primitives-traits/src/block/mod.rs | 3 + crates/primitives/src/block.rs | 26 --- crates/primitives/src/transaction/mod.rs | 5 + crates/primitives/src/transaction/pooled.rs | 12 ++ crates/rpc/rpc-api/src/otterscan.rs | 11 +- crates/rpc/rpc-builder/src/lib.rs | 54 ++++-- crates/rpc/rpc-builder/tests/it/http.rs | 176 ++++++++++------- crates/rpc/rpc-builder/tests/it/middleware.rs | 4 +- crates/rpc/rpc-eth-api/Cargo.toml | 1 + crates/rpc/rpc-eth-api/src/core.rs | 30 ++- crates/rpc/rpc-eth-api/src/helpers/block.rs | 28 ++- crates/rpc/rpc-eth-api/src/helpers/call.rs | 21 ++- crates/rpc/rpc-eth-api/src/helpers/fee.rs | 3 +- .../rpc-eth-api/src/helpers/pending_block.rs | 178 +++++++----------- crates/rpc/rpc-eth-api/src/helpers/signer.rs | 11 +- crates/rpc/rpc-eth-api/src/helpers/spec.rs | 5 +- crates/rpc/rpc-eth-api/src/helpers/state.rs | 10 +- crates/rpc/rpc-eth-api/src/helpers/trace.rs | 41 ++-- .../rpc-eth-api/src/helpers/transaction.rs | 14 +- crates/rpc/rpc-eth-api/src/lib.rs | 2 +- crates/rpc/rpc-eth-api/src/types.rs | 5 +- crates/rpc/rpc-eth-types/src/pending_block.rs | 10 +- crates/rpc/rpc-testing-util/src/debug.rs | 4 +- crates/rpc/rpc-testing-util/tests/it/trace.rs | 4 +- crates/rpc/rpc-types-compat/Cargo.toml | 1 + crates/rpc/rpc-types-compat/src/block.rs | 78 +++++--- crates/rpc/rpc/src/debug.rs | 56 +++--- crates/rpc/rpc/src/engine.rs | 3 +- crates/rpc/rpc/src/eth/bundle.rs | 31 +-- crates/rpc/rpc/src/eth/core.rs | 20 +- crates/rpc/rpc/src/eth/helpers/block.rs | 25 ++- crates/rpc/rpc/src/eth/helpers/call.rs | 4 +- .../rpc/rpc/src/eth/helpers/pending_block.rs | 94 ++++++++- crates/rpc/rpc/src/eth/helpers/signer.rs | 29 +-- crates/rpc/rpc/src/eth/helpers/spec.rs | 11 +- crates/rpc/rpc/src/eth/helpers/trace.rs | 11 +- crates/rpc/rpc/src/eth/helpers/transaction.rs | 6 +- crates/rpc/rpc/src/eth/sim_bundle.rs | 16 +- crates/rpc/rpc/src/otterscan.rs | 33 +++- crates/rpc/rpc/src/trace.rs | 65 ++++--- .../provider/src/providers/consistent.rs | 6 +- crates/storage/storage-api/src/header.rs | 3 + crates/transaction-pool/src/traits.rs | 10 +- 53 files changed, 851 insertions(+), 511 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 666293e58..37d05d1e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9052,6 +9052,7 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-primitives", + "alloy-rlp", "alloy-rpc-types-eth", "alloy-rpc-types-mev", "alloy-serde", @@ -9171,6 +9172,7 @@ dependencies = [ "alloy-rpc-types-eth", "jsonrpsee-types", "reth-primitives", + "reth-primitives-traits", "serde", "serde_json", ] diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index dcd24df5c..b5dd44841 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -97,7 +97,9 @@ where where Engine::ExecutionPayloadEnvelopeV3: From + PayloadEnvelopeExt, Engine::ExecutionPayloadEnvelopeV4: From + PayloadEnvelopeExt, - AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt, + AddOns::EthApi: EthApiSpec> + + EthTransactions + + TraceExt, { let mut chain = Vec::with_capacity(length as usize); for i in 0..length { diff --git a/crates/e2e-test-utils/src/rpc.rs b/crates/e2e-test-utils/src/rpc.rs index 37ee12987..cdc72a295 100644 --- a/crates/e2e-test-utils/src/rpc.rs +++ b/crates/e2e-test-utils/src/rpc.rs @@ -4,6 +4,7 @@ use alloy_primitives::{Bytes, B256}; use reth_chainspec::EthereumHardforks; use reth_node_api::{FullNodeComponents, NodePrimitives}; use reth_node_builder::{rpc::RpcRegistry, NodeTypes}; +use reth_provider::BlockReader; use reth_rpc_api::DebugApiServer; use reth_rpc_eth_api::{ helpers::{EthApiSpec, EthTransactions, TraceExt}, @@ -26,7 +27,9 @@ where >, >, >, - EthApi: EthApiSpec + EthTransactions + TraceExt, + EthApi: EthApiSpec> + + EthTransactions + + TraceExt, { /// Injects a raw transaction into the node tx pool via RPC server pub async fn inject_tx(&self, raw_tx: Bytes) -> Result { diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index 648edc193..104ecef9e 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -927,6 +927,7 @@ where alloy_rpc_types::Transaction, alloy_rpc_types::Block, alloy_rpc_types::Receipt, + alloy_rpc_types::Header, >::chain_id(&client) .await })? diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index edc10fecc..a4010e52d 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -19,7 +19,7 @@ use reth_node_core::{ }; use reth_payload_builder::PayloadStore; use reth_primitives::EthPrimitives; -use reth_provider::providers::ProviderNodeTypes; +use reth_provider::{providers::ProviderNodeTypes, BlockReader}; use reth_rpc::{ eth::{EthApiTypes, FullEthApiServer}, EthApi, @@ -408,7 +408,16 @@ where PayloadBuilder: PayloadBuilder::Engine>, Pool: TransactionPool::Transaction>, >, - EthApi: EthApiTypes + FullEthApiServer + AddDevSigners + Unpin + 'static, + EthApi: EthApiTypes + + FullEthApiServer< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + Header = reth_primitives::Header, + >, + > + AddDevSigners + + Unpin + + 'static, EV: EngineValidatorBuilder, { /// Launches the RPC servers with the given context and an additional hook for extending @@ -531,7 +540,16 @@ where PayloadBuilder: PayloadBuilder::Engine>, Pool: TransactionPool::Transaction>, >, - EthApi: EthApiTypes + FullEthApiServer + AddDevSigners + Unpin + 'static, + EthApi: EthApiTypes + + FullEthApiServer< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + Header = reth_primitives::Header, + >, + > + AddDevSigners + + Unpin + + 'static, EV: EngineValidatorBuilder, { type Handle = RpcHandle; diff --git a/crates/optimism/rpc/src/eth/block.rs b/crates/optimism/rpc/src/eth/block.rs index a37a8a152..3899e0b7f 100644 --- a/crates/optimism/rpc/src/eth/block.rs +++ b/crates/optimism/rpc/src/eth/block.rs @@ -1,12 +1,14 @@ //! Loads and formats OP block RPC response. +use alloy_consensus::BlockHeader; use alloy_rpc_types_eth::BlockId; use op_alloy_network::Network; use op_alloy_rpc_types::OpTransactionReceipt; use reth_chainspec::ChainSpecProvider; +use reth_node_api::BlockBody; use reth_optimism_chainspec::OpChainSpec; -use reth_primitives::TransactionMeta; -use reth_provider::HeaderProvider; +use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; +use reth_provider::{BlockReader, HeaderProvider}; use reth_rpc_eth_api::{ helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, RpcReceipt, @@ -19,6 +21,7 @@ where Self: LoadBlock< Error = OpEthApiError, NetworkTypes: Network, + Provider: BlockReader, >, N: OpNodeCore + HeaderProvider>, { @@ -30,22 +33,22 @@ where Self: LoadReceipt, { if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? { - let block_number = block.number; - let base_fee = block.base_fee_per_gas; + let block_number = block.number(); + let base_fee = block.base_fee_per_gas(); let block_hash = block.hash(); - let excess_blob_gas = block.excess_blob_gas; - let timestamp = block.timestamp; + let excess_blob_gas = block.excess_blob_gas(); + let timestamp = block.timestamp(); let l1_block_info = reth_optimism_evm::extract_l1_info(&block.body).map_err(OpEthApiError::from)?; return block .body - .transactions - .into_iter() + .transactions() + .iter() .zip(receipts.iter()) .enumerate() - .map(|(idx, (ref tx, receipt))| -> Result<_, _> { + .map(|(idx, (tx, receipt))| -> Result<_, _> { let meta = TransactionMeta { tx_hash: tx.hash(), index: idx as u64, diff --git a/crates/optimism/rpc/src/eth/call.rs b/crates/optimism/rpc/src/eth/call.rs index c9d874f73..f76917564 100644 --- a/crates/optimism/rpc/src/eth/call.rs +++ b/crates/optimism/rpc/src/eth/call.rs @@ -1,9 +1,9 @@ use super::OpNodeCore; use crate::{OpEthApi, OpEthApiError}; -use alloy_consensus::Header; use alloy_primitives::{Bytes, TxKind, U256}; use alloy_rpc_types_eth::transaction::TransactionRequest; use reth_evm::ConfigureEvm; +use reth_provider::ProviderHeader; use reth_rpc_eth_api::{ helpers::{estimate::EstimateCall, Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking}, FromEthApiError, IntoEthApiError, @@ -28,7 +28,7 @@ where impl Call for OpEthApi where - Self: LoadState> + SpawnBlocking, + Self: LoadState>> + SpawnBlocking, Self::Error: From, N: OpNodeCore, { diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index 0e657bf04..4304a2a37 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -13,7 +13,6 @@ use reth_optimism_primitives::OpPrimitives; use std::{fmt, sync::Arc}; -use alloy_consensus::Header; use alloy_primitives::U256; use op_alloy_network::Optimism; use reth_chainspec::{EthChainSpec, EthereumHardforks}; @@ -22,8 +21,8 @@ use reth_network_api::NetworkInfo; use reth_node_builder::EthApiBuilderCtx; use reth_provider::{ BlockNumReader, BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, - EvmEnvProvider, NodePrimitivesProvider, ProviderBlock, ProviderReceipt, StageCheckpointReader, - StateProviderFactory, + EvmEnvProvider, NodePrimitivesProvider, ProviderBlock, ProviderHeader, ProviderReceipt, + ProviderTx, StageCheckpointReader, StateProviderFactory, }; use reth_rpc::eth::{core::EthApiInner, DevSigner}; use reth_rpc_eth_api::{ @@ -155,13 +154,15 @@ where Network: NetworkInfo, >, { + type Transaction = ProviderTx; + #[inline] fn starting_block(&self) -> U256 { self.inner.eth_api.starting_block() } #[inline] - fn signers(&self) -> &parking_lot::RwLock>> { + fn signers(&self) -> &parking_lot::RwLock>>>> { self.inner.eth_api.signers() } } @@ -236,7 +237,13 @@ where impl Trace for OpEthApi where - Self: RpcNodeCore + LoadState>, + Self: RpcNodeCore + + LoadState< + Evm: ConfigureEvm< + Header = ProviderHeader, + Transaction = ProviderTx, + >, + >, N: OpNodeCore, { } diff --git a/crates/optimism/rpc/src/eth/pending_block.rs b/crates/optimism/rpc/src/eth/pending_block.rs index eebb61c8c..5c437de76 100644 --- a/crates/optimism/rpc/src/eth/pending_block.rs +++ b/crates/optimism/rpc/src/eth/pending_block.rs @@ -1,28 +1,36 @@ //! Loads OP pending block for a RPC response. use crate::OpEthApi; -use alloy_consensus::Header; -use alloy_eips::BlockNumberOrTag; -use alloy_primitives::{BlockNumber, B256}; +use alloy_consensus::{ + constants::EMPTY_WITHDRAWALS, proofs::calculate_transaction_root, Header, EMPTY_OMMER_ROOT_HASH, +}; +use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE, BlockNumberOrTag}; +use alloy_primitives::{B256, U256}; +use op_alloy_network::Network; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_evm::ConfigureEvm; use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism; -use reth_primitives::{Receipt, SealedBlockWithSenders, TransactionSigned}; +use reth_primitives::{logs_bloom, BlockBody, Receipt, SealedBlockWithSenders, TransactionSigned}; use reth_provider::{ - BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ExecutionOutcome, ProviderTx, - ReceiptProvider, StateProviderFactory, + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderBlock, + ProviderHeader, ProviderReceipt, ProviderTx, ReceiptProvider, StateProviderFactory, }; use reth_rpc_eth_api::{ helpers::{LoadPendingBlock, SpawnBlocking}, - FromEthApiError, RpcNodeCore, + EthApiTypes, FromEthApiError, RpcNodeCore, }; use reth_rpc_eth_types::{EthApiError, PendingBlock}; use reth_transaction_pool::{PoolTransaction, TransactionPool}; -use revm::primitives::BlockEnv; +use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg, ExecutionResult, SpecId}; impl LoadPendingBlock for OpEthApi where - Self: SpawnBlocking, + Self: SpawnBlocking + + EthApiTypes< + NetworkTypes: Network< + HeaderResponse = alloy_rpc_types_eth::Header>, + >, + >, N: RpcNodeCore< Provider: BlockReaderIdExt< Transaction = reth_primitives::TransactionSigned, @@ -37,7 +45,11 @@ where >, { #[inline] - fn pending_block(&self) -> &tokio::sync::Mutex> { + fn pending_block( + &self, + ) -> &tokio::sync::Mutex< + Option, ProviderReceipt>>, + > { self.inner.eth_api.pending_block() } @@ -68,20 +80,76 @@ where Ok(Some((block, receipts))) } - fn receipts_root( + fn assemble_block( &self, - block_env: &BlockEnv, - execution_outcome: &ExecutionOutcome, - block_number: BlockNumber, - ) -> B256 { - execution_outcome - .generic_receipts_root_slow(block_number, |receipts| { - calculate_receipt_root_no_memo_optimism( - receipts, - self.provider().chain_spec().as_ref(), - block_env.timestamp.to::(), - ) - }) - .expect("Block is present") + cfg: CfgEnvWithHandlerCfg, + block_env: BlockEnv, + parent_hash: B256, + state_root: B256, + transactions: Vec>, + receipts: &[ProviderReceipt], + ) -> reth_provider::ProviderBlock { + let chain_spec = self.provider().chain_spec(); + + let transactions_root = calculate_transaction_root(&transactions); + let receipts_root = calculate_receipt_root_no_memo_optimism( + &receipts.iter().collect::>(), + &chain_spec, + block_env.timestamp.to::(), + ); + + let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| &r.logs)); + + let header = Header { + parent_hash, + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: block_env.coinbase, + state_root, + transactions_root, + receipts_root, + withdrawals_root: (cfg.handler_cfg.spec_id >= SpecId::SHANGHAI) + .then_some(EMPTY_WITHDRAWALS), + logs_bloom, + timestamp: block_env.timestamp.to::(), + mix_hash: block_env.prevrandao.unwrap_or_default(), + nonce: BEACON_NONCE.into(), + base_fee_per_gas: Some(block_env.basefee.to::()), + number: block_env.number.to::(), + gas_limit: block_env.gas_limit.to::(), + difficulty: U256::ZERO, + gas_used: receipts.last().map(|r| r.cumulative_gas_used).unwrap_or_default(), + blob_gas_used: (cfg.handler_cfg.spec_id >= SpecId::CANCUN).then(|| { + transactions.iter().map(|tx| tx.blob_gas_used().unwrap_or_default()).sum::() + }), + excess_blob_gas: block_env.get_blob_excess_gas().map(Into::into), + extra_data: Default::default(), + parent_beacon_block_root: (cfg.handler_cfg.spec_id >= SpecId::CANCUN) + .then_some(B256::ZERO), + requests_hash: (cfg.handler_cfg.spec_id >= SpecId::PRAGUE) + .then_some(EMPTY_REQUESTS_HASH), + target_blobs_per_block: None, + }; + + // seal the block + reth_primitives::Block { + header, + body: BlockBody { transactions, ommers: vec![], withdrawals: None }, + } + } + + fn assemble_receipt( + &self, + tx: &reth_primitives::RecoveredTx>, + result: ExecutionResult, + cumulative_gas_used: u64, + ) -> reth_provider::ProviderReceipt { + #[allow(clippy::needless_update)] + Receipt { + tx_type: tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + ..Default::default() + } } } diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index cfc81ab64..c1e0a7301 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -7,7 +7,9 @@ use op_alloy_consensus::OpTxEnvelope; use op_alloy_rpc_types::Transaction; use reth_node_api::FullNodeComponents; use reth_primitives::{RecoveredTx, TransactionSigned}; -use reth_provider::{BlockReaderIdExt, ReceiptProvider, TransactionsProvider}; +use reth_provider::{ + BlockReader, BlockReaderIdExt, ProviderTx, ReceiptProvider, TransactionsProvider, +}; use reth_rpc_eth_api::{ helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, FromEthApiError, FullEthApiTypes, RpcNodeCore, RpcNodeCoreExt, TransactionCompat, @@ -20,9 +22,9 @@ use crate::{eth::OpNodeCore, OpEthApi, OpEthApiError, SequencerClient}; impl EthTransactions for OpEthApi where Self: LoadTransaction, - N: OpNodeCore, + N: OpNodeCore>>, { - fn signers(&self) -> &parking_lot::RwLock>> { + fn signers(&self) -> &parking_lot::RwLock>>>> { self.inner.eth_api.signers() } diff --git a/crates/primitives-traits/src/block/mod.rs b/crates/primitives-traits/src/block/mod.rs index fcbf02a76..53afc7377 100644 --- a/crates/primitives-traits/src/block/mod.rs +++ b/crates/primitives-traits/src/block/mod.rs @@ -4,6 +4,7 @@ pub mod body; pub mod header; use alloc::fmt; +use alloy_rlp::{Decodable, Encodable}; use crate::{ BlockBody, BlockHeader, FullBlockBody, FullBlockHeader, InMemorySize, MaybeArbitrary, @@ -39,6 +40,8 @@ pub trait Block: + InMemorySize + MaybeSerde + MaybeArbitrary + + Encodable + + Decodable { /// Header part of the block. type Header: BlockHeader; diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 9edbb2471..799e3e7a4 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -447,31 +447,6 @@ where } } -impl reth_primitives_traits::Block for SealedBlock -where - H: reth_primitives_traits::BlockHeader, - B: reth_primitives_traits::BlockBody, -{ - type Header = H; - type Body = B; - - fn new(header: Self::Header, body: Self::Body) -> Self { - Self { header: SealedHeader::seal(header), body } - } - - fn header(&self) -> &Self::Header { - self.header.header() - } - - fn body(&self) -> &Self::Body { - &self.body - } - - fn split(self) -> (Self::Header, Self::Body) { - (self.header.unseal(), self.body) - } -} - #[cfg(any(test, feature = "arbitrary"))] impl<'a, H, B> arbitrary::Arbitrary<'a> for SealedBlock where @@ -1022,7 +997,6 @@ mod tests { const fn _traits() { const fn assert_block() {} assert_block::(); - assert_block::(); } /// Check parsing according to EIP-1898. diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index d0b88c4b1..f7211489e 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1506,6 +1506,11 @@ impl RecoveredTx { pub const fn from_signed_transaction(signed_transaction: T, signer: Address) -> Self { Self { signed_transaction, signer } } + + /// Applies the given closure to the inner transactions. + pub fn map_transaction(self, f: impl FnOnce(T) -> Tx) -> RecoveredTx { + RecoveredTx::from_signed_transaction(f(self.signed_transaction), self.signer) + } } impl Encodable for RecoveredTx { diff --git a/crates/primitives/src/transaction/pooled.rs b/crates/primitives/src/transaction/pooled.rs index cdcc6b808..93a3c1823 100644 --- a/crates/primitives/src/transaction/pooled.rs +++ b/crates/primitives/src/transaction/pooled.rs @@ -654,6 +654,18 @@ impl TryFrom for PooledTransactionsElement { } } +impl From for TransactionSigned { + fn from(element: PooledTransactionsElement) -> Self { + match element { + PooledTransactionsElement::Legacy(tx) => tx.into(), + PooledTransactionsElement::Eip2930(tx) => tx.into(), + PooledTransactionsElement::Eip1559(tx) => tx.into(), + PooledTransactionsElement::Eip7702(tx) => tx.into(), + PooledTransactionsElement::BlobTransaction(blob_tx) => blob_tx.into_parts().0, + } + } +} + #[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for PooledTransactionsElement { /// Generates an arbitrary `PooledTransactionsElement`. diff --git a/crates/rpc/rpc-api/src/otterscan.rs b/crates/rpc/rpc-api/src/otterscan.rs index b4679ae5c..eb2cb21a2 100644 --- a/crates/rpc/rpc-api/src/otterscan.rs +++ b/crates/rpc/rpc-api/src/otterscan.rs @@ -1,7 +1,6 @@ use alloy_eips::BlockId; use alloy_json_rpc::RpcObject; use alloy_primitives::{Address, Bytes, TxHash, B256}; -use alloy_rpc_types_eth::Header; use alloy_rpc_types_trace::otterscan::{ BlockDetails, ContractCreator, InternalOperation, OtsBlockTransactions, TraceEntry, TransactionsWithReceipts, @@ -11,7 +10,7 @@ use jsonrpsee::{core::RpcResult, proc_macros::rpc}; /// Otterscan rpc interface. #[cfg_attr(not(feature = "client"), rpc(server, namespace = "ots"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "ots"))] -pub trait Otterscan { +pub trait Otterscan { /// Get the block header by block number, required by otterscan. /// Otterscan currently requires this endpoint, used as: /// @@ -20,7 +19,7 @@ pub trait Otterscan { /// /// Ref: #[method(name = "getHeaderByNumber", aliases = ["erigon_getHeaderByNumber"])] - async fn get_header_by_number(&self, block_number: u64) -> RpcResult>; + async fn get_header_by_number(&self, block_number: u64) -> RpcResult>; /// Check if a certain address contains a deployed code. #[method(name = "hasCode")] @@ -48,11 +47,11 @@ pub trait Otterscan { /// Tailor-made and expanded version of eth_getBlockByNumber for block details page in /// Otterscan. #[method(name = "getBlockDetails")] - async fn get_block_details(&self, block_number: u64) -> RpcResult; + async fn get_block_details(&self, block_number: u64) -> RpcResult>; /// Tailor-made and expanded version of eth_getBlockByHash for block details page in Otterscan. #[method(name = "getBlockDetailsByHash")] - async fn get_block_details_by_hash(&self, block_hash: B256) -> RpcResult; + async fn get_block_details_by_hash(&self, block_hash: B256) -> RpcResult>; /// Get paginated transactions for a certain block. Also remove some verbose fields like logs. #[method(name = "getBlockTransactions")] @@ -61,7 +60,7 @@ pub trait Otterscan { block_number: u64, page_number: usize, page_size: usize, - ) -> RpcResult>; + ) -> RpcResult>; /// Gets paginated inbound/outbound transaction calls for a certain address. #[method(name = "searchTransactionsBefore")] diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 1d8bfb9c2..df2556448 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -207,7 +207,8 @@ use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers}; use reth_primitives::{EthPrimitives, NodePrimitives}; use reth_provider::{ AccountReader, BlockReader, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, - EvmEnvProvider, FullRpcProvider, HeaderProvider, ReceiptProvider, StateProviderFactory, + EvmEnvProvider, FullRpcProvider, HeaderProvider, ProviderBlock, ProviderHeader, + ProviderReceipt, ReceiptProvider, StateProviderFactory, }; use reth_rpc::{ AdminApi, DebugApi, EngineEthApi, EthBundle, MinerApi, NetApi, OtterscanApi, RPCApi, RethApi, @@ -216,7 +217,7 @@ use reth_rpc::{ use reth_rpc_api::servers::*; use reth_rpc_eth_api::{ helpers::{Call, EthApiSpec, EthTransactions, LoadPendingBlock, TraceExt}, - EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcReceipt, RpcTransaction, + EthApiServer, EthApiTypes, FullEthApiServer, RpcBlock, RpcHeader, RpcReceipt, RpcTransaction, }; use reth_rpc_eth_types::{EthConfig, EthStateCache, EthSubscriptionIdProvider}; use reth_rpc_layer::{AuthLayer, Claims, CompressionLayer, JwtAuthValidator, JwtSecret}; @@ -276,9 +277,9 @@ pub async fn launch Result where Provider: FullRpcProvider< - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, - Header = reth_primitives::Header, + Block = ProviderBlock, + Receipt = ProviderReceipt, + Header = ProviderHeader, > + AccountReader + ChangeSetReader, Pool: TransactionPool::Transaction> + 'static, @@ -286,7 +287,13 @@ where Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, EvmConfig: ConfigureEvm
, - EthApi: FullEthApiServer, + EthApi: FullEthApiServer< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + Header = reth_primitives::Header, + >, + >, BlockExecutor: BlockExecutorProvider< Primitives: NodePrimitives< Block = reth_primitives::Block, @@ -672,7 +679,13 @@ where where EngineT: EngineTypes, EngineApi: EngineApiServer, - EthApi: FullEthApiServer, + EthApi: FullEthApiServer< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + Header = reth_primitives::Header, + >, + >, Provider: BlockReader< Block = ::Block, Receipt = ::Receipt, @@ -792,7 +805,13 @@ where eth: DynEthApiBuilder, ) -> TransportRpcModules<()> where - EthApi: FullEthApiServer, + EthApi: FullEthApiServer< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + Header = reth_primitives::Header, + >, + >, Provider: BlockReader< Block = ::Block, Receipt = ::Receipt, @@ -1134,6 +1153,7 @@ where RpcTransaction, RpcBlock, RpcReceipt, + RpcHeader, > + EthApiTypes, BlockExecutor: BlockExecutorProvider>, @@ -1170,10 +1190,16 @@ where /// If called outside of the tokio runtime. See also [`Self::eth_api`] pub fn register_debug(&mut self) -> &mut Self where - EthApi: EthApiSpec + EthTransactions + TraceExt, + EthApi: EthApiSpec + + EthTransactions< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + >, + > + TraceExt, Provider: BlockReader< Block = ::Block, - Receipt = reth_primitives::Receipt, + Receipt = ::Receipt, >, { let debug_api = self.debug_api(); @@ -1339,7 +1365,13 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EthApi: FullEthApiServer, + EthApi: FullEthApiServer< + Provider: BlockReader< + Block = reth_primitives::Block, + Receipt = reth_primitives::Receipt, + Header = reth_primitives::Header, + >, + >, BlockExecutor: BlockExecutorProvider< Primitives: NodePrimitives< Block = reth_primitives::Block, diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index a8393b0a9..357e3135e 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -5,7 +5,7 @@ use crate::utils::{launch_http, launch_http_ws, launch_ws}; use alloy_eips::{BlockId, BlockNumberOrTag}; use alloy_primitives::{hex_literal::hex, Address, Bytes, TxHash, B256, B64, U256, U64}; use alloy_rpc_types_eth::{ - transaction::TransactionRequest, Block, FeeHistory, Filter, Index, Log, + transaction::TransactionRequest, Block, FeeHistory, Filter, Header, Index, Log, PendingTransactionFilterKind, SyncStatus, Transaction, TransactionReceipt, }; use alloy_rpc_types_trace::filter::TraceFilter; @@ -174,16 +174,24 @@ where .unwrap(); // Implemented - EthApiClient::::protocol_version(client).await.unwrap(); - EthApiClient::::chain_id(client).await.unwrap(); - EthApiClient::::accounts(client).await.unwrap(); - EthApiClient::::get_account(client, address, block_number.into()) + EthApiClient::::protocol_version(client).await.unwrap(); + EthApiClient::::chain_id(client).await.unwrap(); + EthApiClient::::accounts(client).await.unwrap(); + EthApiClient::::get_account( + client, + address, + block_number.into(), + ) + .await + .unwrap(); + EthApiClient::::block_number(client).await.unwrap(); + EthApiClient::::get_code(client, address, None) .await .unwrap(); - EthApiClient::::block_number(client).await.unwrap(); - EthApiClient::::get_code(client, address, None).await.unwrap(); - EthApiClient::::send_raw_transaction(client, tx).await.unwrap(); - EthApiClient::::fee_history( + EthApiClient::::send_raw_transaction(client, tx) + .await + .unwrap(); + EthApiClient::::fee_history( client, U64::from(0), block_number, @@ -191,11 +199,13 @@ where ) .await .unwrap(); - EthApiClient::::balance(client, address, None).await.unwrap(); - EthApiClient::::transaction_count(client, address, None) + EthApiClient::::balance(client, address, None) .await .unwrap(); - EthApiClient::::storage_at( + EthApiClient::::transaction_count(client, address, None) + .await + .unwrap(); + EthApiClient::::storage_at( client, address, U256::default().into(), @@ -203,64 +213,79 @@ where ) .await .unwrap(); - EthApiClient::::block_by_hash(client, hash, false).await.unwrap(); - EthApiClient::::block_by_number(client, block_number, false) + EthApiClient::::block_by_hash(client, hash, false) .await .unwrap(); - EthApiClient::::block_transaction_count_by_number( + EthApiClient::::block_by_number( + client, + block_number, + false, + ) + .await + .unwrap(); + EthApiClient::::block_transaction_count_by_number( client, block_number, ) .await .unwrap(); - EthApiClient::::block_transaction_count_by_hash(client, hash) - .await - .unwrap(); - EthApiClient::::block_uncles_count_by_hash(client, hash) - .await - .unwrap(); - EthApiClient::::block_uncles_count_by_number(client, block_number) - .await - .unwrap(); - EthApiClient::::uncle_by_block_hash_and_index(client, hash, index) - .await - .unwrap(); - EthApiClient::::uncle_by_block_number_and_index( - client, - block_number, - index, + EthApiClient::::block_transaction_count_by_hash( + client, hash, ) .await .unwrap(); - EthApiClient::::sign(client, address, bytes.clone()) - .await - .unwrap_err(); - EthApiClient::::sign_typed_data(client, address, typed_data) - .await - .unwrap_err(); - EthApiClient::::transaction_by_hash(client, tx_hash) + EthApiClient::::block_uncles_count_by_hash(client, hash) .await .unwrap(); - EthApiClient::::transaction_by_block_hash_and_index( + EthApiClient::::block_uncles_count_by_number( + client, + block_number, + ) + .await + .unwrap(); + EthApiClient::::uncle_by_block_hash_and_index( client, hash, index, ) .await .unwrap(); - EthApiClient::::transaction_by_block_number_and_index( + EthApiClient::::uncle_by_block_number_and_index( client, block_number, index, ) .await .unwrap(); - EthApiClient::::create_access_list( + EthApiClient::::sign(client, address, bytes.clone()) + .await + .unwrap_err(); + EthApiClient::::sign_typed_data( + client, address, typed_data, + ) + .await + .unwrap_err(); + EthApiClient::::transaction_by_hash(client, tx_hash) + .await + .unwrap(); + EthApiClient::::transaction_by_block_hash_and_index( + client, hash, index, + ) + .await + .unwrap(); + EthApiClient::::transaction_by_block_number_and_index( + client, + block_number, + index, + ) + .await + .unwrap(); + EthApiClient::::create_access_list( client, call_request.clone(), Some(block_number.into()), ) .await .unwrap_err(); - EthApiClient::::estimate_gas( + EthApiClient::::estimate_gas( client, call_request.clone(), Some(block_number.into()), @@ -268,7 +293,7 @@ where ) .await .unwrap_err(); - EthApiClient::::call( + EthApiClient::::call( client, call_request.clone(), Some(block_number.into()), @@ -277,44 +302,47 @@ where ) .await .unwrap_err(); - EthApiClient::::syncing(client).await.unwrap(); - EthApiClient::::send_transaction( + EthApiClient::::syncing(client).await.unwrap(); + EthApiClient::::send_transaction( client, transaction_request.clone(), ) .await .unwrap_err(); - EthApiClient::::sign_transaction(client, transaction_request) - .await - .unwrap_err(); - EthApiClient::::hashrate(client).await.unwrap(); - EthApiClient::::submit_hashrate( + EthApiClient::::sign_transaction( + client, + transaction_request, + ) + .await + .unwrap_err(); + EthApiClient::::hashrate(client).await.unwrap(); + EthApiClient::::submit_hashrate( client, U256::default(), B256::default(), ) .await .unwrap(); - EthApiClient::::gas_price(client).await.unwrap_err(); - EthApiClient::::max_priority_fee_per_gas(client) + EthApiClient::::gas_price(client).await.unwrap_err(); + EthApiClient::::max_priority_fee_per_gas(client) .await .unwrap_err(); - EthApiClient::::get_proof(client, address, vec![], None) + EthApiClient::::get_proof(client, address, vec![], None) .await .unwrap(); // Unimplemented assert!(is_unimplemented( - EthApiClient::::author(client).await.err().unwrap() + EthApiClient::::author(client).await.err().unwrap() )); assert!(is_unimplemented( - EthApiClient::::is_mining(client).await.err().unwrap() + EthApiClient::::is_mining(client).await.err().unwrap() )); assert!(is_unimplemented( - EthApiClient::::get_work(client).await.err().unwrap() + EthApiClient::::get_work(client).await.err().unwrap() )); assert!(is_unimplemented( - EthApiClient::::submit_work( + EthApiClient::::submit_work( client, B64::default(), B256::default(), @@ -402,28 +430,32 @@ where let nonce = 1; let block_hash = B256::default(); - OtterscanClient::::get_header_by_number(client, block_number).await.unwrap(); - - OtterscanClient::::has_code(client, address, None).await.unwrap(); - OtterscanClient::::has_code(client, address, Some(block_number.into())) + OtterscanClient::::get_header_by_number(client, block_number) .await .unwrap(); - OtterscanClient::::get_api_level(client).await.unwrap(); + OtterscanClient::::has_code(client, address, None).await.unwrap(); + OtterscanClient::::has_code(client, address, Some(block_number.into())) + .await + .unwrap(); - OtterscanClient::::get_internal_operations(client, tx_hash).await.unwrap(); + OtterscanClient::::get_api_level(client).await.unwrap(); - OtterscanClient::::get_transaction_error(client, tx_hash).await.unwrap(); + OtterscanClient::::get_internal_operations(client, tx_hash).await.unwrap(); - OtterscanClient::::trace_transaction(client, tx_hash).await.unwrap(); + OtterscanClient::::get_transaction_error(client, tx_hash).await.unwrap(); - OtterscanClient::::get_block_details(client, block_number).await.unwrap_err(); + OtterscanClient::::trace_transaction(client, tx_hash).await.unwrap(); - OtterscanClient::::get_block_details_by_hash(client, block_hash) + OtterscanClient::::get_block_details(client, block_number) .await .unwrap_err(); - OtterscanClient::::get_block_transactions( + OtterscanClient::::get_block_details_by_hash(client, block_hash) + .await + .unwrap_err(); + + OtterscanClient::::get_block_transactions( client, block_number, page_number, @@ -434,7 +466,7 @@ where .unwrap(); assert!(is_unimplemented( - OtterscanClient::::search_transactions_before( + OtterscanClient::::search_transactions_before( client, address, block_number, @@ -445,7 +477,7 @@ where .unwrap() )); assert!(is_unimplemented( - OtterscanClient::::search_transactions_after( + OtterscanClient::::search_transactions_after( client, address, block_number, @@ -455,13 +487,13 @@ where .err() .unwrap() )); - assert!(OtterscanClient::::get_transaction_by_sender_and_nonce( + assert!(OtterscanClient::::get_transaction_by_sender_and_nonce( client, sender, nonce ) .await .err() .is_none()); - assert!(OtterscanClient::::get_contract_creator(client, address) + assert!(OtterscanClient::::get_contract_creator(client, address) .await .unwrap() .is_none()); diff --git a/crates/rpc/rpc-builder/tests/it/middleware.rs b/crates/rpc/rpc-builder/tests/it/middleware.rs index 0e2186e56..96d818ed4 100644 --- a/crates/rpc/rpc-builder/tests/it/middleware.rs +++ b/crates/rpc/rpc-builder/tests/it/middleware.rs @@ -1,5 +1,5 @@ use crate::utils::{test_address, test_rpc_builder}; -use alloy_rpc_types_eth::{Block, Receipt, Transaction}; +use alloy_rpc_types_eth::{Block, Header, Receipt, Transaction}; use jsonrpsee::{ server::{middleware::rpc::RpcServiceT, RpcServiceBuilder}, types::Request, @@ -75,7 +75,7 @@ async fn test_rpc_middleware() { .unwrap(); let client = handle.http_client().unwrap(); - EthApiClient::::protocol_version(&client).await.unwrap(); + EthApiClient::::protocol_version(&client).await.unwrap(); let count = mylayer.count.load(Ordering::Relaxed); assert_eq!(count, 1); } diff --git a/crates/rpc/rpc-eth-api/Cargo.toml b/crates/rpc/rpc-eth-api/Cargo.toml index bffd4fa30..95ed98d80 100644 --- a/crates/rpc/rpc-eth-api/Cargo.toml +++ b/crates/rpc/rpc-eth-api/Cargo.toml @@ -34,6 +34,7 @@ reth-node-api.workspace = true reth-trie-common = { workspace = true, features = ["eip1186"] } # ethereum +alloy-rlp.workspace = true alloy-serde.workspace = true alloy-eips.workspace = true alloy-dyn-abi = { workspace = true, features = ["eip712"] } diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 6500c3049..810400c6f 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -8,17 +8,18 @@ use alloy_rpc_types_eth::{ simulate::{SimulatePayload, SimulatedBlock}, state::{EvmOverrides, StateOverride}, transaction::TransactionRequest, - BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, - Index, StateContext, SyncStatus, Work, + BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Index, + StateContext, SyncStatus, Work, }; use alloy_serde::JsonStorageKey; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use reth_provider::BlockReader; use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult}; use tracing::trace; use crate::{ helpers::{EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, FullEthApi}, - RpcBlock, RpcReceipt, RpcTransaction, + RpcBlock, RpcHeader, RpcReceipt, RpcTransaction, }; /// Helper trait, unifies functionality that must be supported to implement all RPC methods for @@ -28,6 +29,7 @@ pub trait FullEthApiServer: RpcTransaction, RpcBlock, RpcReceipt, + RpcHeader, > + FullEthApi + Clone { @@ -38,6 +40,7 @@ impl FullEthApiServer for T where RpcTransaction, RpcBlock, RpcReceipt, + RpcHeader, > + FullEthApi + Clone { @@ -46,7 +49,7 @@ impl FullEthApiServer for T where /// Eth rpc interface: #[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))] -pub trait EthApi { +pub trait EthApi { /// Returns the protocol version encoded as a string. #[method(name = "protocolVersion")] async fn protocol_version(&self) -> RpcResult; @@ -200,11 +203,11 @@ pub trait EthApi { /// Returns the block's header at given number. #[method(name = "getHeaderByNumber")] - async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult>; + async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult>; /// Returns the block's header at given hash. #[method(name = "getHeaderByHash")] - async fn header_by_hash(&self, hash: B256) -> RpcResult>; + async fn header_by_hash(&self, hash: B256) -> RpcResult>; /// `eth_simulateV1` executes an arbitrary number of transactions on top of the requested state. /// The transactions are packed into individual blocks. Overrides can be provided. @@ -366,9 +369,15 @@ impl RpcTransaction, RpcBlock, RpcReceipt, + RpcHeader, > for T where - T: FullEthApi, + T: FullEthApi< + Provider: BlockReader< + Header = alloy_consensus::Header, + Transaction = reth_primitives::TransactionSigned, + >, + >, jsonrpsee_types::error::ErrorObject<'static>: From, { /// Handler for: `eth_protocolVersion` @@ -607,13 +616,16 @@ where } /// Handler for: `eth_getHeaderByNumber` - async fn header_by_number(&self, block_number: BlockNumberOrTag) -> RpcResult> { + async fn header_by_number( + &self, + block_number: BlockNumberOrTag, + ) -> RpcResult>> { trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber"); Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?) } /// Handler for: `eth_getHeaderByHash` - async fn header_by_hash(&self, hash: B256) -> RpcResult> { + async fn header_by_hash(&self, hash: B256) -> RpcResult>> { trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash"); Ok(EthBlocks::rpc_block_header(self, hash.into()).await?) } diff --git a/crates/rpc/rpc-eth-api/src/helpers/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs index cce0aa01b..5f0d9f744 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -4,14 +4,17 @@ use std::sync::Arc; use alloy_consensus::BlockHeader; use alloy_eips::BlockId; -use alloy_rpc_types_eth::{Block, Header, Index}; +use alloy_primitives::Sealable; +use alloy_rlp::Encodable; +use alloy_rpc_types_eth::{Block, BlockTransactions, Header, Index}; use futures::Future; use reth_node_api::BlockBody; use reth_primitives::{SealedBlockFor, SealedBlockWithSenders}; use reth_provider::{ - BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider, ProviderReceipt, + BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider, ProviderHeader, ProviderReceipt, }; use reth_rpc_types_compat::block::from_block; +use revm_primitives::U256; use crate::{ node::RpcNodeCoreExt, EthApiTypes, FromEthApiError, FullEthApiTypes, RpcBlock, RpcNodeCore, @@ -35,10 +38,11 @@ pub type BlockAndReceiptsResult = Result< /// `eth_` namespace. pub trait EthBlocks: LoadBlock { /// Returns the block header for the given block id. + #[expect(clippy::type_complexity)] fn rpc_block_header( &self, block_id: BlockId, - ) -> impl Future, Self::Error>> + Send + ) -> impl Future>>, Self::Error>> + Send where Self: FullEthApiTypes, { @@ -113,7 +117,7 @@ pub trait EthBlocks: LoadBlock { .get_sealed_block_with_senders(block_hash) .await .map_err(Self::Error::from_eth_err)? - .map(|b| b.body.transactions.len())) + .map(|b| b.body.transactions().len())) } } @@ -173,10 +177,11 @@ pub trait EthBlocks: LoadBlock { /// Returns uncle headers of given block. /// /// Returns an empty vec if there are none. + #[expect(clippy::type_complexity)] fn ommers( &self, block_id: BlockId, - ) -> Result>, Self::Error> { + ) -> Result>>, Self::Error> { self.provider().ommers_by_id(block_id).map_err(Self::Error::from_eth_err) } @@ -195,13 +200,22 @@ pub trait EthBlocks: LoadBlock { self.provider() .pending_block() .map_err(Self::Error::from_eth_err)? - .map(|block| block.body.ommers) + .and_then(|block| block.body.ommers().map(|o| o.to_vec())) } else { self.provider().ommers_by_id(block_id).map_err(Self::Error::from_eth_err)? } .unwrap_or_default(); - Ok(uncles.into_iter().nth(index.into()).map(Block::uncle_from_header)) + Ok(uncles.into_iter().nth(index.into()).map(|header| { + let block = alloy_consensus::Block::::uncle(header); + let size = U256::from(block.length()); + Block { + uncles: vec![], + header: Header::from_consensus(block.header.seal_slow(), None, Some(size)), + transactions: BlockTransactions::Uncle, + withdrawals: None, + } + })) } } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index aaa2ce131..f6d665121 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -6,7 +6,7 @@ use crate::{ helpers::estimate::EstimateCall, FromEthApiError, FromEvmError, FullEthApiTypes, IntoEthApiError, RpcBlock, RpcNodeCore, }; -use alloy_consensus::{BlockHeader, Header}; +use alloy_consensus::BlockHeader; use alloy_eips::{eip1559::calc_next_block_base_fee, eip2930::AccessListResult}; use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; use alloy_rpc_types_eth::{ @@ -20,7 +20,9 @@ use reth_chainspec::EthChainSpec; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_node_api::BlockBody; use reth_primitives_traits::SignedTransaction; -use reth_provider::{BlockIdReader, ChainSpecProvider, HeaderProvider}; +use reth_provider::{ + BlockIdReader, BlockReader, ChainSpecProvider, HeaderProvider, ProviderHeader, +}; use reth_revm::{ database::StateProviderDatabase, db::CacheDB, @@ -70,7 +72,12 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock { block: Option, ) -> impl Future> + Send where - Self: LoadBlock + FullEthApiTypes, + Self: LoadBlock< + Provider: BlockReader< + Header = alloy_consensus::Header, + Transaction = reth_primitives::TransactionSigned, + >, + > + FullEthApiTypes, { async move { if payload.block_state_calls.len() > self.max_simulate_blocks() as usize { @@ -456,7 +463,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock { } /// Executes code on state. -pub trait Call: LoadState> + SpawnBlocking { +pub trait Call: + LoadState>> + SpawnBlocking +{ /// Returns default gas limit to use for `eth_call` and tracing RPC methods. /// /// Data access in default trait method implementations. @@ -616,7 +625,7 @@ pub trait Call: LoadState> + SpawnBlocking { // we need to get the state of the parent block because we're essentially replaying the // block the transaction is included in - let parent_block = block.parent_hash; + let parent_block = block.parent_hash(); let this = self.clone(); self.spawn_with_state_at_block(parent_block.into(), move |state| { @@ -629,7 +638,7 @@ pub trait Call: LoadState> + SpawnBlocking { cfg.clone(), block_env.clone(), block_txs, - tx.hash(), + *tx.tx_hash(), )?; let env = EnvWithHandlerCfg::new_with_cfg_env( diff --git a/crates/rpc/rpc-eth-api/src/helpers/fee.rs b/crates/rpc/rpc-eth-api/src/helpers/fee.rs index 5843e945b..e0618cb69 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/fee.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/fee.rs @@ -5,6 +5,7 @@ use alloy_primitives::U256; use alloy_rpc_types_eth::{BlockNumberOrTag, FeeHistory}; use futures::Future; use reth_chainspec::EthChainSpec; +use reth_primitives_traits::BlockBody; use reth_provider::{BlockIdReader, ChainSpecProvider, HeaderProvider}; use reth_rpc_eth_types::{ fee_history::calculate_reward_percentiles_for_block, EthApiError, FeeHistoryCache, @@ -183,7 +184,7 @@ pub trait EthFees: LoadFee { percentiles, header.gas_used(), header.base_fee_per_gas().unwrap_or_default(), - &block.body.transactions, + block.body.transactions(), &receipts, ) .unwrap_or_default(), diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 8a6e5c84b..2ca6c028c 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -3,12 +3,11 @@ use super::SpawnBlocking; use crate::{EthApiTypes, FromEthApiError, FromEvmError, RpcNodeCore}; -use alloy_consensus::{BlockHeader, Header, EMPTY_OMMER_ROOT_HASH}; -use alloy_eips::{ - eip4844::MAX_DATA_GAS_PER_BLOCK, eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE, -}; -use alloy_primitives::{BlockNumber, B256, U256}; -use alloy_rpc_types_eth::{BlockNumberOrTag, Withdrawals}; +use alloy_consensus::{BlockHeader, Transaction}; +use alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK; +use alloy_network::Network; +use alloy_primitives::B256; +use alloy_rpc_types_eth::BlockNumberOrTag; use futures::Future; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_errors::RethError; @@ -17,19 +16,17 @@ use reth_evm::{ ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes, }; use reth_execution_types::ExecutionOutcome; -use reth_primitives::{ - proofs::calculate_transaction_root, Block, BlockBody, BlockExt, InvalidTransactionError, - Receipt, RecoveredTx, SealedBlockWithSenders, -}; +use reth_primitives::{BlockExt, InvalidTransactionError, RecoveredTx, SealedBlockWithSenders}; +use reth_primitives_traits::receipt::ReceiptExt; use reth_provider::{ - BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError, - ProviderReceipt, ProviderTx, ReceiptProvider, StateProviderFactory, + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderBlock, ProviderError, + ProviderHeader, ProviderReceipt, ProviderTx, ReceiptProvider, StateProviderFactory, }; use reth_revm::{ database::StateProviderDatabase, primitives::{ BlockEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, - ResultAndState, SpecId, + ResultAndState, }, }; use reth_rpc_eth_types::{EthApiError, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; @@ -46,29 +43,40 @@ use tracing::debug; /// /// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. pub trait LoadPendingBlock: - EthApiTypes - + RpcNodeCore< - Provider: BlockReaderIdExt< - Transaction = reth_primitives::TransactionSigned, - Block = reth_primitives::Block, - Receipt = reth_primitives::Receipt, - Header = reth_primitives::Header, - > + EvmEnvProvider + EthApiTypes< + NetworkTypes: Network< + HeaderResponse = alloy_rpc_types_eth::Header>, + >, + > + RpcNodeCore< + Provider: BlockReaderIdExt + + EvmEnvProvider> + ChainSpecProvider + StateProviderFactory, Pool: TransactionPool>>, - Evm: ConfigureEvm
>, + Evm: ConfigureEvm< + Header = ProviderHeader, + Transaction = ProviderTx, + >, > { /// Returns a handle to the pending block. /// /// Data access in default (L1) trait method implementations. - fn pending_block(&self) -> &Mutex>; + #[expect(clippy::type_complexity)] + fn pending_block( + &self, + ) -> &Mutex, ProviderReceipt>>>; /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block /// /// If no pending block is available, this will derive it from the `latest` block - fn pending_block_env_and_cfg(&self) -> Result { + #[expect(clippy::type_complexity)] + fn pending_block_env_and_cfg( + &self, + ) -> Result< + PendingBlockEnv, ProviderReceipt>, + Self::Error, + > { if let Some(block) = self.provider().pending_block_with_senders().map_err(Self::Error::from_eth_err)? { @@ -154,8 +162,8 @@ pub trait LoadPendingBlock: // check if the block is still good if let Some(pending_block) = lock.as_ref() { // this is guaranteed to be the `latest` header - if pending.block_env.number.to::() == pending_block.block.number && - parent_hash == pending_block.block.parent_hash && + if pending.block_env.number.to::() == pending_block.block.number() && + parent_hash == pending_block.block.parent_hash() && now <= pending_block.expires_at { return Ok(Some((pending_block.block.clone(), pending_block.receipts.clone()))); @@ -188,34 +196,24 @@ pub trait LoadPendingBlock: } } - /// Assembles a [`Receipt`] for a transaction, based on its [`ExecutionResult`]. + /// Assembles a receipt for a transaction, based on its [`ExecutionResult`]. fn assemble_receipt( &self, - tx: &RecoveredTx, + tx: &RecoveredTx>, result: ExecutionResult, cumulative_gas_used: u64, - ) -> Receipt { - #[allow(clippy::needless_update)] - Receipt { - tx_type: tx.tx_type(), - success: result.is_success(), - cumulative_gas_used, - logs: result.into_logs().into_iter().map(Into::into).collect(), - ..Default::default() - } - } + ) -> ProviderReceipt; - /// Calculates receipts root in block building. - /// - /// Panics if block is not in the [`ExecutionOutcome`]'s block range. - fn receipts_root( + /// Assembles a pending block. + fn assemble_block( &self, - _block_env: &BlockEnv, - execution_outcome: &ExecutionOutcome, - block_number: BlockNumber, - ) -> B256 { - execution_outcome.receipts_root_slow(block_number).expect("Block is present") - } + cfg: CfgEnvWithHandlerCfg, + block_env: BlockEnv, + parent_hash: revm_primitives::B256, + state_root: revm_primitives::B256, + transactions: Vec>, + receipts: &[ProviderReceipt], + ) -> ProviderBlock; /// Builds a pending block using the configured provider and pool. /// @@ -223,12 +221,19 @@ pub trait LoadPendingBlock: /// /// After Cancun, if the origin is the actual pending block, the block includes the EIP-4788 pre /// block contract call using the parent beacon block root received from the CL. + #[expect(clippy::type_complexity)] fn build_block( &self, cfg: CfgEnvWithHandlerCfg, block_env: BlockEnv, parent_hash: B256, - ) -> Result<(SealedBlockWithSenders, Vec), Self::Error> + ) -> Result< + ( + SealedBlockWithSenders>, + Vec>, + ), + Self::Error, + > where EthApiError: From, { @@ -253,14 +258,10 @@ pub trait LoadPendingBlock: block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), )); - let withdrawals: Option = None; - let withdrawals_root = None; - let chain_spec = self.provider().chain_spec(); let mut system_caller = SystemCaller::new(self.evm_config().clone(), chain_spec.clone()); - let parent_beacon_block_root = None; system_caller .pre_block_blockhashes_contract_call(&mut db, &cfg, &block_env, parent_hash) .map_err(|err| EthApiError::Internal(err.into()))?; @@ -301,8 +302,7 @@ pub trait LoadPendingBlock: // There's only limited amount of blob space available per block, so we need to check if // the EIP-4844 can still fit in the block - if let Some(blob_tx) = tx.transaction.as_eip4844() { - let tx_blob_gas = blob_tx.blob_gas(); + if let Some(tx_blob_gas) = tx.blob_gas_used() { if sum_blob_gas_used + tx_blob_gas > MAX_DATA_GAS_PER_BLOCK { // we can't fit this _blob_ transaction into the block, so we mark it as // invalid, which removes its dependent transactions from @@ -360,8 +360,7 @@ pub trait LoadPendingBlock: db.commit(state); // add to the total blob gas used if the transaction successfully executed - if let Some(blob_tx) = tx.transaction.as_eip4844() { - let tx_blob_gas = blob_tx.blob_gas(); + if let Some(tx_blob_gas) = tx.blob_gas_used() { sum_blob_gas_used += tx_blob_gas; // if we've reached the max data gas per block, we can skip blob txs entirely @@ -388,7 +387,7 @@ pub trait LoadPendingBlock: let balance_increments = post_block_withdrawals_balance_increments( chain_spec.as_ref(), block_env.timestamp.try_into().unwrap_or(u64::MAX), - &withdrawals.clone().unwrap_or_default(), + &[], ); // increment account balances for withdrawals @@ -397,66 +396,23 @@ pub trait LoadPendingBlock: // merge all transitions into bundle state. db.merge_transitions(BundleRetention::PlainState); - let execution_outcome = ExecutionOutcome::new( - db.take_bundle(), - vec![receipts.clone()].into(), - block_number, - Vec::new(), - ); + let execution_outcome: ExecutionOutcome> = + ExecutionOutcome::new( + db.take_bundle(), + vec![receipts.clone()].into(), + block_number, + Vec::new(), + ); let hashed_state = db.database.hashed_post_state(execution_outcome.state()); - let receipts_root = self.receipts_root(&block_env, &execution_outcome, block_number); - - let logs_bloom = - execution_outcome.block_logs_bloom(block_number).expect("Block is present"); - // calculate the state root let state_root = db.database.state_root(hashed_state).map_err(Self::Error::from_eth_err)?; - // create the block header - let transactions_root = calculate_transaction_root(&executed_txs); - - // check if cancun is activated to set eip4844 header fields correctly - let blob_gas_used = - (cfg.handler_cfg.spec_id >= SpecId::CANCUN).then_some(sum_blob_gas_used); - - let requests_hash = chain_spec - .is_prague_active_at_timestamp(block_env.timestamp.to::()) - .then_some(EMPTY_REQUESTS_HASH); - - let header = Header { - parent_hash, - ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: block_env.coinbase, - state_root, - transactions_root, - receipts_root, - withdrawals_root, - logs_bloom, - timestamp: block_env.timestamp.to::(), - mix_hash: block_env.prevrandao.unwrap_or_default(), - nonce: BEACON_NONCE.into(), - base_fee_per_gas: Some(base_fee), - number: block_number, - gas_limit: block_gas_limit, - difficulty: U256::ZERO, - gas_used: cumulative_gas_used, - blob_gas_used: blob_gas_used.map(Into::into), - excess_blob_gas: block_env.get_blob_excess_gas().map(Into::into), - extra_data: Default::default(), - parent_beacon_block_root, - requests_hash, - target_blobs_per_block: None, - }; - // Convert Vec> to Vec - let receipts: Vec = receipts.into_iter().flatten().collect(); + let receipts: Vec<_> = receipts.into_iter().flatten().collect(); + let block = + self.assemble_block(cfg, block_env, parent_hash, state_root, executed_txs, &receipts); - // seal the block - let block = Block { - header, - body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals }, - }; Ok((SealedBlockWithSenders { block: block.seal_slow(), senders }, receipts)) } } diff --git a/crates/rpc/rpc-eth-api/src/helpers/signer.rs b/crates/rpc/rpc-eth-api/src/helpers/signer.rs index dc8beab38..85c954147 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/signer.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/signer.rs @@ -4,7 +4,6 @@ use alloy_dyn_abi::TypedData; use alloy_primitives::{Address, PrimitiveSignature as Signature}; use alloy_rpc_types_eth::TransactionRequest; use dyn_clone::DynClone; -use reth_primitives::TransactionSigned; use reth_rpc_eth_types::SignError; use std::result; @@ -13,7 +12,7 @@ pub type Result = result::Result; /// An Ethereum Signer used via RPC. #[async_trait::async_trait] -pub trait EthSigner: Send + Sync + DynClone { +pub trait EthSigner: Send + Sync + DynClone { /// Returns the available accounts for this signer. fn accounts(&self) -> Vec
; @@ -26,17 +25,13 @@ pub trait EthSigner: Send + Sync + DynClone { async fn sign(&self, address: Address, message: &[u8]) -> Result; /// signs a transaction request using the given account in request - async fn sign_transaction( - &self, - request: TransactionRequest, - address: &Address, - ) -> Result; + async fn sign_transaction(&self, request: TransactionRequest, address: &Address) -> Result; /// Encodes and signs the typed data according EIP-712. Payload must implement Eip712 trait. fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result; } -dyn_clone::clone_trait_object!(EthSigner); +dyn_clone::clone_trait_object!( EthSigner); /// Adds 20 random dev signers for access via the API. Used in dev mode. #[auto_impl::auto_impl(&)] diff --git a/crates/rpc/rpc-eth-api/src/helpers/spec.rs b/crates/rpc/rpc-eth-api/src/helpers/spec.rs index 9957a00a4..13ad9b778 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/spec.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/spec.rs @@ -22,11 +22,14 @@ pub trait EthApiSpec: Network: NetworkInfo, > { + /// The transaction type signers are using. + type Transaction; + /// Returns the block node is started on. fn starting_block(&self) -> U256; /// Returns a handle to the signers owned by provider. - fn signers(&self) -> &parking_lot::RwLock>>; + fn signers(&self) -> &parking_lot::RwLock>>>; /// Returns the current ethereum protocol version. fn protocol_version(&self) -> impl Future> + Send { diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index 50ff1b557..4c9ccecd3 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -2,7 +2,7 @@ //! RPC methods. use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking}; use crate::{EthApiTypes, FromEthApiError, RpcNodeCore, RpcNodeCoreExt}; -use alloy_consensus::{constants::KECCAK_EMPTY, Header}; +use alloy_consensus::{constants::KECCAK_EMPTY, BlockHeader}; use alloy_eips::BlockId; use alloy_primitives::{Address, Bytes, B256, U256}; use alloy_rpc_types_eth::{Account, EIP1186AccountProofResponse}; @@ -12,8 +12,8 @@ use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_errors::RethError; use reth_evm::ConfigureEvmEnv; use reth_provider::{ - BlockIdReader, BlockNumReader, ChainSpecProvider, EvmEnvProvider as _, StateProvider, - StateProviderBox, StateProviderFactory, + BlockIdReader, BlockNumReader, ChainSpecProvider, EvmEnvProvider as _, ProviderHeader, + StateProvider, StateProviderBox, StateProviderFactory, }; use reth_rpc_eth_types::{EthApiError, PendingBlockEnv, RpcInvalidTransactionError}; use reth_transaction_pool::TransactionPool; @@ -247,14 +247,14 @@ pub trait LoadState: /// This is used for tracing raw blocks fn evm_env_for_raw_block( &self, - header: &Header, + header: &ProviderHeader, ) -> impl Future> + Send where Self: LoadPendingBlock + SpawnBlocking, { async move { // get the parent config first - let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?; + let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash().into()).await?; let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; self.evm_config().fill_block_env(&mut block_env, header, after_merge); diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs index 114b4c41d..e000218e7 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -3,14 +3,15 @@ use std::{fmt::Display, sync::Arc}; use crate::{FromEvmError, RpcNodeCore}; -use alloy_consensus::Header; +use alloy_consensus::BlockHeader; use alloy_primitives::B256; use alloy_rpc_types_eth::{BlockId, TransactionInfo}; use futures::Future; use reth_chainspec::ChainSpecProvider; use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::SealedBlockWithSenders; -use reth_provider::BlockReader; +use reth_primitives_traits::{BlockBody, SignedTransaction}; +use reth_provider::{BlockReader, ProviderBlock, ProviderHeader, ProviderTx}; use reth_revm::database::StateProviderDatabase; use reth_rpc_eth_types::{ cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, @@ -25,7 +26,15 @@ use revm_primitives::{ use super::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction}; /// Executes CPU heavy tasks. -pub trait Trace: LoadState> { +pub trait Trace: + LoadState< + Provider: BlockReader, + Evm: ConfigureEvm< + Header = ProviderHeader, + Transaction = ProviderTx, + >, +> +{ /// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state /// changes. fn inspect( @@ -190,7 +199,7 @@ pub trait Trace: LoadState( &self, block_id: BlockId, - block: Option::Block>>>, + block: Option>>>, highest_index: Option, config: TracingInspectorConfig, f: F, @@ -271,7 +280,7 @@ pub trait Trace: LoadState( &self, block_id: BlockId, - block: Option>, + block: Option>>>, highest_index: Option, mut inspector_setup: Setup, f: F, @@ -304,7 +313,7 @@ pub trait Trace: LoadState(); @@ -329,7 +338,7 @@ pub trait Trace: LoadState( &self, block_id: BlockId, - block: Option>, + block: Option>>>, config: TracingInspectorConfig, f: F, ) -> impl Future>, Self::Error>> + Send @@ -428,7 +437,7 @@ pub trait Trace: LoadState( &self, block_id: BlockId, - block: Option>, + block: Option>>>, insp_setup: Setup, f: F, ) -> impl Future>, Self::Error>> + Send @@ -459,7 +468,7 @@ pub trait Trace: LoadState + DatabaseCommit>( &self, - block: &SealedBlockWithSenders, + block: &SealedBlockWithSenders>, db: &mut DB, cfg: &CfgEnvWithHandlerCfg, block_env: &BlockEnv, @@ -472,12 +481,12 @@ pub trait Trace: LoadState { /// Returns a handle for signing data. /// /// Singer access in default (L1) trait method implementations. - fn signers(&self) -> &parking_lot::RwLock>>; + #[expect(clippy::type_complexity)] + fn signers(&self) -> &parking_lot::RwLock>>>>; /// Returns the transaction by hash. /// @@ -213,7 +214,7 @@ pub trait EthTransactions: LoadTransaction { let base_fee_per_gas = block.base_fee_per_gas(); if let Some((signer, tx)) = block.transactions_with_sender().nth(index) { let tx_info = TransactionInfo { - hash: Some(tx.hash()), + hash: Some(*tx.tx_hash()), block_hash: Some(block_hash), block_number: Some(block_number), base_fee: base_fee_per_gas.map(u128::from), @@ -294,7 +295,7 @@ pub trait EthTransactions: LoadTransaction { .find(|(_, (signer, tx))| **signer == sender && (*tx).nonce() == nonce) .map(|(index, (signer, tx))| { let tx_info = TransactionInfo { - hash: Some(tx.hash()), + hash: Some(*tx.tx_hash()), block_hash: Some(block_hash), block_number: Some(block_number), base_fee: base_fee_per_gas.map(u128::from), @@ -414,7 +415,7 @@ pub trait EthTransactions: LoadTransaction { &self, from: &Address, txn: TransactionRequest, - ) -> impl Future> + Send { + ) -> impl Future, Self::Error>> + Send { async move { self.find_signer(from)? .sign_transaction(txn, from) @@ -467,10 +468,11 @@ pub trait EthTransactions: LoadTransaction { } /// Returns the signer for the given account, if found in configured signers. + #[expect(clippy::type_complexity)] fn find_signer( &self, account: &Address, - ) -> Result, Self::Error> { + ) -> Result> + 'static)>, Self::Error> { self.signers() .read() .iter() diff --git a/crates/rpc/rpc-eth-api/src/lib.rs b/crates/rpc/rpc-eth-api/src/lib.rs index c4a255985..d9c7f39a4 100644 --- a/crates/rpc/rpc-eth-api/src/lib.rs +++ b/crates/rpc/rpc-eth-api/src/lib.rs @@ -29,7 +29,7 @@ pub use reth_rpc_eth_types::error::{ AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError, }; pub use reth_rpc_types_compat::TransactionCompat; -pub use types::{EthApiTypes, FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction}; +pub use types::{EthApiTypes, FullEthApiTypes, RpcBlock, RpcHeader, RpcReceipt, RpcTransaction}; #[cfg(feature = "client")] pub use bundle::{EthBundleApiClient, EthCallBundleApiClient}; diff --git a/crates/rpc/rpc-eth-api/src/types.rs b/crates/rpc/rpc-eth-api/src/types.rs index c97ea5735..2da1bdac2 100644 --- a/crates/rpc/rpc-eth-api/src/types.rs +++ b/crates/rpc/rpc-eth-api/src/types.rs @@ -24,7 +24,7 @@ pub trait EthApiTypes: Send + Sync + Clone { + Send + Sync; /// Blockchain primitive types, specific to network, e.g. block and transaction. - type NetworkTypes: Network; + type NetworkTypes: Network; /// Conversion methods for transaction RPC type. type TransactionCompat: Send + Sync + Clone + fmt::Debug; @@ -41,6 +41,9 @@ pub type RpcBlock = Block, ::HeaderResponse>; /// Adapter for network specific receipt type. pub type RpcReceipt = ::ReceiptResponse; +/// Adapter for network specific header type. +pub type RpcHeader = ::HeaderResponse; + /// Adapter for network specific error type. pub type RpcError = ::Error; diff --git a/crates/rpc/rpc-eth-types/src/pending_block.rs b/crates/rpc/rpc-eth-types/src/pending_block.rs index bd23e3f42..ef2a61dd7 100644 --- a/crates/rpc/rpc-eth-types/src/pending_block.rs +++ b/crates/rpc/rpc-eth-types/src/pending_block.rs @@ -14,13 +14,13 @@ use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}; /// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block. #[derive(Debug, Clone, Constructor)] -pub struct PendingBlockEnv { +pub struct PendingBlockEnv { /// Configured [`CfgEnvWithHandlerCfg`] for the pending block. pub cfg: CfgEnvWithHandlerCfg, /// Configured [`BlockEnv`] for the pending block. pub block_env: BlockEnv, /// Origin block for the config - pub origin: PendingBlockEnvOrigin, + pub origin: PendingBlockEnvOrigin, } /// The origin for a configured [`PendingBlockEnv`] @@ -77,11 +77,11 @@ impl PendingBlockEnvOrigin { /// Locally built pending block for `pending` tag. #[derive(Debug, Constructor)] -pub struct PendingBlock { +pub struct PendingBlock { /// Timestamp when the pending block is considered outdated. pub expires_at: Instant, /// The locally built pending block. - pub block: SealedBlockWithSenders, + pub block: SealedBlockWithSenders, /// The receipts for the pending block - pub receipts: Vec, + pub receipts: Vec, } diff --git a/crates/rpc/rpc-testing-util/src/debug.rs b/crates/rpc/rpc-testing-util/src/debug.rs index a18771af3..36a01fa59 100644 --- a/crates/rpc/rpc-testing-util/src/debug.rs +++ b/crates/rpc/rpc-testing-util/src/debug.rs @@ -8,7 +8,7 @@ use std::{ use alloy_eips::BlockId; use alloy_primitives::{TxHash, B256}; -use alloy_rpc_types_eth::{transaction::TransactionRequest, Block, Transaction}; +use alloy_rpc_types_eth::{transaction::TransactionRequest, Block, Header, Transaction}; use alloy_rpc_types_trace::{ common::TraceResult, geth::{GethDebugTracerType, GethDebugTracingOptions, GethTrace}, @@ -77,7 +77,7 @@ pub trait DebugApiExt { impl DebugApiExt for T where - T: EthApiClient + DebugApiClient + Sync, + T: EthApiClient + DebugApiClient + Sync, { type Provider = T; diff --git a/crates/rpc/rpc-testing-util/tests/it/trace.rs b/crates/rpc/rpc-testing-util/tests/it/trace.rs index 4c5d2ccb2..e67946f7b 100644 --- a/crates/rpc/rpc-testing-util/tests/it/trace.rs +++ b/crates/rpc/rpc-testing-util/tests/it/trace.rs @@ -1,7 +1,7 @@ //! Integration tests for the trace API. use alloy_primitives::map::HashSet; -use alloy_rpc_types_eth::{Block, Transaction}; +use alloy_rpc_types_eth::{Block, Header, Transaction}; use alloy_rpc_types_trace::{ filter::TraceFilter, parity::TraceType, tracerequest::TraceCallRequest, }; @@ -113,7 +113,7 @@ async fn debug_trace_block_entire_chain() { let client = HttpClientBuilder::default().build(url).unwrap(); let current_block: u64 = - >::block_number(&client) + >::block_number(&client) .await .unwrap() .try_into() diff --git a/crates/rpc/rpc-types-compat/Cargo.toml b/crates/rpc/rpc-types-compat/Cargo.toml index d39443561..d4e1aac88 100644 --- a/crates/rpc/rpc-types-compat/Cargo.toml +++ b/crates/rpc/rpc-types-compat/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] # reth reth-primitives.workspace = true +reth-primitives-traits.workspace = true # ethereum alloy-eips.workspace = true diff --git a/crates/rpc/rpc-types-compat/src/block.rs b/crates/rpc/rpc-types-compat/src/block.rs index 564f5a939..d3238757f 100644 --- a/crates/rpc/rpc-types-compat/src/block.rs +++ b/crates/rpc/rpc-types-compat/src/block.rs @@ -1,13 +1,13 @@ //! Compatibility functions for rpc `Block` type. -use alloy_consensus::Sealed; +use alloy_consensus::{BlockHeader, Sealable, Sealed}; use alloy_eips::eip4895::Withdrawals; use alloy_primitives::{B256, U256}; -use alloy_rlp::Encodable; use alloy_rpc_types_eth::{ Block, BlockTransactions, BlockTransactionsKind, Header, TransactionInfo, }; -use reth_primitives::{Block as PrimitiveBlock, BlockWithSenders, TransactionSigned}; +use reth_primitives::{transaction::SignedTransactionIntoRecoveredExt, BlockWithSenders}; +use reth_primitives_traits::{Block as BlockTrait, BlockBody, SignedTransaction}; use crate::{transaction::from_recovered_with_block_context, TransactionCompat}; @@ -15,19 +15,24 @@ use crate::{transaction::from_recovered_with_block_context, TransactionCompat}; /// [`BlockTransactionsKind`] /// /// If a `block_hash` is provided, then this is used, otherwise the block hash is computed. -pub fn from_block( - block: BlockWithSenders, +#[expect(clippy::type_complexity)] +pub fn from_block( + block: BlockWithSenders, total_difficulty: U256, kind: BlockTransactionsKind, block_hash: Option, tx_resp_builder: &T, -) -> Result, T::Error> { +) -> Result>, T::Error> +where + T: TransactionCompat<<::Body as BlockBody>::Transaction>, + B: BlockTrait, +{ match kind { BlockTransactionsKind::Hashes => { - Ok(from_block_with_tx_hashes::(block, total_difficulty, block_hash)) + Ok(from_block_with_tx_hashes::(block, total_difficulty, block_hash)) } BlockTransactionsKind::Full => { - from_block_full::(block, total_difficulty, block_hash, tx_resp_builder) + from_block_full::(block, total_difficulty, block_hash, tx_resp_builder) } } } @@ -37,13 +42,16 @@ pub fn from_block( /// /// This will populate the `transactions` field with only the hashes of the transactions in the /// block: [`BlockTransactions::Hashes`] -pub fn from_block_with_tx_hashes( - block: BlockWithSenders, +pub fn from_block_with_tx_hashes( + block: BlockWithSenders, total_difficulty: U256, block_hash: Option, -) -> Block { - let block_hash = block_hash.unwrap_or_else(|| block.header.hash_slow()); - let transactions = block.body.transactions.iter().map(|tx| tx.hash()).collect(); +) -> Block> +where + B: BlockTrait, +{ + let block_hash = block_hash.unwrap_or_else(|| block.header().hash_slow()); + let transactions = block.body().transactions().iter().map(|tx| *tx.tx_hash()).collect(); from_block_with_transactions( block.length(), @@ -59,25 +67,30 @@ pub fn from_block_with_tx_hashes( /// /// This will populate the `transactions` field with the _full_ /// [`TransactionCompat::Transaction`] objects: [`BlockTransactions::Full`] -pub fn from_block_full( - mut block: BlockWithSenders, +#[expect(clippy::type_complexity)] +pub fn from_block_full( + block: BlockWithSenders, total_difficulty: U256, block_hash: Option, tx_resp_builder: &T, -) -> Result, T::Error> { - let block_hash = block_hash.unwrap_or_else(|| block.block.header.hash_slow()); - let block_number = block.block.number; - let base_fee_per_gas = block.block.base_fee_per_gas; +) -> Result>, T::Error> +where + T: TransactionCompat<<::Body as BlockBody>::Transaction>, + B: BlockTrait, +{ + let block_hash = block_hash.unwrap_or_else(|| block.block.header().hash_slow()); + let block_number = block.block.header().number(); + let base_fee_per_gas = block.block.header().base_fee_per_gas(); // NOTE: we can safely remove the body here because not needed to finalize the `Block` in // `from_block_with_transactions`, however we need to compute the length before let block_length = block.block.length(); - let transactions = std::mem::take(&mut block.block.body.transactions); + let transactions = block.block.body().transactions().to_vec(); let transactions_with_senders = transactions.into_iter().zip(block.senders); let transactions = transactions_with_senders .enumerate() .map(|(idx, (tx, sender))| { - let tx_hash = tx.hash(); + let tx_hash = *tx.tx_hash(); let signed_tx_ec_recovered = tx.with_signer(sender); let tx_info = TransactionInfo { hash: Some(tx_hash), @@ -87,7 +100,7 @@ pub fn from_block_full( index: Some(idx as u64), }; - from_recovered_with_block_context::( + from_recovered_with_block_context::<_, T>( signed_tx_ec_recovered, tx_info, tx_resp_builder, @@ -105,23 +118,28 @@ pub fn from_block_full( } #[inline] -fn from_block_with_transactions( +fn from_block_with_transactions( block_length: usize, block_hash: B256, - block: PrimitiveBlock, + block: B, total_difficulty: U256, transactions: BlockTransactions, -) -> Block { +) -> Block> { let withdrawals = block - .header - .withdrawals_root + .header() + .withdrawals_root() .is_some() - .then(|| block.body.withdrawals.map(Withdrawals::into_inner).map(Into::into)) + .then(|| block.body().withdrawals().cloned().map(Withdrawals::into_inner).map(Into::into)) .flatten(); - let uncles = block.body.ommers.into_iter().map(|h| h.hash_slow()).collect(); + let uncles = block + .body() + .ommers() + .map(|o| o.iter().map(|h| h.hash_slow()).collect()) + .unwrap_or_default(); + let (header, _) = block.split(); let header = Header::from_consensus( - Sealed::new_unchecked(block.header, block_hash), + Sealed::new_unchecked(header, block_hash), Some(total_difficulty), Some(U256::from(block_length)), ); diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 765b7e719..91236ca9d 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -1,3 +1,4 @@ +use alloy_consensus::BlockHeader; use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag}; use alloy_primitives::{Address, Bytes, B256, U256}; use alloy_rlp::{Decodable, Encodable}; @@ -18,11 +19,11 @@ use reth_evm::{ execute::{BlockExecutorProvider, Executor}, ConfigureEvmEnv, }; -use reth_primitives::{Block, BlockExt, NodePrimitives, SealedBlockWithSenders}; -use reth_primitives_traits::SignedTransaction; +use reth_primitives::{BlockExt, NodePrimitives, SealedBlockWithSenders}; +use reth_primitives_traits::{Block as _, BlockBody, SignedTransaction}; use reth_provider::{ - BlockReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProofProvider, - StateProviderFactory, TransactionVariant, + BlockReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider, ProviderBlock, + StateProofProvider, StateProviderFactory, TransactionVariant, }; use reth_revm::{database::StateProviderDatabase, witness::ExecutionWitnessRecord}; use reth_rpc_api::DebugApiServer; @@ -81,9 +82,8 @@ where + StateProviderFactory + 'static, Eth: EthApiTypes + TraceExt + 'static, - BlockExecutor: BlockExecutorProvider< - Primitives: NodePrimitives::Provider as BlockReader>::Block>, - >, + BlockExecutor: + BlockExecutorProvider>>, { /// Acquires a permit to execute a tracing call. async fn acquire_trace_permit(&self) -> Result { @@ -93,7 +93,7 @@ where /// Trace the entire block asynchronously async fn trace_block( &self, - block: Arc, + block: Arc>>, cfg: CfgEnvWithHandlerCfg, block_env: BlockEnv, opts: GethDebugTracingOptions, @@ -101,8 +101,8 @@ where // replay all transactions of the block let this = self.clone(); self.eth_api() - .spawn_with_state_at_block(block.parent_hash.into(), move |state| { - let mut results = Vec::with_capacity(block.body.transactions.len()); + .spawn_with_state_at_block(block.parent_hash().into(), move |state| { + let mut results = Vec::with_capacity(block.body.transactions().len()); let mut db = CacheDB::new(StateProviderDatabase::new(state)); this.eth_api().apply_pre_execution_changes(&block, &mut db, &cfg, &block_env)?; @@ -110,7 +110,7 @@ where let mut transactions = block.transactions_with_sender().enumerate().peekable(); let mut inspector = None; while let Some((index, (signer, tx))) = transactions.next() { - let tx_hash = tx.hash(); + let tx_hash = *tx.tx_hash(); let env = EnvWithHandlerCfg { env: Env::boxed( @@ -157,18 +157,22 @@ where rlp_block: Bytes, opts: GethDebugTracingOptions, ) -> Result, Eth::Error> { - let block = Block::decode(&mut rlp_block.as_ref()) + let block: ProviderBlock = Decodable::decode(&mut rlp_block.as_ref()) .map_err(BlockError::RlpDecodeRawBlock) .map_err(Eth::Error::from_eth_err)?; - let (cfg, block_env) = self.eth_api().evm_env_for_raw_block(&block.header).await?; + let (cfg, block_env) = self.eth_api().evm_env_for_raw_block(block.header()).await?; // Depending on EIP-2 we need to recover the transactions differently - let senders = if self.inner.provider.chain_spec().is_homestead_active_at_block(block.number) + let senders = if self + .inner + .provider + .chain_spec() + .is_homestead_active_at_block(block.header().number()) { block - .body - .transactions + .body() + .transactions() .iter() .map(|tx| { tx.recover_signer() @@ -178,8 +182,8 @@ where .collect::, Eth::Error>>()? } else { block - .body - .transactions + .body() + .transactions() .iter() .map(|tx| { tx.recover_signer_unchecked() @@ -237,7 +241,7 @@ where // we need to get the state of the parent block because we're essentially replaying the // block the transaction is included in - let state_at: BlockId = block.parent_hash.into(); + let state_at: BlockId = block.parent_hash().into(); let block_hash = block.hash(); let this = self.clone(); @@ -258,7 +262,7 @@ where cfg.clone(), block_env.clone(), block_txs, - tx.hash(), + *tx.tx_hash(), )?; let env = EnvWithHandlerCfg { @@ -277,7 +281,7 @@ where Some(TransactionContext { block_hash: Some(block_hash), tx_index: Some(index), - tx_hash: Some(tx.hash()), + tx_hash: Some(*tx.tx_hash()), }), &mut None, ) @@ -514,15 +518,15 @@ where // we're essentially replaying the transactions in the block here, hence we need the state // that points to the beginning of the block, which is the state at the parent block - let mut at = block.parent_hash; + let mut at = block.parent_hash(); let mut replay_block_txs = true; // if a transaction index is provided, we need to replay the transactions until the index - let num_txs = transaction_index.index().unwrap_or(block.body.transactions.len()); + let num_txs = transaction_index.index().unwrap_or_else(|| block.body.transactions().len()); // but if all transactions are to be replayed, we can use the state at the block itself // this works with the exception of the PENDING block, because its state might not exist if // built locally - if !target_block.is_pending() && num_txs == block.body.transactions.len() { + if !target_block.is_pending() && num_txs == block.body.transactions().len() { at = block.hash(); replay_block_txs = false; } @@ -622,7 +626,7 @@ where .ok_or(EthApiError::HeaderNotFound(block_id.into()))?; self.eth_api() - .spawn_with_state_at_block(block.parent_hash.into(), move |state_provider| { + .spawn_with_state_at_block(block.parent_hash().into(), move |state_provider| { let db = StateProviderDatabase::new(&state_provider); let block_executor = this.inner.block_executor.executor(db); @@ -630,7 +634,7 @@ where let _ = block_executor .execute_with_state_closure( - (&(*block).clone().unseal(), block.difficulty).into(), + (&(*block).clone().unseal(), block.difficulty()).into(), |statedb: &State<_>| { witness_record.record_executed_state(statedb); }, diff --git a/crates/rpc/rpc/src/engine.rs b/crates/rpc/rpc/src/engine.rs index fca78d62d..a9c316571 100644 --- a/crates/rpc/rpc/src/engine.rs +++ b/crates/rpc/rpc/src/engine.rs @@ -9,7 +9,7 @@ use jsonrpsee::core::RpcResult as Result; use reth_rpc_api::{EngineEthApiServer, EthApiServer, EthFilterApiServer}; /// Re-export for convenience pub use reth_rpc_engine_api::EngineApi; -use reth_rpc_eth_api::{FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction}; +use reth_rpc_eth_api::{FullEthApiTypes, RpcBlock, RpcHeader, RpcReceipt, RpcTransaction}; use tracing_futures::Instrument; macro_rules! engine_span { @@ -41,6 +41,7 @@ where RpcTransaction, RpcBlock, RpcReceipt, + RpcHeader, > + FullEthApiTypes, EthFilter: EthFilterApiServer>, { diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index d5117650a..4866033c4 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -1,12 +1,13 @@ //! `Eth` bundle implementation and helpers. -use alloy_consensus::Transaction as _; +use alloy_consensus::{BlockHeader, Transaction as _}; use alloy_primitives::{Keccak256, U256}; use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult}; use jsonrpsee::core::RpcResult; use reth_chainspec::EthChainSpec; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; -use reth_primitives::{PooledTransactionsElement, Transaction}; +use reth_primitives::PooledTransactionsElement; +use reth_primitives_traits::SignedTransaction; use reth_provider::{ChainSpecProvider, HeaderProvider}; use reth_revm::database::StateProviderDatabase; use reth_rpc_eth_api::{ @@ -15,12 +16,13 @@ use reth_rpc_eth_api::{ }; use reth_rpc_eth_types::{utils::recover_raw_transaction, EthApiError, RpcInvalidTransactionError}; use reth_tasks::pool::BlockingTaskGuard; +use reth_transaction_pool::{PoolConsensusTx, PoolPooledTx, PoolTransaction, TransactionPool}; use revm::{ db::{CacheDB, DatabaseCommit, DatabaseRef}, primitives::{ResultAndState, TxEnv}, }; use revm_primitives::{EnvKzgSettings, EnvWithHandlerCfg, SpecId, MAX_BLOB_GAS_PER_BLOCK}; -use std::{ops::Deref, sync::Arc}; +use std::sync::Arc; /// `Eth` bundle implementation. pub struct EthBundle { @@ -42,7 +44,16 @@ impl EthBundle { impl EthBundle where - Eth: EthTransactions + LoadPendingBlock + Call + 'static, + Eth: EthTransactions< + Pool: TransactionPool< + Transaction: PoolTransaction< + Consensus: From, + Pooled = PooledTransactionsElement, + >, + >, + > + LoadPendingBlock + + Call + + 'static, { /// Simulates a bundle of transactions at the top of a given block number with the state of /// another (or the same) block. This can be used to simulate future blocks with the current @@ -79,7 +90,7 @@ where let transactions = txs .into_iter() - .map(recover_raw_transaction::) + .map(recover_raw_transaction::>) .collect::, _>>()? .into_iter() .map(|tx| tx.to_components()) @@ -192,12 +203,10 @@ where })?; } - let tx = tx.into_transaction(); + let tx: PoolConsensusTx = tx.into(); - hasher.update(tx.hash()); - let gas_price = Transaction::effective_tip_per_gas(tx.deref(), basefee) - .ok_or_else(|| RpcInvalidTransactionError::FeeCapTooLow) - .map_err(Eth::Error::from_eth_err)?; + hasher.update(*tx.tx_hash()); + let gas_price = tx.effective_gas_price(basefee); eth_api.evm_config().fill_tx_env(evm.tx_mut(), &tx, signer); let ResultAndState { result, state } = evm.transact().map_err(Eth::Error::from_evm_err)?; @@ -235,7 +244,7 @@ where gas_price: U256::from(gas_price), gas_used, to_address: tx.to(), - tx_hash: tx.hash(), + tx_hash: *tx.tx_hash(), value, revert, }; diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 0a17e5e5f..1fe08d1c5 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -244,7 +244,7 @@ pub struct EthApiInner { /// An interface to interact with the network network: Network, /// All configured Signers - signers: parking_lot::RwLock>>, + signers: parking_lot::RwLock>>>, /// The async cache frontend for eth related data eth_cache: EthStateCache, /// The async gas oracle frontend for gas price suggestions @@ -260,7 +260,7 @@ pub struct EthApiInner { /// The type that can spawn tasks which would otherwise block. task_spawner: Box, /// Cached pending block if any - pending_block: Mutex>, + pending_block: Mutex>>, /// A pool dedicated to CPU heavy blocking tasks. blocking_task_pool: BlockingTaskPool, /// Cache for block fees history @@ -343,7 +343,9 @@ where /// Returns a handle to the pending block. #[inline] - pub const fn pending_block(&self) -> &Mutex> { + pub const fn pending_block( + &self, + ) -> &Mutex>> { &self.pending_block } @@ -397,7 +399,9 @@ where /// Returns a handle to the signers. #[inline] - pub const fn signers(&self) -> &parking_lot::RwLock>> { + pub const fn signers( + &self, + ) -> &parking_lot::RwLock>>> { &self.signers } @@ -579,7 +583,7 @@ mod tests { /// Invalid block range #[tokio::test] async fn test_fee_history_empty() { - let response = as EthApiServer<_, _, _>>::fee_history( + let response = as EthApiServer<_, _, _, _>>::fee_history( &build_test_eth_api(NoopProvider::default()), U64::from(1), BlockNumberOrTag::Latest, @@ -601,7 +605,7 @@ mod tests { let (eth_api, _, _) = prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - let response = as EthApiServer<_, _, _>>::fee_history( + let response = as EthApiServer<_, _, _, _>>::fee_history( ð_api, U64::from(newest_block + 1), newest_block.into(), @@ -624,7 +628,7 @@ mod tests { let (eth_api, _, _) = prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - let response = as EthApiServer<_, _, _>>::fee_history( + let response = as EthApiServer<_, _, _, _>>::fee_history( ð_api, U64::from(1), (newest_block + 1000).into(), @@ -647,7 +651,7 @@ mod tests { let (eth_api, _, _) = prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - let response = as EthApiServer<_, _, _>>::fee_history( + let response = as EthApiServer<_, _, _, _>>::fee_history( ð_api, U64::from(0), newest_block.into(), diff --git a/crates/rpc/rpc/src/eth/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs index 409a3095a..51a76f4e9 100644 --- a/crates/rpc/rpc/src/eth/helpers/block.rs +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -1,8 +1,10 @@ //! Contains RPC handler implementations specific to blocks. +use alloy_consensus::BlockHeader; use alloy_rpc_types_eth::{BlockId, TransactionReceipt}; use reth_primitives::TransactionMeta; -use reth_provider::{BlockReader, HeaderProvider}; +use reth_primitives_traits::{BlockBody, SignedTransaction}; +use reth_provider::BlockReader; use reth_rpc_eth_api::{ helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, RpcNodeCoreExt, RpcReceipt, @@ -16,7 +18,10 @@ where Self: LoadBlock< Error = EthApiError, NetworkTypes: alloy_network::Network, - Provider: HeaderProvider, + Provider: BlockReader< + Transaction = reth_primitives::TransactionSigned, + Receipt = reth_primitives::Receipt, + >, >, Provider: BlockReader, { @@ -28,21 +33,21 @@ where Self: LoadReceipt, { if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? { - let block_number = block.number; - let base_fee = block.base_fee_per_gas; + let block_number = block.number(); + let base_fee = block.base_fee_per_gas(); let block_hash = block.hash(); - let excess_blob_gas = block.excess_blob_gas; - let timestamp = block.timestamp; + let excess_blob_gas = block.excess_blob_gas(); + let timestamp = block.timestamp(); return block .body - .transactions - .into_iter() + .transactions() + .iter() .zip(receipts.iter()) .enumerate() .map(|(idx, (tx, receipt))| { let meta = TransactionMeta { - tx_hash: tx.hash(), + tx_hash: *tx.tx_hash(), index: idx as u64, block_hash, block_number, @@ -50,7 +55,7 @@ where excess_blob_gas, timestamp, }; - EthReceiptBuilder::new(&tx, meta, receipt, &receipts) + EthReceiptBuilder::new(tx, meta, receipt, &receipts) .map(|builder| builder.build()) }) .collect::, Self::Error>>() diff --git a/crates/rpc/rpc/src/eth/helpers/call.rs b/crates/rpc/rpc/src/eth/helpers/call.rs index 3835503a4..bddd2b1b8 100644 --- a/crates/rpc/rpc/src/eth/helpers/call.rs +++ b/crates/rpc/rpc/src/eth/helpers/call.rs @@ -3,7 +3,7 @@ use crate::EthApi; use alloy_consensus::Header; use reth_evm::ConfigureEvm; -use reth_provider::BlockReader; +use reth_provider::{BlockReader, ProviderHeader}; use reth_rpc_eth_api::helpers::{ estimate::EstimateCall, Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking, }; @@ -17,7 +17,7 @@ where impl Call for EthApi where - Self: LoadState> + SpawnBlocking, + Self: LoadState>> + SpawnBlocking, EvmConfig: ConfigureEvm
, Provider: BlockReader, { diff --git a/crates/rpc/rpc/src/eth/helpers/pending_block.rs b/crates/rpc/rpc/src/eth/helpers/pending_block.rs index 8d8d15d2e..344f56da8 100644 --- a/crates/rpc/rpc/src/eth/helpers/pending_block.rs +++ b/crates/rpc/rpc/src/eth/helpers/pending_block.rs @@ -1,11 +1,18 @@ //! Support for building a pending block with transactions from local view of mempool. -use alloy_consensus::Header; +use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Header, EMPTY_OMMER_ROOT_HASH}; +use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE}; +use alloy_primitives::U256; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_evm::ConfigureEvm; +use reth_primitives::{ + logs_bloom, + proofs::{calculate_receipt_root_no_memo, calculate_transaction_root}, + BlockBody, Receipt, +}; use reth_provider::{ - BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderTx, - StateProviderFactory, + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderBlock, + ProviderReceipt, ProviderTx, StateProviderFactory, }; use reth_rpc_eth_api::{ helpers::{LoadPendingBlock, SpawnBlocking}, @@ -13,14 +20,16 @@ use reth_rpc_eth_api::{ }; use reth_rpc_eth_types::PendingBlock; use reth_transaction_pool::{PoolTransaction, TransactionPool}; +use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId, B256}; use crate::EthApi; impl LoadPendingBlock for EthApi where - Self: SpawnBlocking - + RpcNodeCore< + Self: SpawnBlocking< + NetworkTypes: alloy_network::Network, + > + RpcNodeCore< Provider: BlockReaderIdExt< Transaction = reth_primitives::TransactionSigned, Block = reth_primitives::Block, @@ -34,10 +43,81 @@ where >, Evm: ConfigureEvm
>, >, - Provider: BlockReader, + Provider: BlockReader, { #[inline] - fn pending_block(&self) -> &tokio::sync::Mutex> { + fn pending_block( + &self, + ) -> &tokio::sync::Mutex< + Option, ProviderReceipt>>, + > { self.inner.pending_block() } + + fn assemble_block( + &self, + cfg: CfgEnvWithHandlerCfg, + block_env: BlockEnv, + parent_hash: revm_primitives::B256, + state_root: revm_primitives::B256, + transactions: Vec>, + receipts: &[ProviderReceipt], + ) -> reth_provider::ProviderBlock { + let transactions_root = calculate_transaction_root(&transactions); + let receipts_root = calculate_receipt_root_no_memo(&receipts.iter().collect::>()); + + let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| &r.logs)); + + let header = Header { + parent_hash, + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: block_env.coinbase, + state_root, + transactions_root, + receipts_root, + withdrawals_root: (cfg.handler_cfg.spec_id >= SpecId::SHANGHAI) + .then_some(EMPTY_WITHDRAWALS), + logs_bloom, + timestamp: block_env.timestamp.to::(), + mix_hash: block_env.prevrandao.unwrap_or_default(), + nonce: BEACON_NONCE.into(), + base_fee_per_gas: Some(block_env.basefee.to::()), + number: block_env.number.to::(), + gas_limit: block_env.gas_limit.to::(), + difficulty: U256::ZERO, + gas_used: receipts.last().map(|r| r.cumulative_gas_used).unwrap_or_default(), + blob_gas_used: (cfg.handler_cfg.spec_id >= SpecId::CANCUN).then(|| { + transactions.iter().map(|tx| tx.blob_gas_used().unwrap_or_default()).sum::() + }), + excess_blob_gas: block_env.get_blob_excess_gas().map(Into::into), + extra_data: Default::default(), + parent_beacon_block_root: (cfg.handler_cfg.spec_id >= SpecId::CANCUN) + .then_some(B256::ZERO), + requests_hash: (cfg.handler_cfg.spec_id >= SpecId::PRAGUE) + .then_some(EMPTY_REQUESTS_HASH), + target_blobs_per_block: None, + }; + + // seal the block + reth_primitives::Block { + header, + body: BlockBody { transactions, ommers: vec![], withdrawals: None }, + } + } + + fn assemble_receipt( + &self, + tx: &reth_primitives::RecoveredTx>, + result: revm_primitives::ExecutionResult, + cumulative_gas_used: u64, + ) -> reth_provider::ProviderReceipt { + #[allow(clippy::needless_update)] + Receipt { + tx_type: tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + ..Default::default() + } + } } diff --git a/crates/rpc/rpc/src/eth/helpers/signer.rs b/crates/rpc/rpc/src/eth/helpers/signer.rs index 022c3153b..3528a966e 100644 --- a/crates/rpc/rpc/src/eth/helpers/signer.rs +++ b/crates/rpc/rpc/src/eth/helpers/signer.rs @@ -10,7 +10,6 @@ use alloy_primitives::{eip191_hash_message, Address, PrimitiveSignature as Signa use alloy_rpc_types_eth::TransactionRequest; use alloy_signer::SignerSync; use alloy_signer_local::PrivateKeySigner; -use reth_primitives::TransactionSigned; use reth_provider::BlockReader; use reth_rpc_eth_api::helpers::{signer::Result, AddDevSigners, EthSigner}; use reth_rpc_eth_types::SignError; @@ -35,14 +34,14 @@ pub struct DevSigner { #[allow(dead_code)] impl DevSigner { /// Generates a random dev signer which satisfies [`EthSigner`] trait - pub fn random() -> Box { + pub fn random() -> Box> { let mut signers = Self::random_signers(1); signers.pop().expect("expect to generate at least one signer") } /// Generates provided number of random dev signers /// which satisfy [`EthSigner`] trait - pub fn random_signers(num: u32) -> Vec> { + pub fn random_signers(num: u32) -> Vec + 'static>> { let mut signers = Vec::with_capacity(num as usize); for _ in 0..num { let sk = PrivateKeySigner::random_with(&mut rand::thread_rng()); @@ -51,7 +50,7 @@ impl DevSigner { let addresses = vec![address]; let accounts = HashMap::from([(address, sk)]); - signers.push(Box::new(Self { addresses, accounts }) as Box); + signers.push(Box::new(Self { addresses, accounts }) as Box>); } signers } @@ -67,7 +66,7 @@ impl DevSigner { } #[async_trait::async_trait] -impl EthSigner for DevSigner { +impl EthSigner for DevSigner { fn accounts(&self) -> Vec
{ self.addresses.clone() } @@ -83,11 +82,7 @@ impl EthSigner for DevSigner { self.sign_hash(hash, address) } - async fn sign_transaction( - &self, - request: TransactionRequest, - address: &Address, - ) -> Result { + async fn sign_transaction(&self, request: TransactionRequest, address: &Address) -> Result { // create local signer wallet from signing key let signer = self.accounts.get(address).ok_or(SignError::NoAccount)?.clone(); let wallet = EthereumWallet::from(signer); @@ -98,7 +93,7 @@ impl EthSigner for DevSigner { // decode transaction into signed transaction type let encoded = txn_envelope.encoded_2718(); - let txn_signed = TransactionSigned::decode_2718(&mut encoded.as_ref()) + let txn_signed = T::decode_2718(&mut encoded.as_ref()) .map_err(|_| SignError::InvalidTransactionRequest)?; Ok(txn_signed) @@ -115,6 +110,7 @@ mod tests { use alloy_consensus::Transaction; use alloy_primitives::{Bytes, U256}; use alloy_rpc_types_eth::TransactionInput; + use reth_primitives::TransactionSigned; use revm_primitives::TxKind; use super::*; @@ -197,7 +193,9 @@ mod tests { let data: TypedData = serde_json::from_str(eip_712_example).unwrap(); let signer = build_signer(); let from = *signer.addresses.first().unwrap(); - let sig = signer.sign_typed_data(from, &data).unwrap(); + let sig = + EthSigner::::sign_typed_data(&signer, from, &data) + .unwrap(); let expected = Signature::new( U256::from_str_radix( "5318aee9942b84885761bb20e768372b76e7ee454fc4d39b59ce07338d15a06c", @@ -219,7 +217,9 @@ mod tests { let message = b"Test message"; let signer = build_signer(); let from = *signer.addresses.first().unwrap(); - let sig = signer.sign(from, message).await.unwrap(); + let sig = EthSigner::::sign(&signer, from, message) + .await + .unwrap(); let expected = Signature::new( U256::from_str_radix( "54313da7432e4058b8d22491b2e7dbb19c7186c35c24155bec0820a8a2bfe0c1", @@ -255,7 +255,8 @@ mod tests { nonce: Some(0u64), ..Default::default() }; - let txn_signed = signer.sign_transaction(request, &from).await; + let txn_signed: std::result::Result = + signer.sign_transaction(request, &from).await; assert!(txn_signed.is_ok()); assert_eq!(Bytes::from(message.to_vec()), txn_signed.unwrap().input().0); diff --git a/crates/rpc/rpc/src/eth/helpers/spec.rs b/crates/rpc/rpc/src/eth/helpers/spec.rs index f7bc89ae2..41c4a5b07 100644 --- a/crates/rpc/rpc/src/eth/helpers/spec.rs +++ b/crates/rpc/rpc/src/eth/helpers/spec.rs @@ -1,7 +1,9 @@ use alloy_primitives::U256; use reth_chainspec::EthereumHardforks; use reth_network_api::NetworkInfo; -use reth_provider::{BlockNumReader, BlockReader, ChainSpecProvider, StageCheckpointReader}; +use reth_provider::{ + BlockNumReader, BlockReader, ChainSpecProvider, ProviderTx, StageCheckpointReader, +}; use reth_rpc_eth_api::{helpers::EthApiSpec, RpcNodeCore}; use crate::EthApi; @@ -16,11 +18,16 @@ where >, Provider: BlockReader, { + type Transaction = ProviderTx; + fn starting_block(&self) -> U256 { self.inner.starting_block() } - fn signers(&self) -> &parking_lot::RwLock>> { + fn signers( + &self, + ) -> &parking_lot::RwLock>>> + { self.inner.signers() } } diff --git a/crates/rpc/rpc/src/eth/helpers/trace.rs b/crates/rpc/rpc/src/eth/helpers/trace.rs index ed7150153..69b4d9806 100644 --- a/crates/rpc/rpc/src/eth/helpers/trace.rs +++ b/crates/rpc/rpc/src/eth/helpers/trace.rs @@ -1,15 +1,20 @@ //! Contains RPC handler implementations specific to tracing. -use alloy_consensus::Header; use reth_evm::ConfigureEvm; -use reth_provider::BlockReader; +use reth_provider::{BlockReader, ProviderHeader, ProviderTx}; use reth_rpc_eth_api::helpers::{LoadState, Trace}; use crate::EthApi; impl Trace for EthApi where - Self: LoadState>, + Self: LoadState< + Provider: BlockReader, + Evm: ConfigureEvm< + Header = ProviderHeader, + Transaction = ProviderTx, + >, + >, Provider: BlockReader, { } diff --git a/crates/rpc/rpc/src/eth/helpers/transaction.rs b/crates/rpc/rpc/src/eth/helpers/transaction.rs index 647e16c25..04ed812fa 100644 --- a/crates/rpc/rpc/src/eth/helpers/transaction.rs +++ b/crates/rpc/rpc/src/eth/helpers/transaction.rs @@ -1,6 +1,6 @@ //! Contains RPC handler implementations specific to transactions -use reth_provider::{BlockReader, BlockReaderIdExt, TransactionsProvider}; +use reth_provider::{BlockReader, BlockReaderIdExt, ProviderTx, TransactionsProvider}; use reth_rpc_eth_api::{ helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, FullEthApiTypes, RpcNodeCoreExt, @@ -13,10 +13,10 @@ impl EthTransactions for EthApi where Self: LoadTransaction, - Provider: BlockReader, + Provider: BlockReader>, { #[inline] - fn signers(&self) -> &parking_lot::RwLock>> { + fn signers(&self) -> &parking_lot::RwLock>>>> { self.inner.signers() } } diff --git a/crates/rpc/rpc/src/eth/sim_bundle.rs b/crates/rpc/rpc/src/eth/sim_bundle.rs index 0702d7df0..f4e77b4fb 100644 --- a/crates/rpc/rpc/src/eth/sim_bundle.rs +++ b/crates/rpc/rpc/src/eth/sim_bundle.rs @@ -1,5 +1,6 @@ //! `Eth` Sim bundle implementation and helpers. +use alloy_consensus::BlockHeader; use alloy_eips::BlockNumberOrTag; use alloy_primitives::U256; use alloy_rpc_types_eth::BlockId; @@ -10,8 +11,7 @@ use alloy_rpc_types_mev::{ use jsonrpsee::core::RpcResult; use reth_chainspec::EthChainSpec; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; -use reth_primitives::{PooledTransactionsElement, TransactionSigned}; -use reth_provider::{ChainSpecProvider, HeaderProvider}; +use reth_provider::{ChainSpecProvider, HeaderProvider, ProviderTx}; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::MevSimApiServer; use reth_rpc_eth_api::{ @@ -20,6 +20,7 @@ use reth_rpc_eth_api::{ }; use reth_rpc_eth_types::{utils::recover_raw_transaction, EthApiError}; use reth_tasks::pool::BlockingTaskGuard; +use reth_transaction_pool::{PoolConsensusTx, PoolPooledTx, PoolTransaction, TransactionPool}; use revm::{ db::CacheDB, primitives::{Address, EnvWithHandlerCfg, ResultAndState, SpecId, TxEnv}, @@ -45,9 +46,9 @@ const SBUNDLE_PAYOUT_MAX_COST: u64 = 30_000; /// A flattened representation of a bundle item containing transaction and associated metadata. #[derive(Clone, Debug)] -pub struct FlattenedBundleItem { +pub struct FlattenedBundleItem { /// The signed transaction - pub tx: TransactionSigned, + pub tx: T, /// The address that signed the transaction pub signer: Address, /// Whether the transaction is allowed to revert @@ -93,7 +94,7 @@ where fn parse_and_flatten_bundle( &self, request: &SendBundleRequest, - ) -> Result, EthApiError> { + ) -> Result>>, EthApiError> { let mut items = Vec::new(); // Stack for processing bundles @@ -171,10 +172,11 @@ where match &body[idx] { BundleItem::Tx { tx, can_revert } => { let recovered_tx = - recover_raw_transaction::(tx.clone()) + recover_raw_transaction::>(tx.clone()) .map_err(EthApiError::from)?; let (tx, signer) = recovered_tx.to_components(); - let tx = tx.into_transaction(); + let tx: PoolConsensusTx = + ::Transaction::pooled_into_consensus(tx); let refund_percent = validity.as_ref().and_then(|v| v.refund.as_ref()).and_then(|refunds| { diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index d19dcf4d6..173a2ff34 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -1,8 +1,8 @@ -use alloy_consensus::Transaction; +use alloy_consensus::{BlockHeader, Transaction}; use alloy_eips::{BlockId, BlockNumberOrTag}; use alloy_network::{ReceiptResponse, TransactionResponse}; use alloy_primitives::{Address, Bytes, TxHash, B256, U256}; -use alloy_rpc_types_eth::{BlockTransactions, Header, TransactionReceipt}; +use alloy_rpc_types_eth::{BlockTransactions, TransactionReceipt}; use alloy_rpc_types_trace::{ otterscan::{ BlockDetails, ContractCreator, InternalOperation, OperationType, OtsBlockTransactions, @@ -15,7 +15,7 @@ use jsonrpsee::{core::RpcResult, types::ErrorObjectOwned}; use reth_rpc_api::{EthApiServer, OtterscanServer}; use reth_rpc_eth_api::{ helpers::{EthTransactions, TraceExt}, - FullEthApiTypes, RpcBlock, RpcReceipt, RpcTransaction, TransactionCompat, + FullEthApiTypes, RpcBlock, RpcHeader, RpcReceipt, RpcTransaction, TransactionCompat, }; use reth_rpc_eth_types::{utils::binary_search, EthApiError}; use reth_rpc_server_types::result::internal_rpc_err; @@ -49,7 +49,7 @@ where &self, block: RpcBlock, receipts: Vec>, - ) -> RpcResult { + ) -> RpcResult>> { // blob fee is burnt, so we don't need to calculate it let total_fees = receipts .iter() @@ -61,18 +61,23 @@ where } #[async_trait] -impl OtterscanServer> for OtterscanApi +impl OtterscanServer, RpcHeader> + for OtterscanApi where Eth: EthApiServer< RpcTransaction, RpcBlock, RpcReceipt, + RpcHeader, > + EthTransactions + TraceExt + 'static, { /// Handler for `{ots,erigon}_getHeaderByNumber` - async fn get_header_by_number(&self, block_number: u64) -> RpcResult> { + async fn get_header_by_number( + &self, + block_number: u64, + ) -> RpcResult>> { self.eth.header_by_number(BlockNumberOrTag::Number(block_number)).await } @@ -165,7 +170,10 @@ where } /// Handler for `ots_getBlockDetails` - async fn get_block_details(&self, block_number: u64) -> RpcResult> { + async fn get_block_details( + &self, + block_number: u64, + ) -> RpcResult>> { let block_id = block_number.into(); let block = self.eth.block_by_number(block_id, true); let block_id = block_id.into(); @@ -178,7 +186,10 @@ where } /// Handler for `getBlockDetailsByHash` - async fn get_block_details_by_hash(&self, block_hash: B256) -> RpcResult> { + async fn get_block_details_by_hash( + &self, + block_hash: B256, + ) -> RpcResult>> { let block = self.eth.block_by_hash(block_hash, true); let block_id = block_hash.into(); let receipts = self.eth.block_receipts(block_id); @@ -195,7 +206,9 @@ where block_number: u64, page_number: usize, page_size: usize, - ) -> RpcResult, Header>> { + ) -> RpcResult< + OtsBlockTransactions, RpcHeader>, + > { let block_id = block_number.into(); // retrieve full block and its receipts let block = self.eth.block_by_number(block_id, true); @@ -236,7 +249,7 @@ where } // Crop receipts and transform them into OtsTransactionReceipt - let timestamp = Some(block.header.timestamp); + let timestamp = Some(block.header.timestamp()); let receipts = receipts .drain(page_start..page_end) .zip(transactions.iter().map(Transaction::ty)) diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 009203f75..44867f513 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,4 +1,4 @@ -use alloy_consensus::Header; +use alloy_consensus::BlockHeader as _; use alloy_eips::BlockId; use alloy_primitives::{map::HashSet, Bytes, B256, U256}; use alloy_rpc_types_eth::{ @@ -19,13 +19,14 @@ use reth_consensus_common::calc::{ base_block_reward, base_block_reward_pre_merge, block_reward, ommer_reward, }; use reth_evm::ConfigureEvmEnv; -use reth_primitives::PooledTransactionsElement; +use reth_primitives_traits::{BlockBody, BlockHeader}; use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::TraceApiServer; use reth_rpc_eth_api::{helpers::TraceExt, FromEthApiError}; use reth_rpc_eth_types::{error::EthApiError, utils::recover_raw_transaction}; use reth_tasks::pool::BlockingTaskGuard; +use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool}; use revm::{ db::{CacheDB, DatabaseCommit}, primitives::EnvWithHandlerCfg, @@ -116,8 +117,8 @@ where trace_types: HashSet, block_id: Option, ) -> Result { - let tx = recover_raw_transaction::(tx)? - .into_ecrecovered_transaction(); + let tx = recover_raw_transaction::>(tx)? + .map_transaction(::Transaction::pooled_into_consensus); let (cfg, block, at) = self.eth_api().evm_env_at(block_id.unwrap_or_default()).await?; @@ -313,11 +314,13 @@ where // add reward traces for all blocks for block in &blocks { - if let Some(base_block_reward) = self.calculate_base_block_reward(&block.header)? { + if let Some(base_block_reward) = + self.calculate_base_block_reward(block.header.header())? + { all_traces.extend( self.extract_reward_traces( - &block.header, - &block.body.ommers, + block.header.header(), + block.body.ommers(), base_block_reward, ) .into_iter() @@ -393,10 +396,12 @@ where maybe_traces.map(|traces| traces.into_iter().flatten().collect::>()); if let (Some(block), Some(traces)) = (maybe_block, maybe_traces.as_mut()) { - if let Some(base_block_reward) = self.calculate_base_block_reward(&block.header)? { + if let Some(base_block_reward) = + self.calculate_base_block_reward(block.header.header())? + { traces.extend(self.extract_reward_traces( - &block.header, - &block.body.ommers, + block.block.header(), + block.body.ommers(), base_block_reward, )); } @@ -490,7 +495,7 @@ where Ok(Some(BlockOpcodeGas { block_hash: block.hash(), - block_number: block.header.number, + block_number: block.header.number(), transactions, })) } @@ -500,25 +505,28 @@ where /// - if Paris hardfork is activated, no block rewards are given /// - if Paris hardfork is not activated, calculate block rewards with block number only /// - if Paris hardfork is unknown, calculate block rewards with block number and ttd - fn calculate_base_block_reward(&self, header: &Header) -> Result, Eth::Error> { + fn calculate_base_block_reward( + &self, + header: &H, + ) -> Result, Eth::Error> { let chain_spec = self.provider().chain_spec(); - let is_paris_activated = chain_spec.is_paris_active_at_block(header.number); + let is_paris_activated = chain_spec.is_paris_active_at_block(header.number()); Ok(match is_paris_activated { Some(true) => None, - Some(false) => Some(base_block_reward_pre_merge(&chain_spec, header.number)), + Some(false) => Some(base_block_reward_pre_merge(&chain_spec, header.number())), None => { // if Paris hardfork is unknown, we need to fetch the total difficulty at the // block's height and check if it is pre-merge to calculate the base block reward if let Some(header_td) = self .provider() - .header_td_by_number(header.number) + .header_td_by_number(header.number()) .map_err(Eth::Error::from_eth_err)? { base_block_reward( chain_spec.as_ref(), - header.number, - header.difficulty, + header.number(), + header.difficulty(), header_td, ) } else { @@ -531,30 +539,33 @@ where /// Extracts the reward traces for the given block: /// - block reward /// - uncle rewards - fn extract_reward_traces( + fn extract_reward_traces( &self, - header: &Header, - ommers: &[Header], + header: &H, + ommers: Option<&[H]>, base_block_reward: u128, ) -> Vec { - let mut traces = Vec::with_capacity(ommers.len() + 1); + let ommers_cnt = ommers.map(|o| o.len()).unwrap_or_default(); + let mut traces = Vec::with_capacity(ommers_cnt + 1); - let block_reward = block_reward(base_block_reward, ommers.len()); + let block_reward = block_reward(base_block_reward, ommers_cnt); traces.push(reward_trace( header, RewardAction { - author: header.beneficiary, + author: header.beneficiary(), reward_type: RewardType::Block, value: U256::from(block_reward), }, )); + let Some(ommers) = ommers else { return traces }; + for uncle in ommers { - let uncle_reward = ommer_reward(base_block_reward, header.number, uncle.number); + let uncle_reward = ommer_reward(base_block_reward, header.number(), uncle.number()); traces.push(reward_trace( header, RewardAction { - author: uncle.beneficiary, + author: uncle.beneficiary(), reward_type: RewardType::Uncle, value: U256::from(uncle_reward), }, @@ -715,10 +726,10 @@ struct TraceApiInner { /// Helper to construct a [`LocalizedTransactionTrace`] that describes a reward to the block /// beneficiary. -fn reward_trace(header: &Header, reward: RewardAction) -> LocalizedTransactionTrace { +fn reward_trace(header: &H, reward: RewardAction) -> LocalizedTransactionTrace { LocalizedTransactionTrace { block_hash: Some(header.hash_slow()), - block_number: Some(header.number), + block_number: Some(header.number()), transaction_hash: None, transaction_position: None, trace: TransactionTrace { diff --git a/crates/storage/provider/src/providers/consistent.rs b/crates/storage/provider/src/providers/consistent.rs index 5aea5be27..9c7973b14 100644 --- a/crates/storage/provider/src/providers/consistent.rs +++ b/crates/storage/provider/src/providers/consistent.rs @@ -24,7 +24,7 @@ use reth_primitives::{ Account, BlockWithSenders, SealedBlockFor, SealedBlockWithSenders, SealedHeader, StorageEntry, TransactionMeta, }; -use reth_primitives_traits::{Block, BlockBody}; +use reth_primitives_traits::BlockBody; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; use reth_storage_api::{ @@ -1036,7 +1036,7 @@ impl TransactionsProvider for ConsistentProvider { self.get_in_memory_or_storage_by_block( id, |provider| provider.transactions_by_block(id), - |block_state| Ok(Some(block_state.block_ref().block().body().transactions().to_vec())), + |block_state| Ok(Some(block_state.block_ref().block().body.transactions().to_vec())), ) } @@ -1047,7 +1047,7 @@ impl TransactionsProvider for ConsistentProvider { self.get_in_memory_or_storage_by_block_range_while( range, |db_provider, range, _| db_provider.transactions_by_block_range(range), - |block_state, _| Some(block_state.block_ref().block().body().transactions().to_vec()), + |block_state, _| Some(block_state.block_ref().block().body.transactions().to_vec()), |_| true, ) } diff --git a/crates/storage/storage-api/src/header.rs b/crates/storage/storage-api/src/header.rs index 2f1c9750e..b2d2c1663 100644 --- a/crates/storage/storage-api/src/header.rs +++ b/crates/storage/storage-api/src/header.rs @@ -5,6 +5,9 @@ use reth_primitives_traits::BlockHeader; use reth_storage_errors::provider::ProviderResult; use std::ops::RangeBounds; +/// A helper type alias to access [`HeaderProvider::Header`]. +pub type ProviderHeader

=

::Header; + /// Client trait for fetching `Header` related data. #[auto_impl::auto_impl(&, Arc)] pub trait HeaderProvider: Send + Sync { diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index aa238ded2..2859d71b9 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -43,6 +43,9 @@ pub type PeerId = alloy_primitives::B512; /// Helper type alias to access [`PoolTransaction::Consensus`] for a given [`TransactionPool`]. pub type PoolConsensusTx

= <

::Transaction as PoolTransaction>::Consensus; +/// Helper type alias to access [`PoolTransaction::Pooled`] for a given [`TransactionPool`]. +pub type PoolPooledTx

= <

::Transaction as PoolTransaction>::Pooled; + /// General purpose abstraction of a transaction-pool. /// /// This is intended to be used by API-consumers such as RPC that need inject new incoming, @@ -964,7 +967,7 @@ pub trait PoolTransaction: type TryFromConsensusError: fmt::Display; /// Associated type representing the raw consensus variant of the transaction. - type Consensus; + type Consensus: From; /// Associated type representing the recovered pooled variant of the transaction. type Pooled: SignedTransaction; @@ -1003,6 +1006,11 @@ pub trait PoolTransaction: tx: RecoveredTx, ) -> Result, Self::TryFromConsensusError>; + /// Converts the `Pooled` type into the `Consensus` type. + fn pooled_into_consensus(tx: Self::Pooled) -> Self::Consensus { + tx.into() + } + /// Hash of the transaction. fn hash(&self) -> &TxHash;