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

Shared memory between calls #673

Merged
merged 23 commits into from Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3d09aa5
feat: shared memory primitive
Aug 14, 2023
9ad9da8
feat(shared_memory): available inside interpreter and ready to use
Aug 23, 2023
1e69907
chore(memory): replaced memory with shared memory
Aug 24, 2023
b415024
chore(shared_memory): tests, completed replaced old memory, some bug …
Aug 25, 2023
caad052
chore(shared_memory): moved under interpreter crate; small refactorin…
Aug 29, 2023
2bcddef
chore(shared_memory): memory limit feature management
Aug 30, 2023
bdd1ccc
chore(shared_memory): make benchmarks use right amount of gas for pro…
Aug 31, 2023
e91224e
chore(shared_memory): formatting
Aug 31, 2023
ed4079f
chore(shared_memory): improved shared_memory! macro
Sep 1, 2023
3c5946c
chore(shared_memory): replace Rc<Refcell with mutable reference
Sep 5, 2023
27978c7
chore(shared_memory): dropped f64::sqrt for no_std code
Sep 5, 2023
b524b18
fix(shared_memory): conflicts
Sep 23, 2023
eb74892
Merge branch 'main' of https://github.com/lorenzofero/revm into share…
Sep 23, 2023
c7945eb
fix(shared_memory): restore free_context_memory where needed
Sep 26, 2023
07ece23
chore(SharedMemory): refactoring
Sep 27, 2023
23a1191
chore(SharedMemory): internal refactoring part 2
Sep 29, 2023
6b6119e
chore(SharedMemory): sync
Oct 3, 2023
39efbe9
chore(SharedMemory): test with more allocations
Oct 4, 2023
986a03b
chore(SharedMemory): refactoring for simplifying logic
Oct 4, 2023
181eb05
chore(SharedMemory): sync
Oct 6, 2023
1da0f38
chore(SharedMemory): remove memory file from sync
Oct 6, 2023
b6ed337
chore(SharedMemory): docs
Oct 6, 2023
b82ea0d
fix(SharedMemory): restore cfg memory limit
Oct 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion crates/interpreter/src/host.rs
Expand Up @@ -2,6 +2,7 @@ use crate::primitives::Bytecode;
use crate::{
primitives::{Address, Bytes, Env, B256, U256},
CallInputs, CreateInputs, Gas, InstructionResult, Interpreter, SelfDestructResult,
SharedMemory,
};
use alloc::vec::Vec;
pub use dummy::DummyHost;
Expand Down Expand Up @@ -63,12 +64,17 @@ pub trait Host {
fn log(&mut self, address: Address, topics: Vec<B256>, data: Bytes);

/// Invoke a call operation.
fn call(&mut self, input: &mut CallInputs) -> (InstructionResult, Gas, Bytes);
fn call(
&mut self,
input: &mut CallInputs,
shared_memory: &mut SharedMemory,
) -> (InstructionResult, Gas, Bytes);

/// Invoke a create operation.
fn create(
&mut self,
inputs: &mut CreateInputs,
shared_memory: &mut SharedMemory,
) -> (InstructionResult, Option<Address>, Gas, Bytes);

/// Mark `address` to be deleted, with funds transferred to `target`.
Expand Down
8 changes: 7 additions & 1 deletion crates/interpreter/src/host/dummy.rs
Expand Up @@ -2,6 +2,7 @@ use crate::primitives::{hash_map::Entry, Bytecode, Bytes, HashMap, U256};
use crate::{
primitives::{Address, Env, Log, B256, KECCAK_EMPTY},
CallInputs, CreateInputs, Gas, Host, InstructionResult, Interpreter, SelfDestructResult,
SharedMemory,
};
use alloc::vec::Vec;

Expand Down Expand Up @@ -138,12 +139,17 @@ impl Host for DummyHost {
fn create(
&mut self,
_inputs: &mut CreateInputs,
_shared_memory: &mut SharedMemory,
) -> (InstructionResult, Option<Address>, Gas, Bytes) {
panic!("Create is not supported for this host")
}

#[inline]
fn call(&mut self, _input: &mut CallInputs) -> (InstructionResult, Gas, Bytes) {
fn call(
&mut self,
_input: &mut CallInputs,
_shared_memory: &mut SharedMemory,
) -> (InstructionResult, Gas, Bytes) {
panic!("Call is not supported for this host")
}
}
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/control.rs
Expand Up @@ -53,7 +53,7 @@ fn return_inner(interpreter: &mut Interpreter, result: InstructionResult) {
// important: offset must be ignored if len is zero
if len != 0 {
let offset = as_usize_or_fail!(interpreter, offset);
memory_resize!(interpreter, offset, len);
shared_memory_resize!(interpreter, offset, len);
interpreter.return_offset = offset;
}
interpreter.return_len = len;
Expand Down
28 changes: 14 additions & 14 deletions crates/interpreter/src/instructions/host.rs
Expand Up @@ -109,11 +109,11 @@ pub fn extcodecopy<H: Host, SPEC: Spec>(interpreter: &mut Interpreter, host: &mu
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
let code_offset = min(as_usize_saturated!(code_offset), code.len());
memory_resize!(interpreter, memory_offset, len);
shared_memory_resize!(interpreter, memory_offset, len);

// Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it
interpreter
.memory
.shared_memory
.set_data(memory_offset, code_offset, len, code.bytes());
}

Expand Down Expand Up @@ -197,8 +197,8 @@ pub fn log<H: Host, const N: usize>(interpreter: &mut Interpreter, host: &mut H)
Bytes::new()
} else {
let offset = as_usize_or_fail!(interpreter, offset);
memory_resize!(interpreter, offset, len);
Bytes::copy_from_slice(interpreter.memory.slice(offset, len))
shared_memory_resize!(interpreter, offset, len);
Bytes::copy_from_slice(interpreter.shared_memory.slice(offset, len))
};

if interpreter.stack.len() < N {
Expand Down Expand Up @@ -273,8 +273,8 @@ pub fn prepare_create_inputs<H: Host, const IS_CREATE2: bool, SPEC: Spec>(
}

let code_offset = as_usize_or_fail!(interpreter, code_offset);
memory_resize!(interpreter, code_offset, len);
Bytes::copy_from_slice(interpreter.memory.slice(code_offset, len))
shared_memory_resize!(interpreter, code_offset, len);
Bytes::copy_from_slice(interpreter.shared_memory.slice(code_offset, len))
};

let scheme = if IS_CREATE2 {
Expand Down Expand Up @@ -315,7 +315,8 @@ pub fn create<H: Host, const IS_CREATE2: bool, SPEC: Spec>(
return;
};

let (return_reason, address, gas, return_data) = host.create(&mut create_input);
let (return_reason, address, gas, return_data) =
host.create(&mut create_input, interpreter.shared_memory);

interpreter.return_data_buffer = match return_reason {
// Save data to return data buffer if the create reverted
Expand Down Expand Up @@ -399,16 +400,16 @@ fn prepare_call_inputs<H: Host, SPEC: Spec>(
let in_len = as_usize_or_fail!(interpreter, in_len);
let input = if in_len != 0 {
let in_offset = as_usize_or_fail!(interpreter, in_offset);
memory_resize!(interpreter, in_offset, in_len);
Bytes::copy_from_slice(interpreter.memory.slice(in_offset, in_len))
shared_memory_resize!(interpreter, in_offset, in_len);
Bytes::copy_from_slice(interpreter.shared_memory.slice(in_offset, in_len))
} else {
Bytes::new()
};

*result_len = as_usize_or_fail!(interpreter, out_len);
*result_offset = if *result_len != 0 {
let out_offset = as_usize_or_fail!(interpreter, out_offset);
memory_resize!(interpreter, out_offset, *result_len);
shared_memory_resize!(interpreter, out_offset, *result_len);
out_offset
} else {
usize::MAX //unrealistic value so we are sure it is not used
Expand Down Expand Up @@ -535,10 +536,9 @@ pub fn call_inner<H: Host, SPEC: Spec>(
};

// Call host to interact with target contract
let (reason, gas, return_data) = host.call(&mut call_input);
let (reason, gas, return_data) = host.call(&mut call_input, interpreter.shared_memory);

interpreter.return_data_buffer = return_data;

let target_len = min(out_len, interpreter.return_data_buffer.len());

match reason {
Expand All @@ -549,7 +549,7 @@ pub fn call_inner<H: Host, SPEC: Spec>(
interpreter.gas.record_refund(gas.refunded());
}
interpreter
.memory
.shared_memory
.set(out_offset, &interpreter.return_data_buffer[..target_len]);
push!(interpreter, U256::from(1));
}
Expand All @@ -558,7 +558,7 @@ pub fn call_inner<H: Host, SPEC: Spec>(
interpreter.gas.erase_cost(gas.remaining());
}
interpreter
.memory
.shared_memory
.set(out_offset, &interpreter.return_data_buffer[..target_len]);
push!(interpreter, U256::ZERO);
}
Expand Down
8 changes: 4 additions & 4 deletions crates/interpreter/src/instructions/macros.rs
Expand Up @@ -50,26 +50,26 @@ macro_rules! gas_or_fail {
};
}

macro_rules! memory_resize {
macro_rules! shared_memory_resize {
($interp:expr, $offset:expr, $len:expr) => {
if let Some(new_size) =
crate::interpreter::next_multiple_of_32($offset.saturating_add($len))
{
#[cfg(feature = "memory_limit")]
if new_size > ($interp.memory_limit as usize) {
Copy link
Member

Choose a reason for hiding this comment

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

Should we reintroduce the memory limit?

if $interp.shared_memory.limit_reached(new_size) {
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
return;
}

if new_size > $interp.memory.len() {
if new_size > $interp.shared_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::MemoryLimitOOG;
return;
}
}
$interp.memory.resize(new_size);
$interp.shared_memory.resize(new_size);
}
} else {
$interp.instruction_result = InstructionResult::MemoryOOG;
Expand Down
24 changes: 15 additions & 9 deletions crates/interpreter/src/instructions/memory.rs
Expand Up @@ -9,32 +9,38 @@ pub fn mload<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index);
let index = as_usize_or_fail!(interpreter, index);
memory_resize!(interpreter, index, 32);
shared_memory_resize!(interpreter, index, 32);
push!(
interpreter,
U256::from_be_bytes::<32>(interpreter.memory.slice(index, 32).try_into().unwrap())
U256::from_be_bytes::<32>(
interpreter
.shared_memory
.slice(index, 32)
.try_into()
.unwrap()
)
);
}

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

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

pub fn msize<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::BASE);
push!(interpreter, U256::from(interpreter.memory.len()));
push!(interpreter, U256::from(interpreter.shared_memory.len()));
}

// EIP-5656: MCOPY - Memory copying instruction
Expand All @@ -53,7 +59,7 @@ pub fn mcopy<H: Host, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H)
let dst = as_usize_or_fail!(interpreter, dst);
let src = as_usize_or_fail!(interpreter, src);
// resize memory
memory_resize!(interpreter, max(dst, src), len);
shared_memory_resize!(interpreter, max(dst, src), len);
// copy memory in place
interpreter.memory.copy(dst, src, len);
interpreter.shared_memory.copy(dst, src, len);
}
23 changes: 13 additions & 10 deletions crates/interpreter/src/instructions/system.rs
Expand Up @@ -12,8 +12,8 @@ pub fn keccak256<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
KECCAK_EMPTY
} else {
let from = as_usize_or_fail!(interpreter, from);
memory_resize!(interpreter, from, len);
crate::primitives::keccak256(interpreter.memory.slice(from, len))
shared_memory_resize!(interpreter, from, len);
crate::primitives::keccak256(interpreter.shared_memory.slice(from, len))
};

