Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
51 changes: 51 additions & 0 deletions crates/primitives/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ bitflags! {
/// used only for pre spurious dragon hardforks where existing and empty were two separate states.
/// it became same state after EIP-161: State trie clearing
const LoadedAsNotExisting = 0b0001000;
/// used to mark account as cold
const Cold = 0b0010000;
}
}

Expand Down Expand Up @@ -100,6 +102,21 @@ impl Account {
self.status -= AccountStatus::Created;
}

/// Mark account as cold.
pub fn mark_cold(&mut self) {
self.status |= AccountStatus::Cold;
}

/// Mark account as warm and return true if it was previously cold.
pub fn mark_warm(&mut self) -> bool {
if self.status.contains(AccountStatus::Cold) {
self.status -= AccountStatus::Cold;
true
} else {
false
}
}

/// Is account loaded as not existing from database
/// This is needed for pre spurious dragon hardforks where
/// existing and empty were two separate states.
Expand Down Expand Up @@ -147,6 +164,8 @@ pub struct StorageSlot {
pub previous_or_original_value: U256,
/// When loaded with sload present value is set to original value
pub present_value: U256,
/// Represents if the storage slot is cold.
pub is_cold: bool,
}

impl StorageSlot {
Expand All @@ -155,6 +174,7 @@ impl StorageSlot {
Self {
previous_or_original_value: original,
present_value: original,
is_cold: false,
}
}

Expand All @@ -163,6 +183,7 @@ impl StorageSlot {
Self {
previous_or_original_value,
present_value,
is_cold: false,
}
}

Expand All @@ -180,6 +201,16 @@ impl StorageSlot {
pub fn present_value(&self) -> U256 {
self.present_value
}

/// Marks the storage slot as cold.
pub fn mark_cold(&mut self) {
self.is_cold = true;
}

/// Marks the storage slot as warm and returns a bool indicating if it was previously cold.
pub fn mark_warm(&mut self) -> bool {
core::mem::replace(&mut self.is_cold, false)
}
}

/// AccountInfo account information.
Expand Down Expand Up @@ -348,4 +379,24 @@ mod tests {
assert!(account.is_touched());
assert!(!account.is_selfdestructed());
}

#[test]
fn account_is_cold() {
let mut account = Account::default();

// Account is not cold by default
assert!(!account.status.contains(crate::AccountStatus::Cold));

// When marking warm account as warm again, it should return false
assert!(!account.mark_warm());

// Mark account as cold
account.mark_cold();

// Account is cold
assert!(account.status.contains(crate::AccountStatus::Cold));

// When marking cold account as warm, it should return true
assert!(account.mark_warm());
}
}
16 changes: 12 additions & 4 deletions crates/revm/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl JournaledState {
for entry in journal_entries.into_iter().rev() {
match entry {
JournalEntry::AccountLoaded { address } => {
state.remove(&address);
state.get_mut(&address).unwrap().mark_cold();
}
JournalEntry::AccountTouched { address } => {
if is_spurious_dragon_enabled && address == PRECOMPILE3 {
Expand Down Expand Up @@ -378,7 +378,7 @@ impl JournaledState {
if let Some(had_value) = had_value {
storage.get_mut(&key).unwrap().present_value = had_value;
} else {
storage.remove(&key);
storage.get_mut(&key).unwrap().mark_cold();
}
}
JournalEntry::TransientStorageChange {
Expand Down Expand Up @@ -556,7 +556,11 @@ impl JournaledState {
db: &mut DB,
) -> Result<(&mut Account, bool), EVMError<DB::Error>> {
Ok(match self.state.entry(address) {
Entry::Occupied(entry) => (entry.into_mut(), false),
Entry::Occupied(entry) => {
let account = entry.into_mut();
let is_cold = account.mark_warm();
(account, is_cold)
}
Entry::Vacant(vac) => {
let account =
if let Some(account) = db.basic(address).map_err(EVMError::Database)? {
Expand Down Expand Up @@ -642,7 +646,11 @@ impl JournaledState {
// only if account is created in this tx we can assume that storage is empty.
let is_newly_created = account.is_created();
let load = match account.storage.entry(key) {
Entry::Occupied(occ) => (occ.get().present_value, false),
Entry::Occupied(occ) => {
let slot = occ.into_mut();
let is_cold = slot.mark_warm();
(slot.present_value, is_cold)
}
Entry::Vacant(vac) => {
// if storage was cleared, we don't need to ping db.
let value = if is_newly_created {
Expand Down