tycho_types/models/config/
mod.rs

1//! Blockchain config and params.
2
3pub use self::params::*;
4use crate::cell::*;
5use crate::dict::{Dict, DictKey};
6use crate::error::Error;
7use crate::models::currency::ExtraCurrencyCollection;
8use crate::models::global_version::GlobalVersion;
9use crate::num::Tokens;
10
11mod params;
12
13#[cfg(test)]
14mod tests;
15
16/// Blockchain config.
17#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct BlockchainConfig {
20    /// Configuration contract address.
21    pub address: HashBytes,
22    /// Configuration parameters.
23    pub params: BlockchainConfigParams,
24}
25
26impl BlockchainConfig {
27    /// Creates a new blockchain config with only the address set.
28    pub fn new_empty(address: HashBytes) -> Self {
29        let mut params = BlockchainConfigParams(Dict::new());
30        params
31            .set_raw(ConfigParam0::ID, CellBuilder::build_from(address).unwrap())
32            .unwrap();
33
34        Self { address, params }
35    }
36}
37
38impl std::ops::Deref for BlockchainConfig {
39    type Target = BlockchainConfigParams;
40
41    #[inline]
42    fn deref(&self) -> &Self::Target {
43        &self.params
44    }
45}
46
47impl std::ops::DerefMut for BlockchainConfig {
48    #[inline]
49    fn deref_mut(&mut self) -> &mut Self::Target {
50        &mut self.params
51    }
52}
53
54/// A non-empty dictionary with blockchain config params.
55#[derive(Debug, Clone, Eq, PartialEq)]
56#[repr(transparent)]
57pub struct BlockchainConfigParams(Dict<u32, Cell>);
58
59impl BlockchainConfigParams {
60    /// Creates a dictionary from a raw cell.
61    ///
62    /// NOTE: Root is mandatory since the configs dictionary can't be empty.
63    pub fn from_raw(dict_root: Cell) -> Self {
64        Self(Dict::from_raw(Some(dict_root)))
65    }
66
67    /// Returns the elector account address (in masterchain).
68    ///
69    /// Uses [`ConfigParam1`].
70    pub fn get_elector_address(&self) -> Result<HashBytes, Error> {
71        ok!(self.get::<ConfigParam1>()).ok_or(Error::CellUnderflow)
72    }
73
74    /// Updates the elector account address (in masterchain).
75    ///
76    /// Uses [`ConfigParam1`].
77    pub fn set_elector_address(&mut self, address: &HashBytes) -> Result<bool, Error> {
78        self.set_raw(ConfigParam1::ID, ok!(CellBuilder::build_from(address)))
79    }
80
81    /// Returns the minter account address (in masterchain).
82    ///
83    /// Uses [`ConfigParam2`] with a fallback to [`ConfigParam0`] (config).
84    pub fn get_minter_address(&self) -> Result<HashBytes, Error> {
85        match ok!(self.get::<ConfigParam2>()) {
86            Some(address) => Ok(address),
87            None => ok!(self.get::<ConfigParam0>()).ok_or(Error::CellUnderflow),
88        }
89    }
90
91    /// Updates the minter account address (in masterchain).
92    ///
93    /// Uses [`ConfigParam2`].
94    pub fn set_minter_address(&mut self, address: &HashBytes) -> Result<bool, Error> {
95        self.set_raw(ConfigParam2::ID, ok!(CellBuilder::build_from(address)))
96    }
97
98    /// Returns the burning config.
99    ///
100    /// Uses [`ConfigParam5`].
101    pub fn get_burning_config(&self) -> Result<BurningConfig, Error> {
102        ok!(self.get::<ConfigParam5>()).ok_or(Error::CellUnderflow)
103    }
104
105    /// Updates the burning config.
106    ///
107    /// Uses [`ConfigParam5`].
108    pub fn set_burning_config(&mut self, config: &BurningConfig) -> Result<bool, Error> {
109        self.set_raw(ConfigParam5::ID, ok!(CellBuilder::build_from(config)))
110    }
111
112    /// Returns the fee collector account address (in masterchain).
113    ///
114    /// Uses [`ConfigParam3`] with a fallback to [`ConfigParam1`] (elector).
115    pub fn get_fee_collector_address(&self) -> Result<HashBytes, Error> {
116        match ok!(self.get::<ConfigParam3>()) {
117            Some(address) => Ok(address),
118            None => ok!(self.get::<ConfigParam1>()).ok_or(Error::CellUnderflow),
119        }
120    }
121
122    /// Updates the fee collector address (in masterchain).
123    ///
124    /// Uses [`ConfigParam3`].
125    pub fn set_fee_collector_address(&mut self, address: &HashBytes) -> Result<bool, Error> {
126        self.set_raw(ConfigParam3::ID, ok!(CellBuilder::build_from(address)))
127    }
128
129    /// Returns the lowest supported block version and required capabilities.
130    ///
131    /// Uses [`ConfigParam8`].
132    pub fn get_global_version(&self) -> Result<GlobalVersion, Error> {
133        ok!(self.get::<ConfigParam8>()).ok_or(Error::CellUnderflow)
134    }
135
136    /// Updates the global version.
137    ///
138    /// Uses [`ConfigParam8`].
139    pub fn set_global_version(&mut self, version: &GlobalVersion) -> Result<bool, Error> {
140        self.set_raw(ConfigParam8::ID, ok!(CellBuilder::build_from(version)))
141    }
142
143    /// Returns a list of params that must be present in config.
144    ///
145    /// Uses [`ConfigParam9`].
146    pub fn get_mandatory_params(&self) -> Result<Dict<u32, ()>, Error> {
147        ok!(self.get::<ConfigParam9>()).ok_or(Error::CellUnderflow)
148    }
149
150    /// Updates a list of params that must be present in config.
151    ///
152    /// Uses [`ConfigParam9`].
153    pub fn set_mandatory_params(&mut self, params: &[u32]) -> Result<bool, Error> {
154        let mut dict = Dict::new();
155        for id in params {
156            ok!(dict.set(*id, ()));
157        }
158        self.set_raw(
159            ConfigParam9::ID,
160            ok!(CellBuilder::build_from(NonEmptyDict(dict))),
161        )
162    }
163
164    /// Returns a list of params that have a different set of update requirements.
165    ///
166    /// Uses [`ConfigParam10`].
167    pub fn get_critical_params(&self) -> Result<Dict<u32, ()>, Error> {
168        ok!(self.get::<ConfigParam10>()).ok_or(Error::CellUnderflow)
169    }
170
171    /// Updates a list of params that have a different set of update requirements.
172    ///
173    /// Uses [`ConfigParam10`].
174    pub fn set_critical_params(&mut self, params: &[u32]) -> Result<bool, Error> {
175        let mut dict = Dict::new();
176        for id in params {
177            ok!(dict.set(*id, ()));
178        }
179        self.set_raw(
180            ConfigParam10::ID,
181            ok!(CellBuilder::build_from(NonEmptyDict(dict))),
182        )
183    }
184
185    /// Returns a dictionary with workchain descriptions.
186    ///
187    /// Uses [`ConfigParam12`].
188    pub fn get_workchains(&self) -> Result<Dict<i32, WorkchainDescription>, Error> {
189        ok!(self.get::<ConfigParam12>()).ok_or(Error::CellUnderflow)
190    }
191
192    /// Updates a list of workchain descriptions.
193    ///
194    /// Uses [`ConfigParam12`].
195    pub fn set_workchains(
196        &mut self,
197        workchains: &Dict<i32, WorkchainDescription>,
198    ) -> Result<bool, Error> {
199        self.set_raw(ConfigParam12::ID, ok!(CellBuilder::build_from(workchains)))
200    }
201
202    /// Returns a block creation reward for the specified workchain in tokens.
203    ///
204    /// Uses [`ConfigParam14`].
205    pub fn get_block_creation_reward(&self, masterchain: bool) -> Result<Tokens, Error> {
206        let rewards = ok!(self.get_block_creation_rewards());
207        Ok(if masterchain {
208            rewards.masterchain_block_fee
209        } else {
210            rewards.basechain_block_fee
211        })
212    }
213
214    /// Returns a block creation rewards in tokens.
215    ///
216    /// Uses [`ConfigParam14`].
217    pub fn get_block_creation_rewards(&self) -> Result<BlockCreationRewards, Error> {
218        ok!(self.get::<ConfigParam14>()).ok_or(Error::CellUnderflow)
219    }
220
221    /// Updates a block creation rewards in tokens.
222    ///
223    /// Uses [`ConfigParam14`].
224    pub fn set_block_creation_rewards(
225        &mut self,
226        rewards: &BlockCreationRewards,
227    ) -> Result<bool, Error> {
228        self.set_raw(ConfigParam14::ID, ok!(CellBuilder::build_from(rewards)))
229    }
230
231    /// Returns election timings.
232    ///
233    /// Uses [`ConfigParam15`].
234    pub fn get_election_timings(&self) -> Result<ElectionTimings, Error> {
235        ok!(self.get::<ConfigParam15>()).ok_or(Error::CellUnderflow)
236    }
237
238    /// Updates election timings.
239    ///
240    /// Uses [`ConfigParam15`].
241    pub fn set_election_timings(&mut self, timings: &ElectionTimings) -> Result<bool, Error> {
242        self.set_raw(ConfigParam15::ID, ok!(CellBuilder::build_from(timings)))
243    }
244
245    /// Returns possible validator count.
246    ///
247    /// Uses [`ConfigParam16`].
248    pub fn get_validator_count_params(&self) -> Result<ValidatorCountParams, Error> {
249        ok!(self.get::<ConfigParam16>()).ok_or(Error::CellUnderflow)
250    }
251
252    /// Updates possible validator count.
253    ///
254    /// Uses [`ConfigParam16`].
255    pub fn set_validator_count_params(
256        &mut self,
257        params: &ValidatorCountParams,
258    ) -> Result<bool, Error> {
259        self.set_raw(ConfigParam16::ID, ok!(CellBuilder::build_from(params)))
260    }
261
262    /// Returns validator stake range and factor.
263    ///
264    /// Uses [`ConfigParam17`].
265    pub fn get_validator_stake_params(&self) -> Result<ValidatorStakeParams, Error> {
266        ok!(self.get::<ConfigParam17>()).ok_or(Error::CellUnderflow)
267    }
268
269    /// Updates validator stake range and factor.
270    ///
271    /// Uses [`ConfigParam17`].
272    pub fn set_validator_stake_params(
273        &mut self,
274        params: &ValidatorStakeParams,
275    ) -> Result<bool, Error> {
276        self.set_raw(ConfigParam17::ID, ok!(CellBuilder::build_from(params)))
277    }
278
279    /// Returns a list with a history of all storage prices.
280    ///
281    /// Uses [`ConfigParam18`].
282    pub fn get_storage_prices(&self) -> Result<Dict<u32, StoragePrices>, Error> {
283        ok!(self.get::<ConfigParam18>()).ok_or(Error::CellUnderflow)
284    }
285
286    /// Updates a list with a history of all storage prices.
287    ///
288    /// Uses [`ConfigParam18`].
289    pub fn set_storage_prices(&mut self, prices: &[StoragePrices]) -> Result<bool, Error> {
290        let mut dict = Dict::<u32, StoragePrices>::new();
291        for (i, prices) in prices.iter().enumerate() {
292            ok!(dict.set(i as u32, *prices));
293        }
294        self.set_raw(
295            ConfigParam18::ID,
296            ok!(CellBuilder::build_from(NonEmptyDict(dict))),
297        )
298    }
299
300    /// Returns a global id.
301    pub fn get_global_id(&self) -> Result<i32, Error> {
302        ok!(self.get::<ConfigParam19>()).ok_or(Error::CellUnderflow)
303    }
304
305    /// Updates a global id.
306    pub fn set_global_id(&mut self, global_id: i32) -> Result<bool, Error> {
307        self.set_raw(
308            ConfigParam19::ID,
309            ok!(CellBuilder::build_from(global_id as u32)),
310        )
311    }
312
313    /// Returns gas limits and prices.
314    ///
315    /// Uses [`ConfigParam20`] (for masterchain) or [`ConfigParam21`] (for other workchains).
316    pub fn get_gas_prices(&self, masterchain: bool) -> Result<GasLimitsPrices, Error> {
317        ok!(if masterchain {
318            self.get::<ConfigParam20>()
319        } else {
320            self.get::<ConfigParam21>()
321        })
322        .ok_or(Error::CellUnderflow)
323    }
324
325    /// Updates gas limits and prices.
326    ///
327    /// Uses [`ConfigParam20`] (for masterchain) or [`ConfigParam21`] (for other workchains).
328    pub fn set_gas_prices(
329        &mut self,
330        masterchain: bool,
331        prices: &GasLimitsPrices,
332    ) -> Result<bool, Error> {
333        let id = if masterchain {
334            ConfigParam20::ID
335        } else {
336            ConfigParam21::ID
337        };
338        self.set_raw(id, ok!(CellBuilder::build_from(prices)))
339    }
340
341    /// Returns block limits.
342    ///
343    /// Uses [`ConfigParam22`] (for masterchain) or [`ConfigParam23`] (for other workchains).
344    pub fn get_block_limits(&self, masterchain: bool) -> Result<BlockLimits, Error> {
345        ok!(if masterchain {
346            self.get::<ConfigParam22>()
347        } else {
348            self.get::<ConfigParam23>()
349        })
350        .ok_or(Error::CellUnderflow)
351    }
352
353    /// Updates block limits.
354    ///
355    /// Uses [`ConfigParam22`] (for masterchain) or [`ConfigParam23`] (for other workchains).
356    pub fn set_block_limits(
357        &mut self,
358        masterchain: bool,
359        limits: &BlockLimits,
360    ) -> Result<bool, Error> {
361        let id = if masterchain {
362            ConfigParam22::ID
363        } else {
364            ConfigParam23::ID
365        };
366        self.set_raw(id, ok!(CellBuilder::build_from(limits)))
367    }
368
369    /// Returns message forwarding prices.
370    ///
371    /// Uses [`ConfigParam24`] (for masterchain) or [`ConfigParam25`] (for other workchains).
372    pub fn get_msg_forward_prices(&self, masterchain: bool) -> Result<MsgForwardPrices, Error> {
373        ok!(if masterchain {
374            self.get::<ConfigParam24>()
375        } else {
376            self.get::<ConfigParam25>()
377        })
378        .ok_or(Error::CellUnderflow)
379    }
380
381    /// Updates message forwarding prices.
382    ///
383    /// Uses [`ConfigParam24`] (for masterchain) or [`ConfigParam25`] (for other workchains).
384    pub fn set_msg_forward_prices(
385        &mut self,
386        masterchain: bool,
387        prices: &MsgForwardPrices,
388    ) -> Result<bool, Error> {
389        let id = if masterchain {
390            ConfigParam24::ID
391        } else {
392            ConfigParam25::ID
393        };
394        self.set_raw(id, ok!(CellBuilder::build_from(prices)))
395    }
396
397    /// Returns a catchain config.
398    ///
399    /// Uses [`ConfigParam28`].
400    #[cfg(not(feature = "tycho"))]
401    pub fn get_catchain_config(&self) -> Result<CatchainConfig, Error> {
402        ok!(self.get::<ConfigParam28>()).ok_or(Error::CellUnderflow)
403    }
404
405    /// Updates a catchain config.
406    ///
407    /// Uses [`ConfigParam28`].
408    #[cfg(not(feature = "tycho"))]
409    pub fn set_catchain_config(&mut self, config: &CatchainConfig) -> Result<bool, Error> {
410        self.set_raw(ConfigParam28::ID, ok!(CellBuilder::build_from(config)))
411    }
412
413    /// Returns a collation config.
414    ///
415    /// Uses [`ConfigParam28`].
416    #[cfg(feature = "tycho")]
417    pub fn get_collation_config(&self) -> Result<CollationConfig, Error> {
418        ok!(self.get::<ConfigParam28>()).ok_or(Error::CellUnderflow)
419    }
420
421    /// Updates a collation config.
422    ///
423    /// Uses [`ConfigParam28`].
424    #[cfg(feature = "tycho")]
425    pub fn set_collation_config(&mut self, config: &CollationConfig) -> Result<bool, Error> {
426        self.set_raw(ConfigParam28::ID, ok!(CellBuilder::build_from(config)))
427    }
428
429    /// Returns a consensus config.
430    ///
431    /// Uses [`ConfigParam29`].
432    pub fn get_consensus_config(&self) -> Result<ConsensusConfig, Error> {
433        ok!(self.get::<ConfigParam29>()).ok_or(Error::CellUnderflow)
434    }
435
436    /// Updates a consensus config.
437    ///
438    /// Uses [`ConfigParam29`].
439    pub fn set_consensus_config(&mut self, config: &ConsensusConfig) -> Result<bool, Error> {
440        self.set_raw(ConfigParam29::ID, ok!(CellBuilder::build_from(config)))
441    }
442
443    /// Returns a list of fundamental account addresses (in masterchain).
444    ///
445    /// Uses [`ConfigParam31`].
446    pub fn get_fundamental_addresses(&self) -> Result<Dict<HashBytes, ()>, Error> {
447        ok!(self.get::<ConfigParam31>()).ok_or(Error::CellUnderflow)
448    }
449
450    /// Updates a list of fundamental account addresses (in masterchain).
451    ///
452    /// Uses [`ConfigParam31`].
453    pub fn set_fundamental_addresses(&mut self, addresses: &[HashBytes]) -> Result<bool, Error> {
454        let mut dict = Dict::<HashBytes, ()>::new();
455        for address in addresses {
456            ok!(dict.set(*address, ()));
457        }
458        self.set_raw(ConfigParam31::ID, ok!(CellBuilder::build_from(dict)))
459    }
460
461    /// Returns `true` if the config contains info about the previous validator set.
462    ///
463    /// Uses [`ConfigParam32`] or [`ConfigParam33`].
464    pub fn contains_prev_validator_set(&self) -> Result<bool, Error> {
465        Ok(ok!(self.contains::<ConfigParam32>()) || ok!(self.contains::<ConfigParam33>()))
466    }
467
468    /// Returns `true` if the config contains info about the next validator set.
469    ///
470    /// Uses [`ConfigParam36`] or [`ConfigParam37`].
471    pub fn contains_next_validator_set(&self) -> Result<bool, Error> {
472        Ok(ok!(self.contains::<ConfigParam36>()) || ok!(self.contains::<ConfigParam37>()))
473    }
474
475    /// Returns the previous validator set.
476    ///
477    /// Uses [`ConfigParam33`] (temp prev validators) or [`ConfigParam32`] (prev validators).
478    pub fn get_previous_validator_set(&self) -> Result<Option<ValidatorSet>, Error> {
479        match ok!(self.get::<ConfigParam33>()) {
480            None => self.get::<ConfigParam32>(),
481            set => Ok(set),
482        }
483    }
484
485    /// Returns the current validator set.
486    ///
487    /// Uses [`ConfigParam35`] (temp validators) or [`ConfigParam34`] (current validators).
488    pub fn get_current_validator_set(&self) -> Result<ValidatorSet, Error> {
489        match ok!(self.get::<ConfigParam35>()) {
490            Some(set) => Ok(set),
491            None => ok!(self.get::<ConfigParam34>()).ok_or(Error::CellUnderflow),
492        }
493    }
494
495    /// Returns the next validator set.
496    ///
497    /// Uses [`ConfigParam37`] (temp next validators) or [`ConfigParam36`] (next validators).
498    pub fn get_next_validator_set(&self) -> Result<Option<ValidatorSet>, Error> {
499        match ok!(self.get::<ConfigParam37>()) {
500            None => self.get::<ConfigParam36>(),
501            set => Ok(set),
502        }
503    }
504
505    /// Returns size limits.
506    pub fn get_size_limits(&self) -> Result<SizeLimitsConfig, Error> {
507        ok!(self.get::<ConfigParam43>()).ok_or(Error::CellUnderflow)
508    }
509
510    /// Updates size limits.
511    pub fn set_size_limits(&mut self, size_limits: &SizeLimitsConfig) -> Result<bool, Error> {
512        self.set_raw(ConfigParam43::ID, ok!(CellBuilder::build_from(size_limits)))
513    }
514
515    /// Returns authority marks config.
516    pub fn get_authority_marks_config(&self) -> Result<AuthorityMarksConfig, Error> {
517        ok!(self.get::<ConfigParam100>()).ok_or(Error::CellUnderflow)
518    }
519
520    /// Updates authority marks config.
521    pub fn set_authority_marks_config(
522        &mut self,
523        params: &AuthorityMarksConfig,
524    ) -> Result<bool, Error> {
525        self.set_raw(ConfigParam100::ID, ok!(CellBuilder::build_from(params)))
526    }
527
528    /// Returns `true` if the config contains a param for the specified id.
529    pub fn contains<'a, T: KnownConfigParam<'a>>(&'a self) -> Result<bool, Error> {
530        self.0.contains_key(T::ID)
531    }
532
533    /// Returns `true` if the config contains a param for the specified id.
534    pub fn contains_raw(&self, id: u32) -> Result<bool, Error> {
535        self.0.contains_key(id)
536    }
537
538    /// Tries to get a parameter from the blockchain config.
539    pub fn get<'a, T: KnownConfigParam<'a>>(&'a self) -> Result<Option<T::Value>, Error> {
540        let Some(mut slice) = ok!(self.get_raw(T::ID)) else {
541            return Ok(None);
542        };
543        match <T::Wrapper as Load<'a>>::load_from(&mut slice) {
544            Ok(wrapped) => Ok(Some(wrapped.into_inner())),
545            Err(e) => Err(e),
546        }
547    }
548
549    /// Tries to update a parameter in the blockchain config.
550    pub fn set<'a, T: KnownConfigParam<'a>>(&'a mut self, value: &T::Value) -> Result<bool, Error> {
551        let value = ok!(CellBuilder::build_from(T::Wrapper::wrap_inner(value)));
552        self.set_raw(T::ID, value)
553    }
554
555    /// Tries to get a raw parameter from the blockchain config (as slice).
556    pub fn get_raw(&self, id: u32) -> Result<Option<CellSlice<'_>>, Error> {
557        match ok!(self.get_raw_cell_ref(id)) {
558            Some(cell) => cell.as_slice().map(Some),
559            None => Ok(None),
560        }
561    }
562
563    /// Tries to get a raw parameter from the blockchain config (as cell).
564    pub fn get_raw_cell(&self, id: u32) -> Result<Option<Cell>, Error> {
565        match ok!(self.0.get_raw(id)) {
566            Some(slice) => match slice.get_reference_cloned(0) {
567                Ok(cell) => Ok(Some(cell)),
568                Err(e) => Err(e),
569            },
570            None => Ok(None),
571        }
572    }
573
574    /// Tries to get a raw parameter from the blockchain config (as cell ref).
575    pub fn get_raw_cell_ref(&self, id: u32) -> Result<Option<&'_ DynCell>, Error> {
576        match ok!(self.0.get_raw(id)) {
577            Some(slice) => match slice.get_reference(0) {
578                Ok(cell) => Ok(Some(cell)),
579                Err(e) => Err(e),
580            },
581            None => Ok(None),
582        }
583    }
584
585    /// Tries to set a parameter in the blockchain config.
586    ///
587    /// NOTE: Use with caution, as it doesn't check the value structure.
588    pub fn set_raw(&mut self, id: u32, value: Cell) -> Result<bool, Error> {
589        self.0.set(id, value)
590    }
591
592    /// Removes a parameter from the blockchain config.
593    ///
594    /// NOTE: Removing a zero parameter successfully does nothing
595    /// and returns `None` as it is required and externaly managed.
596    pub fn remove(&mut self, id: u32) -> Result<Option<Cell>, Error> {
597        if id == 0 {
598            return Ok(None);
599        }
600        self.0.remove(id)
601    }
602
603    /// Returns a reference to the underlying dictionary.
604    pub fn as_dict(&self) -> &Dict<u32, Cell> {
605        &self.0
606    }
607}
608
609impl Store for BlockchainConfigParams {
610    fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
611        match self.0.root() {
612            Some(root) => builder.store_reference(root.clone()),
613            None => Err(Error::InvalidData),
614        }
615    }
616}
617
618impl<'a> Load<'a> for BlockchainConfigParams {
619    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
620        let root = ok!(slice.load_reference_cloned());
621        Ok(Self(Dict::from(Some(root))))
622    }
623}
624
625/// Marker trait which is implemented for known config params.
626pub trait KnownConfigParam<'a> {
627    /// Parameter index in a configuration dictionary.
628    const ID: u32;
629
630    /// Associated value type.
631    type Value;
632
633    /// Value wrapper.
634    type Wrapper: ConfigParamWrapper<Self::Value> + Store + Load<'a>;
635}
636
637/// Trait to customize config param representation.
638pub trait ConfigParamWrapper<T> {
639    /// Converts this wrapper into an underlying type.
640    fn into_inner(self) -> T;
641
642    /// Converts an inner type into a wrapper.
643    fn wrap_inner(inner: &T) -> &Self;
644}
645
646/// Identity wrapper for [`ConfigParamWrapper`].
647#[repr(transparent)]
648pub struct ParamIdentity<T>(T);
649
650impl<T> ConfigParamWrapper<T> for ParamIdentity<T> {
651    #[inline]
652    fn into_inner(self) -> T {
653        self.0
654    }
655
656    #[inline]
657    fn wrap_inner(inner: &T) -> &Self {
658        // SAFETY: `ParamIdentity` is a transparent wrapper.
659        unsafe { &*(inner as *const T).cast() }
660    }
661}
662
663impl<'a, T: Load<'a>> Load<'a> for ParamIdentity<T> {
664    #[inline]
665    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
666        match T::load_from(slice) {
667            Ok(value) => Ok(Self(value)),
668            Err(e) => Err(e),
669        }
670    }
671}
672
673impl<T: Store> Store for ParamIdentity<T> {
674    #[inline]
675    fn store_into(&self, builder: &mut CellBuilder, cx: &dyn CellContext) -> Result<(), Error> {
676        self.0.store_into(builder, cx)
677    }
678}
679
680#[cfg(feature = "serde")]
681impl<T: serde::Serialize> serde::Serialize for ParamIdentity<T> {
682    #[inline]
683    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
684        self.0.serialize(serializer)
685    }
686}
687
688#[cfg(feature = "serde")]
689impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ParamIdentity<T> {
690    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
691    where
692        D: serde::Deserializer<'de>,
693    {
694        T::deserialize(deserializer).map(Self)
695    }
696}
697
698/// Dict wrapper for [`ConfigParamWrapper`] for parsing non-empty dictionaries.
699#[repr(transparent)]
700pub struct NonEmptyDict<T>(T);
701
702impl<T> ConfigParamWrapper<T> for NonEmptyDict<T> {
703    fn into_inner(self) -> T {
704        self.0
705    }
706
707    #[inline]
708    fn wrap_inner(inner: &T) -> &Self {
709        // SAFETY: `NonEmptyDict` is a transparent wrapper.
710        unsafe { &*(inner as *const T).cast() }
711    }
712}
713
714impl<'a, K, V> Load<'a> for NonEmptyDict<Dict<K, V>>
715where
716    K: DictKey,
717{
718    #[inline]
719    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
720        match Dict::load_from_root_ext(slice, Cell::empty_context()) {
721            Ok(value) => Ok(Self(value)),
722            Err(e) => Err(e),
723        }
724    }
725}
726
727impl<K, V> Store for NonEmptyDict<Dict<K, V>> {
728    fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
729        match self.0.root() {
730            Some(root) => builder.store_slice(ok!(root.as_slice())),
731            None => Err(Error::InvalidData),
732        }
733    }
734}
735
736#[cfg(feature = "serde")]
737impl serde::Serialize for NonEmptyDict<Dict<u32, ()>> {
738    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
739        use serde::ser::SerializeSeq;
740
741        let mut seq = serializer.serialize_seq(None)?;
742        for entry in self.0.iter() {
743            match entry {
744                Ok((key, _)) => ok!(seq.serialize_element(&key)),
745                Err(e) => return Err(serde::ser::Error::custom(e)),
746            }
747        }
748        seq.end()
749    }
750}
751
752#[cfg(feature = "serde")]
753impl<'de> serde::Deserialize<'de> for NonEmptyDict<Dict<u32, ()>> {
754    #[inline]
755    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
756        use serde::de::Error;
757
758        let parsed = ok!(Vec::<u32>::deserialize(deserializer));
759        if parsed.is_empty() {
760            return Err(Error::custom("dictionary is empty"));
761        }
762
763        let mut res = Dict::new();
764        for item in parsed {
765            ok!(res.set(item, ()).map_err(Error::custom));
766        }
767
768        Ok(Self(res))
769    }
770}
771
772#[cfg(feature = "serde")]
773impl serde::Serialize for NonEmptyDict<Dict<u32, StoragePrices>> {
774    #[inline]
775    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
776        self.0.serialize(serializer)
777    }
778}
779
780#[cfg(feature = "serde")]
781impl<'de> serde::Deserialize<'de> for NonEmptyDict<Dict<u32, StoragePrices>> {
782    #[inline]
783    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
784        let res = ok!(Dict::deserialize(deserializer));
785        if res.is_empty() {
786            return Err(serde::de::Error::custom("dictionary is empty"));
787        }
788        Ok(Self(res))
789    }
790}
791
792macro_rules! define_config_params {
793    ($(
794        $(#[doc = $doc:expr])*
795        $(#[cfg($($cfg_attrs:tt)*)])?
796        $(#[serde($($serde_attrs:tt)*)])?
797        $id:literal => $ident:ident($($ty:tt)*)
798    ),*$(,)?) => {
799        $(
800            $(#[cfg($($cfg_attrs)*)])?
801            $(#[doc = $doc])*
802            pub struct $ident;
803
804            $(#[cfg($($cfg_attrs)*)])?
805            impl<'a> KnownConfigParam<'a> for $ident {
806                const ID: u32 = $id;
807
808                define_config_params!(@wrapper $($ty)*);
809            }
810        )*
811
812        #[cfg(feature = "serde")]
813        impl serde::Serialize for BlockchainConfigParams {
814            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
815            where
816                S: serde::Serializer,
817            {
818                use serde::ser::{Error, SerializeMap};
819
820                let dict = &self.0;
821                if !serializer.is_human_readable() {
822                    return crate::boc::BocRepr::serialize(dict, serializer);
823                }
824
825                let mut map = serializer.serialize_map(None)?;
826
827                for entry in dict.iter() {
828                    let (key, value) = match entry {
829                        Ok(entry) => entry,
830                        Err(e) => return Err(Error::custom(e)),
831                    };
832
833                    {
834                        match key {
835                            $(
836                                $(#[cfg($($cfg_attrs)*)])?
837                                $($id => {
838                                    let value = define_config_params!(
839                                        @ser
840                                        $ident,
841                                        value,
842                                        $($serde_attrs)*
843                                    );
844                                    ok!(map.serialize_entry(&key, &value));
845                                },)?
846                            )*
847                            _ => ok!(map.serialize_entry(&key, value.as_ref())),
848                        }
849                    }
850                }
851
852                map.end()
853            }
854        }
855
856        #[cfg(feature = "serde")]
857        impl<'de> serde::Deserialize<'de> for BlockchainConfigParams {
858            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
859            where
860                D: serde::Deserializer<'de>,
861            {
862                use serde::de::{Error, Visitor, MapAccess};
863
864                #[derive(serde::Deserialize)]
865                struct RawValue(#[serde(with = "crate::boc::Boc")] Cell);
866
867                struct MapVisitor;
868
869                impl<'de> Visitor<'de> for MapVisitor {
870                    type Value = BlockchainConfigParams;
871
872                    fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
873                        f.write_str("a config params map")
874                    }
875
876                    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
877                    where
878                        M: MapAccess<'de>,
879                    {
880                        let mut dict = Dict::new();
881
882                        while let Some(key) = access.next_key::<u32>()? {
883                            let value = match key {
884                                $(
885                                    $(#[cfg($($cfg_attrs)*)])?
886                                    $($id => define_config_params!(
887                                        @de
888                                        $ident,
889                                        access,
890                                        $($serde_attrs)*
891                                    ),)?
892                                )*
893                                _ => {
894                                    let RawValue(cell) = ok!(access.next_value());
895                                    cell
896                                }
897                            };
898                            ok!(dict.set(key, value).map_err(Error::custom));
899                        }
900
901                        Ok(BlockchainConfigParams(dict))
902                    }
903                }
904
905                if deserializer.is_human_readable() {
906                    deserializer.deserialize_map(MapVisitor)
907                } else {
908                    crate::boc::BocRepr::deserialize(deserializer)
909                }
910            }
911        }
912    };
913
914    (@wrapper $wrapper:ident => $($ty:tt)*) => {
915        type Value = $($ty)*;
916        type Wrapper = $wrapper<Self::Value>;
917    };
918    (@wrapper $($ty:tt)*) => {
919        type Value = $($ty)*;
920        type Wrapper = ParamIdentity<Self::Value>;
921    };
922
923    (@ser $ident:ident, $value:ident, transparent) => {{
924        ok!($value.parse::<<$ident as KnownConfigParam>::Wrapper>().map_err(Error::custom))
925    }};
926    (@ser $ident:ident, $value:ident, remote = $remote:ident) => {{
927        let value = ok!($value.parse::<<$ident as KnownConfigParam>::Wrapper>().map_err(Error::custom));
928        $remote(<<$ident as KnownConfigParam>::Wrapper>::into_inner(value))
929    }};
930
931    (@de $ident:ident, $access:ident, transparent) => {{
932        let parsed = ok!($access.next_value::<<$ident as KnownConfigParam>::Wrapper>());
933        ok!(CellBuilder::build_from(&parsed).map_err(Error::custom))
934    }};
935    (@de $ident:ident, $access:ident, remote = $remote:ident) => {{
936        let parsed = ok!($access.next_value::<$remote>());
937        ok!(CellBuilder::build_from(&parsed.0).map_err(Error::custom))
938    }};
939}
940
941define_config_params! {
942    /// Configuration account address (in masterchain).
943    #[serde(transparent)]
944    0 => ConfigParam0(HashBytes),
945
946    /// Elector account address (in masterchain).
947    #[serde(transparent)]
948    1 => ConfigParam1(HashBytes),
949
950    /// Minter account address (in masterchain).
951    #[serde(transparent)]
952    2 => ConfigParam2(HashBytes),
953
954    /// Fee collector account address (in masterchain).
955    #[serde(transparent)]
956    3 => ConfigParam3(HashBytes),
957
958    /// DNS root account address (in masterchain).
959    #[serde(transparent)]
960    4 => ConfigParam4(HashBytes),
961
962    /// Burning config.
963    #[serde(transparent)]
964    5 => ConfigParam5(BurningConfig),
965
966    /// Mint new price and mint add price (unused).
967    6 => ConfigParam6(CellSlice<'a>),
968
969    /// Target amount of minted extra currencies.
970    #[serde(transparent)]
971    7 => ConfigParam7(ExtraCurrencyCollection),
972
973    /// The lowest supported block version and required capabilities.
974    ///
975    /// Contains a [`GlobalVersion`].
976    #[serde(transparent)]
977    8 => ConfigParam8(GlobalVersion),
978
979    /// Params that must be present in config.
980    #[serde(transparent)]
981    9 => ConfigParam9(NonEmptyDict => Dict<u32, ()>),
982
983    /// Params that have a different set of update requirements.
984    #[serde(transparent)]
985    10 => ConfigParam10(NonEmptyDict => Dict<u32, ()>),
986
987    /// Config voting setup params.
988    ///
989    /// Contains a [`ConfigVotingSetup`].
990    #[serde(transparent)]
991    11 => ConfigParam11(ConfigVotingSetup),
992
993    /// Known workchain descriptions.
994    ///
995    /// Contains a dictionary with workchain id as key and [`WorkchainDescription`] as value.
996    #[serde(transparent)]
997    12 => ConfigParam12(Dict<i32, WorkchainDescription>),
998
999    /// Complaint pricing.
1000    13 => ConfigParam13(CellSlice<'a>),
1001
1002    /// Block creation reward for masterchain and basechain.
1003    ///
1004    /// Contains a [`BlockCreationRewards`].
1005    #[serde(transparent)]
1006    14 => ConfigParam14(BlockCreationRewards),
1007
1008    /// Validators election timings.
1009    ///
1010    /// Contains [`ElectionTimings`].
1011    #[serde(transparent)]
1012    15 => ConfigParam15(ElectionTimings),
1013
1014    /// Range of number of validators.
1015    ///
1016    /// Contains a [`ValidatorCountParams`].
1017    #[serde(transparent)]
1018    16 => ConfigParam16(ValidatorCountParams),
1019
1020    /// Validator stake range and factor.
1021    ///
1022    /// Contains [`ValidatorStakeParams`]
1023    #[serde(transparent)]
1024    17 => ConfigParam17(ValidatorStakeParams),
1025
1026    /// Storage prices for different intervals of time.
1027    ///
1028    /// Contains a dictionary with a history of all [`StoragePrices`].
1029    #[serde(transparent)]
1030    18 => ConfigParam18(NonEmptyDict => Dict<u32, StoragePrices>),
1031
1032    /// Global ID.
1033    #[serde(transparent)]
1034    19 => ConfigParam19(i32),
1035
1036    /// Masterchain gas limits and prices.
1037    ///
1038    /// Contains [`GasLimitsPrices`].
1039    #[serde(transparent)]
1040    20 => ConfigParam20(GasLimitsPrices),
1041
1042    /// Base workchain gas limits and prices.
1043    ///
1044    /// Contains [`GasLimitsPrices`].
1045    #[serde(transparent)]
1046    21 => ConfigParam21(GasLimitsPrices),
1047
1048    /// Masterchain block limits.
1049    ///
1050    /// Contains [`BlockLimits`].
1051    #[serde(transparent)]
1052    22 => ConfigParam22(BlockLimits),
1053
1054    /// Base workchain block limits.
1055    ///
1056    /// Contains [`BlockLimits`].
1057    #[serde(transparent)]
1058    23 => ConfigParam23(BlockLimits),
1059
1060    /// Message forwarding prices for masterchain.
1061    ///
1062    /// Contains [`MsgForwardPrices`].
1063    #[serde(transparent)]
1064    24 => ConfigParam24(MsgForwardPrices),
1065
1066    /// Message forwarding prices for base workchain.
1067    ///
1068    /// Contains [`MsgForwardPrices`].
1069    #[serde(transparent)]
1070    25 => ConfigParam25(MsgForwardPrices),
1071
1072    /// Catchain configuration params.
1073    ///
1074    /// Contains a [`CatchainConfig`].
1075    #[cfg(not(feature = "tycho"))]
1076    #[serde(transparent)]
1077    28 => ConfigParam28(CatchainConfig),
1078
1079    /// Collation configuration params.
1080    ///
1081    /// Contains a [`CollationConfig`].
1082    #[cfg(feature = "tycho")]
1083    #[serde(transparent)]
1084    28 => ConfigParam28(CollationConfig),
1085
1086    /// Consensus configuration params.
1087    ///
1088    /// Contains a [`ConsensusConfig`].
1089    #[serde(transparent)]
1090    29 => ConfigParam29(ConsensusConfig),
1091
1092    /// Delector configuration params.
1093    30 => ConfigParam30(CellSlice<'a>),
1094
1095    /// Fundamental smartcontract addresses.
1096    ///
1097    /// Contains a dictionary with addresses (in masterchain) of fundamental contracts as keys.
1098    #[serde(remote = HashBytesList)]
1099    31 => ConfigParam31(Dict<HashBytes, ()>),
1100
1101    /// Previous validator set.
1102    ///
1103    /// Contains a [`ValidatorSet`].
1104    #[serde(transparent)]
1105    32 => ConfigParam32(ValidatorSet),
1106
1107    /// Previous temporary validator set.
1108    ///
1109    /// Contains a [`ValidatorSet`].
1110    #[serde(transparent)]
1111    33 => ConfigParam33(ValidatorSet),
1112
1113    /// Current validator set.
1114    ///
1115    /// Contains a [`ValidatorSet`].
1116    #[serde(transparent)]
1117    34 => ConfigParam34(ValidatorSet),
1118
1119    /// Current temporary validator set.
1120    ///
1121    /// Contains a [`ValidatorSet`].
1122    #[serde(transparent)]
1123    35 => ConfigParam35(ValidatorSet),
1124
1125    /// Next validator set.
1126    ///
1127    /// Contains a [`ValidatorSet`].
1128    #[serde(transparent)]
1129    36 => ConfigParam36(ValidatorSet),
1130
1131    /// Next temporary validator set.
1132    ///
1133    /// Contains a [`ValidatorSet`].
1134    #[serde(transparent)]
1135    37 => ConfigParam37(ValidatorSet),
1136
1137    /// Size limits.
1138    ///
1139    /// Contains a [`SizeLimitsConfig`].
1140    #[serde(transparent)]
1141    43 => ConfigParam43(SizeLimitsConfig),
1142
1143    /// Mint once config (can be used by L2 to mint native currency).
1144    ///
1145    /// Contains a [`MintOnceConfig`].
1146    #[serde(transparent)]
1147    50 => ConfigParam50(MintOnceConfig),
1148
1149    /// Authority marks config.
1150    ///
1151    /// Contains an [`AuthorityMarksConfig`].
1152    #[serde(transparent)]
1153    100 => ConfigParam100(AuthorityMarksConfig),
1154}
1155
1156#[cfg(feature = "serde")]
1157#[repr(transparent)]
1158struct HashBytesList(Dict<HashBytes, ()>);
1159
1160#[cfg(feature = "serde")]
1161impl serde::Serialize for HashBytesList {
1162    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1163        use serde::ser::SerializeSeq;
1164
1165        let mut seq = serializer.serialize_seq(None)?;
1166        for entry in self.0.iter() {
1167            match entry {
1168                Ok((ref key, _)) => ok!(seq.serialize_element(key)),
1169                Err(e) => return Err(serde::ser::Error::custom(e)),
1170            }
1171        }
1172        seq.end()
1173    }
1174}
1175
1176#[cfg(feature = "serde")]
1177impl<'de> serde::Deserialize<'de> for HashBytesList {
1178    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1179    where
1180        D: serde::Deserializer<'de>,
1181    {
1182        use serde::de::Error;
1183
1184        let parsed = ok!(Vec::<HashBytes>::deserialize(deserializer));
1185
1186        let mut res = Dict::new();
1187        for item in parsed {
1188            ok!(res.set(item, ()).map_err(Error::custom));
1189        }
1190
1191        Ok(Self(res))
1192    }
1193}