Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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
9 changes: 7 additions & 2 deletions crates/interpreter/src/gas/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ 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)))
copy_cost(VERYLOW, len, COPY)
}

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

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

/// `LOG` opcode cost calculation.
Expand Down
80 changes: 33 additions & 47 deletions crates/interpreter/src/instructions/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,12 @@ 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 {
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);

let len = as_usize_or_fail!(interpreter, len);
// Inform the optimizer that the bytecode cannot be EOF to remove a bounds check.
assume!(!interpreter.contract.bytecode.is_eof());
// Note: this can't panic because we resized memory to fit.
interpreter.shared_memory.set_data(
memory_offset,
code_offset,
len,
interpreter.contract.bytecode.original_byte_slice(),
);
let source = interpreter.contract.bytecode.original_byte_slice().as_ptr();
copy_to_memory(interpreter, memory_offset, code_offset, len, source);
}

pub fn calldataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down Expand Up @@ -94,21 +82,9 @@ 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 {
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);

// Note: this can't panic because we resized memory to fit.
interpreter.shared_memory.set_data(
memory_offset,
data_offset,
len,
&interpreter.contract.input,
);
let source = interpreter.contract.input.as_ptr();
copy_to_memory(interpreter, memory_offset, data_offset, len, source);
}

/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
Expand All @@ -127,8 +103,6 @@ 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);

Expand All @@ -139,22 +113,8 @@ pub fn returndatacopy<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interprete
return;
}

// if len is zero memory is not resized.
if len == 0 {
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,
);
let source = interpreter.return_data_buffer.as_ptr();
copy_to_memory(interpreter, memory_offset, data_offset, len, source);
}

/// Part of EOF `<https://eips.ethereum.org/EIPS/eip-7069>`.
Expand All @@ -179,6 +139,32 @@ pub fn returndataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &m
*offset = B256::from(output).into();
}

// common logic for copying data from a source buffer to the EVM's memory
fn copy_to_memory(
interpreter: &mut Interpreter,
memory_offset: U256,
data_offset: usize,
len: usize,
source: *const u8,
Copy link
Collaborator

@DaniPopes DaniPopes Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source's length is not len, this should be *const [u8]. This is why tests are failing

) {
Copy link
Member

@rakita rakita Jul 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would return a Option<usize> here that represents memory_offset.
https://github.com/bluealloy/revm/pull/1655/files#r1694998333

Without return function silently fails, and can work only if it is in the last line of instruction.

gas_or_fail!(interpreter, gas::verylowcopy_cost(len as u64));
if len == 0 {
return;
}
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.
unsafe {
interpreter.shared_memory.set_data(
memory_offset,
data_offset,
len,
std::slice::from_raw_parts(source, len),
);
}
}

pub fn gas<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::BASE);
push!(interpreter, U256::from(interpreter.gas.remaining()));
Expand Down