Skip to content

Commit 8e0738b

Browse files
committed
simulation impl
1 parent d52ed99 commit 8e0738b

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

src/payload/checkpoint.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,18 @@ impl<P: Platform> Checkpoint<P> {
195195
Ok(self.apply_with(mutation, None))
196196
}
197197

198+
/// Executes transaction on top of the current checkpoint. The execution will use the
199+
/// cumulative state of all checkpoints in the current checkpoint history as
200+
/// its state.
201+
pub fn simulate<S>(
202+
&self,
203+
executable: impl IntoExecutable<P, S>,
204+
) -> Result<ExecutionResult<P>, ExecutionError<P>> {
205+
executable
206+
.try_into_executable()?
207+
.simulate(self.block(), self)
208+
}
209+
198210
/// Creates a new checkpoint on top of the current checkpoint and tags it.
199211
/// The execution will use the cumulative state of all checkpoints in the
200212
/// current checkpoint history as its state.

src/payload/exec.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,61 @@ impl<P: Platform> Executable<P> {
259259
state,
260260
})
261261
}
262+
263+
/// Executes this executable as a single unit of state transition and returns
264+
/// the outcome of the execution. If the
265+
/// executable is invalid, no execution result will be produced.
266+
///
267+
/// For details on what makes an executable invalid see the
268+
/// [`simulate_transaction`] and [`simulate_bundle`] methods.
269+
pub fn simulate<DB>(
270+
self,
271+
block: &BlockContext<P>,
272+
db: &DB,
273+
) -> Result<ExecutionResult<P>, ExecutionError<P>>
274+
where
275+
DB: DatabaseRef<Error = ProviderError> + Debug,
276+
{
277+
match self {
278+
Self::Bundle(_) => unreachable!("asd"),
279+
Self::Transaction(tx) => Self::simulate_transaction(tx, block, db)
280+
.map_err(ExecutionError::InvalidTransaction),
281+
}
282+
}
283+
284+
/// Executes a single transaction and returns the outcome of the execution.
285+
///
286+
/// Notes:
287+
/// - Transactions that are invalid and cause EVM failures will not produce an
288+
/// execution result.
289+
///
290+
/// - Transactions that fail gracefully (revert or halt) will produce an
291+
/// execution result and state changes. It is up to higher levels of the
292+
/// system to decide what to do with such transactions, e.g., whether to
293+
/// remove them from the payload or not (see [`RevertProtection`]).
294+
fn simulate_transaction<DB>(
295+
tx: Recovered<types::Transaction<P>>,
296+
block: &BlockContext<P>,
297+
db: &DB,
298+
) -> Result<ExecutionResult<P>, types::EvmError<P, ProviderError>>
299+
where
300+
DB: DatabaseRef<Error = ProviderError> + Debug,
301+
{
302+
let mut state = State::builder()
303+
.with_database(WrapDatabaseRef(db))
304+
.build();
305+
306+
let result = block
307+
.evm_config()
308+
.evm_with_env(&mut state, block.evm_env().clone())
309+
.transact(&tx)?;
310+
311+
Ok(ExecutionResult {
312+
source: Executable::Transaction(tx),
313+
results: vec![result.result],
314+
state: BundleState::default(),
315+
})
316+
}
262317
}
263318

264319
impl<P: Platform> Executable<P> {

0 commit comments

Comments
 (0)