Skip to content

Commit

Permalink
feat: Different OutOfGas Error types (#354)
Browse files Browse the repository at this point in the history
* feat: Different OutOfGas Error types

* fix: implement Serialize trait for OutOfGasError

* replace old OOG errors with new ones
  • Loading branch information
chirag-bgh authored Feb 2, 2023
1 parent 10187ed commit 9b663bb
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 36 deletions.
20 changes: 19 additions & 1 deletion crates/interpreter/src/instruction_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ pub enum InstructionResult {

// error codes
OutOfGas = 0x50,
MemoryOOG = 0x51,
MemoryLimitOOG = 0x52,
PrecompileOOG = 0x53,
InvalidOperandOOG = 0x54,
OpcodeNotFound,
CallNotAllowedInsideStatic,
StateChangeDuringStaticCall,
Expand Down Expand Up @@ -58,7 +62,21 @@ impl From<InstructionResult> for SuccessOrHalt {
InstructionResult::Revert => Self::Revert,
InstructionResult::CallTooDeep => Self::Internal, // not gonna happen for first call
InstructionResult::OutOfFund => Self::Internal, // Check for first call is done separately.
InstructionResult::OutOfGas => Self::Halt(Halt::OutOfGas),
InstructionResult::OutOfGas => Self::Halt(Halt::OutOfGas(
revm_primitives::OutOfGasError::BasicOutOfGas,
)),
InstructionResult::MemoryLimitOOG => {
Self::Halt(Halt::OutOfGas(revm_primitives::OutOfGasError::MemoryLimit))
}
InstructionResult::MemoryOOG => {
Self::Halt(Halt::OutOfGas(revm_primitives::OutOfGasError::Memory))
}
InstructionResult::PrecompileOOG => {
Self::Halt(Halt::OutOfGas(revm_primitives::OutOfGasError::Precompile))
}
InstructionResult::InvalidOperandOOG => Self::Halt(Halt::OutOfGas(
revm_primitives::OutOfGasError::InvalidOperand,
)),
InstructionResult::OpcodeNotFound => Self::Halt(Halt::OpcodeNotFound),
InstructionResult::CallNotAllowedInsideStatic => Self::Internal, // first call is not static call
InstructionResult::StateChangeDuringStaticCall => Self::Internal,
Expand Down
8 changes: 4 additions & 4 deletions crates/interpreter/src/instructions/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ pub fn pc(interpreter: &mut Interpreter, _host: &mut dyn Host) {
pub fn ret(interpreter: &mut Interpreter, _host: &mut dyn Host) {
// zero gas cost gas!(interp,gas::ZERO);
pop!(interpreter, start, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
if len == 0 {
interpreter.return_range = usize::MAX..usize::MAX;
} else {
let offset = as_usize_or_fail!(interpreter, start, InstructionResult::OutOfGas);
let offset = as_usize_or_fail!(interpreter, start, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, offset, len);
interpreter.return_range = offset..(offset + len);
}
Expand All @@ -67,11 +67,11 @@ pub fn revert<SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut dyn Host) {
// EIP-140: REVERT instruction
check!(interpreter, SPEC::enabled(BYZANTIUM));
pop!(interpreter, start, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
if len == 0 {
interpreter.return_range = usize::MAX..usize::MAX;
} else {
let offset = as_usize_or_fail!(interpreter, start, InstructionResult::OutOfGas);
let offset = as_usize_or_fail!(interpreter, start, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, offset, len);
interpreter.return_range = offset..(offset + len);
}
Expand Down
33 changes: 23 additions & 10 deletions crates/interpreter/src/instructions/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,19 @@ pub fn extcodecopy<SPEC: Spec>(interpreter: &mut Interpreter, host: &mut dyn Hos
}
let (code, is_cold) = ret.unwrap();

let len = as_usize_or_fail!(interpreter, len_u256, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len_u256, InstructionResult::InvalidOperandOOG);
gas_or_fail!(
interpreter,
gas::extcodecopy_cost::<SPEC>(len as u64, is_cold)
);
if len == 0 {
return;
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset, InstructionResult::OutOfGas);
let memory_offset = as_usize_or_fail!(
interpreter,
memory_offset,
InstructionResult::InvalidOperandOOG
);
let code_offset = min(as_usize_saturated!(code_offset), code.len());
memory_resize!(interpreter, memory_offset, len);

Expand Down Expand Up @@ -167,12 +171,12 @@ pub fn log<const N: u8, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut dy
check_staticcall!(interpreter);

pop!(interpreter, offset, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
gas_or_fail!(interpreter, gas::log_cost(N, len as u64));
let data = if len == 0 {
Bytes::new()
} else {
let offset = as_usize_or_fail!(interpreter, offset, InstructionResult::OutOfGas);
let offset = as_usize_or_fail!(interpreter, offset, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, offset, len);
Bytes::copy_from_slice(interpreter.memory.get_slice(offset, len))
};
Expand Down Expand Up @@ -226,12 +230,16 @@ pub fn create<const IS_CREATE2: bool, SPEC: Spec>(
interpreter.return_data_buffer = Bytes::new();

pop!(interpreter, value, code_offset, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);

let code = if len == 0 {
Bytes::new()
} else {
let code_offset = as_usize_or_fail!(interpreter, code_offset, InstructionResult::OutOfGas);
let code_offset = as_usize_or_fail!(
interpreter,
code_offset,
InstructionResult::InvalidOperandOOG
);
memory_resize!(interpreter, code_offset, len);
Bytes::copy_from_slice(interpreter.memory.get_slice(code_offset, len))
};
Expand Down Expand Up @@ -347,18 +355,23 @@ pub fn call_inner<SPEC: Spec>(

pop!(interpreter, in_offset, in_len, out_offset, out_len);

let in_len = as_usize_or_fail!(interpreter, in_len, InstructionResult::OutOfGas);
let in_len = as_usize_or_fail!(interpreter, in_len, InstructionResult::InvalidOperandOOG);
let input = if in_len != 0 {
let in_offset = as_usize_or_fail!(interpreter, in_offset, InstructionResult::OutOfGas);
let in_offset =
as_usize_or_fail!(interpreter, in_offset, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, in_offset, in_len);
Bytes::copy_from_slice(interpreter.memory.get_slice(in_offset, in_len))
} else {
Bytes::new()
};

let out_len = as_usize_or_fail!(interpreter, out_len, InstructionResult::OutOfGas);
let out_len = as_usize_or_fail!(interpreter, out_len, InstructionResult::InvalidOperandOOG);
let out_offset = if out_len != 0 {
let out_offset = as_usize_or_fail!(interpreter, out_offset, InstructionResult::OutOfGas);
let out_offset = as_usize_or_fail!(
interpreter,
out_offset,
InstructionResult::InvalidOperandOOG
);
memory_resize!(interpreter, out_offset, out_len);
out_offset
} else {
Expand Down
8 changes: 4 additions & 4 deletions crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,22 @@ macro_rules! memory_resize {
{
#[cfg(feature = "memory_limit")]
if new_size > ($interp.memory_limit as usize) {
$interp.instruction_result = InstructionResult::OutOfGas;
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
return;
}

if new_size > $interp.memory.len() {
if crate::USE_GAS {
let num_bytes = new_size / 32;
if !$interp.gas.record_memory(crate::gas::memory_gas(num_bytes)) {
$interp.instruction_result = InstructionResult::OutOfGas;
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
return;
}
}
$interp.memory.resize(new_size);
}
} else {
$interp.instruction_result = InstructionResult::OutOfGas;
$interp.instruction_result = InstructionResult::MemoryOOG;
return;
}
}};
Expand Down Expand Up @@ -222,7 +222,7 @@ macro_rules! as_usize_saturated {

macro_rules! as_usize_or_fail {
( $interp:expr, $v:expr ) => {{
as_usize_or_fail!($interp, $v, InstructionResult::OutOfGas)
as_usize_or_fail!($interp, $v, InstructionResult::InvalidOperandOOG)
}};

( $interp:expr, $v:expr, $reason:expr ) => {{
Expand Down
6 changes: 3 additions & 3 deletions crates/interpreter/src/instructions/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{interpreter::Interpreter, primitives::U256, Host, InstructionResult}
pub fn mload(interpreter: &mut Interpreter, _host: &mut dyn Host) {
// gas!(interp, gas::VERYLOW);
pop!(interpreter, index);
let index = as_usize_or_fail!(interpreter, index, InstructionResult::OutOfGas);
let index = as_usize_or_fail!(interpreter, index, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, index, 32);
push!(
interpreter,
Expand All @@ -16,15 +16,15 @@ pub fn mload(interpreter: &mut Interpreter, _host: &mut dyn Host) {
pub fn mstore(interpreter: &mut Interpreter, _host: &mut dyn Host) {
// gas!(interp, gas::VERYLOW);
pop!(interpreter, index, value);
let index = as_usize_or_fail!(interpreter, index, InstructionResult::OutOfGas);
let index = as_usize_or_fail!(interpreter, index, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, index, 32);
interpreter.memory.set_u256(index, value);
}

pub fn mstore8(interpreter: &mut Interpreter, _host: &mut dyn Host) {
// gas!(interp, gas::VERYLOW);
pop!(interpreter, index, value);
let index = as_usize_or_fail!(interpreter, index, InstructionResult::OutOfGas);
let index = as_usize_or_fail!(interpreter, index, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, index, 1);
let value = value.as_le_bytes()[0];
// Safety: we resized our memory two lines above.
Expand Down
29 changes: 20 additions & 9 deletions crates/interpreter/src/instructions/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ use core::cmp::min;

pub fn sha3(interpreter: &mut Interpreter, _host: &mut dyn Host) {
pop!(interpreter, from, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
gas_or_fail!(interpreter, gas::sha3_cost(len as u64));
let hash = if len == 0 {
KECCAK_EMPTY
} else {
let from = as_usize_or_fail!(interpreter, from, InstructionResult::OutOfGas);
let from = as_usize_or_fail!(interpreter, from, InstructionResult::InvalidOperandOOG);
memory_resize!(interpreter, from, len);
keccak256(interpreter.memory.get_slice(from, len))
};
Expand All @@ -38,12 +38,16 @@ pub fn codesize(interpreter: &mut Interpreter, _host: &mut dyn Host) {

pub fn codecopy(interpreter: &mut Interpreter, _host: &mut dyn Host) {
pop!(interpreter, memory_offset, code_offset, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
if len == 0 {
return;
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset, InstructionResult::OutOfGas);
let memory_offset = as_usize_or_fail!(
interpreter,
memory_offset,
InstructionResult::InvalidOperandOOG
);
let code_offset = as_usize_saturated!(code_offset);
memory_resize!(interpreter, memory_offset, len);

Expand Down Expand Up @@ -85,12 +89,16 @@ pub fn callvalue(interpreter: &mut Interpreter, _host: &mut dyn Host) {

pub fn calldatacopy(interpreter: &mut Interpreter, _host: &mut dyn Host) {
pop!(interpreter, memory_offset, data_offset, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
if len == 0 {
return;
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset, InstructionResult::OutOfGas);
let memory_offset = as_usize_or_fail!(
interpreter,
memory_offset,
InstructionResult::InvalidOperandOOG
);
let data_offset = as_usize_saturated!(data_offset);
memory_resize!(interpreter, memory_offset, len);

Expand All @@ -114,7 +122,7 @@ pub fn returndatacopy<SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut dyn
// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
check!(interpreter, SPEC::enabled(BYZANTIUM));
pop!(interpreter, memory_offset, offset, len);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::OutOfGas);
let len = as_usize_or_fail!(interpreter, len, InstructionResult::InvalidOperandOOG);
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
let data_offset = as_usize_saturated!(offset);
let (data_end, overflow) = data_offset.overflowing_add(len);
Expand All @@ -123,8 +131,11 @@ pub fn returndatacopy<SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut dyn
return;
}
if len != 0 {
let memory_offset =
as_usize_or_fail!(interpreter, memory_offset, InstructionResult::OutOfGas);
let memory_offset = as_usize_or_fail!(
interpreter,
memory_offset,
InstructionResult::InvalidOperandOOG
);
memory_resize!(interpreter, memory_offset, len);
interpreter.memory.set(
memory_offset,
Expand Down
18 changes: 17 additions & 1 deletion crates/primitives/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub enum Eval {
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Halt {
OutOfGas,
OutOfGas(OutOfGasError),
OpcodeNotFound,
InvalidFEOpcode,
InvalidJump,
Expand All @@ -132,3 +132,19 @@ pub enum Halt {
/// Error on created contract that begins with EF
CreateContractStartingWithEF,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OutOfGasError {
// Basic OOG error
BasicOutOfGas,
// Tried to expand past REVM limit
MemoryLimit,
// Basic OOG error from memory expansion
Memory,
// Precompile threw OOG error
Precompile,
// When performing something that takes a U256 and casts down to a u64, if its too large this would fire
// i.e. in `as_usize_or_fail`
InvalidOperand,
}
8 changes: 4 additions & 4 deletions crates/revm/src/evm_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,9 +576,9 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB,
}
}
}
// if we have enought gas
// if we have enough gas
self.data.journaled_state.checkpoint_commit();
// Do analysis of bytecode streight away.
// Do analysis of bytecode straight away.
let bytecode = match self.data.env.cfg.perf_analyse_created_bytecodes {
AnalysisKind::Raw => Bytecode::new_raw(bytes.clone()),
AnalysisKind::Check => Bytecode::new_raw(bytes.clone()).to_checked(),
Expand Down Expand Up @@ -697,12 +697,12 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB,
(InstructionResult::Return, gas, Bytes::from(data))
} else {
self.data.journaled_state.checkpoint_revert(checkpoint);
(InstructionResult::OutOfGas, gas, Bytes::new())
(InstructionResult::PrecompileOOG, gas, Bytes::new())
}
}
Err(e) => {
let ret = if let precompile::Error::OutOfGas = e {
InstructionResult::OutOfGas
InstructionResult::PrecompileOOG
} else {
InstructionResult::PrecompileError
};
Expand Down

0 comments on commit 9b663bb

Please sign in to comment.