1use alloy_primitives::{address, Address, Bytes, B256, U256};
8use revm::{database::State, Database};
9use tracing::info;
10
11use arb_storage::{
12 set_account_code, set_account_nonce, Storage, StorageBackedBigUint, StorageBackedBytes,
13 ARBOS_STATE_ADDRESS,
14};
15use arbos::{
16 arbos_state::ArbosState, arbos_types::ParsedInitMessage, burn::SystemBurner, l1_pricing,
17 l2_pricing,
18};
19
20const GENESIS_PRECOMPILE_ADDRESSES: [Address; 14] = [
25 address!("0000000000000000000000000000000000000064"), address!("0000000000000000000000000000000000000065"), address!("0000000000000000000000000000000000000066"), address!("0000000000000000000000000000000000000067"), address!("0000000000000000000000000000000000000068"), address!("0000000000000000000000000000000000000069"), address!("000000000000000000000000000000000000006b"), address!("000000000000000000000000000000000000006c"), address!("000000000000000000000000000000000000006d"), address!("000000000000000000000000000000000000006e"), address!("000000000000000000000000000000000000006f"), address!("0000000000000000000000000000000000000070"), address!("00000000000000000000000000000000000000ff"), address!("00000000000000000000000000000000000a4b05"), ];
40
41pub const INITIAL_ARBOS_VERSION: u64 = 10;
44
45pub const DEFAULT_CHAIN_OWNER: Address = address!("0000000000000000000000000000000000000000");
47
48#[derive(Debug, Clone, Copy, Default)]
60pub struct ArbOSInit {
61 pub native_token_supply_management_enabled: bool,
62 pub transaction_filtering_enabled: bool,
63}
64
65pub fn initialize_arbos_state<D: Database>(
66 state: &mut State<D>,
67 init_msg: &ParsedInitMessage,
68 chain_id: u64,
69 target_arbos_version: u64,
70 chain_owner: Address,
71 arbos_init: ArbOSInit,
72) -> Result<(), String> {
73 let state_ptr: *mut State<D> = state as *mut State<D>;
74
75 let backing = Storage::new(state_ptr, B256::ZERO);
77 if backing.get_uint64_by_uint64(0).unwrap_or(0) != 0 {
78 return Err("ArbOS state already initialized".into());
79 }
80
81 info!(
82 target: "arb::genesis",
83 chain_id,
84 target_arbos_version,
85 initial_l1_base_fee = %init_msg.initial_l1_base_fee,
86 "Initializing ArbOS state"
87 );
88
89 set_account_nonce(state, ARBOS_STATE_ADDRESS, 1);
91
92 backing
94 .set_by_uint64(0, B256::from(U256::from(1u64)))
95 .map_err(|_| "failed to set initial version")?;
96
97 StorageBackedBigUint::new(state_ptr, B256::ZERO, 4)
99 .set(U256::from(chain_id))
100 .map_err(|_| "failed to set chain ID")?;
101
102 for addr in &GENESIS_PRECOMPILE_ADDRESSES {
104 set_account_code(state, *addr, Bytes::from_static(&[0xFE]));
105 }
106
107 if target_arbos_version >= 2 {
109 let mut hash = B256::ZERO;
110 hash[12..32].copy_from_slice(chain_owner.as_slice());
111 backing
112 .set_by_uint64(3, hash)
113 .map_err(|_| "failed to set network fee account")?;
114 }
115
116 if !init_msg.serialized_chain_config.is_empty() {
118 let cc_sto = backing.open_sub_storage(&[7]); let cc_bytes = StorageBackedBytes::new(cc_sto);
120 cc_bytes
121 .set(&init_msg.serialized_chain_config)
122 .map_err(|_| "failed to store chain config")?;
123 }
124
125 let l1_sto = backing.open_sub_storage(&[0]); let rewards_recipient = if target_arbos_version >= 2 {
128 chain_owner
129 } else {
130 Address::ZERO
131 };
132 l1_pricing::L1PricingState::initialize(
133 &l1_sto,
134 rewards_recipient,
135 init_msg.initial_l1_base_fee,
136 );
137
138 let l2_sto = backing.open_sub_storage(&[1]); l2_pricing::L2PricingState::initialize(&l2_sto);
141
142 let ret_sto = backing.open_sub_storage(&[2]); arbos::retryables::RetryableState::initialize(&ret_sto)
145 .map_err(|_| "failed to initialize retryable state")?;
146
147 let at_sto = backing.open_sub_storage(&[3]); arbos::address_table::initialize_address_table(&at_sto);
150
151 let co_sto = backing.open_sub_storage(&[4]); arbos::address_set::initialize_address_set(&co_sto)
154 .map_err(|_| "failed to initialize chain owners")?;
155
156 let ma_sto = backing.open_sub_storage(&[5]); arbos::merkle_accumulator::initialize_merkle_accumulator(&ma_sto);
159
160 let bh_sto = backing.open_sub_storage(&[6]); arbos::blockhash::initialize_blockhashes(&bh_sto);
163
164 let _feat_sto = backing.open_sub_storage(&[9]); let mut arb_state = ArbosState::open(state_ptr, SystemBurner::new(None, false))
170 .map_err(|_| "failed to open ArbOS state after initial setup")?;
171
172 arb_state
173 .chain_owners
174 .add(chain_owner)
175 .map_err(|_| "failed to add chain owner")?;
176
177 if arbos_init.native_token_supply_management_enabled {
178 arb_state
179 .set_native_token_management_from_time(1)
180 .map_err(|_| "failed to set native token enabled from time")?;
181 }
182 if arbos_init.transaction_filtering_enabled {
183 arb_state
184 .set_transaction_filtering_from_time(1)
185 .map_err(|_| "failed to set transaction filtering from time")?;
186 }
187
188 if target_arbos_version > 1 {
190 arb_state
191 .upgrade_arbos_version(target_arbos_version, true)
192 .map_err(|_| format!("failed to upgrade ArbOS to version {target_arbos_version}"))?;
193 }
194
195 info!(
196 target: "arb::genesis",
197 final_version = arb_state.arbos_version(),
198 "ArbOS state initialized"
199 );
200
201 Ok(())
202}
203
204pub fn is_arbos_initialized<D: Database>(state: &mut State<D>) -> bool {
206 let state_ptr: *mut State<D> = state as *mut State<D>;
207 let backing = Storage::new(state_ptr, B256::ZERO);
208 backing.get_uint64_by_uint64(0).unwrap_or(0) != 0
209}