mod context_precompiles;
pub(crate) mod evm_context;
mod inner_evm_context;
pub use context_precompiles::{
ContextPrecompile, ContextPrecompiles, ContextStatefulPrecompile, ContextStatefulPrecompileArc,
ContextStatefulPrecompileBox, ContextStatefulPrecompileMut,
};
pub use evm_context::EvmContext;
pub use inner_evm_context::InnerEvmContext;
use revm_interpreter::{as_u64_saturated, Eip7702CodeLoad, StateLoad};
use crate::{
db::{Database, EmptyDB},
interpreter::{AccountLoad, Host, SStoreResult, SelfDestructResult},
primitives::{Address, Bytes, Env, HandlerCfg, Log, B256, BLOCK_HASH_HISTORY, U256},
};
use std::boxed::Box;
pub struct Context<EXT, DB: Database> {
pub evm: EvmContext<DB>,
pub external: EXT,
}
impl<EXT: Clone, DB: Database + Clone> Clone for Context<EXT, DB>
where
DB::Error: Clone,
{
fn clone(&self) -> Self {
Self {
evm: self.evm.clone(),
external: self.external.clone(),
}
}
}
impl Default for Context<(), EmptyDB> {
fn default() -> Self {
Self::new_empty()
}
}
impl Context<(), EmptyDB> {
pub fn new_empty() -> Context<(), EmptyDB> {
Context {
evm: EvmContext::new(EmptyDB::new()),
external: (),
}
}
}
impl<DB: Database> Context<(), DB> {
pub fn new_with_db(db: DB) -> Context<(), DB> {
Context {
evm: EvmContext::new_with_env(db, Box::default()),
external: (),
}
}
}
impl<EXT, DB: Database> Context<EXT, DB> {
pub fn new(evm: EvmContext<DB>, external: EXT) -> Context<EXT, DB> {
Context { evm, external }
}
}
pub struct ContextWithHandlerCfg<EXT, DB: Database> {
pub context: Context<EXT, DB>,
pub cfg: HandlerCfg,
}
impl<EXT, DB: Database> ContextWithHandlerCfg<EXT, DB> {
pub fn new(context: Context<EXT, DB>, cfg: HandlerCfg) -> Self {
Self { cfg, context }
}
}
impl<EXT: Clone, DB: Database + Clone> Clone for ContextWithHandlerCfg<EXT, DB>
where
DB::Error: Clone,
{
fn clone(&self) -> Self {
Self {
context: self.context.clone(),
cfg: self.cfg,
}
}
}
impl<EXT, DB: Database> Host for Context<EXT, DB> {
#[inline]
fn env(&self) -> &Env {
&self.evm.env
}
fn env_mut(&mut self) -> &mut Env {
&mut self.evm.env
}
fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
let block_number = as_u64_saturated!(self.env().block.number);
let Some(diff) = block_number.checked_sub(requested_number) else {
return Some(B256::ZERO);
};
if diff == 0 {
return Some(B256::ZERO);
}
if diff <= BLOCK_HASH_HISTORY {
return self
.evm
.block_hash(requested_number)
.map_err(|e| self.evm.error = Err(e))
.ok();
}
Some(B256::ZERO)
}
fn load_account_delegated(&mut self, address: Address) -> Option<AccountLoad> {
self.evm
.load_account_delegated(address)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
fn balance(&mut self, address: Address) -> Option<StateLoad<U256>> {
self.evm
.balance(address)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
fn code(&mut self, address: Address) -> Option<Eip7702CodeLoad<Bytes>> {
self.evm
.code(address)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
fn code_hash(&mut self, address: Address) -> Option<Eip7702CodeLoad<B256>> {
self.evm
.code_hash(address)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
fn sload(&mut self, address: Address, index: U256) -> Option<StateLoad<U256>> {
self.evm
.sload(address, index)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
fn sstore(
&mut self,
address: Address,
index: U256,
value: U256,
) -> Option<StateLoad<SStoreResult>> {
self.evm
.sstore(address, index, value)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
fn tload(&mut self, address: Address, index: U256) -> U256 {
self.evm.tload(address, index)
}
fn tstore(&mut self, address: Address, index: U256, value: U256) {
self.evm.tstore(address, index, value)
}
fn log(&mut self, log: Log) {
self.evm.journaled_state.log(log);
}
fn selfdestruct(
&mut self,
address: Address,
target: Address,
) -> Option<StateLoad<SelfDestructResult>> {
self.evm
.inner
.journaled_state
.selfdestruct(address, target, &mut self.evm.inner.db)
.map_err(|e| self.evm.error = Err(e))
.ok()
}
}