Skip to content

feat(devnet2): eip7907 Meter Contract Code Size And Increase Limit #2605

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

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 2 additions & 0 deletions bins/revme/src/cmd/statetest/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use revm::{
Context, ExecuteCommitEvm, MainBuilder, MainContext,
};
use serde_json::json;
use state::CodeSize;
use statetest_types::{SpecName, Test, TestSuite};

use std::{
Expand Down Expand Up @@ -247,6 +248,7 @@ pub fn execute_test_suite(
let acc_info = revm::state::AccountInfo {
balance: info.balance,
code_hash,
code_size: Some(CodeSize::Known(bytecode.len())),
code: Some(bytecode),
nonce: info.nonce,
};
Expand Down
2 changes: 1 addition & 1 deletion crates/context/interface/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Context trait and related types.
pub use crate::journaled_state::StateLoad;
pub use crate::journaled_state::{StateCodeLoad, StateLoad};
use crate::{
result::FromStringError, Block, Cfg, Database, JournalTr, LocalContextTr, Transaction,
};
Expand Down
85 changes: 70 additions & 15 deletions crates/context/interface/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub trait JournalTr {
fn load_account_code(
&mut self,
address: Address,
) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
) -> Result<StateCodeLoad<&mut Account>, <Self::Database as Database>::Error>;

/// Loads the account delegated.
fn load_account_delegated(
Expand All @@ -133,7 +133,7 @@ pub trait JournalTr {

/// Sets bytecode and calculates hash.
///
/// Assume account is warm.
/// Assume account warm. In case of EIP-7907, marks code as warm.
#[inline]
fn set_code(&mut self, address: Address, code: Bytecode) {
let hash = code.hash_slow();
Expand All @@ -145,30 +145,34 @@ pub trait JournalTr {
fn code(
&mut self,
address: Address,
) -> Result<StateLoad<Bytes>, <Self::Database as Database>::Error> {
let a = self.load_account_code(address)?;
// SAFETY: Safe to unwrap as load_code will insert code if it is empty.
let code = a.info.code.as_ref().unwrap();
let code = code.original_bytes();
) -> Result<StateCodeLoad<Bytes>, <Self::Database as Database>::Error> {
self.load_account_code(address).map(|a| {
a.map(|a| {
// SAFETY: Safe to unwrap as load_code will insert code if it is empty.
a.info.code.as_ref().unwrap().original_bytes()
})
})
}

Ok(StateLoad::new(code, a.is_cold))
/// Returns code size of the account.
#[inline]
fn code_size(
&mut self,
address: Address,
) -> Result<StateCodeLoad<usize>, <Self::Database as Database>::Error> {
self.code(address).map(|i| i.map(|b| b.len()))
}

/// Gets code hash of account.
fn code_hash(
&mut self,
address: Address,
) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
let acc = self.load_account_code(address)?;
let acc = self.load_account(address)?;
if acc.is_empty() {
return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
}
// SAFETY: Safe to unwrap as load_code will insert code if it is empty.
let _code = acc.info.code.as_ref().unwrap();

let hash = acc.info.code_hash;

Ok(StateLoad::new(hash, acc.is_cold))
Ok(acc.map(|a| a.info.code_hash))
}

/// Called at the end of the transaction to clean all residue data from journal.
Expand Down Expand Up @@ -276,6 +280,53 @@ impl<T> StateLoad<T> {
}
}

/// Duplicates StateLoad, adding code cold status.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StateCodeLoad<T> {
/// Returned data
pub data: T,
/// Is account is cold loaded
pub is_cold: bool,
/// Is account code cold loaded
pub is_code_cold: bool,
}

impl<T> Deref for StateCodeLoad<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.data
}
}

impl<T> DerefMut for StateCodeLoad<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}

impl<T> StateCodeLoad<T> {
/// Returns a new [`StateCodeLoad`] with the given data and cold load statuses.
pub fn new(data: T, is_cold: bool, is_code_cold: bool) -> Self {
Self {
data,
is_cold,
is_code_cold,
}
}

/// Maps the data of the [`StateCodeLoad`] to a new value.
///
/// Useful for transforming the data of the [`StateCodeLoad`] without changing the cold load statuses.
pub fn map<B, F>(self, f: F) -> StateCodeLoad<B>
where
F: FnOnce(T) -> B,
{
StateCodeLoad::new(f(self.data), self.is_cold, self.is_code_cold)
}
}

