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

Cancun support #3

Merged
merged 6 commits into from
May 22, 2024
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
19 changes: 18 additions & 1 deletion core/src/eval/misc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::Control;
use crate::{ExitError, ExitFatal, ExitRevert, ExitSucceed, Machine};
use core::cmp::min;
use core::cmp::{max, min};
use primitive_types::{H256, U256};

#[inline]
Expand Down Expand Up @@ -92,6 +92,23 @@ pub fn mload(state: &mut Machine) -> Control {
Control::Continue(1)
}

/// Support for EIP-5656: MCOPY instruction.
#[inline]
pub fn mcopy(state: &mut Machine) -> Control {
pop_u256!(state, dst, src, len);
try_or_fail!(state.memory.resize_offset(max(dst, src), len));

if len.is_zero() {
return Control::Continue(1);
}

let dst = as_usize_or_fail!(dst);
let src = as_usize_or_fail!(src);
let len = as_usize_or_fail!(len);
state.memory.copy(dst, src, len);
Control::Continue(1)
}

#[inline]
pub fn mstore(state: &mut Machine) -> Control {
pop_u256!(state, index);
Expand Down
5 changes: 5 additions & 0 deletions core/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ fn eval_jumpdest(_state: &mut Machine, _opcode: Opcode, _position: usize) -> Con
Control::Continue(1)
}

