1use crate::{
23 frame::EthFrame, instructions::InstructionProvider, ExecuteCommitEvm, ExecuteEvm, Handler,
24 MainnetHandler, PrecompileProvider,
25};
26use context::{result::ExecResultAndState, ContextSetters, ContextTr, Evm, JournalTr, TxEnv};
27use database_interface::DatabaseCommit;
28use interpreter::{interpreter::EthInterpreter, InterpreterResult};
29use primitives::{address, eip7825, Address, Bytes, TxKind};
30use state::EvmState;
31
32pub const SYSTEM_ADDRESS: Address = address!("0xfffffffffffffffffffffffffffffffffffffffe");
34
35pub trait SystemCallTx: Sized {
42 fn new_system_tx(system_contract_address: Address, data: Bytes) -> Self {
44 Self::new_system_tx_with_caller(SYSTEM_ADDRESS, system_contract_address, data)
45 }
46
47 fn new_system_tx_with_caller(
49 caller: Address,
50 system_contract_address: Address,
51 data: Bytes,
52 ) -> Self;
53}
54
55impl SystemCallTx for TxEnv {
56 fn new_system_tx_with_caller(
57 caller: Address,
58 system_contract_address: Address,
59 data: Bytes,
60 ) -> Self {
61 TxEnv::builder()
62 .caller(caller)
63 .data(data)
64 .kind(TxKind::Call(system_contract_address))
65 .gas_limit(eip7825::TX_GAS_LIMIT_CAP)
66 .build()
67 .unwrap()
68 }
69}
70
71pub trait SystemCallEvm: ExecuteEvm {
76 fn transact_system_call_with_caller(
83 &mut self,
84 caller: Address,
85 system_contract_address: Address,
86 data: Bytes,
87 ) -> Result<Self::ExecutionResult, Self::Error>;
88
89 fn transact_system_call(
91 &mut self,
92 system_contract_address: Address,
93 data: Bytes,
94 ) -> Result<Self::ExecutionResult, Self::Error> {
95 self.transact_system_call_with_caller(SYSTEM_ADDRESS, system_contract_address, data)
96 }
97
98 fn transact_system_call_finalize(
102 &mut self,
103 system_contract_address: Address,
104 data: Bytes,
105 ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
106 self.transact_system_call_with_caller_finalize(
107 SYSTEM_ADDRESS,
108 system_contract_address,
109 data,
110 )
111 }
112
113 fn transact_system_call_with_caller_finalize(
115 &mut self,
116 caller: Address,
117 system_contract_address: Address,
118 data: Bytes,
119 ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
120 let result =
121 self.transact_system_call_with_caller(caller, system_contract_address, data)?;
122 let state = self.finalize();
123 Ok(ExecResultAndState::new(result, state))
124 }
125}
126
127pub trait SystemCallCommitEvm: SystemCallEvm + ExecuteCommitEvm {
129 fn transact_system_call_commit(
131 &mut self,
132 system_contract_address: Address,
133 data: Bytes,
134 ) -> Result<Self::ExecutionResult, Self::Error> {
135 self.transact_system_call_with_caller_commit(SYSTEM_ADDRESS, system_contract_address, data)
136 }
137
138 fn transact_system_call_with_caller_commit(
140 &mut self,
141 caller: Address,
142 system_contract_address: Address,
143 data: Bytes,
144 ) -> Result<Self::ExecutionResult, Self::Error>;
145}
146
147impl<CTX, INSP, INST, PRECOMPILES> SystemCallEvm
148 for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
149where
150 CTX: ContextTr<Journal: JournalTr<State = EvmState>, Tx: SystemCallTx> + ContextSetters,
151 INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
152 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
153{
154 fn transact_system_call_with_caller(
155 &mut self,
156 caller: Address,
157 system_contract_address: Address,
158 data: Bytes,
159 ) -> Result<Self::ExecutionResult, Self::Error> {
160 self.set_tx(CTX::Tx::new_system_tx_with_caller(
162 caller,
163 system_contract_address,
164 data,
165 ));
166 MainnetHandler::default().run_system_call(self)
168 }
169}
170
171impl<CTX, INSP, INST, PRECOMPILES> SystemCallCommitEvm
172 for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
173where
174 CTX: ContextTr<Journal: JournalTr<State = EvmState>, Db: DatabaseCommit, Tx: SystemCallTx>
175 + ContextSetters,
176 INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
177 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
178{
179 fn transact_system_call_with_caller_commit(
180 &mut self,
181 caller: Address,
182 system_contract_address: Address,
183 data: Bytes,
184 ) -> Result<Self::ExecutionResult, Self::Error> {
185 self.transact_system_call_with_caller_finalize(caller, system_contract_address, data)
186 .map(|output| {
187 self.db_mut().commit(output.state);
188 output.result
189 })
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use crate::{MainBuilder, MainContext};
196
197 use super::*;
198 use context::{
199 result::{ExecutionResult, Output, SuccessReason},
200 Context,
201 };
202 use database::InMemoryDB;
203 use primitives::{b256, bytes, StorageKey, U256};
204 use state::{AccountInfo, Bytecode};
205
206 const HISTORY_STORAGE_ADDRESS: Address = address!("0x0000F90827F1C53a10cb7A02335B175320002935");
207 static HISTORY_STORAGE_CODE: Bytes = bytes!("0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500");
208
209 #[test]
210 fn test_system_call() {
211 let mut db = InMemoryDB::default();
212 db.insert_account_info(
213 HISTORY_STORAGE_ADDRESS,
214 AccountInfo::default().with_code(Bytecode::new_legacy(HISTORY_STORAGE_CODE.clone())),
215 );
216
217 let block_hash =
218 b256!("0x1111111111111111111111111111111111111111111111111111111111111111");
219
220 let mut my_evm = Context::mainnet()
221 .with_db(db)
222 .modify_block_chained(|b| b.number = U256::ONE)
224 .build_mainnet();
225 let output = my_evm
226 .transact_system_call_finalize(HISTORY_STORAGE_ADDRESS, block_hash.0.into())
227 .unwrap();
228
229 assert_eq!(
230 output.result,
231 ExecutionResult::Success {
232 reason: SuccessReason::Stop,
233 gas_used: 22143,
234 gas_refunded: 0,
235 logs: vec![],
236 output: Output::Call(Bytes::default())
237 }
238 );
239 assert_eq!(output.state.len(), 1);
241 assert_eq!(
242 output.state[&HISTORY_STORAGE_ADDRESS]
243 .storage
244 .get(&StorageKey::from(0))
245 .map(|slot| slot.present_value)
246 .unwrap_or_default(),
247 U256::from_be_bytes(block_hash.0),
248 "State is not updated {:?}",
249 output.state
250 );
251 }
252}