Skip to content

Commit 3888dd6

Browse files
authored
Fix: exec doc, readability (#20)
1 parent 34235ee commit 3888dd6

File tree

1 file changed

+75
-88
lines changed

1 file changed

+75
-88
lines changed

src/payload/exec.rs

Lines changed: 75 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl<P: Platform> Executable<P> {
9494
///
9595
/// - Transactions that fail gracefully (revert or halt) will produce an
9696
/// execution result and state changes. It is up to higher levels of the
97-
/// system to decide what to do with such transactions, e.g. whether to
97+
/// system to decide what to do with such transactions, e.g., whether to
9898
/// remove them from the payload or not (see [`RevertProtection`]).
9999
fn execute_transaction<DB>(
100100
tx: Recovered<types::Transaction<P>>,
@@ -123,54 +123,63 @@ impl<P: Platform> Executable<P> {
123123
})
124124
}
125125

126-
/// Executes a bundle of transactions and returns the outcome of the execution
127-
/// of all transactions in the bundle along with the aggregate of all state
128-
/// changes.
126+
/// Executes a bundle of transactions and returns the execution outcome of all
127+
/// transactions in the bundle along with the aggregate of all state changes.
129128
///
130129
/// Notes:
131130
/// - Bundles that are not eligible for execution in the current block are
132-
/// considered invalid and no execution result will be produced.
131+
/// considered invalid, and no execution result will be produced.
133132
///
134133
/// - All transactions in the bundle are executed in the order in which they
135134
/// were defined in the bundle.
136135
///
137-
/// - Each transaction is executed on the state that was produced by the
138-
/// previous transaction in the bundle.
136+
/// - Each transaction is executed on the state produced by the previous
137+
/// transaction in the bundle.
139138
///
140139
/// - First transaction in the bundle is executed on the state of the
141140
/// checkpoint that we are building on.
142141
///
143-
/// - Transactions that cause EVM errors will invalidate the whole bundle and
144-
/// no execution result will be produced (similar behavior to invalid loose
145-
/// txs),
146-
/// - Unless the transaction that is failing is optional
147-
/// [`Bundle::is_optional`]. In that case a new version of the bundle
148-
/// will be created by removing the invalid failing transaction through
149-
/// [`Bundle::without_transaction`].
142+
/// - Transactions that cause EVM errors will invalidate the bundle, and no
143+
/// execution result will be produced (similar behavior to invalid loose
144+
/// txs). Bundle transaction can be marked optional [`Bundle::is_optional`],
145+
/// and invalid outcomes are handled differently:
146+
/// - If the invalid transaction is optional, a new version of the bundle
147+
/// will be created without the invalid transaction by removing it
148+
/// through [`Bundle::without_transaction`].
150149
/// - If removing the invalid optional transaction results in an empty
151150
/// bundle, the bundle will be considered invalid and no execution
152151
/// result will be produced.
153152
///
154-
/// - If a transaction in the bundle fails gracefully (revert or halt):
155-
/// - If the bundle allows this tx to fail [`Bundle::is_allowed_to_fail`],
156-
/// the bundle will be considered valid and the execution result will be
157-
/// produced including this tx. State changes from the failed
158-
/// transaction will be included in the aggregate state, e.g gas used,
159-
/// nonces incremented, etc. Cleaning up transactions that are allowed
160-
/// to fail and are optional from a bundle is beyond the scope of this
161-
/// method. This is implemented by higher levels of the system, such as
162-
/// the [`RevertProtection`] step in the pipelines API.
163-
/// - If the bundle does not allow this tx to fail, but the transaction is
164-
/// optional, then it will be removed from the bundle.
165-
/// - If the bundle does not allow this tx to fail and the transaction is
166-
/// not optional, then the bundle will be considered invalid and no
167-
/// execution result will be produced.
153+
/// - Transactions that fail gracefully (revert or halt) and are not optional
154+
/// will invalidate the bundle, and no execution result will be produced.
155+
/// Bundle transaction can be marked as allowed to fail
156+
/// [`Bundle::is_allowed_to_fail`], and failure outcomes are handled
157+
/// differently:
158+
/// - If the bundle allows the failing transaction to fail, the bundle
159+
/// will still be considered valid. The execution result will be
160+
/// produced, including this failed transaction. State changes from the
161+
/// failed transaction will be included in the aggregate state, e.g.,
162+
/// gas used, nonces incremented, etc. Cleaning up transactions that are
163+
/// allowed to fail and are optional from a bundle is beyond the scope
164+
/// of this method. This is implemented by higher levels of the system,
165+
/// such as the [`RevertProtection`] step in the pipelines API.
166+
/// - If the bundle does not allow this failed transaction to fail, but
167+
/// the transaction is optional, then it will be removed from the
168+
/// bundle. The bundle stays valid.
169+
///
170+
/// See truth table:
171+
/// | success | `allowed_to_fail` | optional | Action |
172+
/// | ------: | :---------------: | :------: | :------ |
173+
/// | true | *don’t care* | *any* | include |
174+
/// | false | true | *any* | include |
175+
/// | false | false | true | discard |
176+
/// | false | false | false | error |
168177
///
169178
/// - At the end of the bundle execution, the bundle implementation will have
170179
/// a chance to validate any other platform-specific post-execution
171180
/// requirements. For example, the bundle may require that the state after
172181
/// the execution has a certain balance in some account, etc. If this check
173-
/// fails, the bundle will be considered invalid and no execution result
182+
/// fails, the bundle will be considered invalid, and no execution result
174183
/// will be produced.
175184
fn execute_bundle<DB>(
176185
bundle: types::Bundle<P>,
@@ -196,65 +205,43 @@ impl<P: Platform> Executable<P> {
196205
let mut results = Vec::with_capacity(bundle.transactions().len());
197206

198207
for transaction in bundle.transactions() {
208+
let tx_hash = *transaction.tx_hash();
209+
let optional = bundle.is_optional(tx_hash);
210+
let allowed_to_fail = bundle.is_allowed_to_fail(tx_hash);
211+
199212
let result = evm_config
200213
.evm_with_env(&mut db, evm_env.clone())
201214
.transact(transaction);
202215

203216
match result {
204-
// valid transaction
205-
Ok(ExecResultAndState { result, state }) => {
206-
if !result.is_success() {
207-
match (
208-
bundle.is_allowed_to_fail(*transaction.tx_hash()),
209-
bundle.is_optional(*transaction.tx_hash()),
210-
) {
211-
// transaction is not allowed to fail, but it is optional,
212-
// we can remove it from the bundle and continue executing the
213-
// bundle.
214-
(false, true) => {
215-
discarded.push(*transaction.tx_hash());
216-
continue;
217-
}
218-
219-
// transaction is not allowed to fail and is not optional,
220-
// this invalidates the whole bundle and we cannot produce an
221-
// execution result.
222-
(false, false) => {
223-
return Err(ExecutionError::BundleTransactionReverted(
224-
*transaction.tx_hash(),
225-
));
226-
}
227-
// transaction is allowed to fail, include it
228-
_ => {}
229-
}
230-
}
231-
232-
// transaction will be included
217+
// Valid transaction or allowed to fail: include it in the bundle
218+
Ok(ExecResultAndState { result, state })
219+
if result.is_success() || allowed_to_fail =>
220+
{
233221
results.push(result);
234222
db.commit(state);
235223
}
236-
// Invalid transaction
224+
// Optional failing transaction, not allowed to fail
225+
// or optional invalid transaction: discard it
226+
Ok(_) | Err(_) if optional => {
227+
discarded.push(tx_hash);
228+
}
229+
// Non-Optional failing transaction, not allowed to fail: invalidate the
230+
// bundle
231+
Ok(_) => {
232+
return Err(ExecutionError::BundleTransactionReverted(tx_hash));
233+
}
234+
// Non-Optional invalid transaction: invalidate the bundle
237235
Err(err) => {
238-
if bundle.is_optional(*transaction.tx_hash()) {
239-
// If the transaction is optional, we can skip it
240-
// and continue with the next transaction.
241-
discarded.push(*transaction.tx_hash());
242-
continue;
243-
}
244-
245-
return Err(ExecutionError::InvalidBundleTransaction(
246-
*transaction.tx_hash(),
247-
err,
248-
));
236+
return Err(ExecutionError::InvalidBundleTransaction(tx_hash, err));
249237
}
250238
}
251239
}
252240

253-
// produce a new bundle without the discarded transactions
254-
let mut bundle = bundle;
255-
for tx in discarded {
256-
bundle = bundle.without_transaction(tx);
257-
}
241+
// reduce the bundle by removing discarded transactions
242+
let bundle = discarded
243+
.into_iter()
244+
.fold(bundle, |b, tx| b.without_transaction(tx));
258245

259246
// extract all the state changes that were made by executing
260247
// transactions in this bundle.
@@ -299,7 +286,7 @@ impl<P: Platform> Executable<P> {
299286
}
300287
}
301288

302-
/// Convinience trait that allows all types that can be executed to be used as a
289+
/// Convenience trait that allows all types that can be executed to be used as a
303290
/// parameter to the `Checkpoint::apply` method.
304291
pub trait IntoExecutable<P: Platform, S = ()> {
305292
fn try_into_executable(self) -> Result<Executable<P>, RecoveryError>;
@@ -315,7 +302,7 @@ impl<P: Platform> IntoExecutable<P, Variant<0>> for types::Transaction<P> {
315302
}
316303
}
317304

318-
/// Transactions from the transaction pool can be converted infalliably into
305+
/// Transactions from the transaction pool can be converted infallibly into
319306
/// an executable because the transaction pool discards transactions
320307
/// that have invalid signatures.
321308
impl<P: Platform> IntoExecutable<P, Variant<1>>
@@ -326,7 +313,7 @@ impl<P: Platform> IntoExecutable<P, Variant<1>>
326313
}
327314
}
328315

329-
/// Signature recovered individual transactions are always infalliably
316+
/// Signature-recovered individual transactions are always infallibly
330317
/// convertable into an executable.
331318
impl<P: Platform> IntoExecutable<P, Variant<2>>
332319
for Recovered<types::Transaction<P>>
@@ -336,7 +323,7 @@ impl<P: Platform> IntoExecutable<P, Variant<2>>
336323
}
337324
}
338325

