use core::ops::{Deref, DerefMut};
use database_interface::{Database, DatabaseGetter};
use primitives::{Address, HashSet, Log, B256, U256};
use specification::hardfork::SpecId;
use state::{Account, Bytecode};
use std::boxed::Box;
use crate::host::{SStoreResult, SelfDestructResult};
pub trait Journal {
type Database: Database;
type FinalOutput;
fn new(database: Self::Database) -> Self;
fn db_ref(&self) -> &Self::Database;
fn db(&mut self) -> &mut Self::Database;
fn sload(
&mut self,
address: Address,
key: U256,
) -> Result<StateLoad<U256>, <Self::Database as Database>::Error>;
fn sstore(
&mut self,
address: Address,
key: U256,
value: U256,
) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error>;
fn tload(&mut self, address: Address, key: U256) -> U256;
fn tstore(&mut self, address: Address, key: U256, value: U256);
fn log(&mut self, log: Log);
fn selfdestruct(
&mut self,
address: Address,
target: Address,
) -> Result<StateLoad<SelfDestructResult>, <Self::Database as Database>::Error>;
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 warm_precompiles(&mut self, addresses: HashSet<Address>);
fn precompile_addresses(&self) -> &HashSet<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<StateLoad<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 is_delegate_account_cold: Option<bool>,
pub is_empty: bool,
}
pub type JournalDBError<CTX> =
<<<CTX as JournalGetter>::Journal as Journal>::Database as Database>::Error;
pub trait JournalGetter: DatabaseGetter {
type Journal: Journal<Database = <Self as DatabaseGetter>::Database>;
fn journal(&mut self) -> &mut Self::Journal;
fn journal_ref(&self) -> &Self::Journal;
}
impl<T: JournalGetter> JournalGetter for &mut T {
type Journal = T::Journal;
fn journal(&mut self) -> &mut Self::Journal {
T::journal(*self)
}
fn journal_ref(&self) -> &Self::Journal {
T::journal_ref(*self)
}
}
impl<T: JournalGetter> JournalGetter for Box<T> {
type Journal = T::Journal;
fn journal(&mut self) -> &mut Self::Journal {
T::journal(self.as_mut())
}
fn journal_ref(&self) -> &Self::Journal {
T::journal_ref(self.as_ref())
}
}