Skip to content

Commit 6a7f74e

Browse files
authored
docs: improve transaction trait documentation (#103)
* docs: improve transaction trait documentation Adds comprehensive documentation for transaction-related traits to help users understand how consensus transactions are converted for EVM execution. Key improvements: - Enhanced module-level docs explaining the trait system's purpose - Added detailed trait documentation with examples for IntoTxEnv, FromRecoveredTx, FromTxWithEncoded, and ExecutableTx - Clarified the transaction flow from consensus types to EVM execution - Added context to BlockExecutor methods explaining ExecutableTx usage - Fixed all documentation links to use proper Rust doc syntax - Updated references from TransactionSigned to EthereumTxEnvelope This makes it much clearer how recovered consensus transactions can be seamlessly converted into the transaction type that the EVM operates on. Closes #97 * fmt * docs * docs
1 parent 3723cbb commit 6a7f74e

File tree

3 files changed

+216
-14
lines changed

3 files changed

+216
-14
lines changed

crates/evm/src/block/mod.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ pub struct BlockExecutionResult<T> {
3434
}
3535

3636
/// Helper trait to encapsulate requirements for a type to be used as input for [`BlockExecutor`].
37+
///
38+
/// This trait combines the requirements for a transaction to be executable by a block executor:
39+
/// - Must be convertible to the EVM's transaction environment via [`IntoTxEnv`]
40+
/// - Must provide access to the transaction and signer via [`RecoveredTx`]
41+
/// - Must be [`Copy`] for efficient handling during block execution (the expectation here is that
42+
/// this always passed as & reference)
43+
///
44+
/// This trait is automatically implemented for any type that meets these requirements.
45+
/// Common implementations include:
46+
/// - [`Recovered<T>`](alloy_consensus::transaction::Recovered) where `T` is a transaction type
47+
/// - [`WithEncoded<Recovered<T>>`](alloy_eips::eip2718::WithEncoded) for transactions with encoded
48+
/// bytes
49+
///
50+
/// The trait ensures that the block executor can both execute the transaction in the EVM
51+
/// and access the original transaction data for receipt generation.
3752
pub trait ExecutableTx<E: BlockExecutor + ?Sized>:
3853
IntoTxEnv<<E::Evm as Evm>::Tx> + RecoveredTx<E::Transaction> + Copy
3954
{
@@ -73,17 +88,61 @@ impl CommitChanges {
7388
/// relevant information about the block execution.
7489
pub trait BlockExecutor {
7590
/// Input transaction type.
91+
///
92+
/// This represents the consensus transaction type that the block executor operates on.
93+
/// It's typically a type from the consensus layer (e.g.,
94+
/// [`EthereumTxEnvelope`](alloy_consensus::EthereumTxEnvelope)) that contains
95+
/// the raw transaction data, signature, and other consensus-level information.
96+
///
97+
/// This type is used in several contexts:
98+
/// - As the generic parameter for [`RecoveredTx<T>`](crate::RecoveredTx) in [`ExecutableTx`]
99+
/// - As the generic parameter for [`FromRecoveredTx<T>`](crate::FromRecoveredTx) and
100+
/// [`FromTxWithEncoded<T>`](crate::FromTxWithEncoded) in the EVM constraint
101+
/// - To generate receipts after transaction execution
102+
///
103+
/// The transaction flow is:
104+
/// 1. `Self::Transaction` (consensus tx) →
105+
/// [`Recovered<Self::Transaction>`](alloy_consensus::transaction::Recovered) (with sender)
106+
/// 2. [`Recovered<Self::Transaction>`](alloy_consensus::transaction::Recovered) →
107+
/// [`TxEnv`](revm::context::TxEnv) (via [`FromRecoveredTx`])
108+
/// 3. [`TxEnv`](revm::context::TxEnv) → EVM execution → [`ExecutionResult`]
109+
/// 4. [`ExecutionResult`] + `Self::Transaction` → `Self::Receipt`
110+
///
111+
/// Common examples:
112+
/// - [`EthereumTxEnvelope`](alloy_consensus::EthereumTxEnvelope) for all Ethereum transaction
113+
/// variants
114+
/// - `OpTxEnvelope` for opstack transaction variants
76115
type Transaction;
77116
/// Receipt type this executor produces.
78117
type Receipt;
79118
/// EVM used by the executor.
119+
///
120+
/// The EVM's transaction type (`Evm::Tx`) must be able to be constructed from both:
121+
/// - [`FromRecoveredTx<Self::Transaction>`](crate::FromRecoveredTx) - for transactions with
122+
/// recovered senders
123+
/// - [`FromTxWithEncoded<Self::Transaction>`](crate::FromTxWithEncoded) - for transactions with
124+
/// encoded bytes
125+
///
126+
/// This constraint ensures that the block executor can convert consensus transactions
127+
/// into the EVM's transaction format for execution.
80128
type Evm: Evm<Tx: FromRecoveredTx<Self::Transaction> + FromTxWithEncoded<Self::Transaction>>;
81129

82130
/// Applies any necessary changes before executing the block's transactions.
83131
fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError>;
84132

85133
/// Executes a single transaction and applies execution result to internal state.
86134
///
135+
/// This method accepts any type implementing [`ExecutableTx`], which ensures the transaction:
136+
/// - Can be converted to the EVM's transaction environment for execution
137+
/// - Provides access to the original transaction and signer for receipt generation
138+
///
139+
/// Common input types include:
140+
/// - `&Recovered<Transaction>` - A transaction with its recovered sender
141+
/// - `&WithEncoded<Recovered<Transaction>>` - A transaction with sender and encoded bytes
142+
///
143+
/// The transaction is executed in the EVM, state changes are committed, and a receipt
144+
/// is generated internally.
145+
///
87146
/// Returns the gas used by the transaction.
88147
fn execute_transaction(
89148
&mut self,
@@ -94,6 +153,14 @@ pub trait BlockExecutor {
94153

95154
/// Executes a single transaction and applies execution result to internal state. Invokes the
96155
/// given closure with an internal [`ExecutionResult`] produced by the EVM.
156+
///
157+
/// This method is similar to [`execute_transaction`](Self::execute_transaction) but provides
158+
/// access to the raw execution result before it's converted to a receipt. This is useful for:
159+
/// - Custom logging or metrics collection
160+
/// - Debugging transaction execution
161+
/// - Extracting additional information from the execution result
162+
///
163+
/// The transaction is always committed after the closure is invoked.
97164
fn execute_transaction_with_result_closure(
98165
&mut self,
99166
tx: impl ExecutableTx<Self>,
@@ -110,7 +177,22 @@ pub trait BlockExecutor {
110177
/// given closure with an internal [`ExecutionResult`] produced by the EVM, and commits the
111178
/// transaction to the state on [`CommitChanges::Yes`].
112179
///
113-
/// Returns [`None`] if transaction was skipped via [`CommitChanges::No`].
180+
/// This is the most flexible transaction execution method, allowing conditional commitment
181+
/// based on the execution result. The closure receives the execution result and returns
182+
/// whether to commit the changes to state.
183+
///
184+
/// Use cases:
185+
/// - Conditional execution based on transaction outcome
186+
/// - Simulating transactions without committing
187+
/// - Custom validation logic before committing
188+
///
189+
/// The [`ExecutableTx`] constraint ensures that:
190+
/// 1. The transaction can be converted to `TxEnv` via [`IntoTxEnv`] for EVM execution
191+
/// 2. The original transaction and signer can be accessed via [`RecoveredTx`] for receipt
192+
/// generation
193+
///
194+
/// Returns [`None`] if commiting changes from the transaction should be skipped via
195+
/// [`CommitChanges::No`], otherwise returns the gas used by the transaction.
114196
fn execute_transaction_with_commit_condition(
115197
&mut self,
116198
tx: impl ExecutableTx<Self>,
@@ -153,6 +235,26 @@ pub trait BlockExecutor {
153235
fn evm(&self) -> &Self::Evm;
154236

155237
/// Executes all transactions in a block, applying pre and post execution changes.
238+
///
239+
/// This is a convenience method that orchestrates the complete block execution flow:
240+
/// 1. Applies pre-execution changes (system calls, irregular state transitions)
241+
/// 2. Executes all transactions in order
242+
/// 3. Applies post-execution changes (block rewards, system calls)
243+
///
244+
/// Each transaction in the iterator must implement [`ExecutableTx`], ensuring it can be:
245+
/// - Converted to the EVM's transaction format for execution
246+
/// - Used to generate receipts with access to the original transaction data
247+
///
248+
/// # Example
249+
///
250+
/// ```ignore
251+
/// let recovered_txs: Vec<Recovered<Transaction>> = block.transactions
252+
/// .iter()
253+
/// .map(|tx| tx.recover_signer())
254+
/// .collect::<Result<_, _>>()?;
255+
///
256+
/// let result = executor.execute_block(recovered_txs.iter())?;
257+
/// ```
156258
fn execute_block(
157259
mut self,
158260
transactions: impl IntoIterator<Item = impl ExecutableTx<Self>>,
@@ -221,6 +323,10 @@ pub trait BlockExecutorFactory: 'static {
221323
type ExecutionCtx<'a>: Clone;
222324

223325
/// Transaction type used by the executor, see [`BlockExecutor::Transaction`].
326+
///
327+
/// This should be the same consensus transaction type that the block executor operates on.
328+
/// It represents the transaction format from your consensus layer that needs to be
329+
/// executed by the EVM.
224330
type Transaction;
225331

226332
/// Receipt type produced by the executor, see [`BlockExecutor::Receipt`].

crates/evm/src/evm.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,20 @@ pub trait Evm {
2828
type DB;
2929
/// The transaction object that the EVM will execute.
3030
///
31-
/// Implementations are expected to rely on a single entrypoint for transaction execution such
32-
/// as [`revm::context::TxEnv`]. The actual set of valid inputs is not limited by allowing to
33-
/// provide any [`IntoTxEnv`] implementation for [`Evm::transact`] method.
31+
/// This type represents the transaction environment that the EVM operates on internally.
32+
/// Typically this is [`revm::context::TxEnv`], which contains all necessary transaction
33+
/// data like sender, gas limits, value, and calldata.
34+
///
35+
/// The EVM accepts flexible transaction inputs through the [`IntoTxEnv`] trait. This means
36+
/// that while the EVM internally works with `Self::Tx` (usually `TxEnv`), users can pass
37+
/// various transaction formats to [`Evm::transact`], including:
38+
/// - Direct [`TxEnv`](revm::context::TxEnv) instances
39+
/// - [`Recovered<T>`](alloy_consensus::transaction::Recovered) where `T` implements
40+
/// [`crate::FromRecoveredTx`]
41+
/// - [`WithEncoded<Recovered<T>>`](alloy_eips::eip2718::WithEncoded) where `T` implements
42+
/// [`crate::FromTxWithEncoded`]
43+
///
44+
/// This design allows the EVM to accept recovered consensus transactions seamlessly.
3445
type Tx: IntoTxEnv<Self::Tx>;
3546
/// Error type returned by EVM. Contains either errors related to invalid transactions or
3647
/// internal irrecoverable execution errors.
@@ -59,8 +70,17 @@ pub trait Evm {
5970
tx: Self::Tx,
6071
) -> Result<ResultAndState<Self::HaltReason>, Self::Error>;
6172

62-
/// Same as [`Evm::transact_raw`], but takes a [`IntoTxEnv`] implementation, thus allowing to
63-
/// support transacting with an external type.
73+
/// Same as [`Evm::transact_raw`], but takes any type implementing [`IntoTxEnv`].
74+
///
75+
/// This is the primary method for executing transactions. It accepts flexible input types
76+
/// that can be converted to the EVM's transaction environment, including:
77+
/// - [`TxEnv`](revm::context::TxEnv) - Direct transaction environment
78+
/// - [`Recovered<T>`](alloy_consensus::transaction::Recovered) - Consensus transaction with
79+
/// recovered sender
80+
/// - [`WithEncoded<Recovered<T>>`](alloy_eips::eip2718::WithEncoded) - Transaction with sender
81+
/// and encoded bytes
82+
///
83+
/// The conversion happens automatically through the [`IntoTxEnv`] trait.
6484
fn transact(
6585
&mut self,
6686
tx: impl IntoTxEnv<Self::Tx>,

crates/evm/src/tx.rs

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
//! Abstraction of an executable transaction.
1+
//! Transaction abstractions for EVM execution.
2+
//!
3+
//! This module provides traits and implementations for converting various transaction formats
4+
//! into a unified transaction environment ([`TxEnv`]) that the EVM can execute. The main purpose
5+
//! of these traits is to enable flexible transaction input while maintaining type safety.
26
37
use alloy_consensus::{
48
crypto::secp256k1, transaction::Recovered, EthereumTxEnvelope, TxEip1559, TxEip2930, TxEip4844,
@@ -13,6 +17,26 @@ use alloy_primitives::{Address, Bytes, TxKind};
1317
use revm::{context::TxEnv, context_interface::either::Either};
1418

1519
/// Trait marking types that can be converted into a transaction environment.
20+
///
21+
/// This is the primary trait that enables flexible transaction input for the EVM. The EVM's
22+
/// associated type `Evm::Tx` must implement this trait, and the `transact` method accepts
23+
/// any type implementing [`IntoTxEnv<Evm::Tx>`](IntoTxEnv).
24+
///
25+
/// # Example
26+
///
27+
/// ```ignore
28+
/// // Direct TxEnv usage
29+
/// let tx_env = TxEnv { caller: address, gas_limit: 100_000, ... };
30+
/// evm.transact(tx_env)?;
31+
///
32+
/// // Using a recovered transaction
33+
/// let recovered = tx.recover_signer()?;
34+
/// evm.transact(recovered)?;
35+
///
36+
/// // Using a transaction with encoded bytes
37+
/// let with_encoded = WithEncoded::new(recovered, encoded_bytes);
38+
/// evm.transact(with_encoded)?;
39+
/// ```
1640
pub trait IntoTxEnv<TxEnv> {
1741
/// Converts `self` into [`TxEnv`].
1842
fn into_tx_env(self) -> TxEnv;
@@ -34,9 +58,33 @@ where
3458
}
3559
}
3660

37-
/// Helper user-facing trait to allow implementing [`IntoTxEnv`] on instances of [`Recovered`].
61+
/// Helper trait for building a transaction environment from a recovered transaction.
62+
///
63+
/// This trait enables the conversion of consensus transaction types (which have been recovered
64+
/// with their sender address) into the EVM's transaction environment. It's automatically used
65+
/// when a [`Recovered<T>`] type is passed to the EVM's `transact` method.
66+
///
67+
/// The expectation is that any recovered consensus transaction can be converted into the
68+
/// transaction type that the EVM operates on (typically [`TxEnv`]).
69+
///
70+
/// # Implementation
71+
///
72+
/// This trait is implemented for all standard Ethereum transaction types ([`TxLegacy`],
73+
/// [`TxEip2930`], [`TxEip1559`], [`TxEip4844`], [`TxEip7702`]) and transaction envelopes
74+
/// ([`EthereumTxEnvelope`]).
75+
///
76+
/// # Example
77+
///
78+
/// ```ignore
79+
/// // Recover the signer from a transaction
80+
/// let recovered = tx.recover_signer()?;
81+
///
82+
/// // The recovered transaction can now be used with the EVM
83+
/// // This works because Recovered<T> implements IntoTxEnv when T implements FromRecoveredTx
84+
/// evm.transact(recovered)?;
85+
/// ```
3886
pub trait FromRecoveredTx<Tx> {
39-
/// Builds a `TxEnv` from a transaction and a sender address.
87+
/// Builds a [`TxEnv`] from a transaction and a sender address.
4088
fn from_recovered_tx(tx: &Tx, sender: Address) -> Self;
4189
}
4290

@@ -237,9 +285,9 @@ impl FromTxWithEncoded<TxEip7702> for TxEnv {
237285
}
238286
}
239287

240-
/// Helper trait to abstract over different `Recovered<T>` implementations.
288+
/// Helper trait to abstract over different [`Recovered<T>`] implementations.
241289
///
242-
/// Implemented for `Recovered<T>`, `Recovered<&T>`, `&Recovered<T>`, `&Recovered<&T>`
290+
/// Implemented for [`Recovered<T>`], `Recovered<&T>`, `&Recovered<T>`, `&Recovered<&T>`
243291
#[auto_impl::auto_impl(&)]
244292
pub trait RecoveredTx<T> {
245293
/// Returns the transaction.
@@ -279,10 +327,38 @@ impl<Tx, T: RecoveredTx<Tx>> RecoveredTx<Tx> for WithEncoded<T> {
279327
}
280328
}
281329

282-
/// Helper user-facing trait to allow implementing [`IntoTxEnv`] on instances of [`WithEncoded`].
283-
/// This allows creating transaction environments directly from EIP-2718 encoded bytes.
330+
/// Helper trait for building a transaction environment from a transaction with its encoded form.
331+
///
332+
/// This trait enables the conversion of consensus transaction types along with their EIP-2718
333+
/// encoded bytes into the EVM's transaction environment. It's automatically used when a
334+
/// [`WithEncoded<Recovered<T>>`](WithEncoded) type is passed to the EVM's `transact` method.
335+
///
336+
/// The main purpose of this trait is to allow preserving the original encoded transaction data
337+
/// alongside the parsed transaction, which can be useful for:
338+
/// - Signature verification
339+
/// - Transaction hash computation
340+
/// - Re-encoding for network propagation
341+
/// - Optimism transaction handling (which requires encoded data, for Data availability costs).
342+
///
343+
/// # Implementation
344+
///
345+
/// Most implementations simply delegate to [`FromRecoveredTx`], ignoring the encoded bytes.
346+
/// However, specialized implementations (like Optimism's `OpTransaction`) may use the encoded
347+
/// data for additional functionality.
348+
///
349+
/// # Example
350+
///
351+
/// ```ignore
352+
/// // Create a transaction with its encoded form
353+
/// let encoded_bytes = tx.encoded_2718();
354+
/// let recovered = tx.recover_signer()?;
355+
/// let with_encoded = WithEncoded::new(recovered, encoded_bytes);
356+
///
357+
/// // The transaction with encoded data can be used with the EVM
358+
/// evm.transact(with_encoded)?;
359+
/// ```
284360
pub trait FromTxWithEncoded<Tx> {
285-
/// Builds a `TxEnv` from a transaction, its sender, and encoded transaction bytes.
361+
/// Builds a [`TxEnv`] from a transaction, its sender, and encoded transaction bytes.
286362
fn from_encoded_tx(tx: &Tx, sender: Address, encoded: Bytes) -> Self;
287363
}
288364

0 commit comments

Comments
 (0)