Skip to main content

tempo_revm/
exec.rs

1use crate::{
2    TempoBlockEnv, TempoInvalidTransaction, TempoTxEnv,
3    error::TempoHaltReason,
4    evm::{TempoContext, TempoEvm},
5    handler::TempoEvmHandler,
6};
7use alloy_evm::{Database, TransactionEnvMut};
8use revm::{
9    DatabaseCommit, ExecuteCommitEvm, ExecuteEvm,
10    context::{ContextSetters, TxEnv, result::ExecResultAndState},
11    context_interface::{
12        ContextTr, JournalTr,
13        result::{EVMError, ExecutionResult},
14    },
15    handler::{Handler, SystemCallTx, system_call::SystemCallEvm},
16    inspector::{InspectCommitEvm, InspectEvm, InspectSystemCallEvm, Inspector, InspectorHandler},
17    primitives::{Address, Bytes},
18    state::EvmState,
19};
20
21/// Total gas system transactions are allowed to use.
22const SYSTEM_CALL_GAS_LIMIT: u64 = 250_000_000;
23
24impl<DB, I> ExecuteEvm for TempoEvm<DB, I>
25where
26    DB: Database,
27{
28    type Tx = TempoTxEnv;
29    type Block = TempoBlockEnv;
30    type State = EvmState;
31    type Error = EVMError<DB::Error, TempoInvalidTransaction>;
32    type ExecutionResult = ExecutionResult<TempoHaltReason>;
33
34    fn set_block(&mut self, block: Self::Block) {
35        self.inner.ctx.set_block(block);
36    }
37
38    fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
39        self.inner.ctx.set_tx(tx);
40        let mut h = TempoEvmHandler::new();
41        h.run(self)
42    }
43
44    fn finalize(&mut self) -> Self::State {
45        self.inner.ctx.journal_mut().finalize()
46    }
47
48    fn replay(
49        &mut self,
50    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
51        let mut h = TempoEvmHandler::new();
52        h.run(self).map(|result| {
53            let state = self.finalize();
54            ExecResultAndState::new(result, state)
55        })
56    }
57}
58
59impl<DB, I> ExecuteCommitEvm for TempoEvm<DB, I>
60where
61    DB: Database + DatabaseCommit,
62{
63    fn commit(&mut self, state: Self::State) {
64        self.inner.ctx.db_mut().commit(state);
65    }
66}
67
68impl<DB, I> InspectEvm for TempoEvm<DB, I>
69where
70    DB: Database,
71    I: Inspector<TempoContext<DB>>,
72{
73    type Inspector = I;
74
75    fn set_inspector(&mut self, inspector: Self::Inspector) {
76        self.inner.inspector = inspector;
77    }
78
79    fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
80        self.inner.ctx.set_tx(tx);
81        let mut h = TempoEvmHandler::new();
82        h.inspect_run(self)
83    }
84}
85
86impl<DB, I> InspectCommitEvm for TempoEvm<DB, I>
87where
88    DB: Database + DatabaseCommit,
89    I: Inspector<TempoContext<DB>>,
90{
91}
92
93impl<DB, I> SystemCallEvm for TempoEvm<DB, I>
94where
95    DB: Database,
96{
97    fn system_call_one_with_caller(
98        &mut self,
99        caller: Address,
100        system_contract_address: Address,
101        data: Bytes,
102    ) -> Result<Self::ExecutionResult, Self::Error> {
103        let mut tx = TxEnv::new_system_tx_with_caller(caller, system_contract_address, data);
104        tx.set_gas_limit(SYSTEM_CALL_GAS_LIMIT);
105        self.inner.ctx.set_tx(tx.into());
106        let mut h = TempoEvmHandler::new();
107        h.run_system_call(self)
108    }
109}
110
111impl<DB, I> InspectSystemCallEvm for TempoEvm<DB, I>
112where
113    DB: Database,
114    I: Inspector<TempoContext<DB>>,
115{
116    fn inspect_one_system_call_with_caller(
117        &mut self,
118        caller: Address,
119        system_contract_address: Address,
120        data: Bytes,
121    ) -> Result<Self::ExecutionResult, Self::Error> {
122        let mut tx = TxEnv::new_system_tx_with_caller(caller, system_contract_address, data);
123        tx.set_gas_limit(SYSTEM_CALL_GAS_LIMIT);
124        self.inner.ctx.set_tx(tx.into());
125        let mut h = TempoEvmHandler::new();
126        h.inspect_run_system_call(self)
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133    use revm::{Context, ExecuteEvm, MainContext, database::EmptyDB};
134
135    /// Test set_block and replay with default TempoEvm.
136    #[test]
137    fn test_set_block_and_replay() {
138        let db = EmptyDB::new();
139        let ctx = Context::mainnet()
140            .with_db(db)
141            .with_block(TempoBlockEnv::default())
142            .with_cfg(Default::default())
143            .with_tx(TempoTxEnv::default());
144        let mut evm = TempoEvm::new(ctx, ());
145
146        // Set block with default fields
147        evm.set_block(TempoBlockEnv::default());
148
149        // Replay executes the current transaction and returns result with state.
150        // With default tx (no calls, system tx), it should succeed.
151        let result = evm.replay();
152        assert!(result.is_ok());
153
154        let exec_result = result.unwrap();
155        assert!(exec_result.result.is_success());
156    }
157}