339-
/// Bundles are also convertible into an executable infalliably.
326+
/// Bundles are also convertible into an executable infallibly.
340327
/// Signature recovery is part of the bundle assembly logic.
341328
impl<P: Platform> IntoExecutable<P, Variant<3>> for types::Bundle<P> {
342329
fn try_into_executable(self) -> Result<Executable<P>, RecoveryError> {
@@ -351,7 +338,7 @@ impl<P: Platform> IntoExecutable<P, Variant<4>> for Executable<P> {
351338
}
352339
}
353340

354-
/// Another checkpoints contents
341+
/// Another checkpoint content
355342
impl<P: Platform> IntoExecutable<P, Variant<5>> for Checkpoint<P> {
356343
fn try_into_executable(self) -> Result<Executable<P>, RecoveryError> {
357344
(&self).try_into_executable()
@@ -360,10 +347,10 @@ impl<P: Platform> IntoExecutable<P, Variant<5>> for Checkpoint<P> {
360347

361348
impl<P: Platform> IntoExecutable<P, Variant<6>> for &Checkpoint<P> {
362349
fn try_into_executable(self) -> Result<Executable<P>, RecoveryError> {
363-
if let Some(bundle) = self.as_bundle() {
364-
Ok(Executable::Bundle(bundle.clone()))
365-
} else if let Some(tx) = self.as_transaction() {
350+
if let Some(tx) = self.as_transaction() {
366351
Ok(Executable::Transaction(tx.clone()))
352+
} else if let Some(bundle) = self.as_bundle() {
353+
Ok(Executable::Bundle(bundle.clone()))
367354
} else {
368355
Err(RecoveryError::new())
369356
}
@@ -387,6 +374,7 @@ impl<P: PlatformWithRpcTypes> IntoExecutable<P, Variant<7>>
387374
/// transaction executions that make up this overall result.
388375
#[derive(Debug, Clone)]
389376
pub struct ExecutionResult<P: Platform> {
377+
/// The executable used to produce this result.
390378
source: Executable<P>,
391379

392380
/// For transactions this is guaranteed to be a single-element vector,
@@ -399,13 +387,13 @@ pub struct ExecutionResult<P: Platform> {
399387
}
400388

401389
impl<P: Platform> ExecutionResult<P> {
402-
/// Returns the executable that was executed to produce this result.
390+
/// Returns the executable used to produce this result.
403391
pub const fn source(&self) -> &Executable<P> {
404392
&self.source
405393
}
406394

407-
/// Returns the aggregate state changes that were made by executing
408-
/// the transactions in this execution unit.
395+
/// Returns the aggregate state changes made by executing the transactions in
396+
/// this execution unit.
409397
pub const fn state(&self) -> &BundleState {
410398
&self.state
411399
}
@@ -420,8 +408,7 @@ impl<P: Platform> ExecutionResult<P> {
420408
self.results.as_slice()
421409
}
422410

423-
/// Returns individual transactions that were executed as part of this
424-
/// execution unit.
411+
/// Returns individual transactions executed as part of this execution unit.
425412
pub fn transactions(&self) -> &[Recovered<types::Transaction<P>>] {
426413
self.source().transactions()
427414
}

0 commit comments

Comments
 (0)