Skip to content

Commit

Permalink
feat: add Transaction AT to TransactionsProvider (#12794)
Browse files Browse the repository at this point in the history
  • Loading branch information
klkvr authored Nov 22, 2024
1 parent 36db1c2 commit 5db3ad1
Show file tree
Hide file tree
Showing 33 changed files with 389 additions and 271 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions crates/node/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,6 @@ pub type HeaderTy<N> = <<N as NodeTypes>::Primitives as NodePrimitives>::BlockHe

/// Helper adapter type for accessing [`NodePrimitives::BlockBody`] on [`NodeTypes`].
pub type BodyTy<N> = <<N as NodeTypes>::Primitives as NodePrimitives>::BlockBody;

/// Helper adapter type for accessing [`NodePrimitives::SignedTx`] on [`NodeTypes`].
pub type TxTy<N> = <<N as NodeTypes>::Primitives as NodePrimitives>::SignedTx;
1 change: 1 addition & 0 deletions crates/optimism/cli/src/ovm_file_codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ impl Encodable2718 for TransactionSigned {
Transaction::Deposit(deposit_tx) => deposit_tx.eip2718_encoded_length(),
}
}

fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
self.transaction.eip2718_encode(&self.signature, out)
}
Expand Down
3 changes: 2 additions & 1 deletion crates/optimism/rpc/src/eth/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_evm::RethL1BlockInfo;
use reth_optimism_forks::OpHardforks;
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned, TxType};
use reth_provider::ChainSpecProvider;
use reth_provider::{ChainSpecProvider, TransactionsProvider};
use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt};
use reth_rpc_eth_types::{receipt::build_receipt, EthApiError};

