espresso_types/v0/v0_99/
chain_config.rs

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/// Global variables for an Espresso blockchain.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(default)]
11pub struct ChainConfig {
12    /// Espresso chain ID
13    pub chain_id: ChainId,
14
15    /// Maximum size in bytes of a block
16    pub max_block_size: BlockSize,
17
18    /// Minimum fee in WEI per byte of payload
19    pub base_fee: FeeAmount,
20
21    /// Fee contract address on L1.
22    ///
23    /// This is optional so that fees can easily be toggled on/off, with no need to deploy a
24    /// contract when they are off. In a future release, after fees are switched on and thoroughly
25    /// tested, this may be made mandatory.
26    #[serde(with = "ethers_serde::option_address")]
27    pub fee_contract: Option<Address>,
28
29    /// Account that receives sequencing fees.
30    ///
31    /// This account in the Espresso fee ledger will always receive every fee paid in Espresso,
32    /// regardless of whether or not their is a `fee_contract` deployed. Once deployed, the fee
33    /// contract can decide what to do with tokens locked in this account in Espresso.
34    pub fee_recipient: FeeAccount,
35
36    /// `StakeTable `(proxy) contract address on L1.
37    ///
38    /// This is optional so that stake can easily be toggled on/off, with no need to deploy a
39    /// contract when they are off. In a future release, after PoS is switched on and thoroughly
40    /// tested, this may be made mandatory.
41    #[serde(with = "ethers_serde::option_address")]
42    pub stake_table_contract: Option<Address>,
43
44    /// Account that receives sequencing bids.
45    pub bid_recipient: Option<FeeAccount>,
46}
47
48#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)]
49/// A commitment to a ChainConfig or a full ChainConfig.
50pub 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        // With `ChainConfig` upgrades we want commitments w/out
79        // fields added >= v0_99 to have the same commitment as <= v0_99
80        // commitment. Therefore `None` values are simply ignored.
81        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(), // arbitrarily chosen chain ID
224            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}