Skip to content

Commit

Permalink
feat(eip7702): apply latest EIP-7702 changes, backport from v52 (#1969)
Browse files Browse the repository at this point in the history
* feat(eip7702): apply latest EIP-7702 changes, backport from v52

* fix eip7702 tests
  • Loading branch information
rakita authored Jan 8, 2025
1 parent c28ea1b commit 6a69c71
Show file tree
Hide file tree
Showing 15 changed files with 186 additions and 258 deletions.
6 changes: 5 additions & 1 deletion crates/bytecode/src/eip7702.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use core::fmt;
use primitives::{bytes, Address, Bytes};
use primitives::{b256, bytes, Address, Bytes, B256};

/// Hash of EF01 bytes that is used for EXTCODEHASH when called from legacy bytecode.
pub const EIP7702_MAGIC_HASH: B256 =
b256!("eadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329");

/// EIP-7702 Version Magic in u16 form
pub const EIP7702_MAGIC: u16 = 0xEF01;
Expand Down
11 changes: 4 additions & 7 deletions crates/context/interface/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ mod dummy;
pub use crate::journaled_state::StateLoad;
pub use dummy::DummyHost;

use crate::{
journaled_state::{AccountLoad, Eip7702CodeLoad},
BlockGetter, CfgGetter, TransactionGetter,
};
use crate::{journaled_state::AccountLoad, BlockGetter, CfgGetter, TransactionGetter};
use auto_impl::auto_impl;
use primitives::{Address, Bytes, Log, B256, U256};

Expand All @@ -15,7 +12,7 @@ use primitives::{Address, Bytes, Log, B256, U256};
#[auto_impl(&mut, Box)]
pub trait Host: TransactionGetter + BlockGetter + CfgGetter {
/// Load an account code.
fn load_account_delegated(&mut self, address: Address) -> Option<AccountLoad>;
fn load_account_delegated(&mut self, address: Address) -> Option<StateLoad<AccountLoad>>;

/// Gets the block hash of the given block `number`.
fn block_hash(&mut self, number: u64) -> Option<B256>;
Expand All @@ -24,10 +21,10 @@ pub trait Host: TransactionGetter + BlockGetter + CfgGetter {
fn balance(&mut self, address: Address) -> Option<StateLoad<U256>>;

/// Gets code of `address` and if the account is cold.
fn code(&mut self, address: Address) -> Option<Eip7702CodeLoad<Bytes>>;
fn code(&mut self, address: Address) -> Option<StateLoad<Bytes>>;

/// Gets code hash of `address` and if the account is cold.
fn code_hash(&mut self, address: Address) -> Option<Eip7702CodeLoad<B256>>;
fn code_hash(&mut self, address: Address) -> Option<StateLoad<B256>>;

/// Gets storage value of `address` at `index` and if the account is cold.
fn sload(&mut self, address: Address, index: U256) -> Option<StateLoad<U256>>;
Expand Down
12 changes: 6 additions & 6 deletions crates/context/interface/src/host/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{Block, BlockGetter, Cfg, CfgGetter, Transaction, TransactionGetter};
use primitives::{hash_map::Entry, Address, Bytes, HashMap, Log, B256, KECCAK_EMPTY, U256};
use std::vec::Vec;

use super::{AccountLoad, Eip7702CodeLoad, StateLoad};
use super::{AccountLoad, StateLoad};

/// A dummy [Host] implementation.
#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -74,8 +74,8 @@ impl<BLOCK: Block, TX: Transaction, CFG: Cfg> CfgGetter for DummyHost<BLOCK, TX,

impl<TX: Transaction, BLOCK: Block, CFG: Cfg> Host for DummyHost<BLOCK, TX, CFG> {
#[inline]
fn load_account_delegated(&mut self, _address: Address) -> Option<AccountLoad> {
Some(AccountLoad::default())
fn load_account_delegated(&mut self, _address: Address) -> Option<StateLoad<AccountLoad>> {
Some(StateLoad::new(AccountLoad::default(), false))
}

#[inline]
Expand All @@ -89,13 +89,13 @@ impl<TX: Transaction, BLOCK: Block, CFG: Cfg> Host for DummyHost<BLOCK, TX, CFG>
}

#[inline]
fn code(&mut self, _address: Address) -> Option<Eip7702CodeLoad<Bytes>> {
fn code(&mut self, _address: Address) -> Option<StateLoad<Bytes>> {
Some(Default::default())
}

#[inline]
fn code_hash(&mut self, _address: Address) -> Option<Eip7702CodeLoad<B256>> {
Some(Eip7702CodeLoad::new_not_delegated(KECCAK_EMPTY, false))
fn code_hash(&mut self, _address: Address) -> Option<StateLoad<B256>> {
Some(StateLoad::new(KECCAK_EMPTY, false))
}

#[inline]
Expand Down
90 changes: 3 additions & 87 deletions crates/context/interface/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub trait Journal {
fn load_account_delegated(
&mut self,
address: Address,
) -> Result<AccountLoad, <Self::Database as Database>::Error>;
) -> Result<StateLoad<AccountLoad>, <Self::Database as Database>::Error>;

/// Sets bytecode with hash. Assume that account is warm.
fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
Expand Down Expand Up @@ -200,94 +200,10 @@ impl<T> StateLoad<T> {
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AccountLoad {
/// Is account and delegate code are loaded
pub load: Eip7702CodeLoad<()>,
/// Is account empty, if true account is not created
pub is_empty: bool,
}

impl Deref for AccountLoad {
type Target = Eip7702CodeLoad<()>;

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

impl DerefMut for AccountLoad {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.load
}
}

/// EIP-7702 code load result that contains optional delegation is_cold information
///
/// [`is_delegate_account_cold`][Self::is_delegate_account_cold] will be [`Some`] if account has delegation.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Eip7702CodeLoad<T> {
/// Returned data
pub state_load: StateLoad<T>,
/// Does account have delegate code and delegated account is cold loaded
pub is_delegate_account_cold: Option<bool>,
}

impl<T> Deref for Eip7702CodeLoad<T> {
type Target = StateLoad<T>;

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

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

impl<T> Eip7702CodeLoad<T> {
/// Returns a new [`Eip7702CodeLoad`] with the given data and without delegation.
pub fn new_state_load(state_load: StateLoad<T>) -> Self {
Self {
state_load,
is_delegate_account_cold: None,
}
}

/// Returns a new [`Eip7702CodeLoad`] with the given data and without delegation.
pub fn new_not_delegated(data: T, is_cold: bool) -> Self {
Self {
state_load: StateLoad::new(data, is_cold),
is_delegate_account_cold: None,
}
}

/// Deconstructs the [`Eip7702CodeLoad`] by extracting data and
/// returning a new [`Eip7702CodeLoad`] with empty data.
pub fn into_components(self) -> (T, Eip7702CodeLoad<()>) {
let is_cold = self.is_cold;
(
self.state_load.data,
Eip7702CodeLoad {
state_load: StateLoad::new((), is_cold),
is_delegate_account_cold: self.is_delegate_account_cold,
},
)
}

/// Sets the delegation cold load status.
pub fn set_delegate_load(&mut self, is_delegate_account_cold: bool) {
self.is_delegate_account_cold = Some(is_delegate_account_cold);
}

/// Returns a new [`Eip7702CodeLoad`] with the given data and delegation cold load status.
pub fn new(state_load: StateLoad<T>, is_delegate_account_cold: bool) -> Self {
Self {
state_load,
is_delegate_account_cold: Some(is_delegate_account_cold),
}
}
/// Is account empty, if `true` account is not created
pub is_empty: bool,
}

/// Helper that extracts database error from [`JournalGetter`].
Expand Down
117 changes: 37 additions & 80 deletions crates/context/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
pub mod performant_access;

use crate::{block::BlockEnv, cfg::CfgEnv, journaled_state::JournaledState, tx::TxEnv};
use bytecode::{Bytecode, EOF_MAGIC_BYTES, EOF_MAGIC_HASH};
use bytecode::{
eip7702::{EIP7702_MAGIC_BYTES, EIP7702_MAGIC_HASH},
EOF_MAGIC_BYTES, EOF_MAGIC_HASH,
};
use context_interface::{
block::BlockSetter,
journaled_state::{AccountLoad, Eip7702CodeLoad},
transaction::TransactionSetter,
Block, BlockGetter, Cfg, CfgGetter, DatabaseGetter, ErrorGetter, Journal, JournalGetter,
Transaction, TransactionGetter,
block::BlockSetter, journaled_state::AccountLoad, transaction::TransactionSetter, Block,
BlockGetter, Cfg, CfgGetter, DatabaseGetter, ErrorGetter, Journal, JournalGetter, Transaction,
TransactionGetter,
};
use database_interface::{Database, EmptyDB};
use derive_where::derive_where;
Expand Down Expand Up @@ -84,53 +85,6 @@ where
DB: Database,
JOURNAL: Journal<Database = DB>,
{
/// Returns account code bytes and if address is cold loaded.
///
/// In case of EOF account it will return `EOF_MAGIC` (0xEF00) as code.
///
// TODO : Move this in Journaled state
#[inline]
pub fn code(
&mut self,
address: Address,
) -> Result<Eip7702CodeLoad<Bytes>, <DB as Database>::Error> {
let a = self.journaled_state.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();
if code.is_eof() {
return Ok(Eip7702CodeLoad::new_not_delegated(
EOF_MAGIC_BYTES.clone(),
a.is_cold,
));
}

if let Bytecode::Eip7702(code) = code {
let address = code.address();
let is_cold = a.is_cold;

let delegated_account = self.journaled_state.load_account_code(address)?;

// SAFETY: Safe to unwrap as load_code will insert code if it is empty.
let delegated_code = delegated_account.info.code.as_ref().unwrap();

let bytes = if delegated_code.is_eof() {
EOF_MAGIC_BYTES.clone()
} else {
delegated_code.original_bytes()
};

return Ok(Eip7702CodeLoad::new(
StateLoad::new(bytes, is_cold),
delegated_account.is_cold,
));
}

Ok(Eip7702CodeLoad::new_not_delegated(
code.original_bytes(),
a.is_cold,
))
}

pub fn with_new_journal<OJOURNAL: Journal<Database = DB>>(
self,
mut journal: OJOURNAL,
Expand Down Expand Up @@ -324,6 +278,28 @@ where
f(&mut self.journaled_state);
}

/// Returns account code bytes and if address is cold loaded.
///
/// In case of EOF account it will return `EOF_MAGIC` (0xEF00) as code.
///
// TODO : Move this in Journaled state
#[inline]
pub fn code(&mut self, address: Address) -> Result<StateLoad<Bytes>, <DB as Database>::Error> {
let a = self.journaled_state.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 = if code.is_eof() {
EOF_MAGIC_BYTES.clone()
} else if code.is_eip7702() {
EIP7702_MAGIC_BYTES.clone()
} else {
code.original_bytes()
};

Ok(StateLoad::new(code, a.is_cold))
}

/// Gets code hash of address.
///
/// In case of EOF account it will return `EOF_MAGIC_HASH`
Expand All @@ -334,42 +310,23 @@ where
pub fn code_hash(
&mut self,
address: Address,
) -> Result<Eip7702CodeLoad<B256>, <DB as Database>::Error> {
) -> Result<StateLoad<B256>, <DB as Database>::Error> {
let acc = self.journaled_state.load_account_code(address)?;
if acc.is_empty() {
return Ok(Eip7702CodeLoad::new_not_delegated(B256::ZERO, acc.is_cold));
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();

// If bytecode is EIP-7702 then we need to load the delegated account.
if let Bytecode::Eip7702(code) = code {
let address = code.address();
let is_cold = acc.is_cold;

let delegated_account = self.journaled_state.load_account_code(address)?;

let hash = if delegated_account.is_empty() {
B256::ZERO
} else if delegated_account.info.code.as_ref().unwrap().is_eof() {
EOF_MAGIC_HASH
} else {
delegated_account.info.code_hash
};

return Ok(Eip7702CodeLoad::new(
StateLoad::new(hash, is_cold),
delegated_account.is_cold,
));
}

let hash = if code.is_eof() {
EOF_MAGIC_HASH
} else if code.is_eip7702() {
EIP7702_MAGIC_HASH
} else {
acc.info.code_hash
};

Ok(Eip7702CodeLoad::new_not_delegated(hash, acc.is_cold))
Ok(StateLoad::new(hash, acc.is_cold))
}
}

Expand Down Expand Up @@ -405,7 +362,7 @@ where
Some(B256::ZERO)
}

fn load_account_delegated(&mut self, address: Address) -> Option<AccountLoad> {
fn load_account_delegated(&mut self, address: Address) -> Option<StateLoad<AccountLoad>> {
self.journaled_state
.load_account_delegated(address)
.map_err(|e| self.error = Err(e))
Expand All @@ -420,11 +377,11 @@ where
.ok()
}

fn code(&mut self, address: Address) -> Option<Eip7702CodeLoad<Bytes>> {
fn code(&mut self, address: Address) -> Option<StateLoad<Bytes>> {
self.code(address).map_err(|e| self.error = Err(e)).ok()
}

fn code_hash(&mut self, address: Address) -> Option<Eip7702CodeLoad<B256>> {
fn code_hash(&mut self, address: Address) -> Option<StateLoad<B256>> {
self.code_hash(address)
.map_err(|e| self.error = Err(e))
.ok()
Expand Down
Loading

0 comments on commit 6a69c71

Please sign in to comment.