Skip to content

Commit

Permalink
feat: support eip-7610
Browse files Browse the repository at this point in the history
  • Loading branch information
hai-rise committed Aug 24, 2024
1 parent a9d7437 commit 171c1fa
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 4 deletions.
11 changes: 11 additions & 0 deletions crates/primitives/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub trait Database {
/// Get account code by its hash.
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;

/// Get if the account already has storage (to support EIP-7610)
fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error>;

/// Get storage value of address at index.
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error>;

Expand Down Expand Up @@ -49,6 +52,9 @@ pub trait DatabaseRef {
/// Get account code by its hash.
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;

/// Get if the account already has storage (to support EIP-7610)
fn has_storage_ref(&self, address: Address) -> Result<bool, Self::Error>;

/// Get storage value of address at index.
fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error>;

Expand Down Expand Up @@ -85,6 +91,11 @@ impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
self.0.storage_ref(address, index)
}

#[inline]
fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
self.0.has_storage_ref(address)
}

#[inline]
fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
self.0.block_hash_ref(number)
Expand Down
8 changes: 8 additions & 0 deletions crates/primitives/src/db/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ impl<S: State, BH: BlockHash> Database for DatabaseComponents<S, BH> {
.map_err(Self::Error::State)
}

fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
self.state.has_storage(address).map_err(Self::Error::State)
}

fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
self.state
.storage(address, index)
Expand All @@ -63,6 +67,10 @@ impl<S: StateRef, BH: BlockHashRef> DatabaseRef for DatabaseComponents<S, BH> {
.map_err(Self::Error::State)
}

fn has_storage_ref(&self, address: Address) -> Result<bool, Self::Error> {
self.state.has_storage(address).map_err(Self::Error::State)
}

fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
self.state
.storage(address, index)
Expand Down
14 changes: 14 additions & 0 deletions crates/primitives/src/db/components/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub trait State {
/// Get account code by its hash
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;

/// Get if the account already has storage (to support EIP-7610)
fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error>;

/// Get storage value of address at index.
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error>;
}
Expand All @@ -30,6 +33,9 @@ pub trait StateRef {
/// Get account code by its hash
fn code_by_hash(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;

/// Get if the account already has storage (to support EIP-7610)
fn has_storage(&self, address: Address) -> Result<bool, Self::Error>;

/// Get storage value of address at index.
fn storage(&self, address: Address, index: U256) -> Result<U256, Self::Error>;
}
Expand All @@ -48,6 +54,10 @@ where
StateRef::code_by_hash(*self, code_hash)
}

fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
StateRef::has_storage(*self, address)
}

fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
StateRef::storage(*self, address, index)
}
Expand All @@ -67,6 +77,10 @@ where
self.deref().code_by_hash(code_hash)
}

fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
self.deref().has_storage(address)
}

fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
self.deref().storage(address, index)
}
Expand Down
14 changes: 14 additions & 0 deletions crates/revm/src/context/evm_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,17 @@ impl<DB: Database> EvmContext<DB> {
// warm load account.
self.load_account(created_address)?;

// This only check with the pre-execution state. Can storage be cleared after load?
let address_has_storage = self
.db
.has_storage(created_address)
.map_err(EVMError::Database)?;

// create account, transfer funds and make the journal checkpoint.
let checkpoint = match self.journaled_state.create_account_checkpoint(
inputs.caller,
created_address,
address_has_storage,
inputs.value,
spec_id,
) {
Expand Down Expand Up @@ -421,10 +428,17 @@ impl<DB: Database> EvmContext<DB> {
// Load account so it needs to be marked as warm for access list.
self.load_account(created_address)?;

// This only check with the pre-execution state. Can storage be cleared after load?
let address_has_storage = self
.db
.has_storage(created_address)
.map_err(EVMError::Database)?;

// create account, transfer funds and make the journal checkpoint.
let checkpoint = match self.journaled_state.create_account_checkpoint(
inputs.caller,
created_address,
address_has_storage,
inputs.value,
spec_id,
) {
Expand Down
12 changes: 11 additions & 1 deletion crates/revm/src/db/alloydb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ impl<T: Transport + Clone, N: Network, P: Provider<T, N>> DatabaseRef for AlloyD
// This is not needed, as the code is already loaded with basic_ref
}

fn has_storage_ref(&self, _address: Address) -> Result<bool, Self::Error> {
// FIXME
Ok(false)
}

fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
let f = self
.provider
Expand All @@ -151,7 +156,7 @@ impl<T: Transport + Clone, N: Network, P: Provider<T, N>> Database for AlloyDB<T
type Error = TransportError;

#[inline]
fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
fn basic(&mut self, address: Address, _: bool) -> Result<Option<AccountInfo>, Self::Error> {
<Self as DatabaseRef>::basic_ref(self, address)
}

Expand All @@ -160,6 +165,11 @@ impl<T: Transport + Clone, N: Network, P: Provider<T, N>> Database for AlloyDB<T
<Self as DatabaseRef>::code_by_hash_ref(self, code_hash)
}

#[inline]
fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
<Self as DatabaseRef>::has_storage_ref(self, address)
}

#[inline]
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
<Self as DatabaseRef>::storage_ref(self, address, index)
Expand Down
10 changes: 10 additions & 0 deletions crates/revm/src/db/emptydb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ impl<E> Database for EmptyDBTyped<E> {
<Self as DatabaseRef>::code_by_hash_ref(self, code_hash)
}

#[inline]
fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
<Self as DatabaseRef>::has_storage_ref(self, address)
}

