#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AccountStatus {
#[default]
LoadedNotExisting,
Loaded,
LoadedEmptyEIP161,
InMemoryChange,
Changed,
Destroyed,
DestroyedChanged,
DestroyedAgain,
}
impl AccountStatus {
pub fn is_not_modified(&self) -> bool {
matches!(
self,
Self::LoadedNotExisting | Self::Loaded | Self::LoadedEmptyEIP161
)
}
pub fn was_destroyed(&self) -> bool {
matches!(
self,
Self::Destroyed | Self::DestroyedChanged | Self::DestroyedAgain
)
}
pub fn is_storage_known(&self) -> bool {
matches!(
self,
Self::LoadedNotExisting
| Self::InMemoryChange
| Self::Destroyed
| Self::DestroyedChanged
| Self::DestroyedAgain
)
}
pub fn is_modified_and_not_destroyed(&self) -> bool {
matches!(self, Self::Changed | Self::InMemoryChange)
}
pub fn on_created(&self) -> Self {
match self {
Self::DestroyedAgain
| Self::Destroyed
| Self::DestroyedChanged => Self::DestroyedChanged,
Self::LoadedNotExisting
| Self::LoadedEmptyEIP161
| Self::Loaded
| Self::Changed
| Self::InMemoryChange => {
Self::InMemoryChange
}
}
}
pub fn on_touched_empty_post_eip161(&self) -> Self {
match self {
Self::LoadedNotExisting => Self::LoadedNotExisting,
Self::InMemoryChange | Self::Destroyed | Self::LoadedEmptyEIP161 => Self::Destroyed,
Self::DestroyedAgain | Self::DestroyedChanged => Self::DestroyedAgain,
Self::Changed | Self::Loaded => Self::Destroyed,
}
}
pub fn on_changed(&self, had_no_nonce_and_code: bool) -> Self {
match self {
Self::LoadedNotExisting => Self::InMemoryChange,
Self::LoadedEmptyEIP161 => Self::InMemoryChange,
Self::Loaded => {
if had_no_nonce_and_code {
Self::InMemoryChange
} else {
Self::Changed
}
}
Self::Changed => Self::Changed,
Self::InMemoryChange => Self::InMemoryChange,
Self::DestroyedChanged => Self::DestroyedChanged,
Self::Destroyed | Self::DestroyedAgain => Self::DestroyedChanged,
}
}
pub fn on_selfdestructed(&self) -> Self {
match self {
Self::LoadedNotExisting => Self::LoadedNotExisting,
Self::DestroyedChanged | Self::DestroyedAgain | Self::Destroyed => Self::DestroyedAgain,
_ => Self::Destroyed,
}
}
pub fn transition(&mut self, other: Self) {
*self = match (self.was_destroyed(), other.was_destroyed()) {
(true, false) => Self::DestroyedChanged,
(false, false) if *self == Self::InMemoryChange => Self::InMemoryChange,
_ => other,
};
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_account_status() {
assert!(AccountStatus::Loaded.is_not_modified());
assert!(AccountStatus::LoadedEmptyEIP161.is_not_modified());
assert!(AccountStatus::LoadedNotExisting.is_not_modified());
assert!(!AccountStatus::Changed.is_not_modified());
assert!(!AccountStatus::InMemoryChange.is_not_modified());
assert!(!AccountStatus::Destroyed.is_not_modified());
assert!(!AccountStatus::DestroyedChanged.is_not_modified());
assert!(!AccountStatus::DestroyedAgain.is_not_modified());
assert!(!AccountStatus::LoadedEmptyEIP161.is_storage_known());
assert!(AccountStatus::LoadedNotExisting.is_storage_known());
assert!(AccountStatus::InMemoryChange.is_storage_known());
assert!(AccountStatus::Destroyed.is_storage_known());
assert!(AccountStatus::DestroyedChanged.is_storage_known());
assert!(AccountStatus::DestroyedAgain.is_storage_known());
assert!(!AccountStatus::Loaded.is_storage_known());
assert!(!AccountStatus::Changed.is_storage_known());
assert!(!AccountStatus::LoadedEmptyEIP161.was_destroyed());
assert!(!AccountStatus::LoadedNotExisting.was_destroyed());
assert!(!AccountStatus::InMemoryChange.was_destroyed());
assert!(AccountStatus::Destroyed.was_destroyed());
assert!(AccountStatus::DestroyedChanged.was_destroyed());
assert!(AccountStatus::DestroyedAgain.was_destroyed());
assert!(!AccountStatus::Loaded.was_destroyed());
assert!(!AccountStatus::Changed.was_destroyed());
assert!(AccountStatus::Changed.is_modified_and_not_destroyed());
assert!(AccountStatus::InMemoryChange.is_modified_and_not_destroyed());
assert!(!AccountStatus::Loaded.is_modified_and_not_destroyed());
assert!(!AccountStatus::LoadedEmptyEIP161.is_modified_and_not_destroyed());
assert!(!AccountStatus::LoadedNotExisting.is_modified_and_not_destroyed());
assert!(!AccountStatus::Destroyed.is_modified_and_not_destroyed());
assert!(!AccountStatus::DestroyedChanged.is_modified_and_not_destroyed());
assert!(!AccountStatus::DestroyedAgain.is_modified_and_not_destroyed());
}
#[test]
fn test_on_created() {
assert_eq!(
AccountStatus::Destroyed.on_created(),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::DestroyedAgain.on_created(),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::DestroyedChanged.on_created(),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::LoadedNotExisting.on_created(),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::Loaded.on_created(),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::LoadedEmptyEIP161.on_created(),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::Changed.on_created(),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::InMemoryChange.on_created(),
AccountStatus::InMemoryChange
);
}
#[test]
fn test_on_touched_empty_post_eip161() {
assert_eq!(
AccountStatus::LoadedNotExisting.on_touched_empty_post_eip161(),
AccountStatus::LoadedNotExisting
);
assert_eq!(
AccountStatus::InMemoryChange.on_touched_empty_post_eip161(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::Destroyed.on_touched_empty_post_eip161(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::LoadedEmptyEIP161.on_touched_empty_post_eip161(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::DestroyedAgain.on_touched_empty_post_eip161(),
AccountStatus::DestroyedAgain
);
assert_eq!(
AccountStatus::DestroyedChanged.on_touched_empty_post_eip161(),
AccountStatus::DestroyedAgain
);
assert_eq!(
AccountStatus::Loaded.on_touched_empty_post_eip161(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::Changed.on_touched_empty_post_eip161(),
AccountStatus::Destroyed
);
}
#[test]
fn test_on_changed() {
assert_eq!(
AccountStatus::LoadedNotExisting.on_changed(true),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::LoadedNotExisting.on_changed(false),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::LoadedEmptyEIP161.on_changed(true),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::LoadedEmptyEIP161.on_changed(false),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::Loaded.on_changed(true),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::Loaded.on_changed(false),
AccountStatus::Changed
);
assert_eq!(
AccountStatus::Changed.on_changed(true),
AccountStatus::Changed
);
assert_eq!(
AccountStatus::Changed.on_changed(false),
AccountStatus::Changed
);
assert_eq!(
AccountStatus::InMemoryChange.on_changed(true),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::InMemoryChange.on_changed(false),
AccountStatus::InMemoryChange
);
assert_eq!(
AccountStatus::DestroyedChanged.on_changed(true),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::DestroyedChanged.on_changed(false),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::Destroyed.on_changed(true),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::Destroyed.on_changed(false),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::DestroyedAgain.on_changed(true),
AccountStatus::DestroyedChanged
);
assert_eq!(
AccountStatus::DestroyedAgain.on_changed(false),
AccountStatus::DestroyedChanged
);
}
#[test]
fn test_on_selfdestructed() {
assert_eq!(
AccountStatus::LoadedNotExisting.on_selfdestructed(),
AccountStatus::LoadedNotExisting
);
assert_eq!(
AccountStatus::DestroyedChanged.on_selfdestructed(),
AccountStatus::DestroyedAgain
);
assert_eq!(
AccountStatus::DestroyedAgain.on_selfdestructed(),
AccountStatus::DestroyedAgain
);
assert_eq!(
AccountStatus::Destroyed.on_selfdestructed(),
AccountStatus::DestroyedAgain
);
assert_eq!(
AccountStatus::Loaded.on_selfdestructed(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::LoadedEmptyEIP161.on_selfdestructed(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::InMemoryChange.on_selfdestructed(),
AccountStatus::Destroyed
);
assert_eq!(
AccountStatus::Changed.on_selfdestructed(),
AccountStatus::Destroyed
);
}
#[test]
fn test_transition() {
let mut status = AccountStatus::Destroyed;
status.transition(AccountStatus::Loaded);
assert_eq!(status, AccountStatus::DestroyedChanged);
let mut status = AccountStatus::DestroyedChanged;
status.transition(AccountStatus::InMemoryChange);
assert_eq!(status, AccountStatus::DestroyedChanged);
let mut status = AccountStatus::DestroyedAgain;
status.transition(AccountStatus::Changed);
assert_eq!(status, AccountStatus::DestroyedChanged);
let mut status = AccountStatus::InMemoryChange;
status.transition(AccountStatus::Loaded);
assert_eq!(status, AccountStatus::InMemoryChange);
let mut status = AccountStatus::InMemoryChange;
status.transition(AccountStatus::Changed);
assert_eq!(status, AccountStatus::InMemoryChange);
let mut status = AccountStatus::Loaded;
status.transition(AccountStatus::Changed);
assert_eq!(status, AccountStatus::Changed);
let mut status = AccountStatus::LoadedNotExisting;
status.transition(AccountStatus::InMemoryChange);
assert_eq!(status, AccountStatus::InMemoryChange);
let mut status = AccountStatus::LoadedEmptyEIP161;
status.transition(AccountStatus::Loaded);
assert_eq!(status, AccountStatus::Loaded);
let mut status = AccountStatus::Destroyed;
status.transition(AccountStatus::DestroyedChanged);
assert_eq!(status, AccountStatus::DestroyedChanged);
let mut status = AccountStatus::DestroyedAgain;
status.transition(AccountStatus::Destroyed);
assert_eq!(status, AccountStatus::Destroyed);
let mut status = AccountStatus::Loaded;
status.transition(AccountStatus::Destroyed);
assert_eq!(status, AccountStatus::Destroyed);
let mut status = AccountStatus::Changed;
status.transition(AccountStatus::DestroyedAgain);
assert_eq!(status, AccountStatus::DestroyedAgain);
}
}