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: Different OutOfGas Error types #354

Merged
merged 3 commits into from
Feb 2, 2023
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
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