#[inline]
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
<Self as DatabaseRef>::storage_ref(self, address, index)
Expand All @@ -90,6 +95,11 @@ impl<E> DatabaseRef for EmptyDBTyped<E> {
Ok(Bytecode::default())
}

#[inline]
fn has_storage_ref(&self, _address: Address) -> Result<bool, Self::Error> {
Ok(false)
}

#[inline]
fn storage_ref(&self, _address: Address, _index: U256) -> Result<U256, Self::Error> {
Ok(U256::default())
Expand Down
9 changes: 9 additions & 0 deletions crates/revm/src/db/ethersdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl<M: Middleware> DatabaseRef for EthersDB<M> {
// not needed because we already load code with basic info
}

fn has_storage_ref(&self, _address: Address) -> Result<bool, Self::Error> {
todo!()
}

fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
let add = eH160::from(address.0 .0);
let index = H256::from(index.to_be_bytes());
Expand Down Expand Up @@ -165,6 +169,11 @@ impl<M: Middleware> Database for EthersDB<M> {
<Self as DatabaseRef>::code_by_hash_ref(self, code_hash)
}

#[inline]
fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
<Self as DatabaseRef>::has_storage_ref(self, address)
}

#[inline]
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
<Self as DatabaseRef>::storage_ref(self, address, index)
Expand Down
18 changes: 18 additions & 0 deletions crates/revm/src/db/in_memory_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
}
}

fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
Ok(match self.accounts.get(&address) {
Some(account) => !account.storage.is_empty(),
_ => false,
})
}

/// Get the value in an account's storage slot.
///
/// It is assumed that account is already loaded.
Expand Down Expand Up @@ -263,6 +270,13 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
}
}

fn has_storage_ref(&self, address: Address) -> Result<bool, Self::Error> {
Ok(match self.accounts.get(&address) {
Some(account) => !account.storage.is_empty(),
_ => false,
})
}

fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
match self.accounts.get(&address) {
Some(acc_entry) => match acc_entry.storage.get(&index) {
Expand Down Expand Up @@ -397,6 +411,10 @@ impl Database for BenchmarkDB {
Ok(Bytecode::default())
}

fn has_storage(&mut self, _address: Address) -> Result<bool, Self::Error> {
Ok(false)
}

/// Get storage value of address at index.
fn storage(&mut self, _address: Address, _index: U256) -> Result<U256, Self::Error> {
Ok(U256::default())
Expand Down
14 changes: 14 additions & 0 deletions crates/revm/src/db/states/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,20 @@ impl<DB: Database> Database for State<DB> {
res
}

fn has_storage(&mut self, address: Address) -> Result<bool, Self::Error> {
Ok(
match self
.cache
.accounts
.get(&address)
.and_then(|account| account.account.clone())
{
Some(account) => !account.storage.is_empty(),
_ => false,
},
)
}

fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
// Account is guaranteed to be loaded.
// Note that storage from bundle is already loaded with account.
Expand Down
13 changes: 10 additions & 3 deletions crates/revm/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ impl JournaledState {
&mut self,
caller: Address,
address: Address,
address_has_storage: bool,
balance: U256,
spec_id: SpecId,
) -> Result<JournalCheckpoint, InstructionResult> {
Expand All @@ -261,11 +262,17 @@ impl JournaledState {
let account = self.state.get_mut(&address).unwrap();
let last_journal = self.journal.last_mut().unwrap();

// New account can be created if:
// New account cannot be created if:
// Bytecode is not empty.
// Nonce is not zero
// Account is not precompile.
if account.info.code_hash != KECCAK_EMPTY || account.info.nonce != 0 {
// Account is precompile.
// EIP-7610: Storage is not empty.
if account.info.code_hash != KECCAK_EMPTY
|| account.info.nonce != 0
|| self.warm_preloaded_addresses.contains(&address)
// Do we enable this check only for some `spec_id`?
|| address_has_storage
{
self.checkpoint_revert(checkpoint);
return Err(InstructionResult::CreateCollision);
}
Expand Down

0 comments on commit 171c1fa

Please sign in to comment.