Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
Introduce call return handler
Browse files Browse the repository at this point in the history
  • Loading branch information
rakita committed Sep 22, 2023
1 parent 572f52c commit feec29a
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 245 deletions.
198 changes: 0 additions & 198 deletions crates/interpreter/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,85 +95,6 @@ impl Gas {
true
}

/// Consume the revert gas.
#[cfg(not(feature = "optimism"))]
#[inline]
pub fn consume_revert_gas(&mut self, ret_gas: Gas) {
self.erase_cost(ret_gas.remaining());
}

/// Consume revert gas limit.
#[cfg(feature = "optimism")]
#[inline]
pub fn consume_revert_gas(
&mut self,
is_optimism: bool,
is_deposit: bool,
is_regolith: bool,
ret_gas: Gas,
) {
// On Optimism, deposit transactions report gas usage uniquely to other
// transactions due to them being pre-paid on L1.
//
// Hardfork Behavior:
// - Bedrock (revert path):
// - Deposit transactions (all) report the gas limit as the amount of gas
// used on failure. No refunds.
// - Regular transactions receive a refund on remaining gas as normal.
// - Regolith (revert path):
// - Deposit transactions (all) report the actual gas used as the amount of
// gas used on failure. Refunds on remaining gas enabled.
// - Regular transactions receive a refund on remaining gas as normal.
if is_optimism && (!is_deposit || is_regolith) {
self.erase_cost(ret_gas.remaining());
}
}

/// Consumes the remaining gas.
#[cfg(not(feature = "optimism"))]
#[inline]
pub fn consume_gas(&mut self, ret_gas: Gas) {
self.erase_cost(ret_gas.remaining());
self.record_refund(ret_gas.refunded());
}

/// Consume remaining gas.
#[cfg(feature = "optimism")]
#[inline]
pub fn consume_gas(
&mut self,
is_optimism: bool,
is_deposit: bool,
is_regolith: bool,
tx_system: Option<bool>,
gas_limit: u64,
ret_gas: Gas,
) {
// On Optimism, deposit transactions report gas usage uniquely to other
// transactions due to them being pre-paid on L1.
//
// Hardfork Behavior:
// - Bedrock (success path):
// - Deposit transactions (non-system) report their gas limit as the usage.
// No refunds.
// - Deposit transactions (system) report 0 gas used. No refunds.
// - Regular transactions report gas usage as normal.
// - Regolith (success path):
// - Deposit transactions (all) report their gas used as normal. Refunds
// enabled.
// - Regular transactions report their gas used as normal.
if is_optimism && (!is_deposit || is_regolith) {
// For regular transactions prior to Regolith and all transactions after
// Regolith, gas is reported as normal.
self.erase_cost(ret_gas.remaining());
self.record_refund(ret_gas.refunded());
} else if is_deposit && tx_system.unwrap_or(false) {
// System transactions were a special type of deposit transaction in
// the Bedrock hardfork that did not incur any gas costs.
self.erase_cost(gas_limit);
}
}

/// used in memory_resize! macro to record gas used for memory expansion.
#[inline]
pub fn record_memory(&mut self, gas_memory: u64) -> bool {
Expand All @@ -195,122 +116,3 @@ impl Gas {
self.record_refund(refund);
}
}

