revm_handler/
system_call.rs1use crate::{
2 instructions::InstructionProvider, EthFrame, ExecuteCommitEvm, ExecuteEvm, Handler,
3 MainnetHandler, PrecompileProvider,
4};
5use context::{ContextSetters, ContextTr, Evm, JournalOutput, JournalTr, TxEnv};
6use database_interface::DatabaseCommit;
7use interpreter::{interpreter::EthInterpreter, InterpreterResult};
8use primitives::{address, Address, Bytes, TxKind};
9
10pub const SYSTEM_ADDRESS: Address = address!("0xfffffffffffffffffffffffffffffffffffffffe");
11
12pub trait SystemCallTx {
19 fn new_system_tx(data: Bytes, system_contract_address: Address) -> Self;
21}
22
23impl SystemCallTx for TxEnv {
24 fn new_system_tx(data: Bytes, system_contract_address: Address) -> Self {
25 TxEnv {
26 caller: SYSTEM_ADDRESS,
27 data,
28 kind: TxKind::Call(system_contract_address),
29 gas_limit: 30_000_000,
30 ..Default::default()
31 }
32 }
33}
34
35pub trait SystemCallEvm: ExecuteEvm {
40 fn transact_system_call(
47 &mut self,
48 data: Bytes,
49 system_contract_address: Address,
50 ) -> Self::Output;
51}
52
53pub trait SystemCallCommitEvm: SystemCallEvm + ExecuteCommitEvm {
55 fn transact_system_call_commit(
57 &mut self,
58 data: Bytes,
59 system_contract_address: Address,
60 ) -> Self::CommitOutput;
61}
62
63impl<CTX, INSP, INST, PRECOMPILES> SystemCallEvm for Evm<CTX, INSP, INST, PRECOMPILES>
64where
65 CTX: ContextTr<Journal: JournalTr<FinalOutput = JournalOutput>, Tx: SystemCallTx>
66 + ContextSetters,
67 INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
68 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
69{
70 fn transact_system_call(
71 &mut self,
72 data: Bytes,
73 system_contract_address: Address,
74 ) -> Self::Output {
75 self.set_tx(CTX::Tx::new_system_tx(data, system_contract_address));
77 let mut handler = MainnetHandler::<_, _, EthFrame<_, _, _>>::default();
79 handler.run_system_call(self)
80 }
81}
82
83impl<CTX, INSP, INST, PRECOMPILES> SystemCallCommitEvm for Evm<CTX, INSP, INST, PRECOMPILES>
84where
85 CTX: ContextTr<
86 Journal: JournalTr<FinalOutput = JournalOutput>,
87 Db: DatabaseCommit,
88 Tx: SystemCallTx,
89 > + ContextSetters,
90 INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
91 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
92{
93 fn transact_system_call_commit(
94 &mut self,
95 data: Bytes,
96 system_contract_address: Address,
97 ) -> Self::CommitOutput {
98 self.transact_system_call(data, system_contract_address)
99 .map(|r| {
100 self.db().commit(r.state);
101 r.result
102 })
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use crate::{MainBuilder, MainContext};
109
110 use super::*;
111 use context::{
112 result::{ExecutionResult, Output, SuccessReason},
113 Context,
114 };
115 use database::InMemoryDB;
116 use primitives::{b256, bytes, U256};
117 use state::{AccountInfo, Bytecode};
118
119 const HISTORY_STORAGE_ADDRESS: Address = address!("0x0000F90827F1C53a10cb7A02335B175320002935");
120 static HISTORY_STORAGE_CODE: Bytes = bytes!("0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500");
121
122 #[test]
123 fn test_system_call() {
124 let mut db = InMemoryDB::default();
125 db.insert_account_info(
126 HISTORY_STORAGE_ADDRESS,
127 AccountInfo::default().with_code(Bytecode::new_legacy(HISTORY_STORAGE_CODE.clone())),
128 );
129
130 let block_hash =
131 b256!("0x1111111111111111111111111111111111111111111111111111111111111111");
132
133 let mut my_evm = Context::mainnet()
134 .with_db(db)
135 .modify_block_chained(|b| b.number = 1)
137 .build_mainnet();
138 let res = my_evm
139 .transact_system_call(block_hash.0.into(), HISTORY_STORAGE_ADDRESS)
140 .unwrap();
141
142 let result = res.result;
143 let state = res.state;
144 assert_eq!(
145 result,
146 ExecutionResult::Success {
147 reason: SuccessReason::Stop,
148 gas_used: 22143,
149 gas_refunded: 0,
150 logs: vec![],
151 output: Output::Call(Bytes::default())
152 }
153 );
154 assert_eq!(state.len(), 1);
156 assert_eq!(
157 state[&HISTORY_STORAGE_ADDRESS]
158 .storage
159 .get(&U256::from(0))
160 .map(|slot| slot.present_value)
161 .unwrap_or_default(),
162 U256::from_be_bytes(block_hash.0),
163 "State is not updated {state:?}"
164 );
165 }
166}