Skip to main content

tycho_block_util/config/
mod.rs

1use anyhow::{Context, Result};
2use tycho_types::error::Error;
3use tycho_types::models::{
4    BlockchainConfig, ConfigParam0, ConfigParam32, ConfigParam33, ConfigParam34, ConfigParam35,
5    ConfigParam36, ConfigParam37, KnownConfigParam,
6};
7use tycho_types::prelude::*;
8
9pub fn compute_gas_price_factor(is_masterchain: bool, gas_price: u64) -> Result<u64> {
10    const fn base_gas_price(is_masterchain: bool) -> u64 {
11        if is_masterchain {
12            10_000 << 16
13        } else {
14            1_000 << 16
15        }
16    }
17
18    let base_gas_price = base_gas_price(is_masterchain);
19    Ok(gas_price.checked_shl(16).context("gas price is too big")? / base_gas_price)
20}
21
22pub const fn apply_price_factor(mut value: u128, price_factor: u64) -> u128 {
23    value = value.saturating_mul(price_factor as u128);
24
25    let r = value & 0xffff != 0;
26    (value >> 16) + r as u128
27}
28
29pub fn build_elections_data_to_sign(
30    election_id: u32,
31    stake_factor: u32,
32    address: &HashBytes,
33    adnl_addr: &HashBytes,
34) -> Vec<u8> {
35    const TL_ID: u32 = 0x654C5074;
36
37    let mut data = Vec::with_capacity(4 + 4 + 4 + 32 + 32);
38    data.extend_from_slice(&TL_ID.to_be_bytes());
39    data.extend_from_slice(&election_id.to_be_bytes());
40    data.extend_from_slice(&stake_factor.to_be_bytes());
41    data.extend_from_slice(address.as_slice());
42    data.extend_from_slice(adnl_addr.as_array());
43    data
44}
45
46pub trait BlockchainConfigExt {
47    /// Check that config is valid.
48    fn validate_params(&self) -> Result<()>;
49
50    /// Returns a cell with the previous validator set.
51    ///
52    /// Uses [`ConfigParam33`] (temp prev validators) or [`ConfigParam32`] (prev validators).
53    fn get_prev_validator_set_raw(&self) -> Result<Option<Cell>, Error> {
54        match self.get_raw_cell(ConfigParam33::ID)? {
55            None => self.get_raw_cell(ConfigParam32::ID),
56            set => Ok(set),
57        }
58    }
59
60    /// Returns a cell with the current validator set.
61    ///
62    /// Uses [`ConfigParam35`] (temp validators) or [`ConfigParam34`] (current validators).
63    fn get_current_validator_set_raw(&self) -> Result<Cell, Error> {
64        match self.get_raw_cell(ConfigParam35::ID)? {
65            None => self.get_raw_cell(ConfigParam34::ID)?,
66            set => set,
67        }
68        .ok_or(Error::CellUnderflow)
69    }
70
71    /// Returns a cell with the next validator set.
72    ///
73    /// Uses [`ConfigParam37`] (temp next validators) or [`ConfigParam36`] (next validators).
74    fn get_next_validator_set_raw(&self) -> Result<Option<Cell>, Error> {
75        match self.get_raw_cell(ConfigParam37::ID)? {
76            None => self.get_raw_cell(ConfigParam36::ID),
77            set => Ok(set),
78        }
79    }
80
81    fn get_raw_cell(&self, id: u32) -> Result<Option<Cell>, Error>;
82}
83
84impl BlockchainConfigExt for BlockchainConfig {
85    fn validate_params(&self) -> Result<()> {
86        let Some(config_address) = self.params.get::<ConfigParam0>()? else {
87            anyhow::bail!("config address is absent");
88        };
89        anyhow::ensure!(config_address == self.address, "config address mismatch");
90
91        let params = self.get_mandatory_params()?;
92        for id in params.keys() {
93            let id = id?;
94            if !self
95                .contains_raw(id)
96                .with_context(|| format!("failed to get config param {id}"))?
97            {
98                anyhow::bail!("mandatory config param {id} is absent");
99            }
100        }
101
102        Ok(())
103    }
104
105    fn get_raw_cell(&self, id: u32) -> Result<Option<Cell>, Error> {
106        let Some(value) = self.params.as_dict().get_raw(id)? else {
107            return Ok(None);
108        };
109        value.get_reference_cloned(0).map(Some)
110    }
111}