diff --git a/crates/rpc/rpc-api/src/eth.rs b/crates/rpc/rpc-api/src/eth.rs index 88923df602f3..db03e13fb11a 100644 --- a/crates/rpc/rpc-api/src/eth.rs +++ b/crates/rpc/rpc-api/src/eth.rs @@ -92,6 +92,12 @@ pub trait EthApi { index: Index, ) -> RpcResult>; + /// Returns the EIP-2718 encoded transaction if it exists. + /// + /// If this is a EIP-4844 transaction that is in the pool it will include the sidecar. + #[method(name = "getRawTransactionByHash")] + async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult>; + /// Returns the information about a transaction requested by transaction hash. #[method(name = "getTransactionByHash")] async fn transaction_by_hash(&self, hash: B256) -> RpcResult>; diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 08b14ded5b50..e5c78809e682 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -153,6 +153,12 @@ where Ok(EthApi::ommer_by_block_and_index(self, number, index).await?) } + /// Handler for: `eth_getRawTransactionByHash` + async fn raw_transaction_by_hash(&self, hash: B256) -> Result> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash"); + Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?) + } + /// Handler for: `eth_getTransactionByHash` async fn transaction_by_hash(&self, hash: B256) -> Result> { trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash"); diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index afe7856927bf..27087903421a 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -11,6 +11,7 @@ use crate::{ }, EthApi, EthApiSpec, }; +use alloy_rlp::Encodable; use async_trait::async_trait; use reth_network_api::NetworkInfo; use reth_node_api::ConfigureEvmEnv; @@ -146,6 +147,15 @@ pub trait EthTransactions: Send + Sync { block: BlockId, ) -> EthResult>>; + /// Returns the EIP-2718 encoded transaction by hash. + /// + /// If this is a pooled EIP-4844 transaction, the blob sidecar is included. + /// + /// Checks the pool and state. + /// + /// Returns `Ok(None)` if no matching transaction was found. + async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult>; + /// Returns the transaction by hash. /// /// Checks the pool and state. @@ -428,6 +438,22 @@ where self.block_by_id(block).await.map(|block| block.map(|block| block.body)) } + async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> { + // Note: this is mostly used to fetch pooled transactions so we check the pool first + if let Some(tx) = self.pool().get_pooled_transaction_element(hash).map(|tx| { + let mut buf = Vec::new(); + tx.encode(&mut buf); + buf + }) { + return Ok(Some(tx.into())); + } + + self.on_blocking_task(|this| async move { + Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) + }) + .await + } + async fn transaction_by_hash(&self, hash: B256) -> EthResult> { // Try to find the transaction on disk let mut resp = self