diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs index b20c4f79b2..468855b906 100644 --- a/crates/primitives/src/transaction/signature.rs +++ b/crates/primitives/src/transaction/signature.rs @@ -6,7 +6,7 @@ use reth_rlp::{Decodable, DecodeError, Encodable}; /// transaction and used to determine the sender of /// the transaction; formally Tr and Ts. This is expanded in Appendix F of yellow paper. #[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)] pub struct Signature { /// The R field of the signature; the point on the curve. pub r: U256, diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index 7978378148..ad109d084e 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -9,7 +9,8 @@ use jsonrpsee::{ types::error::{CallError, ErrorCode}, }; use reth_primitives::{ - hex_literal::hex, Address, BlockId, BlockNumberOrTag, Bytes, NodeRecord, H256, H64, U256, + hex_literal::hex, Address, BlockId, BlockNumberOrTag, Bytes, NodeRecord, TxHash, H256, H64, + U256, }; use reth_rpc_api::{ clients::{AdminApiClient, EthApiClient}, @@ -50,6 +51,7 @@ where let address = Address::default(); let index = Index::default(); let hash = H256::default(); + let tx_hash = TxHash::default(); let block_number = BlockNumberOrTag::default(); let call_request = CallRequest::default(); let transaction_request = TransactionRequest::default(); @@ -75,21 +77,13 @@ where 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).await.unwrap(); - EthApiClient::create_access_list(client, call_request.clone(), None).await.unwrap(); + 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(); // Unimplemented assert!(is_unimplemented(EthApiClient::syncing(client).await.err().unwrap())); assert!(is_unimplemented(EthApiClient::author(client).await.err().unwrap())); - assert!(is_unimplemented(EthApiClient::transaction_by_hash(client, hash).await.err().unwrap())); - assert!(is_unimplemented( - EthApiClient::transaction_by_block_hash_and_index(client, hash, index).await.err().unwrap() - )); - assert!(is_unimplemented( - EthApiClient::transaction_by_block_number_and_index(client, block_number, index) - .await - .err() - .unwrap() - )); assert!(is_unimplemented(EthApiClient::transaction_receipt(client, hash).await.err().unwrap())); assert!(is_unimplemented( EthApiClient::call(client, call_request.clone(), None, None).await.err().unwrap() diff --git a/crates/rpc/rpc-types/src/eth/transaction/mod.rs b/crates/rpc/rpc-types/src/eth/transaction/mod.rs index a04a3cbd78..f6a2f42133 100644 --- a/crates/rpc/rpc-types/src/eth/transaction/mod.rs +++ b/crates/rpc/rpc-types/src/eth/transaction/mod.rs @@ -74,7 +74,7 @@ impl Transaction { /// /// The block hash, number, and tx index fields should be from the original block where the /// transaction was mined. - pub(crate) fn from_recovered_with_block_context( + pub fn from_recovered_with_block_context( tx: TransactionSignedEcRecovered, block_hash: H256, block_number: BlockNumber, @@ -142,7 +142,7 @@ impl Transaction { max_fee_per_gas, max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas().map(U128::from), signature: Some(Signature::from_primitive_signature( - signed_tx.signature().clone(), + *signed_tx.signature(), signed_tx.chain_id(), )), gas: U256::from(signed_tx.gas_limit()), diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 3c8a3f9624..0ff4310e0f 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -117,29 +117,26 @@ where } /// Handler for: `eth_getTransactionByHash` - async fn transaction_by_hash( - &self, - _hash: H256, - ) -> Result> { - Err(internal_rpc_err("unimplemented")) + async fn transaction_by_hash(&self, hash: H256) -> Result> { + Ok(EthApi::transaction_by_hash(self, hash).await?) } /// Handler for: `eth_getTransactionByBlockHashAndIndex` async fn transaction_by_block_hash_and_index( &self, - _hash: H256, - _index: Index, + hash: H256, + index: Index, ) -> Result> { - Err(internal_rpc_err("unimplemented")) + Ok(EthApi::transaction_by_block_and_tx_index(self, hash, index).await?) } /// Handler for: `eth_getTransactionByBlockNumberAndIndex` async fn transaction_by_block_number_and_index( &self, - _number: BlockNumberOrTag, - _index: Index, + number: BlockNumberOrTag, + index: Index, ) -> Result> { - Err(internal_rpc_err("unimplemented")) + Ok(EthApi::transaction_by_block_and_tx_index(self, number, index).await?) } /// Handler for: `eth_getTransactionReceipt` diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index f861c0585b..72ce26a63f 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -1,13 +1,12 @@ //! Contains RPC handler implementations specific to transactions - use crate::{ eth::error::{EthApiError, EthResult}, EthApi, }; -use reth_primitives::{Bytes, FromRecoveredTransaction, TransactionSigned, H256}; +use reth_primitives::{BlockId, Bytes, FromRecoveredTransaction, TransactionSigned, H256, U256}; use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderFactory}; use reth_rlp::Decodable; -use reth_rpc_types::TransactionRequest; +use reth_rpc_types::{Index, Transaction, TransactionRequest}; use reth_transaction_pool::{TransactionOrigin, TransactionPool}; impl EthApi @@ -20,6 +19,58 @@ where unimplemented!() } + /// Finds a given trasaction by its hash. + pub(crate) async fn transaction_by_hash( + &self, + hash: H256, + ) -> EthResult> { + let tx_by_hash = match self.client().transaction_by_hash(hash)? { + Some(item) => item, + None => return Ok(None), + }; + + if let Some(tx) = tx_by_hash.into_ecrecovered() { + Ok(Some(Transaction::from_recovered_with_block_context( + tx, + // TODO: this is just stubbed out for now still need to fully implement tx => block + H256::default(), + u64::default(), + U256::from(usize::from(Index::default())), + ))) + } else { + Ok(None) + } + } + + /// Get Transaction by Block and tx index within that Block. + /// Used for both: + /// transaction_by_block_hash_and_index() & + /// transaction_by_block_number_and_index() + pub(crate) async fn transaction_by_block_and_tx_index( + &self, + block_id: impl Into, + index: Index, + ) -> EthResult> { + let block_id = block_id.into(); + let Some(block) = self.client().block(block_id)? else { + return Ok(None); + }; + let block_hash = + self.client().block_hash_for_id(block_id)?.ok_or(EthApiError::UnknownBlockNumber)?; + let Some(tx_signed) = block.body.into_iter().nth(usize::from(index)) else { + return Ok(None); + }; + let Some(tx) = tx_signed.into_ecrecovered() else { + return Ok(None); + }; + Ok(Some(Transaction::from_recovered_with_block_context( + tx, + block_hash, + block.header.number, + U256::from(usize::from(index)), + ))) + } + /// Decodes and recovers the transaction and submits it to the pool. /// /// Returns the hash of the transaction.