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
10 changes: 7 additions & 3 deletions crates/primitives/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,13 @@ impl AccountInfo {
}

/// Returns account info without the code.
pub fn without_code(mut self) -> Self {
self.take_bytecode();
self
pub fn without_code(&self) -> Self {
Self {
balance: self.balance,
nonce: self.nonce,
code_hash: self.code_hash,
code: None,
}
}

/// Returns if an account is empty.
Expand Down
64 changes: 63 additions & 1 deletion crates/revm/src/db/states/bundle_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,68 @@ impl BundleState {
self.reverts.push(reverts);
}

/// Generate a [`StateChangeset`] from the bundle state without consuming
/// it.
pub fn to_plain_state(&self, is_value_known: OriginalValuesKnown) -> StateChangeset {
// pessimistically pre-allocate assuming _all_ accounts changed.
let state_len = self.state.len();
let mut accounts = Vec::with_capacity(state_len);
let mut storage = Vec::with_capacity(state_len);

for (address, account) in self.state.iter() {
// append account info if it is changed.
let was_destroyed = account.was_destroyed();
if is_value_known.is_not_known() || account.is_info_changed() {
let info = account.info.as_ref().map(AccountInfo::without_code);
accounts.push((*address, info));
}

// append storage changes

// NOTE: Assumption is that revert is going to remove whole plain storage from
// database so we can check if plain state was wiped or not.
let mut account_storage_changed = Vec::with_capacity(account.storage.len());

for (key, slot) in account.storage.iter().map(|(k, v)| (*k, *v)) {
// If storage was destroyed that means that storage was wiped.
// In that case we need to check if present storage value is different then ZERO.
let destroyed_and_not_zero = was_destroyed && !slot.present_value.is_zero();

// If account is not destroyed check if original values was changed,
// so we can update it.
let not_destroyed_and_changed = !was_destroyed && slot.is_changed();

if is_value_known.is_not_known()
|| destroyed_and_not_zero
|| not_destroyed_and_changed
{
account_storage_changed.push((key, slot.present_value));
}
}

if !account_storage_changed.is_empty() || was_destroyed {
// append storage changes to account.
storage.push(PlainStorageChangeset {
address: *address,
wipe_storage: was_destroyed,
storage: account_storage_changed,
});
}
}

let contracts = self
.contracts
.iter()
// remove empty bytecodes
.filter_map(|(b, code)| (*b != KECCAK_EMPTY).then_some((*b, code.clone())))
.collect::<Vec<_>>();
StateChangeset {
accounts,
storage,
contracts,
}
}

/// Consume the bundle state and return plain state.
pub fn into_plain_state(self, is_value_known: OriginalValuesKnown) -> StateChangeset {
// pessimistically pre-allocate assuming _all_ accounts changed.
Expand All @@ -592,7 +654,7 @@ impl BundleState {
// append account info if it is changed.
let was_destroyed = account.was_destroyed();
if is_value_known.is_not_known() || account.is_info_changed() {
let info = account.info.map(AccountInfo::without_code);
let info = account.info.as_ref().map(AccountInfo::without_code);
accounts.push((address, info));
}

Expand Down
2 changes: 1 addition & 1 deletion crates/revm/src/db/states/plain_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl PlainAccount {
}

/// This type keeps track of the current value of a storage slot.
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StorageSlot {
/// The value of the storage slot before it was changed.
Expand Down