1use crate::{v0_1, v0_3, BlockSize, ChainId, FeeAccount, FeeAmount};
2use alloy::primitives::{Address, U256};
3use alloy_compat::ethers_serde;
4use committable::{Commitment, Committable};
5use itertools::Either;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(default)]
11pub struct ChainConfig {
12 pub chain_id: ChainId,
14
15 pub max_block_size: BlockSize,
17
18 pub base_fee: FeeAmount,
20
21 #[serde(with = "ethers_serde::option_address")]
27 pub fee_contract: Option<Address>,
28
29 pub fee_recipient: FeeAccount,
35
36 #[serde(with = "ethers_serde::option_address")]
42 pub stake_table_contract: Option<Address>,
43
44 pub bid_recipient: Option<FeeAccount>,
46}
47
48#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)]
49pub struct ResolvableChainConfig {
51 pub(crate) chain_config: Either<ChainConfig, Commitment<ChainConfig>>,
52}
53
54impl Committable for ChainConfig {
55 fn tag() -> String {
56 "CHAIN_CONFIG".to_string()
57 }
58
59 fn commit(&self) -> Commitment<Self> {
60 let comm = committable::RawCommitmentBuilder::new(&Self::tag())
61 .fixed_size_field("chain_id", &self.chain_id.to_fixed_bytes())
62 .u64_field("max_block_size", *self.max_block_size)
63 .fixed_size_field("base_fee", &self.base_fee.to_fixed_bytes())
64 .fixed_size_field("fee_recipient", &self.fee_recipient.to_fixed_bytes());
65 let comm = if let Some(addr) = self.fee_contract {
66 comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0)
67 } else {
68 comm.u64_field("fee_contract", 0)
69 };
70
71 let comm = if let Some(addr) = self.stake_table_contract {
72 comm.u64_field("stake_table_contract", 1)
73 .fixed_size_bytes(&addr.0)
74 } else {
75 comm
76 };
77
78 let comm = if let Some(bid_recipient) = self.bid_recipient {
82 comm.fixed_size_field("bid_recipient", &bid_recipient.to_fixed_bytes())
83 } else {
84 comm
85 };
86
87 comm.finalize()
88 }
89}
90
91impl ResolvableChainConfig {
92 pub fn commit(&self) -> Commitment<ChainConfig> {
93 match self.chain_config {
94 Either::Left(config) => config.commit(),
95 Either::Right(commitment) => commitment,
96 }
97 }
98 pub fn resolve(self) -> Option<ChainConfig> {
99 match self.chain_config {
100 Either::Left(config) => Some(config),
101 Either::Right(_) => None,
102 }
103 }
104}
105
106impl From<Commitment<ChainConfig>> for ResolvableChainConfig {
107 fn from(value: Commitment<ChainConfig>) -> Self {
108 Self {
109 chain_config: Either::Right(value),
110 }
111 }
112}
113
114impl From<ChainConfig> for ResolvableChainConfig {
115 fn from(value: ChainConfig) -> Self {
116 Self {
117 chain_config: Either::Left(value),
118 }
119 }
120}
121
122impl From<&v0_1::ResolvableChainConfig> for ResolvableChainConfig {
123 fn from(
124 &v0_1::ResolvableChainConfig { chain_config }: &v0_1::ResolvableChainConfig,
125 ) -> ResolvableChainConfig {
126 match chain_config {
127 Either::Left(chain_config) => ResolvableChainConfig {
128 chain_config: Either::Left(ChainConfig::from(chain_config)),
129 },
130 Either::Right(c) => ResolvableChainConfig {
131 chain_config: Either::Right(Commitment::from_raw(*c.as_ref())),
132 },
133 }
134 }
135}
136
137impl From<&v0_3::ResolvableChainConfig> for ResolvableChainConfig {
138 fn from(
139 &v0_3::ResolvableChainConfig { chain_config }: &v0_3::ResolvableChainConfig,
140 ) -> ResolvableChainConfig {
141 match chain_config {
142 Either::Left(chain_config) => ResolvableChainConfig {
143 chain_config: Either::Left(ChainConfig::from(chain_config)),
144 },
145 Either::Right(c) => ResolvableChainConfig {
146 chain_config: Either::Right(Commitment::from_raw(*c.as_ref())),
147 },
148 }
149 }
150}
151
152impl From<v0_1::ChainConfig> for ChainConfig {
153 fn from(chain_config: v0_1::ChainConfig) -> ChainConfig {
154 let v0_1::ChainConfig {
155 chain_id,
156 max_block_size,
157 base_fee,
158 fee_contract,
159 fee_recipient,
160 ..
161 } = chain_config;
162
163 ChainConfig {
164 chain_id,
165 max_block_size,
166 base_fee,
167 fee_contract,
168 fee_recipient,
169 stake_table_contract: None,
170 bid_recipient: None,
171 }
172 }
173}
174
175impl From<v0_3::ChainConfig> for ChainConfig {
176 fn from(chain_config: v0_3::ChainConfig) -> ChainConfig {
177 let v0_3::ChainConfig {
178 chain_id,
179 max_block_size,
180 base_fee,
181 fee_contract,
182 fee_recipient,
183 stake_table_contract,
184 ..
185 } = chain_config;
186
187 ChainConfig {
188 chain_id,
189 max_block_size,
190 base_fee,
191 fee_contract,
192 fee_recipient,
193 stake_table_contract,
194 bid_recipient: None,
195 }
196 }
197}
198
199impl From<ChainConfig> for v0_1::ChainConfig {
200 fn from(chain_config: ChainConfig) -> v0_1::ChainConfig {
201 let ChainConfig {
202 chain_id,
203 max_block_size,
204 base_fee,
205 fee_contract,
206 fee_recipient,
207 ..
208 } = chain_config;
209
210 v0_1::ChainConfig {
211 chain_id,
212 max_block_size,
213 base_fee,
214 fee_contract,
215 fee_recipient,
216 }
217 }
218}
219
220impl Default for ChainConfig {
221 fn default() -> Self {
222 Self {
223 chain_id: U256::from(35353).into(), max_block_size: 30720.into(),
225 base_fee: 0.into(),
226 fee_contract: None,
227 fee_recipient: Default::default(),
228 stake_table_contract: None,
229 bid_recipient: None,
230 }
231 }
232}
233
234#[cfg(test)]
235mod test {
236 use super::*;
237
238 #[test]
239 fn test_upgrade_chain_config_v99_resolvable_chain_config_from_v1() {
240 let expectation: ResolvableChainConfig = ChainConfig::default().into();
241 let v1_resolvable: v0_1::ResolvableChainConfig = v0_1::ChainConfig::default().into();
242 let v99_resolvable: ResolvableChainConfig = ResolvableChainConfig::from(&v1_resolvable);
243 assert_eq!(expectation, v99_resolvable);
244 let expectation: ResolvableChainConfig = ChainConfig::default().commit().into();
245 let v1_resolvable: v0_1::ResolvableChainConfig =
246 v0_1::ChainConfig::default().commit().into();
247 let v99_resolvable: ResolvableChainConfig = ResolvableChainConfig::from(&v1_resolvable);
248 assert_eq!(expectation, v99_resolvable);
249 }
250
251 #[test]
252 fn test_upgrade_chain_config_v99_resolvable_chain_config_from_v3() {
253 let expectation: ResolvableChainConfig = ChainConfig::default().into();
254 let v3_resolvable: v0_3::ResolvableChainConfig = v0_3::ChainConfig::default().into();
255 let v99_resolvable: ResolvableChainConfig = ResolvableChainConfig::from(&v3_resolvable);
256 assert_eq!(expectation, v99_resolvable);
257 let expectation: ResolvableChainConfig = ChainConfig::default().commit().into();
258 let v3_resolvable: v0_3::ResolvableChainConfig =
259 v0_3::ChainConfig::default().commit().into();
260 let v99_resolvable: ResolvableChainConfig = ResolvableChainConfig::from(&v3_resolvable);
261 assert_eq!(expectation, v99_resolvable);
262 }
263
264 #[test]
265 fn test_upgrade_chain_config_v1_chain_config_from_v99() {
266 let expectation = v0_1::ChainConfig::default();
267 let v99_chain_config = ChainConfig::default();
268 let v1_chain_config = v0_1::ChainConfig::from(v99_chain_config);
269 assert_eq!(expectation, v1_chain_config);
270 }
271
272 #[test]
273 fn test_upgrade_chain_config_v3_chain_config_from_v99() {
274 let expectation = v0_3::ChainConfig::default();
275 let v99_chain_config = ChainConfig::default();
276 let v3_chain_config = v0_3::ChainConfig::from(v99_chain_config);
277 assert_eq!(expectation, v3_chain_config);
278 }
279}