use alloc::{rc::Rc, vec::Vec};
use sha3::{Digest, Keccak256};
use crate::error::ExitError;
#[allow(unused_imports)]
use crate::uint::{H160, H256, U256, U256Ext};
pub trait GasState {
fn gas(&self) -> U256;
}
#[derive(Clone, Debug)]
pub struct RuntimeState {
pub context: Context,
pub transaction_context: Rc<TransactionContext>,
pub retbuf: Vec<u8>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct RuntimeConfig {
pub eip161_empty_check: bool,
pub eip7610_create_check_storage: bool,
pub eip6780_suicide_only_in_same_tx: bool,
pub eip3651_warm_coinbase_address: bool,
}
impl RuntimeConfig {
pub const fn new() -> Self {
Self {
eip161_empty_check: true,
eip7610_create_check_storage: true,
eip6780_suicide_only_in_same_tx: false,
eip3651_warm_coinbase_address: false,
}
}
pub const fn frontier() -> Self {
Self {
eip161_empty_check: false,
eip6780_suicide_only_in_same_tx: false,
eip7610_create_check_storage: true,
eip3651_warm_coinbase_address: false,
}
}
}
impl Default for RuntimeConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct RuntimeStateAndConfig<'config> {
pub state: RuntimeState,
pub config: &'config RuntimeConfig,
}
static DEFAULT_RUNTIME_CONFIG: RuntimeConfig = RuntimeConfig::new();
impl RuntimeStateAndConfig<'static> {
pub fn with_default_config(state: RuntimeState) -> Self {
Self {
state,
config: &DEFAULT_RUNTIME_CONFIG,
}
}
}
impl AsRef<RuntimeState> for RuntimeState {
fn as_ref(&self) -> &RuntimeState {
self
}
}
impl<'config> AsRef<RuntimeState> for RuntimeStateAndConfig<'config> {
fn as_ref(&self) -> &RuntimeState {
&self.state
}
}
impl AsMut<RuntimeState> for RuntimeState {
fn as_mut(&mut self) -> &mut RuntimeState {
self
}
}
impl<'config> AsMut<RuntimeState> for RuntimeStateAndConfig<'config> {
fn as_mut(&mut self) -> &mut RuntimeState {
&mut self.state
}
}
impl<'config> AsRef<RuntimeConfig> for RuntimeStateAndConfig<'config> {
fn as_ref(&self) -> &RuntimeConfig {
self.config
}
}
impl GasState for RuntimeState {
fn gas(&self) -> U256 {
U256::ZERO
}
}
impl<'config> GasState for RuntimeStateAndConfig<'config> {
fn gas(&self) -> U256 {
U256::ZERO
}
}
#[derive(Clone, Debug)]
pub struct Context {
pub address: H160,
pub caller: H160,
pub apparent_value: U256,
}
#[derive(Clone, Debug)]
pub struct TransactionContext {
pub gas_price: U256,
pub origin: H160,
}
#[derive(Clone, Debug)]
pub struct Transfer {
pub source: H160,
pub target: H160,
pub value: U256,
}
#[derive(Clone, Debug)]
pub struct Log {
pub address: H160,
pub topics: Vec<H256>,
pub data: Vec<u8>,
}
#[derive(Clone, Debug)]
pub enum SetCodeOrigin {
Transaction,
Subcall(H160),
}
#[auto_impl::auto_impl(&, Box)]
pub trait RuntimeEnvironment {
fn block_hash(&self, number: U256) -> H256;
fn block_number(&self) -> U256;
fn block_coinbase(&self) -> H160;
fn block_timestamp(&self) -> U256;
fn block_difficulty(&self) -> U256;
fn block_randomness(&self) -> Option<H256>;
fn block_gas_limit(&self) -> U256;
fn block_base_fee_per_gas(&self) -> U256;
fn blob_versioned_hash(&self, index: U256) -> H256;
fn blob_base_fee_per_gas(&self) -> U256;
fn chain_id(&self) -> U256;
}
#[auto_impl::auto_impl(&, Box)]
pub trait RuntimeBaseBackend {
fn balance(&self, address: H160) -> U256;
fn code_size(&self, address: H160) -> U256 {
U256::from_usize(self.code(address).len())
}
fn code_hash(&self, address: H160) -> H256 {
if self.exists(address) {
H256::from_slice(&Keccak256::digest(&self.code(address)[..]))
} else {
H256::default()
}
}
fn code(&self, address: H160) -> Vec<u8>;
fn storage(&self, address: H160, index: H256) -> H256;
fn transient_storage(&self, address: H160, index: H256) -> H256;
fn exists(&self, address: H160) -> bool;
fn can_create(&self, address: H160) -> bool {
self.code_size(address) == U256::ZERO && self.nonce(address) == U256::ZERO
}
fn nonce(&self, address: H160) -> U256;
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TouchKind {
StateChange,
Coinbase,
Access,
}
pub trait RuntimeBackend: RuntimeBaseBackend {
fn original_storage(&self, address: H160, index: H256) -> H256;
fn deleted(&self, address: H160) -> bool;
fn created(&self, address: H160) -> bool;
fn is_cold(&self, address: H160, index: Option<H256>) -> bool;
fn is_hot(&self, address: H160, index: Option<H256>) -> bool {
!self.is_cold(address, index)
}
fn mark_hot(&mut self, address: H160, kind: TouchKind);
fn mark_storage_hot(&mut self, address: H160, index: H256);
fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError>;
fn set_transient_storage(
&mut self,
address: H160,
index: H256,
value: H256,
) -> Result<(), ExitError>;
fn log(&mut self, log: Log) -> Result<(), ExitError>;
fn mark_delete_reset(&mut self, address: H160);
fn mark_create(&mut self, address: H160);
fn reset_storage(&mut self, address: H160);
fn set_code(
&mut self,
address: H160,
code: Vec<u8>,
origin: SetCodeOrigin,
) -> Result<(), ExitError>;
fn deposit(&mut self, target: H160, value: U256);
fn withdrawal(&mut self, source: H160, value: U256) -> Result<(), ExitError>;
fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> {
self.withdrawal(transfer.source, transfer.value)?;
self.deposit(transfer.target, transfer.value);
Ok(())
}
fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError>;
}