use super::{
changes::PlainStorageRevert, AccountStatus, BundleAccount, PlainStateReverts,
StorageWithOriginalValues,
};
use core::ops::{Deref, DerefMut};
use revm_interpreter::primitives::{AccountInfo, Address, HashMap, U256};
use std::vec::Vec;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Reverts(Vec<Vec<(Address, AccountRevert)>>);
impl Deref for Reverts {
type Target = Vec<Vec<(Address, AccountRevert)>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Reverts {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Reverts {
pub fn new(reverts: Vec<Vec<(Address, AccountRevert)>>) -> Self {
Self(reverts)
}
pub fn sort(&mut self) {
for revert in &mut self.0 {
revert.sort_by_key(|(address, _)| *address);
}
}
pub fn extend(&mut self, other: Reverts) {
self.0.extend(other.0);
}
pub fn to_plain_state_reverts(&self) -> PlainStateReverts {
let mut state_reverts = PlainStateReverts::with_capacity(self.0.len());
for reverts in &self.0 {
let mut accounts = Vec::with_capacity(reverts.len());
let mut storage = Vec::with_capacity(reverts.len());
for (address, revert_account) in reverts {
match &revert_account.account {
AccountInfoRevert::RevertTo(acc) => {
accounts.push((*address, Some(acc.clone())))
}
AccountInfoRevert::DeleteIt => accounts.push((*address, None)),
AccountInfoRevert::DoNothing => (),
}
if revert_account.wipe_storage || !revert_account.storage.is_empty() {
storage.push(PlainStorageRevert {
address: *address,
wiped: revert_account.wipe_storage,
storage_revert: revert_account
.storage
.iter()
.map(|(k, v)| (*k, *v))
.collect::<Vec<_>>(),
});
}
}
state_reverts.accounts.push(accounts);
state_reverts.storage.push(storage);
}
state_reverts
}
#[deprecated = "Use `to_plain_state_reverts` instead"]
pub fn into_plain_state_reverts(self) -> PlainStateReverts {
self.to_plain_state_reverts()
}
}
#[derive(Clone, Default, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AccountRevert {
pub account: AccountInfoRevert,
pub storage: HashMap<U256, RevertToSlot>,
pub previous_status: AccountStatus,
pub wipe_storage: bool,
}
impl AccountRevert {
pub fn size_hint(&self) -> usize {
1 + self.storage.len()
}
pub fn new_selfdestructed_again(
status: AccountStatus,
account: AccountInfoRevert,
mut previous_storage: StorageWithOriginalValues,
updated_storage: StorageWithOriginalValues,
) -> Self {
let mut previous_storage: HashMap<U256, RevertToSlot> = previous_storage
.drain()
.map(|(key, value)| (key, RevertToSlot::Some(value.present_value)))
.collect();
for (key, _) in updated_storage {
previous_storage
.entry(key)
.or_insert(RevertToSlot::Destroyed);
}
AccountRevert {
account,
storage: previous_storage,
previous_status: status,
wipe_storage: false,
}
}
pub fn new_selfdestructed_from_bundle(
account_info_revert: AccountInfoRevert,
bundle_account: &mut BundleAccount,
updated_storage: &StorageWithOriginalValues,
) -> Option<Self> {
match bundle_account.status {
AccountStatus::InMemoryChange
| AccountStatus::Changed
| AccountStatus::LoadedEmptyEIP161
| AccountStatus::Loaded => {
let mut ret = AccountRevert::new_selfdestructed_again(
bundle_account.status,
account_info_revert,
bundle_account.storage.drain().collect(),
updated_storage.clone(),
);
ret.wipe_storage = true;
Some(ret)
}
_ => None,
}
}
pub fn new_selfdestructed(
status: AccountStatus,
account: AccountInfoRevert,
mut storage: StorageWithOriginalValues,
) -> Self {
let previous_storage = storage
.iter_mut()
.map(|(key, value)| {
(*key, RevertToSlot::Some(value.present_value))
})
.collect();
Self {
account,
storage: previous_storage,
previous_status: status,
wipe_storage: true,
}
}
pub fn is_empty(&self) -> bool {
self.account == AccountInfoRevert::DoNothing
&& self.storage.is_empty()
&& !self.wipe_storage
}
}
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AccountInfoRevert {
#[default]
DoNothing,
DeleteIt,
RevertTo(AccountInfo),
}
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RevertToSlot {
Some(U256),
Destroyed,
}
impl RevertToSlot {
pub fn to_previous_value(self) -> U256 {
match self {
RevertToSlot::Some(value) => value,
RevertToSlot::Destroyed => U256::ZERO,
}
}
}