Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Handler): Add ClearHandle #1368

Merged
merged 5 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 45 additions & 27 deletions crates/revm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,27 +88,63 @@ impl<EXT, DB: Database> Evm<'_, EXT, DB> {
/// has enough balance to pay for the gas.
#[inline]
pub fn preverify_transaction(&mut self) -> Result<(), EVMError<DB::Error>> {
self.handler.validation().env(&self.context.evm.env)?;
self.handler
.validation()
.initial_tx_gas(&self.context.evm.env)?;
self.handler
.validation()
.tx_against_state(&mut self.context)?;
Ok(())
let output = self.preverify_transaction_inner().map(|_| ());
self.clear();
output
}

/// Calls clear handle of post execution to clear the state for next execution.
fn clear(&mut self) {
self.handler.post_execution().clear(&mut self.context);
}

/// Transact pre-verified transaction
///
/// This function will not validate the transaction.
#[inline]
pub fn transact_preverified(&mut self) -> EVMResult<DB::Error> {
let initial_gas_spend = self
.handler
.validation()
.initial_tx_gas(&self.context.evm.env)
.map_err(|e| {
self.clear();
e
})?;
let output = self.transact_preverified_inner(initial_gas_spend);
let output = self.handler.post_execution().end(&mut self.context, output);
self.clear();
output
}

/// Pre verify transaction inner.
#[inline]
fn preverify_transaction_inner(&mut self) -> Result<u64, EVMError<DB::Error>> {
self.handler.validation().env(&self.context.evm.env)?;
let initial_gas_spend = self
.handler
.validation()
.initial_tx_gas(&self.context.evm.env)?;
self.handler
.validation()
.tx_against_state(&mut self.context)?;
Ok(initial_gas_spend)
}

/// Transact transaction
///
/// This function will validate the transaction.
#[inline]
pub fn transact(&mut self) -> EVMResult<DB::Error> {
let initial_gas_spend = self.preverify_transaction_inner().map_err(|e| {
self.clear();
e
})?;

let output = self.transact_preverified_inner(initial_gas_spend);
self.handler.post_execution().end(&mut self.context, output)
let output = self.handler.post_execution().end(&mut self.context, output);
self.clear();
output
}

/// Returns the reference of handler configuration
Expand Down Expand Up @@ -165,24 +201,6 @@ impl<EXT, DB: Database> Evm<'_, EXT, DB> {
&mut self.context.evm.env.block
}

/// Transact transaction
///
/// This function will validate the transaction.
#[inline]
pub fn transact(&mut self) -> EVMResult<DB::Error> {
self.handler.validation().env(&self.context.evm.env)?;
let initial_gas_spend = self
.handler
.validation()
.initial_tx_gas(&self.context.evm.env)?;
self.handler
.validation()
.tx_against_state(&mut self.context)?;

let output = self.transact_preverified_inner(initial_gas_spend);
self.handler.post_execution().end(&mut self.context, output)
}

/// Modify spec id, this will create new EVM that matches this spec id.
pub fn modify_spec_id(&mut self, spec_id: SpecId) {
self.handler.modify_spec_id(spec_id);
Expand Down
17 changes: 16 additions & 1 deletion crates/revm/src/handler/handle_types/post_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ pub type EndHandle<'a, EXT, DB> = Arc<
+ 'a,
>;

/// Clear handle, doesn't have output, its purpose is to clear the
/// context. It will be always called even on failed validation.
pub type ClearHandle<'a, EXT, DB> = Arc<dyn Fn(&mut Context<EXT, DB>) + 'a>;

/// Handles related to post execution after the stack loop is finished.
pub struct PostExecutionHandler<'a, EXT, DB: Database> {
/// Reimburse the caller with ethereum it didn't spent.
Expand All @@ -43,8 +47,13 @@ pub struct PostExecutionHandler<'a, EXT, DB: Database> {
pub reward_beneficiary: RewardBeneficiaryHandle<'a, EXT, DB>,
/// Main return handle, returns the output of the transact.
pub output: OutputHandle<'a, EXT, DB>,
/// End handle.
/// End handle. Called when execution ends.
/// End in comparison to output will be called every time after execution.
/// Output in case of error will not be called.
pub end: EndHandle<'a, EXT, DB>,
/// Clear handle will be called always. In comparison to end that
/// is called only on execution end, clear handle is called even if validation fails.
pub clear: ClearHandle<'a, EXT, DB>,
}

impl<'a, EXT: 'a, DB: Database + 'a> PostExecutionHandler<'a, EXT, DB> {
Expand All @@ -55,6 +64,7 @@ impl<'a, EXT: 'a, DB: Database + 'a> PostExecutionHandler<'a, EXT, DB> {
reward_beneficiary: Arc::new(mainnet::reward_beneficiary::<SPEC, EXT, DB>),
output: Arc::new(mainnet::output::<EXT, DB>),
end: Arc::new(mainnet::end::<EXT, DB>),
clear: Arc::new(mainnet::clear::<EXT, DB>),
}
}
}
Expand Down Expand Up @@ -94,4 +104,9 @@ impl<'a, EXT, DB: Database> PostExecutionHandler<'a, EXT, DB> {
) -> Result<ResultAndState, EVMError<DB::Error>> {
(self.end)(context, end_output)
}

/// Clean handler.
pub fn clear(&self, context: &mut Context<EXT, DB>) {
(self.clear)(context)
}
}
2 changes: 1 addition & 1 deletion crates/revm/src/handler/mainnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ pub use execution::{
frame_return_with_refund_flag, insert_call_outcome, insert_create_outcome,
insert_eofcreate_outcome, last_frame_return,
};
pub use post_execution::{end, output, reimburse_caller, reward_beneficiary};
pub use post_execution::{clear, end, output, reimburse_caller, reward_beneficiary};
pub use pre_execution::{deduct_caller, deduct_caller_inner, load_accounts, load_precompiles};
pub use validation::{validate_env, validate_initial_tx_gas, validate_tx_against_state};
8 changes: 8 additions & 0 deletions crates/revm/src/handler/mainnet/post_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ pub fn end<EXT, DB: Database>(
evm_output
}

/// Clear handle clears error and journal state.
#[inline]
pub fn clear<EXT, DB: Database>(context: &mut Context<EXT, DB>) {
// clear error and journaled state.
let _ = context.evm.take_error();
context.evm.inner.journaled_state.clear();
}

/// Reward beneficiary with gas fee.
#[inline]
pub fn reward_beneficiary<SPEC: Spec, EXT, DB: Database>(
Expand Down
6 changes: 6 additions & 0 deletions crates/revm/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ impl JournaledState {
}
}

/// Clears the JournaledState. Preserving only the spec.
pub fn clear(&mut self) {
let spec = self.spec;
*self = Self::new(spec, HashSet::new());
}

/// Does cleanup and returns modified state.
///
/// This resets the [JournaledState] to its initial state in [Self::new]
Expand Down
5 changes: 4 additions & 1 deletion documentation/src/crates/revm/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,7 @@ Is a list of functions that are called after the execution. They are called in t
Returns the state changes and the result of the execution.

* `end`:
Always called as the last function of the handler.
Always called after transaction. End handler will not be called if validation fails.

* `clear`:
Clears journal state and error and it is always called for the cleanup.
Loading