use core::ops::{Deref, DerefMut};
use primitives::{Address, Bytes, Log, B256, U256};
mod dummy;
pub use dummy::DummyHost;
use wiring::{default::EnvWiring, EvmWiring};
pub trait Host {
type EvmWiringT: EvmWiring;
fn env(&self) -> &EnvWiring<Self::EvmWiringT>;
fn env_mut(&mut self) -> &mut EnvWiring<Self::EvmWiringT>;
fn load_account_delegated(&mut self, address: Address) -> Option<AccountLoad>;
fn block_hash(&mut self, number: u64) -> Option<B256>;
fn balance(&mut self, address: Address) -> Option<StateLoad<U256>>;
fn code(&mut self, address: Address) -> Option<Eip7702CodeLoad<Bytes>>;
fn code_hash(&mut self, address: Address) -> Option<Eip7702CodeLoad<B256>>;
fn sload(&mut self, address: Address, index: U256) -> Option<StateLoad<U256>>;
fn sstore(
&mut self,
address: Address,
index: U256,
value: U256,
) -> Option<StateLoad<SStoreResult>>;
fn tload(&mut self, address: Address, index: U256) -> U256;
fn tstore(&mut self, address: Address, index: U256, value: U256);
fn log(&mut self, log: Log);
fn selfdestruct(
&mut self,
address: Address,
target: Address,
) -> Option<StateLoad<SelfDestructResult>>;
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SStoreResult {
pub original_value: U256,
pub present_value: U256,
pub new_value: U256,
}
impl SStoreResult {
#[inline]
pub fn is_new_eq_present(&self) -> bool {
self.new_value == self.present_value
}
#[inline]
pub fn is_original_eq_present(&self) -> bool {
self.original_value == self.present_value
}
#[inline]
pub fn is_original_eq_new(&self) -> bool {
self.original_value == self.new_value
}
#[inline]
pub fn is_original_zero(&self) -> bool {
self.original_value.is_zero()
}
#[inline]
pub fn is_present_zero(&self) -> bool {
self.present_value.is_zero()
}
#[inline]
pub fn is_new_zero(&self) -> bool {
self.new_value.is_zero()
}
}
#[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 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 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),
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SelfDestructResult {
pub had_value: bool,
pub target_exists: bool,
pub previously_destroyed: bool,
}
#[cfg(test)]
mod tests {
use database_interface::EmptyDB;
use wiring::EthereumWiring;
use super::*;
fn assert_host<H: Host + ?Sized>() {}
#[test]
fn object_safety() {
assert_host::<DummyHost<EthereumWiring<EmptyDB, ()>>>();
assert_host::<dyn Host<EvmWiringT = EthereumWiring<EmptyDB, ()>>>();
}
}