Expand All @@ -21,6 +21,7 @@ impl<N> LoadReceipt for OpEthApi<N>
where
Self: Send + Sync,
N: FullNodeComponents<Types: NodeTypes<ChainSpec = OpChainSpec>>,
Self::Provider: TransactionsProvider<Transaction = TransactionSigned>,
{
async fn build_transaction_receipt(
&self,
Expand Down
1 change: 1 addition & 0 deletions crates/optimism/rpc/src/eth/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ impl<N> LoadTransaction for OpEthApi<N>
where
Self: SpawnBlocking + FullEthApiTypes,
N: RpcNodeCore<Provider: TransactionsProvider, Pool: TransactionPool>,
Self::Pool: TransactionPool,
{
}

Expand Down
56 changes: 43 additions & 13 deletions crates/primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1624,6 +1624,10 @@ impl Encodable2718 for TransactionSigned {
fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
self.transaction.eip2718_encode(&self.signature, out)
}

fn trie_hash(&self) -> B256 {
self.hash()
}
}

impl Decodable2718 for TransactionSigned {
Expand Down Expand Up @@ -1720,50 +1724,47 @@ impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned {

/// Signed transaction with recovered signer.
#[derive(Debug, Clone, PartialEq, Hash, Eq, AsRef, Deref)]
pub struct TransactionSignedEcRecovered {
pub struct TransactionSignedEcRecovered<T = TransactionSigned> {
/// Signer of the transaction
signer: Address,
/// Signed transaction
#[deref]
#[as_ref]
signed_transaction: TransactionSigned,
signed_transaction: T,
}

// === impl TransactionSignedEcRecovered ===

impl TransactionSignedEcRecovered {
impl<T> TransactionSignedEcRecovered<T> {
/// Signer of transaction recovered from signature
pub const fn signer(&self) -> Address {
self.signer
}

/// Returns a reference to [`TransactionSigned`]
pub const fn as_signed(&self) -> &TransactionSigned {
pub const fn as_signed(&self) -> &T {
&self.signed_transaction
}

/// Transform back to [`TransactionSigned`]
pub fn into_signed(self) -> TransactionSigned {
pub fn into_signed(self) -> T {
self.signed_transaction
}

/// Dissolve Self to its component
pub fn to_components(self) -> (TransactionSigned, Address) {
pub fn to_components(self) -> (T, Address) {
(self.signed_transaction, self.signer)
}

/// Create [`TransactionSignedEcRecovered`] from [`TransactionSigned`] and [`Address`] of the
/// signer.
#[inline]
pub const fn from_signed_transaction(
signed_transaction: TransactionSigned,
signer: Address,
) -> Self {
pub const fn from_signed_transaction(signed_transaction: T, signer: Address) -> Self {
Self { signed_transaction, signer }
}
}

impl Encodable for TransactionSignedEcRecovered {
impl<T: Encodable> Encodable for TransactionSignedEcRecovered<T> {
/// This encodes the transaction _with_ the signature, and an rlp header.
///
/// Refer to docs for [`TransactionSigned::encode`] for details on the exact format.
Expand All @@ -1776,16 +1777,30 @@ impl Encodable for TransactionSignedEcRecovered {
}
}

impl Decodable for TransactionSignedEcRecovered {
impl<T: SignedTransaction> Decodable for TransactionSignedEcRecovered<T> {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let signed_transaction = TransactionSigned::decode(buf)?;
let signed_transaction = T::decode(buf)?;
let signer = signed_transaction
.recover_signer()
.ok_or(RlpError::Custom("Unable to recover decoded transaction signer."))?;
Ok(Self { signer, signed_transaction })
}
}

/// Extension trait for [`SignedTransaction`] to convert it into [`TransactionSignedEcRecovered`].
pub trait SignedTransactionIntoRecoveredExt: SignedTransaction {
/// Consumes the type, recover signer and return [`TransactionSignedEcRecovered`] _without
/// ensuring that the signature has a low `s` value_ (EIP-2).
///
/// Returns `None` if the transaction's signature is invalid.
fn into_ecrecovered_unchecked(self) -> Option<TransactionSignedEcRecovered<Self>> {
let signer = self.recover_signer_unchecked()?;
Some(TransactionSignedEcRecovered::from_signed_transaction(self, signer))
}
}

impl<T> SignedTransactionIntoRecoveredExt for T where T: SignedTransaction {}

/// Bincode-compatible transaction type serde implementations.
#[cfg(feature = "serde-bincode-compat")]
pub mod serde_bincode_compat {
Expand Down Expand Up @@ -1991,6 +2006,21 @@ pub mod serde_bincode_compat {
}
}

/// Recovers a list of signers from a transaction list iterator.
///
/// Returns `None`, if some transaction's signature is invalid
pub fn recover_signers<'a, I, T>(txes: I, num_txes: usize) -> Option<Vec<Address>>
where
T: SignedTransaction,
I: IntoParallelIterator<Item = &'a T> + IntoIterator<Item = &'a T> + Send,
{
if num_txes < *PARALLEL_SENDER_RECOVERY_THRESHOLD {
txes.into_iter().map(|tx| tx.recover_signer()).collect()
} else {
txes.into_par_iter().map(|tx| tx.recover_signer()).collect()
}
}

#[cfg(test)]
mod tests {
use crate::{
Expand Down
3 changes: 3 additions & 0 deletions crates/prune/prune/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ reth-config.workspace = true
reth-prune-types.workspace = true
reth-static-file-types.workspace = true

# ethereum
alloy-eips.workspace = true

# metrics
reth-metrics.workspace = true
metrics.workspace = true
Expand Down
3 changes: 2 additions & 1 deletion crates/prune/prune/src/segments/user/transaction_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
segments::{PruneInput, Segment, SegmentOutput},
PrunerError,
};
use alloy_eips::eip2718::Encodable2718;
use rayon::prelude::*;
use reth_db::{tables, transaction::DbTxMut};
use reth_provider::{BlockReader, DBProvider, TransactionsProvider};
Expand Down Expand Up @@ -58,7 +59,7 @@ where
let hashes = provider
.transactions_by_tx_range(tx_range.clone())?
.into_par_iter()
.map(|transaction| transaction.hash())
.map(|transaction| transaction.trie_hash())
.collect::<Vec<_>>();

// Number of transactions retrieved from the database should match the tx range count
Expand Down
8 changes: 6 additions & 2 deletions crates/rpc/rpc-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! use alloy_consensus::Header;
//! use reth_evm::{execute::BlockExecutorProvider, ConfigureEvm};
//! use reth_network_api::{NetworkInfo, Peers};
//! use reth_primitives::TransactionSigned;
//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider};
//! use reth_rpc::EthApi;
//! use reth_rpc_builder::{
Expand All @@ -36,7 +37,8 @@
//! block_executor: BlockExecutor,
//! consensus: Consensus,
//! ) where
//! Provider: FullRpcProvider + AccountReader + ChangeSetReader,
//! Provider:
//! FullRpcProvider<Transaction = TransactionSigned> + AccountReader + ChangeSetReader,
//! Pool: TransactionPool + Unpin + 'static,
//! Network: NetworkInfo + Peers + Clone + 'static,
//! Events: CanonStateSubscriptions + Clone + 'static,
Expand Down Expand Up @@ -77,6 +79,7 @@
//! use reth_engine_primitives::EngineTypes;
//! use reth_evm::{execute::BlockExecutorProvider, ConfigureEvm};
//! use reth_network_api::{NetworkInfo, Peers};
//! use reth_primitives::TransactionSigned;
//! use reth_provider::{AccountReader, CanonStateSubscriptions, ChangeSetReader, FullRpcProvider};
//! use reth_rpc::EthApi;
//! use reth_rpc_api::EngineApiServer;
Expand Down Expand Up @@ -109,7 +112,8 @@
//! block_executor: BlockExecutor,
//! consensus: Consensus,
//! ) where
//! Provider: FullRpcProvider + AccountReader + ChangeSetReader,
//! Provider:
//! FullRpcProvider<Transaction = TransactionSigned> + AccountReader + ChangeSetReader,
//! Pool: TransactionPool + Unpin + 'static,
//! Network: NetworkInfo + Peers + Clone + 'static,
//! Events: CanonStateSubscriptions + Clone + 'static,
Expand Down
9 changes: 6 additions & 3 deletions crates/rpc/rpc-eth-api/src/helpers/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@
//! loads receipt data w.r.t. network.

use futures::Future;
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned};
use reth_primitives::{Receipt, TransactionMeta};
use reth_provider::TransactionsProvider;

use crate::{EthApiTypes, RpcNodeCoreExt, RpcReceipt};

/// Assembles transaction receipt data w.r.t to network.
///
/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods.
pub trait LoadReceipt: EthApiTypes + RpcNodeCoreExt + Send + Sync {
pub trait LoadReceipt:
EthApiTypes + RpcNodeCoreExt<Provider: TransactionsProvider> + Send + Sync
{
/// Helper method for `eth_getBlockReceipts` and `eth_getTransactionReceipt`.
fn build_transaction_receipt(
&self,
tx: TransactionSigned,
tx: <Self::Provider as TransactionsProvider>::Transaction,
meta: TransactionMeta,
receipt: Receipt,
) -> impl Future<Output = Result<RpcReceipt<Self::NetworkTypes>, Self::Error>> + Send;
Expand Down
20 changes: 16 additions & 4 deletions crates/rpc/rpc-eth-api/src/helpers/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use alloy_primitives::{Address, Bytes, TxHash, B256};
use alloy_rpc_types_eth::{transaction::TransactionRequest, BlockNumberOrTag, TransactionInfo};
use futures::Future;
use reth_primitives::{Receipt, SealedBlockWithSenders, TransactionMeta, TransactionSigned};
use reth_provider::{BlockNumReader, BlockReaderIdExt, ReceiptProvider, TransactionsProvider};
use reth_provider::{
BlockNumReader, BlockReaderIdExt, ProviderTx, ReceiptProvider, TransactionsProvider,
};
use reth_rpc_eth_types::{
utils::{binary_search, recover_raw_transaction},
EthApiError, SignError, TransactionSource,
Expand Down Expand Up @@ -60,10 +62,13 @@ pub trait EthTransactions: LoadTransaction<Provider: BlockReaderIdExt> {
/// Checks the pool and state.
///
/// Returns `Ok(None)` if no matching transaction was found.
#[expect(clippy::complexity)]
fn transaction_by_hash(
&self,
hash: B256,
) -> impl Future<Output = Result<Option<TransactionSource>, Self::Error>> + Send {
) -> impl Future<
Output = Result<Option<TransactionSource<ProviderTx<Self::Provider>>>, Self::Error>,
> + Send {
LoadTransaction::transaction_by_hash(self, hash)
}

Expand Down Expand Up @@ -148,11 +153,15 @@ pub trait EthTransactions: LoadTransaction<Provider: BlockReaderIdExt> {
}

/// Helper method that loads a transaction and its receipt.
#[expect(clippy::complexity)]
fn load_transaction_and_receipt(
&self,
hash: TxHash,
) -> impl Future<
Output = Result<Option<(TransactionSigned, TransactionMeta, Receipt)>, Self::Error>,
Output = Result<
Option<(ProviderTx<Self::Provider>, TransactionMeta, Receipt)>,
Self::Error,
>,
> + Send
where
Self: 'static,
Expand Down Expand Up @@ -477,10 +486,13 @@ pub trait LoadTransaction:
/// Checks the pool and state.
///
/// Returns `Ok(None)` if no matching transaction was found.
#[expect(clippy::complexity)]
fn transaction_by_hash(
&self,
hash: B256,
) -> impl Future<Output = Result<Option<TransactionSource>, Self::Error>> + Send {
) -> impl Future<
Output = Result<Option<TransactionSource<ProviderTx<Self::Provider>>>, Self::Error>,
> + Send {
async move {
// Try to find the transaction on disk
let mut resp = self
Expand Down
35 changes: 21 additions & 14 deletions crates/rpc/rpc-eth-api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ use std::{

use alloy_network::Network;
use alloy_rpc_types_eth::Block;
use reth_primitives::TransactionSigned;
use reth_provider::TransactionsProvider;
use reth_rpc_types_compat::TransactionCompat;

use crate::{AsEthApiError, FromEthApiError, FromEvmError};
use crate::{AsEthApiError, FromEthApiError, FromEvmError, RpcNodeCore};

/// Network specific `eth` API types.
pub trait EthApiTypes: Send + Sync + Clone {
Expand Down Expand Up @@ -43,22 +45,27 @@ pub type RpcReceipt<T> = <T as Network>::ReceiptResponse;
pub type RpcError<T> = <T as EthApiTypes>::Error;

/// Helper trait holds necessary trait bounds on [`EthApiTypes`] to implement `eth` API.
pub trait FullEthApiTypes:
EthApiTypes<
TransactionCompat: TransactionCompat<
Transaction = RpcTransaction<Self::NetworkTypes>,
Error = RpcError<Self>,
>,
>
pub trait FullEthApiTypes
where
Self: RpcNodeCore<Provider: TransactionsProvider<Transaction = TransactionSigned>>
+ EthApiTypes<
TransactionCompat: TransactionCompat<
<Self::Provider as TransactionsProvider>::Transaction,
Transaction = RpcTransaction<Self::NetworkTypes>,
Error = RpcError<Self>,
>,
>,
{
}

impl<T> FullEthApiTypes for T where
T: EthApiTypes<
TransactionCompat: TransactionCompat<
Transaction = RpcTransaction<T::NetworkTypes>,
Error = RpcError<T>,
>,
>
T: RpcNodeCore<Provider: TransactionsProvider<Transaction = TransactionSigned>>
+ EthApiTypes<
TransactionCompat: TransactionCompat<
<Self::Provider as TransactionsProvider>::Transaction,
Transaction = RpcTransaction<T::NetworkTypes>,
Error = RpcError<T>,
>,
>
{
}
1 change: 1 addition & 0 deletions crates/rpc/rpc-eth-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ reth-evm.workspace = true
reth-execution-types.workspace = true
reth-metrics.workspace = true
reth-primitives = { workspace = true, features = ["secp256k1"] }
reth-primitives-traits.workspace = true
reth-storage-api.workspace = true
reth-revm.workspace = true
reth-rpc-server-types.workspace = true
Expand Down
Loading

0 comments on commit 5db3ad1

Please sign in to comment.