Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into eof
Browse files Browse the repository at this point in the history
  • Loading branch information
rakita committed Apr 7, 2024
2 parents 8162f32 + 11e819c commit 63ffb17
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 50 deletions.
23 changes: 11 additions & 12 deletions crates/interpreter/src/instructions/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,27 @@ pub fn rjumpv<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {

pub fn jump<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::MID);
pop!(interpreter, dest);
jump_inner(interpreter, dest);
pop!(interpreter, target);
jump_inner(interpreter, target);
}

pub fn jumpi<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::HIGH);
pop!(interpreter, dest, value);
if value != U256::ZERO {
jump_inner(interpreter, dest);
pop!(interpreter, target, cond);
if cond != U256::ZERO {
jump_inner(interpreter, target);
}
}

#[inline]
fn jump_inner(interpreter: &mut Interpreter, dest: U256) {
let dest = as_usize_or_fail!(interpreter, dest, InstructionResult::InvalidJump);
if interpreter.contract.is_valid_jump(dest) {
// SAFETY: In analysis we are checking create our jump table and we do check above to be
// sure that jump is safe to execute.
interpreter.instruction_pointer = unsafe { interpreter.bytecode.as_ptr().add(dest) };
} else {
fn jump_inner(interpreter: &mut Interpreter, target: U256) {
let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
if !interpreter.contract.is_valid_jump(target) {
interpreter.instruction_result = InstructionResult::InvalidJump;
return;
}
// SAFETY: `is_valid_jump` ensures that `dest` is in bounds.
interpreter.instruction_pointer = unsafe { interpreter.bytecode.as_ptr().add(target) };
}

pub fn jumpdest_or_nop<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
7 changes: 3 additions & 4 deletions crates/interpreter/src/instructions/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,13 @@ pub fn blockhash<H: Host + ?Sized>(interpreter: &mut Interpreter, host: &mut H)
}

pub fn sload<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
pop!(interpreter, index);

let Some((value, is_cold)) = host.sload(interpreter.contract.target_address, index) else {
pop_top!(interpreter, index);
let Some((value, is_cold)) = host.sload(interpreter.contract.target_address, *index) else {
interpreter.instruction_result = InstructionResult::FatalExternalError;
return;
};
gas!(interpreter, gas::sload_cost(SPEC::SPEC_ID, is_cold));
push!(interpreter, value);
*index = value;
}

pub fn sstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
Expand Down
24 changes: 12 additions & 12 deletions crates/interpreter/src/instructions/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@ use core::cmp::max;

pub fn mload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, item);
let index = as_usize_or_fail!(interpreter, item);
resize_memory!(interpreter, index, 32);
*item = interpreter.shared_memory.get_u256(index);
pop_top!(interpreter, top);
let offset = as_usize_or_fail!(interpreter, top);
resize_memory!(interpreter, offset, 32);
*top = interpreter.shared_memory.get_u256(offset);
}

pub fn mstore<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index, value);
let index = as_usize_or_fail!(interpreter, index);
resize_memory!(interpreter, index, 32);
interpreter.shared_memory.set_u256(index, value);
pop!(interpreter, offset, value);
let offset = as_usize_or_fail!(interpreter, offset);
resize_memory!(interpreter, offset, 32);
interpreter.shared_memory.set_u256(offset, value);
}

pub fn mstore8<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index, value);
let index = as_usize_or_fail!(interpreter, index);
resize_memory!(interpreter, index, 1);
interpreter.shared_memory.set_byte(index, value.byte(0))
pop!(interpreter, offset, value);
let offset = as_usize_or_fail!(interpreter, offset);
resize_memory!(interpreter, offset, 1);
interpreter.shared_memory.set_byte(offset, value.byte(0))
}

