espresso_types/v0/v0_3/
chain_config.rs

1use crate::{v0_1, v0_99, 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)]
10pub struct ChainConfig {
11    /// Espresso chain ID
12    pub chain_id: ChainId,
13
14    /// Maximum size in bytes of a block
15    pub max_block_size: BlockSize,
16
17    /// Minimum fee in WEI per byte of payload
18    pub base_fee: FeeAmount,
19
20    /// Fee contract address on L1.
21    ///
22    /// This is optional so that fees can easily be toggled on/off, with no need to deploy a
23    /// contract when they are off. In a future release, after fees are switched on and thoroughly
24    /// tested, this may be made mandatory.
25    #[serde(with = "ethers_serde::option_address")]
26    pub fee_contract: Option<Address>,
27
28    /// Account that receives sequencing fees.
29    ///
30    /// This account in the Espresso fee ledger will always receive every fee paid in Espresso,
31    /// regardless of whether or not their is a `fee_contract` deployed. Once deployed, the fee
32    /// contract can decide what to do with tokens locked in this account in Espresso.
33    pub fee_recipient: FeeAccount,
34
35    /// `StakeTable `(proxy) contract address on L1.
36    ///
37    /// This is optional so that stake can easily be toggled on/off, with no need to deploy a
38    /// contract when they are off. In a future release, after PoS is switched on and thoroughly
39    /// tested, this may be made mandatory.
40    #[serde(with = "ethers_serde::option_address")]
41    pub stake_table_contract: Option<Address>,
42}
43
44#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)]
45pub struct ResolvableChainConfig {
46    pub(crate) chain_config: Either<ChainConfig, Commitment<ChainConfig>>,
47}
48
49impl Committable for ChainConfig {
50    fn tag() -> String {
51        "CHAIN_CONFIG".to_string()
52    }
53
54    fn commit(&self) -> Commitment<Self> {
55        let comm = committable::RawCommitmentBuilder::new(&Self::tag())
56            .fixed_size_field("chain_id", &self.chain_id.to_fixed_bytes())
57            .u64_field("max_block_size", *self.max_block_size)
58            .fixed_size_field("base_fee", &self.base_fee.to_fixed_bytes())
59            .fixed_size_field("fee_recipient", &self.fee_recipient.to_fixed_bytes());
60        let comm = if let Some(addr) = self.fee_contract {
61            comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0)
62        } else {
63            comm.u64_field("fee_contract", 0)
64        };
65        // With `ChainConfig` upgrades we want commitments w/out
66        // fields added >= v0_3 to have the same commitment as <= v0_3
67        // commitment. Therefore `None` values are simply ignored.
68        let comm = if let Some(addr) = self.stake_table_contract {
69            comm.u64_field("stake_table_contract", 1)
70                .fixed_size_bytes(&addr.0)
71        } else {
72            comm
73        };
74
75        comm.finalize()
76    }
77}
78
79impl ResolvableChainConfig {
80    pub fn commit(&self) -> Commitment<ChainConfig> {
81        match self.chain_config {
82            Either::Left(config) => config.commit(),
83            Either::Right(commitment) => commitment,
84        }
85    }
86    pub fn resolve(self) -> Option<ChainConfig> {
87        match self.chain_config {
88            Either::Left(config) => Some(config),
89            Either::Right(_) => None,
90        }
91    }
92}
93
94impl From<Commitment<ChainConfig>> for ResolvableChainConfig {
95    fn from(value: Commitment<ChainConfig>) -> Self {
96        Self {
97            chain_config: Either::Right(value),
98        }
99    }
100}
101
102impl From<ChainConfig> for ResolvableChainConfig {
103    fn from(value: ChainConfig) -> Self {
104        Self {
105            chain_config: Either::Left(value),
106        }
107    }
108}
109
110impl From<&v0_1::ResolvableChainConfig> for ResolvableChainConfig {
111    fn from(
112        &v0_1::ResolvableChainConfig { chain_config }: &v0_1::ResolvableChainConfig,
113    ) -> ResolvableChainConfig {
114        match chain_config {
115            Either::Left(chain_config) => ResolvableChainConfig {
116                chain_config: Either::Left(ChainConfig::from(chain_config)),
117            },
118            Either::Right(c) => ResolvableChainConfig {
119                chain_config: Either::Right(Commitment::from_raw(*c.as_ref())),
120            },
121        }
122    }
123}
124
125impl From<v0_1::ChainConfig> for ChainConfig {
126    fn from(chain_config: v0_1::ChainConfig) -> ChainConfig {
127        let v0_1::ChainConfig {
128            chain_id,
129            max_block_size,
130            base_fee,
131            fee_contract,
132            fee_recipient,
133            ..
134        } = chain_config;
135
136        ChainConfig {
137            chain_id,
138            max_block_size,
139            base_fee,
140            fee_contract,
141            fee_recipient,
142            stake_table_contract: None,
143        }
144    }
145}
146
147impl From<v0_99::ChainConfig> for ChainConfig {
148    fn from(chain_config: v0_99::ChainConfig) -> ChainConfig {
149        let v0_99::ChainConfig {
150            chain_id,
151            max_block_size,
152            base_fee,
153            fee_contract,
154            fee_recipient,
155            stake_table_contract,
156            ..
157        } = chain_config;
158
159        ChainConfig {
160            chain_id,
161            max_block_size,
162            base_fee,
163            fee_contract,
164            fee_recipient,
165            stake_table_contract,
166        }
167    }
168}
169
170impl Default for ChainConfig {
171    fn default() -> Self {
172        Self {
173            chain_id: U256::from(35353).into(), // arbitrarily chosen chain ID
174            max_block_size: 30720.into(),
175            base_fee: 0.into(),
176            fee_contract: None,
177            fee_recipient: Default::default(),
178            stake_table_contract: None,
179        }
180    }
181}