/// Result of the account load from Journal state
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand All @@ -284,4 +335,8 @@ pub struct AccountLoad {
pub is_delegate_account_cold: Option<bool>,
/// Is account empty, if `true` account is not created
pub is_empty: bool,
/// Is account code cold loaded. in case of delegated code
pub is_code_cold: bool,
/// Account code size
pub code_size: Option<usize>,
}
14 changes: 11 additions & 3 deletions crates/context/src/cfg.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This module contains [`CfgEnv`] and implements [`Cfg`] trait for it.
pub use context_interface::Cfg;

use primitives::{eip170, eip3860, eip7825, hardfork::SpecId};
use primitives::{eip170, eip3860, eip7825, eip7907, hardfork::SpecId};
/// EVM configuration
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -257,7 +257,11 @@ impl<SPEC: Into<SpecId> + Copy> Cfg for CfgEnv<SPEC> {

fn max_code_size(&self) -> usize {
self.limit_contract_code_size
.unwrap_or(eip170::MAX_CODE_SIZE)
.unwrap_or(if self.spec.into().is_enabled_in(SpecId::OSAKA) {
eip7907::MAX_CODE_SIZE
} else {
eip170::MAX_CODE_SIZE
})
}

fn max_initcode_size(&self) -> usize {
Expand All @@ -266,7 +270,11 @@ impl<SPEC: Into<SpecId> + Copy> Cfg for CfgEnv<SPEC> {
self.limit_contract_code_size
.map(|size| size.saturating_mul(2))
})
.unwrap_or(eip3860::MAX_INITCODE_SIZE)
.unwrap_or(if self.spec.into().is_enabled_in(SpecId::OSAKA) {
eip7907::MAX_INITCODE_SIZE
} else {
eip3860::MAX_INITCODE_SIZE
})
}

fn is_eip3607_disabled(&self) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions crates/context/src/journal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub use inner::JournalInner;

use bytecode::Bytecode;
use context_interface::{
context::{SStoreResult, SelfDestructResult, StateLoad},
context::{SStoreResult, SelfDestructResult, StateCodeLoad, StateLoad},
journaled_state::{AccountLoad, JournalCheckpoint, JournalTr, TransferError},
};
use core::ops::{Deref, DerefMut};
Expand Down Expand Up @@ -234,7 +234,7 @@ impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
fn load_account_code(
&mut self,
address: Address,
) -> Result<StateLoad<&mut Account>, DB::Error> {
) -> Result<StateCodeLoad<&mut Account>, DB::Error> {
self.inner.load_code(&mut self.database, address)
}

Expand Down
17 changes: 17 additions & 0 deletions crates/context/src/journal/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ pub trait JournalEntryTr {
had_value: StorageValue,
) -> Self;

/// Creates a journal entry for when an account's code is loaded and marked as "warm" for gas metering
fn code_warmed(address: Address) -> Self;

/// Creates a journal entry for when an account's code is modified
fn code_changed(address: Address) -> Self;

Expand Down Expand Up @@ -206,6 +209,13 @@ pub enum JournalEntry {
/// Address of account that had its transient storage changed.
address: Address,
},
/// Entry used to track code warming introduced by EIP-7907.
/// Action: Code warmed
/// Revert: Revert to cold state
CodeWarmed {
/// Address of account that had its code warmed.
address: Address,
},
/// Code changed
/// Action: Account code changed
/// Revert: Revert to previous bytecode.
Expand Down Expand Up @@ -283,6 +293,10 @@ impl JournalEntryTr for JournalEntry {
}
}

fn code_warmed(address: Address) -> Self {
JournalEntry::CodeWarmed { address }
}

fn code_changed(address: Address) -> Self {
JournalEntry::CodeChange { address }
}
Expand Down Expand Up @@ -400,6 +414,9 @@ impl JournalEntryTr for JournalEntry {
transient_storage.insert(tkey, had_value);
}
}
JournalEntry::CodeWarmed { address } => {
state.get_mut(&address).unwrap().mark_code_cold();
}
JournalEntry::CodeChange { address } => {
let acc = state.get_mut(&address).unwrap();
acc.info.code_hash = KECCAK_EMPTY;
Expand Down
48 changes: 39 additions & 9 deletions crates/context/src/journal/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::JournalEntryTr;
use bytecode::Bytecode;
use context_interface::{
context::{SStoreResult, SelfDestructResult, StateLoad},
journaled_state::{AccountLoad, JournalCheckpoint, TransferError},
journaled_state::{AccountLoad, JournalCheckpoint, StateCodeLoad, TransferError},
};
use core::mem;
use database_interface::Database;
Expand Down Expand Up @@ -256,7 +256,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
.expect("Account expected to be loaded") // Always assume that acc is already loaded
}