pub fn msize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
22 changes: 22 additions & 0 deletions crates/interpreter/src/instructions/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,28 @@ impl OpCode {
pub const fn get(self) -> u8 {
self.0
}

/// Returns true if the opcode modifies memory.
/// <https://bluealloy.github.io/revm/crates/interpreter/memory.html#opcodes>
/// <https://github.com/crytic/evm-opcodes>
#[inline]
pub const fn modifies_memory(&self) -> bool {
matches!(
*self,
OpCode::EXTCODECOPY
| OpCode::MLOAD
| OpCode::MSTORE
| OpCode::MSTORE8
| OpCode::MCOPY
| OpCode::CODECOPY
| OpCode::CALLDATACOPY
| OpCode::RETURNDATACOPY
| OpCode::CALL
| OpCode::CALLCODE
| OpCode::DELEGATECALL
| OpCode::STATICCALL
)
}
}

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down
42 changes: 24 additions & 18 deletions crates/interpreter/src/instructions/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ use crate::{
primitives::{Spec, B256, KECCAK_EMPTY, U256},
Host, InstructionResult, Interpreter,
};
use core::ptr;

pub fn keccak256<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
pop!(interpreter, from, len);
let len = as_usize_or_fail!(interpreter, len);
pop_top!(interpreter, offset, len_ptr);
let len = as_usize_or_fail!(interpreter, len_ptr);
gas_or_fail!(interpreter, gas::keccak256_cost(len as u64));
let hash = if len == 0 {
KECCAK_EMPTY
} else {
let from = as_usize_or_fail!(interpreter, from);
let from = as_usize_or_fail!(interpreter, offset);
resize_memory!(interpreter, from, len);
crate::primitives::keccak256(interpreter.shared_memory.slice(from, len))
};

push_b256!(interpreter, hash);
*len_ptr = hash.into();
}

pub fn address<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down Expand Up @@ -56,19 +56,25 @@ pub fn codecopy<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H)

pub fn calldataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, offset);
let offset = as_usize_saturated!(offset);
let load = if offset < interpreter.contract.input.len() {
let have_bytes = 32.min(interpreter.contract.input.len() - offset);
let mut bytes = [0u8; 32];
bytes[..have_bytes]
.copy_from_slice(&interpreter.contract.input[offset..offset + have_bytes]);
B256::new(bytes)
} else {
B256::ZERO
};

push_b256!(interpreter, load);
pop_top!(interpreter, offset_ptr);
let mut word = B256::ZERO;
let offset = as_usize_saturated!(offset_ptr);
if offset < interpreter.contract.input.len() {
let count = 32.min(interpreter.contract.input.len() - offset);
// SAFETY: count is bounded by the calldata length.
// This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
// raw pointers as apparently the compiler cannot optimize the slice version, and using
// `get_unchecked` twice is uglier.
debug_assert!(count <= 32 && offset + count <= interpreter.contract.input.len());
unsafe {
ptr::copy_nonoverlapping(
interpreter.contract.input.as_ptr().add(offset),
word.as_mut_ptr(),
count,
)
};
}
*offset_ptr = word.into();
}

pub fn calldatasize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/interpreter/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl Stack {
/// unchanged.
#[inline]
pub fn push(&mut self, value: U256) -> Result<(), InstructionResult> {
// allows the compiler to optimize out the `Vec::push` capacity check
// Allows the compiler to optimize out the `Vec::push` capacity check.
assume!(self.data.capacity() == STACK_LIMIT);
if self.data.len() == STACK_LIMIT {
return Err(InstructionResult::StackOverflow);
Expand Down
7 changes: 4 additions & 3 deletions crates/revm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,13 +393,14 @@ impl<EXT, DB: Database> Evm<'_, EXT, DB> {
}

impl<EXT, DB: Database> Host for Evm<'_, EXT, DB> {
fn env_mut(&mut self) -> &mut Env {
&mut self.context.evm.env
}
fn env(&self) -> &Env {
&self.context.evm.env
}

fn env_mut(&mut self) -> &mut Env {
&mut self.context.evm.env
}

fn block_hash(&mut self, number: U256) -> Option<B256> {
self.context
.evm
Expand Down

0 comments on commit 63ffb17

Please sign in to comment.