1mod arbaddresstable;
8mod arbaggregator;
9mod arbbls;
10mod arbdebug;
11mod arbfilteredtxmanager;
12mod arbfunctiontable;
13mod arbgasinfo;
14mod arbinfo;
15mod arbnativetokenmanager;
16mod arbosacts;
17mod arbowner;
18mod arbownerpublic;
19mod arbretryabletx;
20mod arbstatistics;
21mod arbsys;
22mod arbwasm;
23mod arbwasmcache;
24mod nodeinterface;
25pub mod storage_slot;
26
27pub use arbaddresstable::{create_arbaddresstable_precompile, ARBADDRESSTABLE_ADDRESS};
28pub use arbaggregator::{create_arbaggregator_precompile, ARBAGGREGATOR_ADDRESS};
29pub use arbbls::{create_arbbls_precompile, ARBBLS_ADDRESS};
30pub use arbdebug::{create_arbdebug_precompile, ARBDEBUG_ADDRESS};
31pub use arbfilteredtxmanager::{
32 create_arbfilteredtxmanager_precompile, ARBFILTEREDTXMANAGER_ADDRESS,
33};
34pub use arbfunctiontable::{create_arbfunctiontable_precompile, ARBFUNCTIONTABLE_ADDRESS};
35pub use arbgasinfo::{create_arbgasinfo_precompile, ARBGASINFO_ADDRESS};
36pub use arbinfo::{create_arbinfo_precompile, ARBINFO_ADDRESS};
37pub use arbnativetokenmanager::{
38 create_arbnativetokenmanager_precompile, ARBNATIVETOKENMANAGER_ADDRESS,
39};
40pub use arbosacts::{create_arbosacts_precompile, ARBOSACTS_ADDRESS};
41pub use arbowner::{create_arbowner_precompile, ARBOWNER_ADDRESS};
42pub use arbownerpublic::{create_arbownerpublic_precompile, ARBOWNERPUBLIC_ADDRESS};
43pub use arbretryabletx::{
44 create_arbretryabletx_precompile, redeem_scheduled_topic, ticket_created_topic,
45 ARBRETRYABLETX_ADDRESS,
46};
47pub use arbstatistics::{create_arbstatistics_precompile, ARBSTATISTICS_ADDRESS};
48pub use arbsys::{
49 create_arbsys_precompile, get_cached_l1_block_number, get_current_l2_block, get_tx_is_aliased,
50 set_cached_l1_block_number, set_current_l2_block, set_tx_is_aliased, store_arbsys_state,
51 take_arbsys_state, ArbSysMerkleState, ARBSYS_ADDRESS,
52};
53pub use arbwasm::{create_arbwasm_precompile, ARBWASM_ADDRESS};
54pub use arbwasmcache::{create_arbwasmcache_precompile, ARBWASMCACHE_ADDRESS};
55pub use nodeinterface::{create_nodeinterface_precompile, NODE_INTERFACE_ADDRESS};
56pub use storage_slot::ARBOS_STATE_ADDRESS;
57
58use alloy_evm::precompiles::PrecompilesMap;
59use revm::precompile::{PrecompileError, PrecompileOutput, PrecompileResult};
60use std::cell::Cell;
61
62thread_local! {
65 static ARBOS_VERSION: Cell<u64> = const { Cell::new(0) };
67 static L1_BLOCK_NUMBER_FOR_EVM: Cell<u64> = const { Cell::new(0) };
69 static EVM_CALL_DEPTH: Cell<usize> = const { Cell::new(0) };
73 static BLOCK_TIMESTAMP: Cell<u64> = const { Cell::new(0) };
76 static CURRENT_GAS_BACKLOG: Cell<u64> = const { Cell::new(0) };
79 static CURRENT_TX_POSTER_FEE: Cell<u128> = const { Cell::new(0) };
82 static POSTER_BALANCE_CORRECTION: Cell<u128> = const { Cell::new(0) };
87 static TX_SENDER_LO: Cell<u128> = const { Cell::new(0) };
89 static TX_SENDER_HI: Cell<u32> = const { Cell::new(0) };
90}
91
92use std::sync::Mutex as StdMutex;
93
94static L2_BLOCKHASH_CACHE: StdMutex<
98 Option<std::collections::HashMap<u64, alloy_primitives::B256>>,
99> = StdMutex::new(None);
100
101pub fn set_l2_block_hash(l2_block_number: u64, hash: alloy_primitives::B256) {
103 let mut cache = L2_BLOCKHASH_CACHE
104 .lock()
105 .expect("L2 blockhash cache lock poisoned");
106 let map = cache.get_or_insert_with(std::collections::HashMap::new);
107 map.insert(l2_block_number, hash);
108}
109
110pub fn get_l2_block_hash(l2_block_number: u64) -> Option<alloy_primitives::B256> {
112 let cache = L2_BLOCKHASH_CACHE
113 .lock()
114 .expect("L2 blockhash cache lock poisoned");
115 cache.as_ref()?.get(&l2_block_number).copied()
116}
117
118pub fn set_arbos_version(version: u64) {
120 ARBOS_VERSION.with(|v| v.set(version));
121}
122
123pub fn get_arbos_version() -> u64 {
125 ARBOS_VERSION.with(|v| v.get())
126}
127
128pub fn set_l1_block_number_for_evm(number: u64) {
130 L1_BLOCK_NUMBER_FOR_EVM.with(|v| v.set(number));
131}
132
133pub fn get_l1_block_number_for_evm() -> u64 {
135 L1_BLOCK_NUMBER_FOR_EVM.with(|v| v.get())
136}
137
138pub fn set_current_gas_backlog(backlog: u64) {
140 CURRENT_GAS_BACKLOG.with(|v| v.set(backlog));
141}
142
143pub fn get_current_gas_backlog() -> u64 {
145 CURRENT_GAS_BACKLOG.with(|v| v.get())
146}
147
148pub fn set_current_tx_poster_fee(fee_wei: u128) {
150 CURRENT_TX_POSTER_FEE.with(|v| v.set(fee_wei));
151}
152
153pub fn get_current_tx_poster_fee() -> u128 {
155 CURRENT_TX_POSTER_FEE.with(|v| v.get())
156}
157
158pub fn set_poster_balance_correction(correction: alloy_primitives::U256) {
160 let val: u128 = correction.try_into().unwrap_or(u128::MAX);
161 POSTER_BALANCE_CORRECTION.with(|v| v.set(val));
162}
163
164pub fn get_poster_balance_correction() -> alloy_primitives::U256 {
166 alloy_primitives::U256::from(POSTER_BALANCE_CORRECTION.with(|v| v.get()))
167}
168
169pub fn set_current_tx_sender(addr: alloy_primitives::Address) {
171 let bytes = addr.as_slice();
172 let lo = u128::from_be_bytes(bytes[4..20].try_into().unwrap_or([0u8; 16]));
173 let hi = u32::from_be_bytes(bytes[0..4].try_into().unwrap_or([0u8; 4]));
174 TX_SENDER_LO.with(|v| v.set(lo));
175 TX_SENDER_HI.with(|v| v.set(hi));
176}
177
178pub fn get_current_tx_sender() -> alloy_primitives::Address {
180 let lo = TX_SENDER_LO.with(|v| v.get());
181 let hi = TX_SENDER_HI.with(|v| v.get());
182 let mut bytes = [0u8; 20];
183 bytes[0..4].copy_from_slice(&hi.to_be_bytes());
184 bytes[4..20].copy_from_slice(&lo.to_be_bytes());
185 alloy_primitives::Address::new(bytes)
186}
187
188pub fn set_evm_depth(depth: usize) {
191 EVM_CALL_DEPTH.with(|v| v.set(depth));
192}
193
194pub fn get_evm_depth() -> usize {
196 EVM_CALL_DEPTH.with(|v| v.get())
197}
198
199pub fn set_block_timestamp(timestamp: u64) {
201 BLOCK_TIMESTAMP.with(|v| v.set(timestamp));
202}
203
204pub fn get_block_timestamp() -> u64 {
206 BLOCK_TIMESTAMP.with(|v| v.get())
207}
208
209fn check_precompile_version(min_version: u64) -> Option<PrecompileResult> {
213 if get_arbos_version() < min_version {
214 Some(Ok(PrecompileOutput::new(0, Default::default())))
215 } else {
216 None
217 }
218}
219
220fn gas_check(gas_limit: u64, result: PrecompileResult) -> PrecompileResult {
223 match result {
224 Ok(ref output) if output.gas_used > gas_limit => Err(PrecompileError::OutOfGas),
225 other => other,
226 }
227}
228
229fn check_method_version(min_version: u64, max_version: u64) -> Option<PrecompileResult> {
232 let v = get_arbos_version();
233 if v < min_version || (max_version > 0 && v > max_version) {
234 Some(Err(PrecompileError::other(
235 "method not available at this ArbOS version",
236 )))
237 } else {
238 None
239 }
240}
241
242pub fn register_arb_precompiles(map: &mut PrecompilesMap) {
244 map.extend_precompiles([
245 (ARBSYS_ADDRESS, create_arbsys_precompile()),
246 (ARBGASINFO_ADDRESS, create_arbgasinfo_precompile()),
247 (ARBINFO_ADDRESS, create_arbinfo_precompile()),
248 (ARBSTATISTICS_ADDRESS, create_arbstatistics_precompile()),
249 (
250 ARBFUNCTIONTABLE_ADDRESS,
251 create_arbfunctiontable_precompile(),
252 ),
253 (ARBOSACTS_ADDRESS, create_arbosacts_precompile()),
254 (ARBOWNERPUBLIC_ADDRESS, create_arbownerpublic_precompile()),
255 (ARBADDRESSTABLE_ADDRESS, create_arbaddresstable_precompile()),
256 (ARBAGGREGATOR_ADDRESS, create_arbaggregator_precompile()),
257 (ARBRETRYABLETX_ADDRESS, create_arbretryabletx_precompile()),
258 (ARBOWNER_ADDRESS, create_arbowner_precompile()),
259 (ARBBLS_ADDRESS, create_arbbls_precompile()),
260 (ARBDEBUG_ADDRESS, create_arbdebug_precompile()),
261 (ARBWASM_ADDRESS, create_arbwasm_precompile()),
262 (ARBWASMCACHE_ADDRESS, create_arbwasmcache_precompile()),
263 (
264 ARBFILTEREDTXMANAGER_ADDRESS,
265 create_arbfilteredtxmanager_precompile(),
266 ),
267 (
268 ARBNATIVETOKENMANAGER_ADDRESS,
269 create_arbnativetokenmanager_precompile(),
270 ),
271 (NODE_INTERFACE_ADDRESS, create_nodeinterface_precompile()),
272 ]);
273}