/// Set code and its hash to the account.
/// Set code and its hash to the account. Marks account code warm.
///
/// Note: Assume account is warm and that hash is calculated from code.
#[inline]
Expand All @@ -268,6 +268,9 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {

account.info.code_hash = hash;
account.info.code = Some(code);

// EIP-7907 account code is loaded and considered warm.
account.mark_code_warm();
}

/// Use it only if you know that acc is warm.
Expand Down Expand Up @@ -588,7 +591,12 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
db: &mut DB,
address: Address,
) -> Result<StateLoad<&mut Account>, DB::Error> {
// load code is false and code loaded state not used by fn callers so is_code_cold is not returned
self.load_account_optional(db, address, false, [])
.map(|state_code_load| StateLoad {
data: state_code_load.data,
is_cold: state_code_load.is_cold,
})
}

/// Loads account into memory. If account is EIP-7702 type it will additionally
Expand All @@ -609,19 +617,27 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
let account = self.load_account_optional(db, address, is_eip7702_enabled, [])?;
let is_empty = account.state_clear_aware_is_empty(spec);

// Get code size if code exists, otherwise None
let code_size = account.info.code.as_ref().map(|code| code.len());

let mut account_load = StateLoad::new(
AccountLoad {
is_delegate_account_cold: None,
is_empty,
is_code_cold: account.is_code_cold,
code_size,
},
account.is_cold,
);

// load delegate code if account is EIP-7702
// load delegate account if account is EIP-7702
if let Some(Bytecode::Eip7702(code)) = &account.info.code {
let address = code.address();
let delegate_account = self.load_account(db, address)?;
let delegate_account = self.load_account_optional(db, address, true, [])?;
account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
account_load.data.code_size =
delegate_account.info.code.as_ref().map(|code| code.len());
account_load.data.is_code_cold = delegate_account.is_code_cold;
}

Ok(account_load)
Expand All @@ -638,7 +654,7 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
&mut self,
db: &mut DB,
address: Address,
) -> Result<StateLoad<&mut Account>, DB::Error> {
) -> Result<StateCodeLoad<&mut Account>, DB::Error> {
self.load_account_optional(db, address, true, [])
}

Expand All @@ -650,12 +666,12 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
address: Address,
load_code: bool,
storage_keys: impl IntoIterator<Item = StorageKey>,
) -> Result<StateLoad<&mut Account>, DB::Error> {
) -> Result<StateCodeLoad<&mut Account>, DB::Error> {
let load = match self.state.entry(address) {
Entry::Occupied(entry) => {
let account = entry.into_mut();
let is_cold = account.mark_warm_with_transaction_id(self.transaction_id);
// if it is colad loaded we need to clear local flags that can interact with selfdestruct
// if it is cold loaded we need to clear local flags that can interact with selfdestruct
if is_cold {
// if it is cold loaded and we have selfdestructed locally it means that
// account was selfdestructed in previous transaction and we need to clear its information and storage.
Expand All @@ -665,10 +681,13 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
}
// unmark locally created
account.unmark_created_locally();
account.mark_code_cold();
}
StateLoad {
let is_code_cold = account.is_code_cold();
StateCodeLoad {
data: account,
is_cold,
is_code_cold,
}
}
Entry::Vacant(vac) => {
Expand All @@ -682,9 +701,10 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
let is_cold = !self.warm_preloaded_addresses.contains(&address)
&& self.warm_coinbase_address.as_ref() != Some(&address);

StateLoad {
StateCodeLoad {
data: vac.insert(account),
is_cold,
is_code_cold: true,
}
}
};
Expand All @@ -693,7 +713,11 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
if load.is_cold {
self.journal.push(ENTRY::account_warmed(address));
}

if load_code {
if address == primitives::address!("0x0000000000000000000000000000000000001100") {
//panic!();
}
let info = &mut load.data.info;
if info.code.is_none() {
let code = if info.code_hash == KECCAK_EMPTY {
Expand All @@ -703,6 +727,12 @@ impl<ENTRY: JournalEntryTr> JournalInner<ENTRY> {
};
info.code = Some(code);
}

// EIP-7907: mark account code as warm loaded and journal if it is warmed
if self.spec.is_enabled_in(SpecId::OSAKA) && load.is_code_cold {
load.data.mark_code_warm();
self.journal.push(ENTRY::code_warmed(address));
}
}

for storage_key in storage_keys.into_iter() {
Expand Down
Loading
Loading