fn eval_mcopy(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control {
self::misc::mcopy(state)
}

fn eval_push0(state: &mut Machine, _opcode: Opcode, position: usize) -> Control {
self::misc::push(state, 0, position)
}
Expand Down Expand Up @@ -497,6 +501,7 @@ pub fn eval(state: &mut Machine, opcode: Opcode, position: usize) -> Control {
table[Opcode::PC.as_usize()] = eval_pc as _;
table[Opcode::MSIZE.as_usize()] = eval_msize as _;
table[Opcode::JUMPDEST.as_usize()] = eval_jumpdest as _;
table[Opcode::MCOPY.as_usize()] = eval_mcopy as _;

table[Opcode::PUSH0.as_usize()] = eval_push0 as _;
table[Opcode::PUSH1.as_usize()] = eval_push1 as _;
Expand Down
58 changes: 56 additions & 2 deletions core/src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{ExitError, ExitFatal};
use alloc::vec::Vec;
use core::cmp::min;
use core::cmp::{max, min};
use core::ops::{BitAnd, Not};
use primitive_types::U256;

Expand Down Expand Up @@ -181,6 +181,15 @@ impl Memory {

self.set(memory_offset, data, Some(ulen))
}

/// Copies part of the memory inside another part of itself.
pub fn copy(&mut self, dst: usize, src: usize, len: usize) {
let resize_offset = max(dst, src);
if self.data.len() < resize_offset + len {
self.data.resize(resize_offset + len, 0);
}
self.data.copy_within(src..src + len, dst);
}
}

/// Rounds up `x` to the closest multiple of 32. If `x % 32 == 0` then `x` is returned.
Expand All @@ -192,7 +201,7 @@ fn next_multiple_of_32(x: U256) -> Option<U256> {

#[cfg(test)]
mod tests {
use super::{next_multiple_of_32, U256};
use super::{next_multiple_of_32, Memory, U256};

#[test]
fn test_next_multiple_of_32() {
Expand Down Expand Up @@ -225,4 +234,49 @@ mod tests {
}
}
}

#[test]
fn test_memory_copy_works() {
// Create a new instance of memory
let mut memory = Memory::new(100usize);

// Set the [0,0,0,1,2,3,4] array as memory data.
//
// We insert the [1,2,3,4] array on index 3,
// that's why we have the zero padding at the beginning.
memory.set(3usize, &[1u8, 2u8, 3u8, 4u8], None).unwrap();
assert_eq!(memory.data(), &[0u8, 0u8, 0u8, 1u8, 2u8, 3u8, 4u8].to_vec());

// Copy 1 byte into index 0.
// As the length is 1, we only copy the byte present on index 3.
memory.copy(0usize, 3usize, 1usize);

// Now the new memory data results in [1,0,0,1,2,3,4]
assert_eq!(memory.data(), &[1u8, 0u8, 0u8, 1u8, 2u8, 3u8, 4u8].to_vec());
}

#[test]
fn test_memory_copy_resize() {
// Create a new instance of memory
let mut memory = Memory::new(100usize);

// Set the [0,0,0,1,2,3,4] array as memory data.
//
// We insert the [1,2,3,4] array on index 3,
// that's why we have the zero padding at the beginning.
memory.set(3usize, &[1u8, 2u8, 3u8, 4u8], None).unwrap();
assert_eq!(memory.data(), &[0u8, 0u8, 0u8, 1u8, 2u8, 3u8, 4u8].to_vec());

// Copy 2 bytes into index 3.
// As the length is 2, we copy the bytes present on indexes 6 and 7,
// which are [4,0].
memory.copy(3usize, 6usize, 2usize);

// Now the new memory data results in [0, 0, 0, 4, 0, 3, 4, 0].
// An extra element is added due to rezising.
assert_eq!(
memory.data(),
&[0u8, 0u8, 0u8, 4u8, 0u8, 3u8, 4u8, 0u8].to_vec()
);
}
}
6 changes: 6 additions & 0 deletions core/src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ impl Opcode {
pub const MSIZE: Opcode = Opcode(0x59);
/// `JUMPDEST`
pub const JUMPDEST: Opcode = Opcode(0x5b);
/// `MCOPY`
pub const MCOPY: Opcode = Opcode(0x5e);

/// `PUSHn`
pub const PUSH0: Opcode = Opcode(0x5f);
Expand Down Expand Up @@ -225,6 +227,10 @@ impl Opcode {
pub const SSTORE: Opcode = Opcode(0x55);
/// `GAS`
pub const GAS: Opcode = Opcode(0x5a);
/// `TLOAD`
pub const TLOAD: Opcode = Opcode(0x5c);
/// `TSTORE`
pub const TSTORE: Opcode = Opcode(0x5d);
/// `LOGn`
pub const LOG0: Opcode = Opcode(0xa0);
pub const LOG1: Opcode = Opcode(0xa1);
Expand Down
8 changes: 8 additions & 0 deletions gasometer/src/costs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ pub fn sstore_cost(
)
}

pub fn tload_cost(config: &Config) -> Result<u64, ExitError> {
Ok(config.gas_storage_read_warm)
}

pub fn tstore_cost(config: &Config) -> Result<u64, ExitError> {
Ok(config.gas_storage_read_warm)
}

pub fn suicide_cost(value: U256, is_cold: bool, target_exists: bool, config: &Config) -> u64 {
let eip161 = !config.empty_considered_exists;
let should_charge_topup = if eip161 {
Expand Down
21 changes: 20 additions & 1 deletion gasometer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ pub fn dynamic_opcode_cost<H: Handler>(
len: U256::from_big_endian(&stack.peek(3)?[..]),
}
}
Opcode::CALLDATACOPY | Opcode::CODECOPY => GasCost::VeryLowCopy {
Opcode::CALLDATACOPY | Opcode::CODECOPY | Opcode::MCOPY => GasCost::VeryLowCopy {
len: U256::from_big_endian(&stack.peek(2)?[..]),
},
Opcode::EXP => GasCost::Exp {
Expand All @@ -599,6 +599,7 @@ pub fn dynamic_opcode_cost<H: Handler>(
target_is_cold: handler.is_cold(address, Some(index))?,
}
}
Opcode::TLOAD => GasCost::TLoad,

Opcode::DELEGATECALL if config.has_delegate_call => {
let target = stack.peek(1)?.into();
Expand Down Expand Up @@ -632,6 +633,7 @@ pub fn dynamic_opcode_cost<H: Handler>(
target_is_cold: handler.is_cold(address, Some(index))?,
}
}
Opcode::TSTORE if !is_static => GasCost::TStore,
Opcode::LOG0 if !is_static => GasCost::Log {
n: 0,
len: U256::from_big_endian(&stack.peek(1)?[..]),
Expand Down Expand Up @@ -704,6 +706,16 @@ pub fn dynamic_opcode_cost<H: Handler>(
len: U256::from_big_endian(&stack.peek(1)?[..]),
}),

Opcode::MCOPY => {
let top0 = U256::from_big_endian(&stack.peek(0)?[..]);
let top1 = U256::from_big_endian(&stack.peek(1)?[..]);
let offset = top0.max(top1);
Some(MemoryCost {
offset,
len: U256::from_big_endian(&stack.peek(2)?[..]),
})
}

Opcode::CODECOPY | Opcode::CALLDATACOPY | Opcode::RETURNDATACOPY => Some(MemoryCost {
offset: U256::from_big_endian(&stack.peek(0)?[..]),
len: U256::from_big_endian(&stack.peek(2)?[..]),
Expand Down Expand Up @@ -867,6 +879,9 @@ impl<'config> Inner<'config> {
target_is_cold,
} => costs::sstore_cost(original, current, new, gas, target_is_cold, self.config)?,

GasCost::TLoad => costs::tload_cost(self.config)?,
GasCost::TStore => costs::tstore_cost(self.config)?,

GasCost::Sha3 { len } => costs::sha3_cost(len)?,
GasCost::Log { n, len } => costs::log_cost(n, len)?,
GasCost::VeryLowCopy { len } => costs::verylowcopy_cost(len)?,
Expand Down Expand Up @@ -1053,6 +1068,10 @@ pub enum GasCost {
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
},
/// Gas cost for `TLOAD`.
TLoad,
/// Gas cost for `TSTORE`.
TStore,
}

/// Storage opcode will access. Used for tracking accessed storage (EIP-2929).
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ pub fn eval<H: Handler>(state: &mut Runtime, opcode: Opcode, handler: &mut H) ->
Opcode::SLOAD => system::sload(state, handler),
Opcode::SSTORE => system::sstore(state, handler),
Opcode::GAS => system::gas(state, handler),
Opcode::TLOAD => system::tload(state, handler),
Opcode::TSTORE => system::tstore(state, handler),
Opcode::LOG0 => system::log(state, 0, handler),
Opcode::LOG1 => system::log(state, 1, handler),
Opcode::LOG2 => system::log(state, 2, handler),
Expand Down
17 changes: 17 additions & 0 deletions runtime/src/eval/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,23 @@ pub fn gas<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
Control::Continue
}

pub fn tload<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop!(runtime, index);
let value = handler.transient_storage(runtime.context.address, index);
push!(runtime, value);

Control::Continue
}

pub fn tstore<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop!(runtime, index, value);

match handler.set_transient_storage(runtime.context.address, index, value) {
Ok(()) => Control::Continue,
Err(e) => Control::Exit(e.into()),
}
}

pub fn log<H: Handler>(runtime: &mut Runtime, n: u8, handler: &mut H) -> Control<H> {
pop_u256!(runtime, offset, len);

Expand Down
10 changes: 10 additions & 0 deletions runtime/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub trait Handler {
fn code(&self, address: H160) -> Vec<u8>;
/// Get storage value of address at index.
fn storage(&self, address: H160, index: H256) -> H256;
/// Get transient storage value of address at index.
fn transient_storage(&self, address: H160, index: H256) -> H256;

/// Get original storage value of address at index.
fn original_storage(&self, address: H160, index: H256) -> H256;

Expand Down Expand Up @@ -77,6 +80,13 @@ pub trait Handler {

/// Set storage value of address at index.
fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError>;
/// Set transient storage value of address at index, transient storage gets discarded after every transaction. (see EIP-1153)
fn set_transient_storage(
&mut self,
address: H160,
index: H256,
value: H256,
) -> Result<(), ExitError>;
/// Create a log owned by address with given topics and data.
fn log(&mut self, address: H160, topics: Vec<H256>, data: Vec<u8>) -> Result<(), ExitError>;
/// Mark an address to be deleted, with funds transferred to target.
Expand Down
32 changes: 32 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ pub struct Config {
pub has_push0: bool,
/// Whether the gasometer is running in estimate mode.
pub estimate: bool,
/// Has EIP-6780. See [EIP-6780](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-6780.md)
pub has_eip_6780: bool,
}

impl Config {
Expand Down Expand Up @@ -342,6 +344,7 @@ impl Config {
has_base_fee: false,
has_push0: false,
estimate: false,
has_eip_6780: false,
}
}

Expand Down Expand Up @@ -396,6 +399,7 @@ impl Config {
has_base_fee: false,
has_push0: false,
estimate: false,
has_eip_6780: false,
}
}

Expand All @@ -419,6 +423,11 @@ impl Config {
Self::config_with_derived_values(DerivedConfigInputs::shanghai())
}

/// Cancun hard fork configuration.
pub const fn cancun() -> Config {
Self::config_with_derived_values(DerivedConfigInputs::cancun())
}

const fn config_with_derived_values(inputs: DerivedConfigInputs) -> Config {
let DerivedConfigInputs {
gas_storage_read_warm,
Expand All @@ -430,6 +439,7 @@ impl Config {
disallow_executable_format,
warm_coinbase_address,
max_initcode_size,
has_eip_6780,
} = inputs;

// See https://eips.ethereum.org/EIPS/eip-2929
Expand Down Expand Up @@ -493,6 +503,7 @@ impl Config {
has_base_fee,
has_push0,
estimate: false,
has_eip_6780,
}
}
}
Expand All @@ -509,6 +520,7 @@ struct DerivedConfigInputs {
disallow_executable_format: bool,
warm_coinbase_address: bool,
max_initcode_size: Option<usize>,
has_eip_6780: bool,
}

impl DerivedConfigInputs {
Expand All @@ -523,6 +535,7 @@ impl DerivedConfigInputs {
disallow_executable_format: false,
warm_coinbase_address: false,
max_initcode_size: None,
has_eip_6780: false,
}
}

Expand All @@ -537,6 +550,7 @@ impl DerivedConfigInputs {
disallow_executable_format: true,
warm_coinbase_address: false,
max_initcode_size: None,
has_eip_6780: false,
}
}

Expand All @@ -551,6 +565,7 @@ impl DerivedConfigInputs {
disallow_executable_format: true,
warm_coinbase_address: false,
max_initcode_size: None,
has_eip_6780: false,
}
}

Expand All @@ -566,6 +581,23 @@ impl DerivedConfigInputs {
warm_coinbase_address: true,
// 2 * 24576 as per EIP-3860
max_initcode_size: Some(0xC000),
has_eip_6780: false,
}
}

const fn cancun() -> Self {
Self {
gas_storage_read_warm: 100,
gas_sload_cold: 2100,
gas_access_list_storage_key: 1900,
decrease_clears_refund: true,
has_base_fee: true,
has_push0: true,
disallow_executable_format: true,
warm_coinbase_address: true,
// 2 * 24576 as per EIP-3860
max_initcode_size: Some(0xC000),
has_eip_6780: true,
}
}
}
Loading