Skip to content

Commit

Permalink
chore: refactor -copy common code (#1799)
Browse files Browse the repository at this point in the history
* chore: refactor *copy common code

* doc link fix
  • Loading branch information
rakita committed Sep 24, 2024
1 parent e7de0bb commit 47169b3
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 29 deletions.
11 changes: 8 additions & 3 deletions crates/interpreter/src/gas/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ pub fn exp_cost(spec_id: SpecId, power: U256) -> Option<u64> {

/// `*COPY` opcodes cost calculation.
#[inline]
pub const fn verylowcopy_cost(len: u64) -> Option<u64> {
VERYLOW.checked_add(tri!(cost_per_word(len, COPY)))
pub const fn copy_cost_verylow(len: u64) -> Option<u64> {
copy_cost(VERYLOW, len)
}

/// `EXTCODECOPY` opcode cost calculation.
Expand All @@ -129,7 +129,12 @@ pub const fn extcodecopy_cost(spec_id: SpecId, len: u64, load: Eip7702CodeLoad<(
} else {
20
};
base_gas.checked_add(tri!(cost_per_word(len, COPY)))
copy_cost(base_gas, len)
}

#[inline]
pub const fn copy_cost(base_cost: u64, len: u64) -> Option<u64> {
base_cost.checked_add(tri!(cost_per_word(len, COPY)))
}

/// `LOG` opcode cost calculation.
Expand Down
7 changes: 5 additions & 2 deletions crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,14 @@ macro_rules! refund {
#[macro_export]
macro_rules! gas_or_fail {
($interp:expr, $gas:expr) => {
$crate::gas_or_fail!($interp, $gas, ())
};
($interp:expr, $gas:expr, $ret:expr) => {
match $gas {
Some(gas_used) => $crate::gas!($interp, gas_used),
Some(gas_used) => $crate::gas!($interp, gas_used, $ret),
None => {
$interp.instruction_result = $crate::InstructionResult::OutOfGas;
return;
return $ret;
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn mcopy<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host:
// into usize or fail
let len = as_usize_or_fail!(interpreter, len);
// deduce gas
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
gas_or_fail!(interpreter, gas::copy_cost_verylow(len as u64));
if len == 0 {
return;
}
Expand Down
48 changes: 26 additions & 22 deletions crates/interpreter/src/instructions/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,10 @@ pub fn codesize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H)
pub fn codecopy<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
pop!(interpreter, memory_offset, code_offset, len);
let len = as_usize_or_fail!(interpreter, len);
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
if len == 0 {
let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
return;
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
};
let code_offset = as_usize_saturated!(code_offset);
resize_memory!(interpreter, memory_offset, len);

// Inform the optimizer that the bytecode cannot be EOF to remove a bounds check.
assume!(!interpreter.contract.bytecode.is_eof());
Expand Down Expand Up @@ -92,14 +89,11 @@ pub fn callvalue<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H)
pub fn calldatacopy<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
pop!(interpreter, memory_offset, data_offset, len);
let len = as_usize_or_fail!(interpreter, len);
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
if len == 0 {
let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
return;
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
let data_offset = as_usize_saturated!(data_offset);
resize_memory!(interpreter, memory_offset, len);
};

let data_offset = as_usize_saturated!(data_offset);
// Note: this can't panic because we resized memory to fit.
interpreter.shared_memory.set_data(
memory_offset,
Expand All @@ -125,33 +119,26 @@ pub fn returndatacopy<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interprete
pop!(interpreter, memory_offset, offset, len);

let len = as_usize_or_fail!(interpreter, len);
gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));

let data_offset = as_usize_saturated!(offset);
let data_end = data_offset.saturating_add(len);

// Old legacy behavior is to panic if data_end is out of scope of return buffer.
// This behavior is changed in EOF.
let data_end = data_offset.saturating_add(len);
if data_end > interpreter.return_data_buffer.len() && !interpreter.is_eof {
interpreter.instruction_result = InstructionResult::OutOfOffset;
return;
}

// if len is zero memory is not resized.
if len == 0 {
let Some(memory_offset) = memory_resize(interpreter, memory_offset, len) else {
return;
}

// resize memory
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
resize_memory!(interpreter, memory_offset, len);
};

// Note: this can't panic because we resized memory to fit.
interpreter.shared_memory.set_data(
memory_offset,
data_offset,
len,
&interpreter.return_data_buffer,
interpreter.return_data_buffer.as_ref(),
);
}

Expand Down Expand Up @@ -182,6 +169,23 @@ pub fn gas<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
push!(interpreter, U256::from(interpreter.gas.remaining()));
}

// common logic for copying data from a source buffer to the EVM's memory
pub fn memory_resize(
interpreter: &mut Interpreter,
memory_offset: U256,
len: usize,
) -> Option<usize> {
// safe to cast usize to u64
gas_or_fail!(interpreter, gas::copy_cost_verylow(len as u64), None);
if len == 0 {
return None;
}
let memory_offset = as_usize_or_fail_ret!(interpreter, memory_offset, None);
resize_memory!(interpreter, memory_offset, len, None);

Some(memory_offset)
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion documentation/src/crates/revm/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Functions can be grouped in five categories and are marked in that way in the co
* Pre-execution functions: [`PreExecutionHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/pre_execution.rs)
* Execution functions: [`ExecutionHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/execution.rs)
* Post-execution functions: [`PostExecutionHandler`](https://github.com/bluealloy/revm/blob/main/crates/revm/src/handler/handle_types/post_execution.rs)
* Instruction table: [`InstructionTable`](https://github.com/bluealloy/revm/blob/main/crates/interpreter/src/opcode.rs)
* Instruction table: [`InstructionTable`](https://github.com/bluealloy/revm/blob/main/crates/interpreter/src/table.rs)

### Handle Registers

Expand Down

0 comments on commit 47169b3

Please sign in to comment.