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
48pub fn initialize_arbos_state<D: Database>(
60 state: &mut State<D>,
61 init_msg: &ParsedInitMessage,
62 chain_id: u64,
63 target_arbos_version: u64,
64 chain_owner: Address,
65) -> Result<(), String> {
66 let state_ptr: *mut State<D> = state as *mut State<D>;
67
68 let backing = Storage::new(state_ptr, B256::ZERO);
70 if backing.get_uint64_by_uint64(0).unwrap_or(0) != 0 {
71 return Err("ArbOS state already initialized".into());
72 }
73
74 info!(
75 target: "arb::genesis",
76 chain_id,
77 target_arbos_version,
78 initial_l1_base_fee = %init_msg.initial_l1_base_fee,
79 "Initializing ArbOS state"
80 );
81
82 set_account_nonce(state, ARBOS_STATE_ADDRESS, 1);
84
85 backing
87 .set_by_uint64(0, B256::from(U256::from(1u64)))
88 .map_err(|_| "failed to set initial version")?;
89
90 StorageBackedBigUint::new(state_ptr, B256::ZERO, 4)
92 .set(U256::from(chain_id))
93 .map_err(|_| "failed to set chain ID")?;
94
95 for addr in &GENESIS_PRECOMPILE_ADDRESSES {
97 set_account_code(state, *addr, Bytes::from_static(&[0xFE]));
98 }
99
100 if target_arbos_version >= 2 {
102 let mut hash = B256::ZERO;
103 hash[12..32].copy_from_slice(chain_owner.as_slice());
104 backing
105 .set_by_uint64(3, hash)
106 .map_err(|_| "failed to set network fee account")?;
107 }
108
109 if !init_msg.serialized_chain_config.is_empty() {
111 let cc_sto = backing.open_sub_storage(&[7]); let cc_bytes = StorageBackedBytes::new(cc_sto);
113 cc_bytes
114 .set(&init_msg.serialized_chain_config)
115 .map_err(|_| "failed to store chain config")?;
116 }
117
118 let l1_sto = backing.open_sub_storage(&[0]); let rewards_recipient = if target_arbos_version >= 2 {
121 chain_owner
122 } else {
123 Address::ZERO
124 };
125 l1_pricing::L1PricingState::initialize(
126 &l1_sto,
127 rewards_recipient,
128 init_msg.initial_l1_base_fee,
129 );
130
131 let l2_sto = backing.open_sub_storage(&[1]); l2_pricing::L2PricingState::initialize(&l2_sto);
134
135 let ret_sto = backing.open_sub_storage(&[2]); arbos::retryables::RetryableState::initialize(&ret_sto)
138 .map_err(|_| "failed to initialize retryable state")?;
139
140 let at_sto = backing.open_sub_storage(&[3]); arbos::address_table::initialize_address_table(&at_sto);
143
144 let co_sto = backing.open_sub_storage(&[4]); arbos::address_set::initialize_address_set(&co_sto)
147 .map_err(|_| "failed to initialize chain owners")?;
148
149 let ma_sto = backing.open_sub_storage(&[5]); arbos::merkle_accumulator::initialize_merkle_accumulator(&ma_sto);
152
153 let bh_sto = backing.open_sub_storage(&[6]); arbos::blockhash::initialize_blockhashes(&bh_sto);
156
157 let _feat_sto = backing.open_sub_storage(&[9]); let mut arb_state = ArbosState::open(state_ptr, SystemBurner::new(None, false))
163 .map_err(|_| "failed to open ArbOS state after initial setup")?;
164
165 if chain_owner != Address::ZERO {
167 arb_state
168 .chain_owners
169 .add(chain_owner)
170 .map_err(|_| "failed to add chain owner")?;
171 }
172
173 if target_arbos_version > 1 {
175 arb_state
176 .upgrade_arbos_version(target_arbos_version, true)
177 .map_err(|_| format!("failed to upgrade ArbOS to version {target_arbos_version}"))?;
178 }
179
180 info!(
181 target: "arb::genesis",
182 final_version = arb_state.arbos_version(),
183 "ArbOS state initialized"
184 );
185
186 Ok(())
187}
188
189pub fn is_arbos_initialized<D: Database>(state: &mut State<D>) -> bool {
191 let state_ptr: *mut State<D> = state as *mut State<D>;
192 let backing = Storage::new(state_ptr, B256::ZERO);
193 backing.get_uint64_by_uint64(0).unwrap_or(0) != 0
194}