use crate::context::{SStoreResult, SelfDestructResult};
use core::ops::{Deref, DerefMut};
use database_interface::Database;
use primitives::{
hardfork::SpecId, Address, Bytes, HashSet, Log, StorageKey, StorageValue, B256, U256,
};
use state::{
bytecode::{EOF_MAGIC_BYTES, EOF_MAGIC_HASH},
Account, Bytecode,
};
use std::vec::Vec;
pub trait JournalTr {
type Database: Database;
type State;
fn new(database: Self::Database) -> Self;
fn db_mut(&mut self) -> &mut Self::Database;
fn db(&self) -> &Self::Database;
fn sload(
&mut self,
address: Address,
key: StorageKey,
) -> Result<StateLoad<StorageValue>, <Self::Database as Database>::Error>;
fn sstore(
&mut self,
address: Address,
key: StorageKey,
value: StorageValue,
) -> Result<StateLoad<SStoreResult>, <Self::Database as Database>::Error>;
fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
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 = StorageKey>,
) -> 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 caller_accounting_journal_entry(
&mut self,
address: Address,
old_balance: U256,
bump_nonce: bool,
);
fn balance_incr(
&mut self,
address: Address,
balance: U256,
) -> Result<(), <Self::Database as Database>::Error>;
fn nonce_bump_journal_entry(&mut self, address: Address);
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);
}
#[inline]
fn code(
&mut self,
address: Address,
) -> Result<StateLoad<Bytes>, <Self::Database as Database>::Error> {
let a = self.load_account_code(address)?;
let code = a.info.code.as_ref().unwrap();
let code = if code.is_eof() {
EOF_MAGIC_BYTES.clone()
} else {
code.original_bytes()
};
Ok(StateLoad::new(code, a.is_cold))
}
fn code_hash(
&mut self,
address: Address,
) -> Result<StateLoad<B256>, <Self::Database as Database>::Error> {
let acc = self.load_account_code(address)?;
if acc.is_empty() {
return Ok(StateLoad::new(B256::ZERO, acc.is_cold));
}
let code = acc.info.code.as_ref().unwrap();
let hash = if code.is_eof() {
EOF_MAGIC_HASH
} else {
acc.info.code_hash
};
Ok(StateLoad::new(hash, acc.is_cold))
}
fn clear(&mut self) {
let _ = self.finalize();
}
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 take_logs(&mut self) -> Vec<Log>;
fn commit_tx(&mut self);
fn discard_tx(&mut self);
fn finalize(&mut self) -> Self::State;
}
#[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,
}