use core::ops::{Deref, DerefMut};
use database_interface::{Database, DatabaseGetter};
use primitives::{Address, B256, U256};
use specification::hardfork::SpecId;
use state::{Account, Bytecode};
use std::boxed::Box;
pub trait JournaledState {
type Database: Database;
type FinalOutput;
fn warm_account_and_storage(
&mut self,
address: Address,
storage_keys: impl IntoIterator<Item = U256>,
) -> Result<(), <Self::Database as Database>::Error>;
fn warm_account(&mut self, address: Address);
fn set_spec_id(&mut self, spec_id: SpecId);
fn touch_account(&mut self, address: Address);
fn transfer(
&mut self,
from: &Address,
to: &Address,
balance: U256,
) -> Result<Option<TransferError>, <Self::Database as Database>::Error>;
fn inc_account_nonce(
&mut self,
address: Address,
) -> Result<Option<u64>, <Self::Database as Database>::Error>;
fn load_account(
&mut self,
address: Address,
) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
fn load_account_code(
&mut self,
address: Address,
) -> Result<StateLoad<&mut Account>, <Self::Database as Database>::Error>;
fn load_account_delegated(
&mut self,
address: Address,
) -> Result<AccountLoad, <Self::Database as Database>::Error>;
fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
#[inline]
fn set_code(&mut self, address: Address, code: Bytecode) {
let hash = code.hash_slow();
self.set_code_with_hash(address, code, hash);
}
fn clear(&mut self);
fn checkpoint(&mut self) -> JournalCheckpoint;
fn checkpoint_commit(&mut self);
fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint);
fn create_account_checkpoint(
&mut self,
caller: Address,
address: Address,
balance: U256,
spec_id: SpecId,
) -> Result<JournalCheckpoint, TransferError>;
fn depth(&self) -> usize;
fn finalize(&mut self) -> Result<Self::FinalOutput, <Self::Database as Database>::Error>;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum TransferError {
OutOfFunds,
OverflowPayment,
CreateCollision,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JournalCheckpoint {
pub log_i: usize,
pub journal_i: usize,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StateLoad<T> {
pub data: T,
pub is_cold: bool,
}
impl<T> Deref for StateLoad<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DerefMut for StateLoad<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T> StateLoad<T> {
pub fn new(data: T, is_cold: bool) -> Self {
Self { data, is_cold }
}
pub fn map<B, F>(self, f: F) -> StateLoad<B>
where
F: FnOnce(T) -> B,
{
StateLoad::new(f(self.data), self.is_cold)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AccountLoad {
pub load: Eip7702CodeLoad<()>,
pub is_empty: bool,
}
impl Deref for AccountLoad {
type Target = Eip7702CodeLoad<()>;
fn deref(&self) -> &Self::Target {
&self.load
}
}
impl DerefMut for AccountLoad {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.load
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Eip7702CodeLoad<T> {
pub state_load: StateLoad<T>,
pub is_delegate_account_cold: Option<bool>,
}
impl<T> Deref for Eip7702CodeLoad<T> {
type Target = StateLoad<T>;
fn deref(&self) -> &Self::Target {
&self.state_load
}
}
impl<T> DerefMut for Eip7702CodeLoad<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state_load
}
}
impl<T> Eip7702CodeLoad<T> {
pub fn new_state_load(state_load: StateLoad<T>) -> Self {
Self {
state_load,
is_delegate_account_cold: None,
}
}
pub fn new_not_delegated(data: T, is_cold: bool) -> Self {
Self {
state_load: StateLoad::new(data, is_cold),
is_delegate_account_cold: None,
}
}
pub fn into_components(self) -> (T, Eip7702CodeLoad<()>) {
let is_cold = self.is_cold;
(
self.state_load.data,
Eip7702CodeLoad {
state_load: StateLoad::new((), is_cold),
is_delegate_account_cold: self.is_delegate_account_cold,
},
)
}
pub fn set_delegate_load(&mut self, is_delegate_account_cold: bool) {
self.is_delegate_account_cold = Some(is_delegate_account_cold);
}
pub fn new(state_load: StateLoad<T>, is_delegate_account_cold: bool) -> Self {
Self {
state_load,
is_delegate_account_cold: Some(is_delegate_account_cold),
}
}
}
pub type JournalStateGetterDBError<CTX> =
<<<CTX as JournalStateGetter>::Journal as JournaledState>::Database as Database>::Error;
pub trait JournalStateGetter: DatabaseGetter {
type Journal: JournaledState<Database = <Self as DatabaseGetter>::Database>;
fn journal(&mut self) -> &mut Self::Journal;
}
impl<T: JournalStateGetter> JournalStateGetter for &mut T {
type Journal = T::Journal;
fn journal(&mut self) -> &mut Self::Journal {
T::journal(*self)
}
}
impl<T: JournalStateGetter> JournalStateGetter for Box<T> {
type Journal = T::Journal;
fn journal(&mut self) -> &mut Self::Journal {
T::journal(self.as_mut())
}
}