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

fix(EOF): MIN_CALLEE_GAS light failure, static-mode check #1599

Merged
merged 3 commits into from
Jul 10, 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
1 change: 1 addition & 0 deletions crates/interpreter/src/gas/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ pub const PER_CONTRACT_CODE_BASE_COST: u64 = 2400;
pub const INITCODE_WORD_COST: u64 = 2;

pub const CALL_STIPEND: u64 = 2300;
pub const MIN_CALLEE_GAS: u64 = CALL_STIPEND;
2 changes: 2 additions & 0 deletions crates/interpreter/src/instruction_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ pub enum InstructionResult {
PrecompileOOG,
InvalidOperandOOG,
OpcodeNotFound,
/// Transferring value with CALL/CALLCODE is not possible in static mode.
CallNotAllowedInsideStatic,
/// State change attempted in static mode.
StateChangeDuringStaticCall,
InvalidFEOpcode,
InvalidJump,
Expand Down
24 changes: 16 additions & 8 deletions crates/interpreter/src/instructions/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod call_helpers;
pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges, resize_memory};

use crate::{
gas::{self, cost_per_word, EOF_CREATE_GAS, KECCAK256WORD},
gas::{self, cost_per_word, EOF_CREATE_GAS, KECCAK256WORD, MIN_CALLEE_GAS},
interpreter::Interpreter,
primitives::{
eof::EofHeader, keccak256, Address, BerlinSpec, Bytes, Eof, Spec, SpecId::*, B256, U256,
Expand Down Expand Up @@ -170,7 +170,6 @@ pub fn extcall_gas_calc<H: Host + ?Sized>(
return None;
};

// TODO(EOF) is_empty should only be checked on delegatecall
let call_cost = gas::call_cost(
BerlinSpec::SPEC_ID,
transfers_value,
Expand All @@ -184,10 +183,17 @@ pub fn extcall_gas_calc<H: Host + ?Sized>(
let gas_reduce = max(interpreter.gas.remaining() / 64, 5000);
let gas_limit = interpreter.gas().remaining().saturating_sub(gas_reduce);

if gas_limit < 2300 {
interpreter.instruction_result = InstructionResult::CallNotAllowedInsideStatic;
// TODO(EOF) error;
// interpreter.instruction_result = InstructionResult::CallGasTooLow;
// The MIN_CALLEE_GAS rule is a replacement for stipend:
// it simplifies the reasoning about the gas costs and is
// applied uniformly for all introduced EXT*CALL instructions.
//
// If Gas available to callee is less than MIN_CALLEE_GAS trigger light failure (Same as Revert).
if gas_limit < MIN_CALLEE_GAS {
// Push 1 to stack to indicate that call light failed.
// It is safe to ignore stack overflow error as we already popped multiple values from stack.
let _ = interpreter.stack_mut().push(U256::from(1));
interpreter.return_data_buffer.clear();
// Return none to continue execution.
return None;
}

Expand Down Expand Up @@ -226,11 +232,14 @@ pub fn extcall<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host

pop!(interpreter, value);
let has_transfer = value != U256::ZERO;
if interpreter.is_static && has_transfer {
interpreter.instruction_result = InstructionResult::CallNotAllowedInsideStatic;
return;
}

let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, has_transfer) else {
return;
};
// TODO Check if static and value 0

// Call host to interact with target contract
interpreter.next_action = InterpreterAction::Call {
Expand Down Expand Up @@ -266,7 +275,6 @@ pub fn extdelegatecall<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpret
let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else {
return;
};
// TODO Check if static and value 0

// Call host to interact with target contract
interpreter.next_action = InterpreterAction::Call {
Expand Down
6 changes: 6 additions & 0 deletions crates/interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,12 @@ impl Interpreter {
&self.stack
}

/// Returns a mutable reference to the interpreter's stack.
#[inline]
pub fn stack_mut(&mut self) -> &mut Stack {
&mut self.stack
}

/// Returns the current program counter.
#[inline]
pub fn program_counter(&self) -> usize {
Expand Down
Loading