push_b256!(interpreter, hash);
Expand Down Expand Up @@ -43,10 +43,10 @@ pub fn codecopy<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
let code_offset = as_usize_saturated!(code_offset);
memory_resize!(interpreter, memory_offset, len);
shared_memory_resize!(interpreter, memory_offset, len);

// Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it
interpreter.memory.set_data(
interpreter.shared_memory.set_data(
memory_offset,
code_offset,
len,
Expand Down Expand Up @@ -89,12 +89,15 @@ pub fn calldatacopy<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
let data_offset = as_usize_saturated!(data_offset);
memory_resize!(interpreter, memory_offset, len);
shared_memory_resize!(interpreter, memory_offset, len);

// Safety: set_data is unsafe function and memory_resize ensures us that it is safe to call it
interpreter
.memory
.set_data(memory_offset, data_offset, len, &interpreter.contract.input);
interpreter.shared_memory.set_data(
memory_offset,
data_offset,
len,
&interpreter.contract.input,
);
}

/// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY
Expand All @@ -121,8 +124,8 @@ pub fn returndatacopy<H: Host, SPEC: Spec>(interpreter: &mut Interpreter, _host:
}
if len != 0 {
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
memory_resize!(interpreter, memory_offset, len);
interpreter.memory.set(
shared_memory_resize!(interpreter, memory_offset, len);
interpreter.shared_memory.set(
memory_offset,
&interpreter.return_data_buffer[data_offset..data_end],
);
Expand Down