#[cfg(test)]
mod tests {
use super::*;

#[cfg(not(feature = "optimism"))]
#[test]
fn test_consume_gas() {
let mut gas = Gas::new(100);
gas.record_cost(50);
assert_eq!(gas.remaining(), 50);
assert_eq!(gas.used, 50);
assert_eq!(gas.all_used_gas, 50);

// Consume the revert gas
gas.consume_gas(Gas::new(50));
assert_eq!(gas, Gas::new(100));
}

#[cfg(not(feature = "optimism"))]
#[test]
fn test_consume_gas_with_refund() {
let mut gas = Gas::new(100);
gas.record_cost(50);
assert_eq!(gas.remaining(), 50);
assert_eq!(gas.used, 50);
assert_eq!(gas.all_used_gas, 50);

// Consume the revert gas
let mut ret_gas = Gas::new(50);
ret_gas.record_refund(50);
gas.consume_gas(ret_gas);
assert_eq!(gas.remaining(), 100);
assert_eq!(gas.used, 0);
assert_eq!(gas.all_used_gas, 0);
assert_eq!(gas.refunded, 50);
}

#[cfg(not(feature = "optimism"))]
#[test]
fn test_revert_gas() {
let mut gas = Gas::new(100);
gas.record_cost(50);
assert_eq!(gas.remaining(), 50);
assert_eq!(gas.used, 50);
assert_eq!(gas.all_used_gas, 50);

// Consume the revert gas
gas.consume_revert_gas(Gas::new(50));
assert_eq!(gas.remaining(), 100);
assert_eq!(gas.used, 0);
assert_eq!(gas.all_used_gas, 0);
}

#[cfg(feature = "optimism")]
#[test]
fn test_revert_gas() {
let mut gas = Gas::new(100);
gas.record_cost(50);

gas.consume_revert_gas(true, false, false, Gas::new(50));
assert_eq!(gas.remaining(), 100);
assert_eq!(gas.used, 0);
assert_eq!(gas.all_used_gas, 0);

let mut gas = Gas::new(100);
gas.consume_revert_gas(false, false, false, Gas::new(50));
}

#[cfg(feature = "optimism")]
#[test]
fn test_revert_gas_non_optimism() {
let mut gas = Gas::new(100);
gas.consume_revert_gas(false, false, false, Gas::new(50));
assert_eq!(gas.remaining(), 100);
}

#[cfg(feature = "optimism")]
#[test]
fn test_consume_gas() {
let mut gas = Gas::new(100);
gas.record_cost(50);

gas.consume_gas(true, true, true, None, 100, Gas::new(50));
assert_eq!(gas.remaining(), 100);
assert_eq!(gas.used, 0);
assert_eq!(gas.all_used_gas, 0);
assert_eq!(gas.refunded, 0);
}

#[cfg(feature = "optimism")]
#[test]
fn test_consume_gas_with_refund() {
let mut gas = Gas::new(100);
gas.record_cost(50);

let mut ret_gas = Gas::new(50);
ret_gas.record_refund(50);
gas.consume_gas(true, true, true, None, 100, ret_gas);
assert_eq!(gas.remaining(), 100);
assert_eq!(gas.used, 0);
assert_eq!(gas.all_used_gas, 0);
assert_eq!(gas.refunded, 50);
}

#[cfg(feature = "optimism")]
#[test]
fn test_consume_gas_sys_deposit_tx() {
let mut gas = Gas::new(100);
gas.record_cost(100);
gas.consume_gas(true, true, false, Some(true), 50, Gas::new(0));
assert_eq!(gas.remaining(), 50);
assert_eq!(gas.used, 50);
assert_eq!(gas.all_used_gas, 50);

gas.consume_gas(true, true, false, Some(true), 50, Gas::new(0));
assert_eq!(gas, Gas::new(100));
}
}
57 changes: 10 additions & 47 deletions crates/revm/src/evm_impl.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::handlers;
use crate::interpreter::{
analysis::to_analysed, gas, instruction_result::SuccessOrHalt, return_ok, return_revert,
CallContext, CallInputs, CallScheme, Contract, CreateInputs, CreateScheme, Gas, Host,
InstructionResult, Interpreter, SelfDestructResult, Transfer, CALL_STACK_LIMIT,
analysis::to_analysed, gas, instruction_result::SuccessOrHalt, return_ok, CallContext,
CallInputs, CallScheme, Contract, CreateInputs, CreateScheme, Gas, Host, InstructionResult,
Interpreter, SelfDestructResult, Transfer, CALL_STACK_LIMIT,
};
use crate::journaled_state::{is_precompile, JournalCheckpoint};
use crate::primitives::{
Expand Down Expand Up @@ -194,7 +195,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
let tx_gas_limit = env.tx.gas_limit;

#[cfg(feature = "optimism")]
let (tx_mint, tx_system, tx_l1_cost, is_deposit, l1_block_info) = {
let (tx_mint, is_deposit, tx_l1_cost, l1_block_info) = {
let is_deposit = env.tx.optimism.source_hash.is_some();

let l1_block_info =
Expand All @@ -213,13 +214,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
.unwrap_or(U256::ZERO)
});

(
env.tx.optimism.mint,
env.tx.optimism.is_system_transaction,
tx_l1_cost,
is_deposit,
l1_block_info,
)
(env.tx.optimism.mint, is_deposit, tx_l1_cost, l1_block_info)
};

let initial_gas_spend = initial_tx_gas::<GSPEC>(
Expand Down Expand Up @@ -287,7 +282,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
let transact_gas_limit = tx_gas_limit - initial_gas_spend;

// call inner handling of call/create
let (exit_reason, ret_gas, output) = match self.data.env.tx.transact_to {
let (call_result, ret_gas, output) = match self.data.env.tx.transact_to {
TransactTo::Call(address) => {
// Nonce is already checked
caller_account.info.nonce = caller_account.info.nonce.saturating_add(1);
Expand Down Expand Up @@ -324,47 +319,15 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
}
};

// Spend the gas limit. Gas is reimbursed when the tx returns successfully.
let mut gas = Gas::new(tx_gas_limit);
gas.record_cost(tx_gas_limit);

if crate::USE_GAS {
match exit_reason {
return_ok!() => {
#[cfg(not(feature = "optimism"))]
gas.consume_gas(ret_gas);
#[cfg(feature = "optimism")]
gas.consume_gas(
self.data.env.cfg.optimism,
is_deposit,
GSPEC::enabled(SpecId::REGOLITH),
tx_system,
tx_gas_limit,
ret_gas,
);
}
return_revert!() => {
#[cfg(not(feature = "optimism"))]
gas.consume_revert_gas(ret_gas);
#[cfg(feature = "optimism")]
gas.consume_revert_gas(
self.data.env.cfg.optimism,
is_deposit,
GSPEC::enabled(SpecId::REGOLITH),
ret_gas,
);
}
_ => {}
}
}
let gas = handlers::handle_call_return::<GSPEC>(self.env(), call_result, ret_gas);

let (state, logs, gas_used, gas_refunded) = self.finalize::<GSPEC>(
&gas,
#[cfg(feature = "optimism")]
l1_block_info.as_ref(),
);

let result = match exit_reason.into() {
let result = match call_result.into() {
SuccessOrHalt::Success(reason) => ExecutionResult::Success {
reason,
gas_used,
Expand Down Expand Up @@ -403,7 +366,7 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> Transact<DB::Error>
return Err(EVMError::Database(self.data.error.take().unwrap()));
}
SuccessOrHalt::InternalContinue => {
panic!("Internal return flags should remain internal {exit_reason:?}")
panic!("Internal return flags should remain internal {call_result:?}")
}
};

Expand Down
Loading

0 comments on commit feec29a

Please sign in to comment.