use crate::{
db::{StateAcc, TryStateAcc},
helpers::{Ctx, Evm, Instruction},
inspectors::Layered,
ErroredState, EvmErrored, EvmExtUnchecked, Trevm,
};
use alloy::{
primitives::{Address, U256},
rpc::types::state::StateOverride,
};
use core::convert::Infallible;
use revm::{
bytecode::opcode::DIFFICULTY,
context::{result::EVMError, Cfg as _, ContextTr},
handler::EthPrecompiles,
inspector::NoOpInspector,
interpreter::instructions::block_info,
primitives::hardfork::SpecId,
state::{AccountInfo, Bytecode, EvmState},
Database, DatabaseCommit, DatabaseRef, Inspector,
};
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database,
Insp: Inspector<Ctx<Db>>,
{
pub fn inner(&self) -> &Evm<Db, Insp> {
self.as_ref()
}
pub fn inner_mut_unchecked(&mut self) -> &mut Evm<Db, Insp> {
&mut self.inner
}
pub fn into_inner(self) -> Box<Evm<Db, Insp>> {
self.inner
}
pub fn into_db(self) -> Db {
self.inner.ctx.journaled_state.database
}
pub fn inspector(&self) -> &Insp {
&self.inner.inspector
}
pub fn inspector_mut(&mut self) -> &mut Insp {
&mut self.inner.inspector
}
pub fn replace_inspector(mut self, inspector: Insp) -> Self {
*self.inspector_mut() = inspector;
self
}
pub fn layer_inspector<Insp2>(
self,
inspector: Insp2,
) -> Trevm<Db, Layered<Insp2, Insp>, TrevmState>
where
Insp2: Inspector<Ctx<Db>>,
{
let inner = Box::new(Evm {
ctx: self.inner.ctx,
inspector: Layered::new(inspector, self.inner.inspector),
instruction: self.inner.instruction,
precompiles: self.inner.precompiles,
frame_stack: self.inner.frame_stack,
});
Trevm { inner, state: self.state }
}
pub fn take_inspector(self) -> (Insp, Trevm<Db, NoOpInspector, TrevmState>) {
let inspector = self.inner.inspector;
let inner = Box::new(Evm {
ctx: self.inner.ctx,
inspector: NoOpInspector,
instruction: self.inner.instruction,
precompiles: self.inner.precompiles,
frame_stack: self.inner.frame_stack,
});
(inspector, Trevm { inner, state: self.state })
}
pub fn set_inspector<Insp2>(self, inspector: Insp2) -> Trevm<Db, Insp2, TrevmState>
where
Insp2: Inspector<Ctx<Db>>,
{
let inner = Box::new(Evm {
ctx: self.inner.ctx,
inspector,
instruction: self.inner.instruction,
precompiles: self.inner.precompiles,
frame_stack: self.inner.frame_stack,
});
Trevm { inner, state: self.state }
}
pub fn with_inspector<Insp2, F, NewState>(
self,
inspector: Insp2,
f: F,
) -> Trevm<Db, Insp, NewState>
where
Insp2: Inspector<Ctx<Db>>,
F: FnOnce(Trevm<Db, Insp2, TrevmState>) -> Trevm<Db, Insp2, NewState>,
{
let (old, this) = self.take_inspector();
let this = f(this.set_inspector(inspector));
this.set_inspector(old)
}
pub fn try_with_inspector<F, Insp2, NewState, E>(
self,
inspector: Insp2,
f: F,
) -> Result<Trevm<Db, Insp, NewState>, EvmErrored<Db, Insp, E>>
where
Insp2: Inspector<Ctx<Db>>,
F: FnOnce(
Trevm<Db, Insp2, TrevmState>,
) -> Result<Trevm<Db, Insp2, NewState>, EvmErrored<Db, Insp2, E>>,
{
let (previous, this) = self.take_inspector();
let this = this.set_inspector(inspector);
match f(this) {
Ok(evm) => Ok(evm.set_inspector(previous)),
Err(evm) => Err(evm.set_inspector(previous)),
}
}
pub fn spec_id(&self) -> SpecId {
self.inner.ctx.cfg().spec()
}
pub fn set_spec_id(&mut self, spec_id: SpecId) {
self.inner.modify_cfg(|cfg| cfg.spec = spec_id);
}
pub fn with_spec_id<F, NewState>(mut self, spec_id: SpecId, f: F) -> Trevm<Db, Insp, NewState>
where
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
{
let old = self.spec_id();
self.set_spec_id(spec_id);
let mut this = f(self);
this.set_spec_id(old);
this
}
pub fn errored<E>(self, error: E) -> EvmErrored<Db, Insp, E> {
EvmErrored { inner: self.inner, state: ErroredState { error } }
}
pub fn apply_state_overrides(
mut self,
overrides: &StateOverride,
) -> Result<Self, EVMError<<Db as Database>::Error>>
where
Db: DatabaseCommit,
{
for (address, account_override) in overrides {
if let Some(balance) = account_override.balance {
self.inner.set_balance(*address, balance).map_err(EVMError::Database)?;
}
if let Some(nonce) = account_override.nonce {
self.inner.set_nonce(*address, nonce).map_err(EVMError::Database)?;
}
if let Some(code) = account_override.code.as_ref() {
self.inner
.set_bytecode(
*address,
Bytecode::new_raw_checked(code.clone())
.map_err(|_| EVMError::Custom("Invalid bytecode".to_string()))?,
)
.map_err(EVMError::Database)?;
}
if let Some(state) = account_override.state.as_ref() {
for (slot, value) in state {
self.inner
.set_storage(
*address,
U256::from_be_bytes((*slot).into()),
U256::from_be_bytes((*value).into()),
)
.map_err(EVMError::Database)?;
}
}
}
Ok(self)
}
pub fn maybe_apply_state_overrides(
self,
overrides: Option<&StateOverride>,
) -> Result<Self, EVMError<<Db as Database>::Error>>
where
Db: DatabaseCommit,
{
if let Some(overrides) = overrides {
self.apply_state_overrides(overrides)
} else {
Ok(self)
}
}
pub fn override_opcode(&mut self, opcode: u8, handler: Instruction<Db>) -> Instruction<Db> {
std::mem::replace(&mut self.inner.instruction.instruction_table[opcode as usize], handler)
}
pub fn disable_opcode(&mut self, opcode: u8) -> Instruction<Db> {
self.override_opcode(opcode, Instruction::new(crate::helpers::forbidden, 0))
}
pub fn with_opcode_override<F, NewState>(
mut self,
opcode: u8,
handler: Instruction<Db>,
f: F,
) -> Trevm<Db, Insp, NewState>
where
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
{
let old = self.override_opcode(opcode, handler);
self.inner.instruction.insert_instruction(opcode, handler);
let mut this = f(self);
this.override_opcode(opcode, old);
this
}
pub fn disable_prevrandao(&mut self) -> Instruction<Db> {
self.disable_opcode(DIFFICULTY)
}
pub fn enable_prevrandao(&mut self) -> Instruction<Db> {
self.override_opcode(DIFFICULTY, Instruction::new(block_info::difficulty, 2))
}
pub fn without_prevrandao<F, NewState>(self, f: F) -> Trevm<Db, Insp, NewState>
where
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
{
self.with_opcode_override(DIFFICULTY, Instruction::new(crate::helpers::forbidden, 0), f)
}
pub fn override_precompiles(&mut self, precompiles: EthPrecompiles) -> EthPrecompiles {
std::mem::replace(&mut self.inner.precompiles, precompiles)
}
pub fn with_precompiles<F, NewState>(
mut self,
precompiles: EthPrecompiles,
f: F,
) -> Trevm<Db, Insp, NewState>
where
F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
{
let old = self.override_precompiles(precompiles);
let mut this = f(self);
this.override_precompiles(old);
this
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database,
Insp: Inspector<Ctx<Db>>,
{
pub fn try_read_account(
&mut self,
address: Address,
) -> Result<Option<AccountInfo>, <Db as Database>::Error> {
self.inner.db_mut().basic(address)
}
pub fn try_read_nonce(&mut self, address: Address) -> Result<u64, <Db as Database>::Error> {
self.try_read_account(address).map(|a| a.map(|a| a.nonce).unwrap_or_default())
}
pub fn try_read_balance(&mut self, address: Address) -> Result<U256, <Db as Database>::Error> {
self.try_read_account(address).map(|a| a.map(|a| a.balance).unwrap_or_default())
}
pub fn try_read_storage(
&mut self,
address: Address,
slot: U256,
) -> Result<U256, <Db as Database>::Error> {
self.inner.db_mut().storage(address, slot)
}
pub fn try_read_code(
&mut self,
address: Address,
) -> Result<Option<Bytecode>, <Db as Database>::Error> {
let acct_info = self.try_read_account(address)?;
match acct_info {
Some(acct) => Ok(Some(self.inner.db_mut().code_by_hash(acct.code_hash)?)),
None => Ok(None),
}
}
pub fn try_gas_allowance(
&mut self,
caller: Address,
gas_price: u128,
) -> Result<u64, <Db as Database>::Error> {
if gas_price == 0 {
return Ok(u64::MAX);
}
let gas_price = U256::from(gas_price);
let balance = self.try_read_balance(caller)?;
Ok((balance / gas_price).saturating_to())
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database + DatabaseRef,
Insp: Inspector<Ctx<Db>>,
{
pub fn try_read_account_ref(
&self,
address: Address,
) -> Result<Option<AccountInfo>, <Db as DatabaseRef>::Error> {
self.inner.db_ref().basic_ref(address)
}
pub fn try_read_nonce_ref(&self, address: Address) -> Result<u64, <Db as DatabaseRef>::Error> {
self.try_read_account_ref(address).map(|a| a.map(|a| a.nonce).unwrap_or_default())
}
pub fn try_read_balance_ref(
&self,
address: Address,
) -> Result<U256, <Db as DatabaseRef>::Error> {
self.try_read_account_ref(address).map(|a| a.map(|a| a.balance).unwrap_or_default())
}
pub fn try_read_storage_ref(
&self,
address: Address,
slot: U256,
) -> Result<U256, <Db as DatabaseRef>::Error> {
self.inner.db_ref().storage_ref(address, slot)
}
pub fn try_read_code_ref(
&self,
address: Address,
) -> Result<Option<Bytecode>, <Db as DatabaseRef>::Error> {
let acct_info = self.try_read_account_ref(address)?;
match acct_info {
Some(acct) => Ok(Some(self.inner.db_ref().code_by_hash_ref(acct.code_hash)?)),
None => Ok(None),
}
}
pub fn try_gas_allowance_ref(
&self,
caller: Address,
gas_price: U256,
) -> Result<u64, <Db as DatabaseRef>::Error> {
if gas_price.is_zero() {
return Ok(u64::MAX);
}
let gas_price = U256::from(gas_price);
let balance = self.try_read_balance_ref(caller)?;
Ok((balance / gas_price).saturating_to())
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database<Error = Infallible>,
Insp: Inspector<Ctx<Db>>,
{
pub fn read_account(&mut self, address: Address) -> Option<AccountInfo> {
self.inner.db_mut().basic(address).expect("infallible")
}
pub fn read_nonce(&mut self, address: Address) -> u64 {
self.read_account(address).map(|a: AccountInfo| a.nonce).unwrap_or_default()
}
pub fn read_balance(&mut self, address: Address) -> U256 {
self.read_account(address).map(|a: AccountInfo| a.balance).unwrap_or_default()
}
pub fn read_storage(&mut self, address: Address, slot: U256) -> U256 {
self.inner.db_mut().storage(address, slot).expect("infallible")
}
pub fn read_code(&mut self, address: Address) -> Option<Bytecode> {
let acct_info = self.read_account(address)?;
Some(self.inner.db_mut().code_by_hash(acct_info.code_hash).expect("infallible"))
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database + DatabaseRef,
Insp: Inspector<Ctx<Db>>,
{
pub fn read_account_ref(&self, address: Address) -> Option<AccountInfo> {
self.inner.db_ref().basic_ref(address).expect("infallible")
}
pub fn read_nonce_ref(&self, address: Address) -> u64 {
self.read_account_ref(address).map(|a: AccountInfo| a.nonce).unwrap_or_default()
}
pub fn read_balance_ref(&self, address: Address) -> U256 {
self.read_account_ref(address).map(|a: AccountInfo| a.balance).unwrap_or_default()
}
pub fn read_storage_ref(&self, address: Address, slot: U256) -> U256 {
self.inner.db_ref().storage_ref(address, slot).expect("infallible")
}
pub fn read_code_ref(&self, address: Address) -> Option<Bytecode> {
let acct_info = self.read_account_ref(address)?;
Some(self.inner.db_ref().code_by_hash_ref(acct_info.code_hash).expect("infallible"))
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database,
Insp: Inspector<Ctx<Db>>,
{
pub fn commit_unchecked(&mut self, state: EvmState)
where
Db: DatabaseCommit,
{
self.inner.db_mut().commit(state);
}
pub fn try_modify_account_unchecked<F: FnOnce(&mut AccountInfo)>(
&mut self,
address: Address,
f: F,
) -> Result<AccountInfo, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.modify_account(address, f)
}
pub fn try_set_nonce_unchecked(
&mut self,
address: Address,
nonce: u64,
) -> Result<u64, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.set_nonce(address, nonce)
}
pub fn try_increment_nonce_unchecked(
&mut self,
address: Address,
) -> Result<u64, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.increment_nonce(address)
}
pub fn try_decrement_nonce_unchecked(
&mut self,
address: Address,
) -> Result<u64, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.decrement_nonce(address)
}
pub fn try_set_storage_unchecked(
&mut self,
address: Address,
slot: U256,
value: U256,
) -> Result<U256, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.set_storage(address, slot, value)
}
pub fn try_set_bytecode_unchecked(
&mut self,
address: Address,
bytecode: Bytecode,
) -> Result<Option<Bytecode>, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.set_bytecode(address, bytecode)
}
pub fn try_increase_balance_unchecked(
&mut self,
address: Address,
amount: U256,
) -> Result<U256, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.increase_balance(address, amount)
}
pub fn try_decrease_balance_unchecked(
&mut self,
address: Address,
amount: U256,
) -> Result<U256, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.decrease_balance(address, amount)
}
pub fn try_set_balance_unchecked(
&mut self,
address: Address,
amount: U256,
) -> Result<U256, <Db as Database>::Error>
where
Db: DatabaseCommit,
{
self.inner.set_balance(address, amount)
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database<Error = Infallible>,
Insp: Inspector<Ctx<Db>>,
{
pub fn modify_account_unchecked(
&mut self,
address: Address,
f: impl FnOnce(&mut AccountInfo),
) -> AccountInfo
where
Db: DatabaseCommit,
{
self.try_modify_account_unchecked(address, f).expect("infallible")
}
pub fn set_nonce_unchecked(&mut self, address: Address, nonce: u64) -> u64
where
Db: DatabaseCommit,
{
self.try_set_nonce_unchecked(address, nonce).expect("infallible")
}
pub fn increment_nonce_unchecked(&mut self, address: Address) -> u64
where
Db: DatabaseCommit,
{
self.try_increment_nonce_unchecked(address).expect("infallible")
}
pub fn decrement_nonce_unchecked(&mut self, address: Address) -> u64
where
Db: DatabaseCommit,
{
self.try_decrement_nonce_unchecked(address).expect("infallible")
}
pub fn set_storage_unchecked(&mut self, address: Address, slot: U256, value: U256) -> U256
where
Db: DatabaseCommit,
{
self.try_set_storage_unchecked(address, slot, value).expect("infallible")
}
pub fn set_bytecode_unchecked(
&mut self,
address: Address,
bytecode: Bytecode,
) -> Option<Bytecode>
where
Db: DatabaseCommit,
{
self.try_set_bytecode_unchecked(address, bytecode).expect("infallible")
}
pub fn increase_balance_unchecked(&mut self, address: Address, amount: U256) -> U256
where
Db: DatabaseCommit,
{
self.try_increase_balance_unchecked(address, amount).expect("infallible")
}
pub fn decrease_balance_unchecked(&mut self, address: Address, amount: U256) -> U256
where
Db: DatabaseCommit,
{
self.try_decrease_balance_unchecked(address, amount).expect("infallible")
}
pub fn set_balance_unchecked(&mut self, address: Address, amount: U256) -> U256
where
Db: DatabaseCommit,
{
self.try_set_balance_unchecked(address, amount).expect("infallible")
}
}
impl<Db, Outer, Inner, TrevmState> Trevm<Db, Layered<Outer, Inner>, TrevmState>
where
Db: Database,
Outer: Inspector<Ctx<Db>>,
Inner: Inspector<Ctx<Db>>,
{
pub fn take_outer(self) -> (Outer, Trevm<Db, Inner, TrevmState>) {
let (outer, inner) = self.inner.inspector.into_parts();
(
outer,
Trevm {
inner: Box::new(Evm {
ctx: self.inner.ctx,
inspector: inner,
instruction: self.inner.instruction,
precompiles: self.inner.precompiles,
frame_stack: self.inner.frame_stack,
}),
state: self.state,
},
)
}
pub fn remove_outer(self) -> Trevm<Db, Inner, TrevmState> {
self.take_outer().1
}
pub fn take_inner(self) -> (Inner, Trevm<Db, Outer, TrevmState>) {
let (outer, inner) = self.inner.inspector.into_parts();
(
inner,
Trevm {
inner: Box::new(Evm {
ctx: self.inner.ctx,
inspector: outer,
instruction: self.inner.instruction,
precompiles: self.inner.precompiles,
frame_stack: self.inner.frame_stack,
}),
state: self.state,
},
)
}
pub fn remove_inner(self) -> Trevm<Db, Outer, TrevmState> {
self.take_inner().1
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database + StateAcc,
Insp: Inspector<Ctx<Db>>,
{
pub fn set_state_clear_flag(&mut self, flag: bool) {
self.inner.db_mut().set_state_clear_flag(flag)
}
}
impl<Db, Insp, TrevmState> Trevm<Db, Insp, TrevmState>
where
Db: Database + TryStateAcc,
Insp: Inspector<Ctx<Db>>,
{
pub fn try_set_state_clear_flag(
&mut self,
flag: bool,
) -> Result<(), <Db as TryStateAcc>::Error> {
self.inner.db_mut().try_set_state_clear_flag(flag)
}
}