/* * Copyright (C) 2019-2024 EverX. All Rights Reserved. * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ use crate::{ define_HashmapE, error::BlockError, dictionary::hashmapaug::HashmapAugType, shard::ShardIdent, shard_accounts::ShardAccounts, signature::{CryptoSignature, SigPubKey}, types::{ChildCell, ExtraCurrencyCollection, Grams, Number8, Number12, Number16, Number13, Number32}, validators::{ValidatorDescr, ValidatorSet}, Serializable, Deserializable, BuilderData, Cell, error, fail, BlockIdExt, HashmapE, HashmapType, IBitstring, Result, SliceData, UInt256, HashmapIterator, }; #[cfg(test)] #[path = "tests/test_config_params.rs"] mod tests; /* 1.6.3. Quick access through the header of masterchain blocks _ config_addr:uint256 config:^(Hashmap 32 ^Cell) = ConfigParams; */ #[derive(Clone, Debug, Eq, PartialEq)] pub struct ConfigParams { pub config_addr: UInt256, pub config_params: HashmapE // <u32, SliceData> } impl Default for ConfigParams { fn default() -> ConfigParams { Self { config_addr: UInt256::default(), config_params: HashmapE::with_bit_len(32) } } } impl ConfigParams { /// create new instance ConfigParams pub fn new() -> Self { Self::default() } } impl ConfigParams { pub const fn with_root(data: Cell) -> Self { Self { config_addr: UInt256::ZERO, config_params: HashmapE::with_hashmap(32, Some(data)) } } pub const fn with_address_and_root(config_addr: UInt256, data: Cell) -> Self { Self { config_addr, config_params: HashmapE::with_hashmap(32, Some(data)) } } pub const fn with_address_and_params(config_addr: UInt256, data: Option<Cell>) -> Self { Self { config_addr, config_params: HashmapE::with_hashmap(32, data) } } /// get config by index pub fn config(&self, index: u32) -> Result<Option<ConfigParamEnum>> { let key = index.write_to_bitstring()?; if let Some(slice) = self.config_params.get(key)? { if let Some(cell) = slice.reference_opt(0) { return Ok(Some(ConfigParamEnum::construct_from_slice_and_number(&mut SliceData::load_cell(cell)?, index)?)); } } Ok(None) } /// get config by index pub fn config_present(&self, index: u32) -> Result<bool> { let key = index.write_to_bitstring()?; if let Some(slice) = self.config_params.get(key)? { if slice.remaining_references() != 0 { return Ok(true) } } Ok(false) } /// set config pub fn set_config(&mut self, config: ConfigParamEnum) -> Result<()> { let mut value = BuilderData::new(); let index = config.write_to_cell(&mut value)?; let key = index.write_to_bitstring()?; self.config_params.set_builder(key, &value)?; Ok(()) } pub fn get_smc_tick_tock(&self, smc_addr: &UInt256, accounts: &ShardAccounts) -> Result<usize> { let account = match accounts.get(smc_addr)? { Some(shard_account) => shard_account.read_account()?, None => fail!("Tick-tock smartcontract not found") }; Ok(account.get_tick_tock().map(|tick_tock| tick_tock.as_usize()).unwrap_or_default()) } pub fn special_ticktock_smartcontracts(&self, tick_tock: usize, accounts: &ShardAccounts) -> Result<Vec<(UInt256, usize)>> { let mut vec = Vec::new(); self.fundamental_smc_addr()?.iterate_keys(|key: UInt256| { let tt = self.get_smc_tick_tock(&key, accounts)?; if (tick_tock & tt) != 0 { vec.push((key, tt)) } Ok(true) })?; Ok(vec) } // // Wrappers // pub fn config_address(&self) -> Result<UInt256> { match self.config(0)? { Some(ConfigParamEnum::ConfigParam0(param)) => Ok(param.config_addr), _ => fail!("no config smc address in config") } } pub fn elector_address(&self) -> Result<UInt256> { match self.config(1)? { Some(ConfigParamEnum::ConfigParam1(param)) => Ok(param.elector_addr), _ => fail!("no elector address in config") } } pub fn minter_address(&self) -> Result<UInt256> { let addr = match self.config(2)? { Some(ConfigParamEnum::ConfigParam2(param)) => param.minter_addr, _ => match self.config(0)? { Some(ConfigParamEnum::ConfigParam0(param)) => param.config_addr, _ => fail!("no minter address in config") } }; Ok(addr) } pub fn fee_collector_address(&self) -> Result<UInt256> { let addr = match self.config(3)? { Some(ConfigParamEnum::ConfigParam3(param)) => param.fee_collector_addr, _ => match self.config(1)? { Some(ConfigParamEnum::ConfigParam1(param)) => param.elector_addr, _ => fail!("no fee collector address in config") } }; Ok(addr) } // TODO 4 dns_root_addr pub fn mint_prices(&self) -> Result<ConfigParam6> { match self.config(6)? { Some(ConfigParamEnum::ConfigParam6(cp)) => Ok(cp), _ => fail!("no config 6 (mint prices)") } } pub fn to_mint(&self) -> Result<ExtraCurrencyCollection> { match self.config(7)? { Some(ConfigParamEnum::ConfigParam7(cp)) => Ok(cp.to_mint), _ => fail!("no config 7 (to mint)") } } pub fn get_global_version(&self) -> Result<GlobalVersion> { match self.config(8)? { Some(ConfigParamEnum::ConfigParam8(gb)) => Ok(gb.global_version), _ => fail!("no global version in config") } } pub fn mandatory_params(&self) -> Result<MandatoryParams> { match self.config(9)? { Some(ConfigParamEnum::ConfigParam9(mp)) => Ok(mp.mandatory_params), _ => fail!("no mandatory params in config") } } // TODO 11 ConfigVotingSetup pub fn workchains(&self) -> Result<Workchains> { match self.config(12)? { Some(ConfigParamEnum::ConfigParam12(param)) => Ok(param.workchains), _ => fail!("Workchains not found in config") } } // TODO 13 compliant pricing pub fn block_create_fees(&self, masterchain: bool) -> Result<Grams> { match self.config(14)? { Some(ConfigParamEnum::ConfigParam14(param)) => if masterchain { Ok(param.block_create_fees.masterchain_block_fee) } else { Ok(param.block_create_fees.basechain_block_fee) } _ => fail!("no block create fee parameter") } } pub fn elector_params(&self) -> Result<ConfigParam15> { match self.config(15)? { Some(ConfigParamEnum::ConfigParam15(param)) => Ok(param), _ => fail!("no elector params in config") } } pub fn validators_count(&self) -> Result<ConfigParam16> { match self.config(16)? { Some(ConfigParamEnum::ConfigParam16(param)) => Ok(param), _ => fail!("no elector params in config") } } pub fn stakes_config(&self) -> Result<ConfigParam17> { match self.config(17)? { Some(ConfigParamEnum::ConfigParam17(param)) => Ok(param), _ => fail!("no stakes params in config") } } // TODO 16 validators count // TODO 17 stakes config pub fn storage_prices(&self) -> Result<ConfigParam18> { match self.config(18)? { Some(ConfigParamEnum::ConfigParam18(param)) => Ok(param), _ => fail!("Storage prices not found") } } pub fn gas_prices(&self, is_masterchain: bool) -> Result<GasLimitsPrices> { if is_masterchain { if let Some(ConfigParamEnum::ConfigParam20(param)) = self.config(20)? { return Ok(param) } } else if let Some(ConfigParamEnum::ConfigParam21(param)) = self.config(21)? { return Ok(param) } fail!("Gas prices not found") } pub fn block_limits(&self, masterchain: bool) -> Result<BlockLimits> { if masterchain { if let Some(ConfigParamEnum::ConfigParam22(param)) = self.config(22)? { return Ok(param) } } else if let Some(ConfigParamEnum::ConfigParam23(param)) = self.config(23)? { return Ok(param) } fail!("BlockLimits not found") } pub fn fwd_prices(&self, is_masterchain: bool) -> Result<MsgForwardPrices> { if is_masterchain { if let Some(ConfigParamEnum::ConfigParam24(param)) = self.config(24)? { return Ok(param) } } else if let Some(ConfigParamEnum::ConfigParam25(param)) = self.config(25)? { return Ok(param) } fail!("Forward prices not found") } pub fn catchain_config(&self) -> Result<CatchainConfig> { match self.config(28)? { Some(ConfigParamEnum::ConfigParam28(ccc)) => Ok(ccc), _ => fail!("no CatchainConfig in config_params") } } pub fn consensus_config(&self) -> Result<ConsensusConfig> { match self.config(29)? { Some(ConfigParamEnum::ConfigParam29(ConfigParam29{ consensus_config})) => Ok(consensus_config), _ => fail!("no ConsensusConfig in config_params") } } // TODO 29 consensus config pub fn fundamental_smc_addr(&self) -> Result<FundamentalSmcAddresses> { match self.config(31)? { Some(ConfigParamEnum::ConfigParam31(param)) => Ok(param.fundamental_smc_addr), _ => fail!("fundamental_smc_addr not found in config") } } pub fn delector_parameters(&self) -> Result<DelectorParams> { match self.config(30)? { Some(ConfigParamEnum::ConfigParam30(param)) => Ok(param), _ => fail!("delector parameters not found in config") } } pub fn prev_validator_set(&self) -> Result<ValidatorSet> { let vset = match self.config(33)? { Some(ConfigParamEnum::ConfigParam33(param)) => param.prev_temp_validators, _ => match self.config(32)? { Some(ConfigParamEnum::ConfigParam32(param)) => param.prev_validators, _ => ValidatorSet::default() } }; Ok(vset) } pub fn prev_validator_set_present(&self) -> Result<bool> { Ok(self.config_present(33)? || self.config_present(32)?) } pub fn validator_set(&self) -> Result<ValidatorSet> { let vset = match self.config(35)? { Some(ConfigParamEnum::ConfigParam35(param)) => param.cur_temp_validators, _ => match self.config(34)? { Some(ConfigParamEnum::ConfigParam34(param)) => param.cur_validators, _ => fail!("no validator set in config") } }; Ok(vset) } pub fn next_validator_set(&self) -> Result<ValidatorSet> { let vset = match self.config(37)? { Some(ConfigParamEnum::ConfigParam37(param)) => param.next_temp_validators, _ => match self.config(36)? { Some(ConfigParamEnum::ConfigParam36(param)) => param.next_validators, _ => ValidatorSet::default() } }; Ok(vset) } pub fn next_validator_set_present(&self) -> Result<bool> { Ok(self.config_present(37)? || self.config_present(36)?) } pub fn read_cur_validator_set_and_cc_conf(&self) -> Result<(ValidatorSet, CatchainConfig)> { Ok(( self.validator_set()?, self.catchain_config()? )) } pub fn copyleft_config(&self) -> Result<ConfigCopyleft> { match self.config(42)? { Some(ConfigParamEnum::ConfigParam42(cp)) => Ok(cp), _ => fail!("no config 42 (copyleft)") } } pub fn suspended_addresses(&self) -> Result<Option<SuspendedAddresses>> { match self.config(44)? { Some(ConfigParamEnum::ConfigParam44(sa)) => Ok(Some(sa)), None => Ok(None), _ => fail!("wrong config 44 (suspended addresses)") } } // TODO 39 validator signed temp keys // ConfigParam58(MeshConfig), pub fn mesh_config(&self) -> Result<Option<MeshConfig>> { match self.config(58)? { Some(ConfigParamEnum::ConfigParam58(mc)) => Ok(Some(mc)), None => Ok(None), _ => fail!("wrong config 58 (mesh config)") } } pub fn mesh_config_for(&self, nw_id: i32) -> Result<ConnectedNwConfig> { self.mesh_config()? .ok_or_else(|| error!("no mesh config"))? .get(&nw_id)? .ok_or_else(|| error!("no mesh config for {}", nw_id)) } pub fn fast_finality_config(&self) -> Result<FastFinalityConfig> { match self.config(61)? { Some(ConfigParamEnum::ConfigParam61(ff)) => Ok(ff), _ => fail!("no fast finality config") } } // ConfigParam62(SmftConfig) pub fn smft_parameters(&self) -> Result<SmftParams> { match self.config(62)? { Some(ConfigParamEnum::ConfigParam62(param)) => Ok(param), _ => fail!("smft parameters not found in config") } } } #[derive(Clone, Copy, Debug)] #[repr(u64)] pub enum GlobalCapabilities { CapNone = 0, CapIhrEnabled = 0x0000_0000_0001, CapCreateStatsEnabled = 0x0000_0000_0002, CapBounceMsgBody = 0x0000_0000_0004, CapReportVersion = 0x0000_0000_0008, CapSplitMergeTransactions = 0x0000_0000_0010, CapShortDequeue = 0x0000_0000_0020, CapMbppEnabled = 0x0000_0000_0040, CapFastStorageStat = 0x0000_0000_0080, CapInitCodeHash = 0x0000_0000_0100, CapOffHypercube = 0x0000_0000_0200, CapMycode = 0x0000_0000_0400, CapSetLibCode = 0x0000_0000_0800, CapFixTupleIndexBug = 0x0000_0000_1000, CapRemp = 0x0000_0000_2000, CapDelections = 0x0000_0000_4000, CapFullBodyInBounced = 0x0000_0001_0000, CapStorageFeeToTvm = 0x0000_0002_0000, CapCopyleft = 0x0000_0004_0000, CapIndexAccounts = 0x0000_0008_0000, #[cfg(feature = "gosh")] CapDiff = 0x0000_0010_0000, CapsTvmBugfixes2022 = 0x0000_0020_0000, // popsave, exception handler, loops CapWorkchains = 0x0000_0040_0000, CapStcontNewFormat = 0x0000_0080_0000, // support old format continuation serialization CapFastStorageStatBugfix = 0x0000_0100_0000, // calc cell datasize using fast storage stat CapResolveMerkleCell = 0x0000_0200_0000, #[cfg(feature = "signature_with_id")] CapSignatureWithId = 0x0000_0400_0000, // use some predefined id during signature check CapBounceAfterFailedAction= 0x0000_0800_0000, #[cfg(feature = "groth")] CapGroth16 = 0x0000_1000_0000, CapFeeInGasUnits = 0x0000_2000_0000, // all fees in config are in gas units CapBigCells = 0x0000_4000_0000, CapSuspendedList = 0x0000_8000_0000, CapFastFinality = 0x0001_0000_0000, CapTvmV19 = 0x0002_0000_0000, // TVM v1.9.x improvemements CapSmft = 0x0004_0000_0000, CapNoSplitOutQueue = 0x0008_0000_0000, // Don't split out queue on shard splitting CapUndeletableAccounts = 0x0010_0000_0000, // Don't delete frozen accounts CapTvmV20 = 0x0020_0000_0000, // BLS instructions CapDuePaymentFix = 0x0040_0000_0000, // No due payments on credit phase and add payed dues to storage fee in TVM CapCommonMessage = 0x0080_0000_0000, CapPipeline = 0x0100_0000_0000, } impl ConfigParams { pub fn get_lt_align(&self) -> u64 { 1_000_000 } pub fn get_max_lt_growth_fast_finality(&self) -> u64 { 100 * self.get_lt_align() - 1 } pub fn get_max_lt_growth(&self) -> u64 { 10 * self.get_lt_align() - 1 } pub fn get_next_block_lt(&self, prev_block_lt: u64) -> u64 { (prev_block_lt / self.get_lt_align() + 1) * self.get_lt_align() } pub fn has_capabilities(&self) -> bool { self.get_global_version().map_or(false, |gb| gb.capabilities != 0) } pub fn has_capability(&self, capability: GlobalCapabilities) -> bool { self.get_global_version().map_or(false, |gb| gb.has_capability(capability)) } pub fn capabilities(&self) -> u64 { self.get_global_version().map_or(0, |gb| gb.capabilities) } pub fn global_version(&self) -> u32 { self.get_global_version().map_or(0, |gb| gb.version) } } impl ConfigParams { pub fn compute_validator_set_cc(&self, shard: &ShardIdent, at: u32, cc_seqno: u32, cc_seqno_delta: &mut u32) -> Result<Vec<ValidatorDescr>> { let (vset, ccc) = self.read_cur_validator_set_and_cc_conf()?; if (*cc_seqno_delta & 0xfffffffe) != 0 { fail!("seqno_delta>1 is not implemented yet"); } *cc_seqno_delta += cc_seqno; vset.calc_subset(&ccc, shard.shard_prefix_with_tag(), shard.workchain_id(), *cc_seqno_delta, at.into()) .map(|(set, _hash)| { set }) } pub fn compute_validator_set(&self, shard: &ShardIdent, _at: u32, cc_seqno: u32) -> Result<Vec<ValidatorDescr>> { let (vset, ccc) = self.read_cur_validator_set_and_cc_conf()?; vset.calc_subset(&ccc, shard.shard_prefix_with_tag(), shard.workchain_id(), cc_seqno, _at.into()) .map(|(set, _seq_no)| set) } } const MANDATORY_CONFIG_PARAMS: [u32; 9] = [18, 20, 21, 22, 23, 24, 25, 28, 34]; impl ConfigParams { pub fn valid_config_data(&self, relax_par0: bool, mparams: Option<MandatoryParams>) -> Result<bool> { if !relax_par0 { match self.config(0) { Ok(Some(ConfigParamEnum::ConfigParam0(param))) if param.config_addr == self.config_addr => (), _ => return Ok(false) } } // porting from Durov's code // previously was not 9 parameter in config params for index in &MANDATORY_CONFIG_PARAMS { if self.config(*index)?.is_none() { log::error!(target: "block", "configuration parameter #{} \ (hardcoded as mandatory) is missing)", index); return Ok(false) } } let result = match self.config(9) { Ok(Some(ConfigParamEnum::ConfigParam9(param))) => self.config_params_present(Some(param.mandatory_params))?, _ => { log::error!(target: "block", "invalid mandatory parameters dictionary while checking \ existence of all mandatory configuration parameters"); false } }; Ok(result && self.config_params_present(mparams)?) } fn config_params_present(&self, params: Option<MandatoryParams>) -> Result<bool> { match params { Some(params) => params.iterate_keys(|index: u32| match self.config(index) { Ok(Some(_)) => Ok(true), _ => { log::error!(target: "block", "configuration parameter #{} \ (declared as mandatory in configuration parameter #9) is missing)", index); Ok(false) } }), None => Ok(true) } } // when these parameters change, the block must be marked as a key block pub fn important_config_parameters_changed(&self, other: &ConfigParams, coarse: bool) -> Result<bool> { if self.config_params == other.config_params { return Ok(false) } if coarse { return Ok(true) } // for now, all parameters are "important" // at least the parameters affecting the computations of validator sets must be considered important // ... Ok(true) } } impl Deserializable for ConfigParams { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.config_addr.read_from(cell)?; *self.config_params.data_mut() = Some(cell.checked_drain_reference()?); Ok(()) } } impl Serializable for ConfigParams { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.checked_append_reference(self.config_params.data().cloned().unwrap_or_default())?; self.config_addr.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Eq, PartialEq)] pub enum ConfigParamEnum { ConfigParam0(ConfigParam0), ConfigParam1(ConfigParam1), ConfigParam2(ConfigParam2), ConfigParam3(ConfigParam3), ConfigParam4(ConfigParam4), ConfigParam5(ConfigParam5), ConfigParam6(ConfigParam6), ConfigParam7(ConfigParam7), ConfigParam8(ConfigParam8), ConfigParam9(ConfigParam9), ConfigParam10(ConfigParam10), ConfigParam11(ConfigParam11), ConfigParam12(ConfigParam12), ConfigParam13(ConfigParam13), ConfigParam14(ConfigParam14), ConfigParam15(ConfigParam15), ConfigParam16(ConfigParam16), ConfigParam17(ConfigParam17), ConfigParam18(ConfigParam18), ConfigParam20(GasLimitsPrices), ConfigParam21(GasLimitsPrices), ConfigParam22(ConfigParam22), ConfigParam23(ConfigParam23), ConfigParam24(MsgForwardPrices), ConfigParam25(MsgForwardPrices), ConfigParam28(CatchainConfig), ConfigParam29(ConfigParam29), ConfigParam30(DelectorParams), ConfigParam31(ConfigParam31), ConfigParam32(ConfigParam32), ConfigParam33(ConfigParam33), ConfigParam34(ConfigParam34), ConfigParam35(ConfigParam35), ConfigParam36(ConfigParam36), ConfigParam37(ConfigParam37), ConfigParam39(ConfigParam39), ConfigParam40(ConfigParam40), ConfigParam42(ConfigCopyleft), ConfigParam44(SuspendedAddresses), ConfigParam58(MeshConfig), ConfigParam61(FastFinalityConfig), ConfigParam62(SmftParams), ConfigParamAny(u32, SliceData), } macro_rules! read_config { ( $cpname:ident, $cname:ident, $slice:expr ) => { { let c = $cname::construct_from($slice)?; Ok(ConfigParamEnum::$cpname(c)) } } } impl ConfigParamEnum { pub fn construct_from_cell_and_number(cell: Cell, index: u32) -> Result<ConfigParamEnum> { Self::construct_from_slice_and_number(&mut SliceData::load_cell(cell)?, index) } /// read config from cell pub fn construct_from_slice_and_number(slice: &mut SliceData, index: u32) -> Result<ConfigParamEnum> { match index { 0 => { read_config!(ConfigParam0, ConfigParam0, slice) }, 1 => { read_config!(ConfigParam1, ConfigParam1, slice) }, 2 => { read_config!(ConfigParam2, ConfigParam2, slice) }, 3 => { read_config!(ConfigParam3, ConfigParam3, slice) }, 4 => { read_config!(ConfigParam4, ConfigParam4, slice) }, 5 => { read_config!(ConfigParam5, ConfigParam5, slice) }, 6 => { read_config!(ConfigParam6, ConfigParam6, slice) }, 7 => { read_config!(ConfigParam7, ConfigParam7, slice) }, 8 => { read_config!(ConfigParam8, ConfigParam8, slice) }, 9 => { read_config!(ConfigParam9, ConfigParam9, slice) }, 10 => { read_config!(ConfigParam10, ConfigParam10, slice) }, 11 => { read_config!(ConfigParam11, ConfigParam11, slice) }, 12 => { read_config!(ConfigParam12, ConfigParam12, slice) }, 13 => { read_config!(ConfigParam13, ConfigParam13, slice) }, 14 => { read_config!(ConfigParam14, ConfigParam14, slice) }, 15 => { read_config!(ConfigParam15, ConfigParam15, slice) }, 16 => { read_config!(ConfigParam16, ConfigParam16, slice) }, 17 => { read_config!(ConfigParam17, ConfigParam17, slice) }, 18 => { read_config!(ConfigParam18, ConfigParam18, slice) }, 20 => { read_config!(ConfigParam20, GasLimitsPrices, slice) }, 21 => { read_config!(ConfigParam21, GasLimitsPrices, slice) }, 22 => { read_config!(ConfigParam22, ConfigParam22, slice) }, 23 => { read_config!(ConfigParam23, ConfigParam23, slice) }, 24 => { read_config!(ConfigParam24, MsgForwardPrices, slice) }, 25 => { read_config!(ConfigParam25, MsgForwardPrices, slice) }, 28 => { read_config!(ConfigParam28, CatchainConfig, slice) }, 29 => { read_config!(ConfigParam29, ConfigParam29, slice) }, 30 => { read_config!(ConfigParam30, DelectorParams, slice) }, 31 => { read_config!(ConfigParam31, ConfigParam31, slice) }, 32 => { read_config!(ConfigParam32, ConfigParam32, slice) }, 33 => { read_config!(ConfigParam33, ConfigParam33, slice) }, 34 => { read_config!(ConfigParam34, ConfigParam34, slice) }, 35 => { read_config!(ConfigParam35, ConfigParam35, slice) }, 36 => { read_config!(ConfigParam36, ConfigParam36, slice) }, 37 => { read_config!(ConfigParam37, ConfigParam37, slice) }, 39 => { read_config!(ConfigParam39, ConfigParam39, slice) }, 40 => { read_config!(ConfigParam40, ConfigParam40, slice) }, 42 => { read_config!(ConfigParam42, ConfigCopyleft, slice) }, 44 => { read_config!(ConfigParam44, SuspendedAddresses, slice) }, 58 => { read_config!(ConfigParam58, MeshConfig, slice) }, 61 => { read_config!(ConfigParam61, FastFinalityConfig, slice) }, 62 => { read_config!(ConfigParam62, SmftParams, slice) }, index => Ok(ConfigParamEnum::ConfigParamAny(index, slice.clone())), } } /// Save config to cell pub fn write_to_cell(&self, cell: &mut BuilderData) -> Result<u32> { match self { ConfigParamEnum::ConfigParam0(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(0)}, ConfigParamEnum::ConfigParam1(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(1)}, ConfigParamEnum::ConfigParam2(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(2)}, ConfigParamEnum::ConfigParam3(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(3)}, ConfigParamEnum::ConfigParam4(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(4)}, ConfigParamEnum::ConfigParam5(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(5)}, ConfigParamEnum::ConfigParam6(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(6)}, ConfigParamEnum::ConfigParam7(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(7)}, ConfigParamEnum::ConfigParam8(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(8)}, ConfigParamEnum::ConfigParam9(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(9)}, ConfigParamEnum::ConfigParam10(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(10)}, ConfigParamEnum::ConfigParam11(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(11)}, ConfigParamEnum::ConfigParam12(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(12)}, ConfigParamEnum::ConfigParam13(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(13)}, ConfigParamEnum::ConfigParam14(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(14)}, ConfigParamEnum::ConfigParam15(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(15)}, ConfigParamEnum::ConfigParam16(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(16)}, ConfigParamEnum::ConfigParam17(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(17)}, ConfigParamEnum::ConfigParam18(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(18)}, ConfigParamEnum::ConfigParam20(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(20)}, ConfigParamEnum::ConfigParam21(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(21)}, ConfigParamEnum::ConfigParam22(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(22)}, ConfigParamEnum::ConfigParam23(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(23)}, ConfigParamEnum::ConfigParam24(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(24)}, ConfigParamEnum::ConfigParam25(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(25)}, ConfigParamEnum::ConfigParam28(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(28)}, ConfigParamEnum::ConfigParam29(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(29)}, ConfigParamEnum::ConfigParam30(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(30)}, ConfigParamEnum::ConfigParam31(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(31)}, ConfigParamEnum::ConfigParam32(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(32)}, ConfigParamEnum::ConfigParam33(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(33)}, ConfigParamEnum::ConfigParam34(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(34)}, ConfigParamEnum::ConfigParam35(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(35)}, ConfigParamEnum::ConfigParam36(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(36)}, ConfigParamEnum::ConfigParam37(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(37)}, ConfigParamEnum::ConfigParam39(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(39)}, ConfigParamEnum::ConfigParam40(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(40)}, ConfigParamEnum::ConfigParam42(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(42)}, ConfigParamEnum::ConfigParam44(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(44)}, ConfigParamEnum::ConfigParam58(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(58)}, ConfigParamEnum::ConfigParam61(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(61)}, ConfigParamEnum::ConfigParam62(ref c) => { cell.checked_append_reference(c.serialize()?)?; Ok(62)}, ConfigParamEnum::ConfigParamAny(index, slice) => { cell.checked_append_reference(slice.clone().into_cell())?; Ok(*index) }, } } } /* _ config_addr:bits256 = ConfigParam 0; */ /// /// Config Param 0 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam0 { pub config_addr: UInt256, } impl ConfigParam0 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam0 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.config_addr.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam0 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.config_addr.write_to(cell)?; Ok(()) } } /* _ elector_addr:bits256 = ConfigParam 1; */ /// /// Config Param 1 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam1 { pub elector_addr: UInt256, } impl ConfigParam1 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam1 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.elector_addr.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam1 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.elector_addr.write_to(cell)?; Ok(()) } } /// /// Config Param 2 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam2 { pub minter_addr: UInt256, } impl ConfigParam2 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam2 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.minter_addr.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam2 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.minter_addr.write_to(cell)?; Ok(()) } } /// /// Config Param 3 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam3 { pub fee_collector_addr: UInt256, } impl ConfigParam3 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam3 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.fee_collector_addr.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam3 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.fee_collector_addr.write_to(cell)?; Ok(()) } } /// /// Config Param 4 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam4 { pub dns_root_addr: UInt256, } impl ConfigParam4 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam4 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.dns_root_addr.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam4 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.dns_root_addr.write_to(cell)?; Ok(()) } } /// /// Config Param 5 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam5 { pub owner_addr: UInt256, } impl Deserializable for ConfigParam5 { fn construct_from(slice: &mut SliceData) -> Result<Self> { let owner_addr = Deserializable::construct_from(slice)?; Ok(ConfigParam5 { owner_addr }) } } impl Serializable for ConfigParam5 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.owner_addr.write_to(cell)?; Ok(()) } } /// /// Config Param 6 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam6 { pub mint_new_price: Grams, pub mint_add_price: Grams, } impl ConfigParam6 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam6 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.mint_new_price.read_from(cell)?; self.mint_add_price.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam6 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.mint_new_price.write_to(cell)?; self.mint_add_price.write_to(cell)?; Ok(()) } } /// /// Config Param 7 structure /// #[derive(Clone, Default, Debug, Eq, PartialEq)] pub struct ConfigParam7 { pub to_mint: ExtraCurrencyCollection, } impl ConfigParam7 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam7 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.to_mint.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam7 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.to_mint.write_to(cell)?; Ok(()) } } /// /// Config Param 8 structure /// // capabilities#c4 version:uint32 capabilities:uint64 = GlobalVersion; // _ GlobalVersion = ConfigParam 8; // all zero if absent #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct GlobalVersion { pub version: u32, pub capabilities: u64, } impl GlobalVersion { pub fn new() -> Self { Self::default() } pub fn has_capability(&self, capability: GlobalCapabilities) -> bool { (self.capabilities & (capability as u64)) != 0 } } const GLOBAL_VERSION_TAG: u8 = 0xC4; impl Deserializable for GlobalVersion { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if tag != GLOBAL_VERSION_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.version.read_from(cell)?; self.capabilities.read_from(cell)?; Ok(()) } } impl Serializable for GlobalVersion { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(GLOBAL_VERSION_TAG)?; self.version.write_to(cell)?; self.capabilities.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam8 { pub global_version: GlobalVersion } impl ConfigParam8 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam8 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.global_version.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam8 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.global_version.write_to(cell)?; Ok(()) } } // _ mandatory_params:(Hashmap 32 True) = ConfigParam 9; define_HashmapE!{MandatoryParams, 32, ()} /// /// Config Param 9 structure /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam9 { pub mandatory_params: MandatoryParams, } impl ConfigParam9 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam9 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.mandatory_params.read_hashmap_root(cell)?; Ok(()) } } impl Serializable for ConfigParam9 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.mandatory_params.write_hashmap_root(cell)?; Ok(()) } } /// /// Config Param 10 structure /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam10 { pub critical_params: MandatoryParams, } impl ConfigParam10 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam10 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.critical_params.read_hashmap_root(cell)?; Ok(()) } } impl Serializable for ConfigParam10 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.critical_params.write_hashmap_root(cell)?; Ok(()) } } /// /// Config Param 14 structure /// // block_grams_created#6b masterchain_block_fee:Grams basechain_block_fee:Grams // = BlockCreateFees; // _ BlockCreateFees = ConfigParam 14; #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct BlockCreateFees { pub masterchain_block_fee: Grams, pub basechain_block_fee: Grams, } impl BlockCreateFees { pub fn new() -> Self { Self::default() } } const BLOCK_CREATE_FEES: u8 = 0x6b; impl Deserializable for BlockCreateFees { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if tag != BLOCK_CREATE_FEES { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.masterchain_block_fee.read_from(cell)?; self.basechain_block_fee.read_from(cell)?; Ok(()) } } impl Serializable for BlockCreateFees { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(BLOCK_CREATE_FEES)?; self.masterchain_block_fee.write_to(cell)?; self.basechain_block_fee.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam14 { pub block_create_fees: BlockCreateFees } impl ConfigParam14 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam14 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.block_create_fees.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam14 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.block_create_fees.write_to(cell)?; Ok(()) } } /// /// Config Param 15 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam15 { pub validators_elected_for: u32, pub elections_start_before: u32, pub elections_end_before: u32, pub stake_held_for: u32, } impl ConfigParam15 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam15 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.validators_elected_for.read_from(cell)?; self.elections_start_before.read_from(cell)?; self.elections_end_before.read_from(cell)?; self.stake_held_for.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam15 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.validators_elected_for.write_to(cell)?; self.elections_start_before.write_to(cell)?; self.elections_end_before.write_to(cell)?; self.stake_held_for.write_to(cell)?; Ok(()) } } /* _ max_validators:(## 16) max_main_validators:(## 16) min_validators:(## 16) { max_validators >= max_main_validators } { max_main_validators >= min_validators } { min_validators >= 1 } = ConfigParam 16; */ /// /// Config Param 16 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam16 { pub max_validators: Number16, pub max_main_validators: Number16, pub min_validators: Number16, } impl ConfigParam16 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam16 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.max_validators.read_from(cell)?; self.max_main_validators.read_from(cell)?; self.min_validators.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam16 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.max_validators.write_to(cell)?; self.max_main_validators.write_to(cell)?; self.min_validators.write_to(cell)?; Ok(()) } } /* _ min_stake: Grams max_stake: Grams min_total_stake: Grams max_stake_factor: uint32 = ConfigParam 17; */ /// /// Config Param 17 structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam17 { pub min_stake: Grams, pub max_stake: Grams, pub min_total_stake: Grams, pub max_stake_factor: u32, } impl ConfigParam17 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam17 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.min_stake.read_from(cell)?; self.max_stake.read_from(cell)?; self.min_total_stake.read_from(cell)?; self.max_stake_factor.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam17 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.min_stake.write_to(cell)?; self.max_stake.write_to(cell)?; self.min_total_stake.write_to(cell)?; self.max_stake_factor.write_to(cell)?; Ok(()) } } /* _#cc utime_since:uint32 bit_price_ps:uint64 cell_price_ps:uint64 mc_bit_price_ps:uint64 mc_cell_price_ps:uint64 = StoragePrices; _ (Hashmap 32 StoragePrices) = ConfigParam 18; */ /// /// StoragePrices structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct StoragePrices { pub utime_since: u32, pub bit_price_ps: u64, pub cell_price_ps: u64, pub mc_bit_price_ps: u64, pub mc_cell_price_ps: u64, } impl StoragePrices { pub fn new() -> Self { Self::default() } } const STORAGE_PRICES_TAG: u8 = 0xCC; impl Deserializable for StoragePrices { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if tag != STORAGE_PRICES_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.utime_since.read_from(cell)?; self.bit_price_ps.read_from(cell)?; self.cell_price_ps.read_from(cell)?; self.mc_bit_price_ps.read_from(cell)?; self.mc_cell_price_ps.read_from(cell)?; Ok(()) } } impl Serializable for StoragePrices { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(STORAGE_PRICES_TAG)?; self.utime_since.write_to(cell)?; self.bit_price_ps.write_to(cell)?; self.cell_price_ps.write_to(cell)?; self.mc_bit_price_ps.write_to(cell)?; self.mc_cell_price_ps.write_to(cell)?; Ok(()) } } define_HashmapE!(ConfigParam18Map, 32, StoragePrices); /// /// ConfigParam 18 struct /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam18 { pub map: ConfigParam18Map, } impl ConfigParam18 { /// get length pub fn len(&self) -> Result<usize> { self.map.len() } /// determine is empty pub fn is_empty(&self) -> bool { self.map.is_empty() } /// get value by index pub fn get(&self, index: u32) -> Result<StoragePrices> { self.map.get(&index)?.ok_or_else(|| error!(BlockError::InvalidIndex(index as usize))) } /// get all value as vector pub fn prices(&self) -> Result<Vec<StoragePrices>> { self.map.export_vector() } /// insert value pub fn insert(&mut self, sp: &StoragePrices) -> Result<()> { let index = match self.map.0.get_max(false, &mut 0)? { Some((key, _value)) => u32::construct_from_bitstring(key)? + 1, None => 0 }; self.map.set(&index, sp) } } impl Deserializable for ConfigParam18 { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { self.map.read_hashmap_root(slice)?; Ok(()) } } impl Serializable for ConfigParam18 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { if self.map.is_empty() { fail!(BlockError::InvalidOperation("self.map is empty".to_string())) } self.map.write_hashmap_root(cell)?; Ok(()) } } /* gas_prices#dd gas_price:uint64 gas_limit:uint64 gas_credit:uint64 block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64 = GasLimitsPrices; gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas_credit:uint64 block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64 = GasLimitsPrices; gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices = GasLimitsPrices; */ /// /// GasLimitsPrices /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct GasLimitsPrices { pub gas_price: u64, pub gas_limit: u64, pub special_gas_limit: u64, pub gas_credit: u64, pub block_gas_limit: u64, pub freeze_due_limit: u64, pub delete_due_limit: u64, pub flat_gas_limit: u64, pub flat_gas_price: u64, pub max_gas_threshold: u128, } impl GasLimitsPrices { pub fn new() -> Self { Self::default() } /// Calculate gas fee by gas used value pub fn calc_gas_fee(&self, gas_used: u64) -> u128 { // There is a flat_gas_limit value which is the minimum gas value possible and has fixed price. // If actual gas value is less then flat_gas_limit then flat_gas_price paid. // If actual gas value is bigger then flat_gas_limit then flat_gas_price paid for first // flat_gas_limit gas and remaining value costs gas_price if gas_used <= self.flat_gas_limit { self.flat_gas_price as u128 } else { // gas_price is pseudo value (shifted by 16 as forward and storage price) // after calculation divide by 0xffff with ceil rounding self.flat_gas_price as u128 + (((gas_used - self.flat_gas_limit) as u128 * self.gas_price as u128 + 0xffff) >> 16) } } /// Get gas price in nanograms pub fn get_real_gas_price(&self) -> u64 { self.gas_price >> 16 } /// Calculate gas by grams balance pub fn calc_gas(&self, value: u128) -> u64 { if value >= self.max_gas_threshold { return self.gas_limit } if value < self.flat_gas_price as u128 { return 0 } let res = ((value - self.flat_gas_price as u128) << 16) / (self.gas_price as u128); self.flat_gas_limit + res as u64 } /// Calculate max gas threshold pub fn calc_max_gas_threshold(&self) -> u128 { let mut result = self.flat_gas_price as u128; if self.gas_limit > self.flat_gas_limit { result += ((self.gas_price as u128) * ((self.gas_limit - self.flat_gas_limit) as u128)) >> 16; } result } } const GAS_PRICES_TAG: u8 = 0xDD; const GAS_PRICES_EXT_TAG: u8 = 0xDE; const GAS_FLAT_PFX_TAG: u8 = 0xD1; impl Deserializable for GasLimitsPrices { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.flat_gas_limit = 0; self.flat_gas_price = 0; self.special_gas_limit = 0; loop { match cell.get_next_byte()? { GAS_PRICES_TAG => { self.gas_price.read_from(cell)?; self.gas_limit.read_from(cell)?; self.gas_credit.read_from(cell)?; self.block_gas_limit.read_from(cell)?; self.freeze_due_limit.read_from(cell)?; self.delete_due_limit.read_from(cell)?; break; } GAS_PRICES_EXT_TAG => { self.gas_price.read_from(cell)?; self.gas_limit.read_from(cell)?; self.special_gas_limit.read_from(cell)?; self.gas_credit.read_from(cell)?; self.block_gas_limit.read_from(cell)?; self.freeze_due_limit.read_from(cell)?; self.delete_due_limit.read_from(cell)?; break; } GAS_FLAT_PFX_TAG => { self.flat_gas_limit.read_from(cell)?; self.flat_gas_price.read_from(cell)?; } tag => { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } } } self.max_gas_threshold = self.calc_max_gas_threshold(); Ok(()) } } impl Serializable for GasLimitsPrices { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(GAS_FLAT_PFX_TAG)?; self.flat_gas_limit.write_to(cell)?; self.flat_gas_price.write_to(cell)?; cell.append_u8(GAS_PRICES_EXT_TAG)?; self.gas_price.write_to(cell)?; self.gas_limit.write_to(cell)?; self.special_gas_limit.write_to(cell)?; self.gas_credit.write_to(cell)?; self.block_gas_limit.write_to(cell)?; self.freeze_due_limit.write_to(cell)?; self.delete_due_limit.write_to(cell)?; Ok(()) } } /* config_mc_gas_prices#_ GasLimitsPrices = ConfigParam 20; */ /* config_gas_prices#_ GasLimitsPrices = ConfigParam 21; */ /* // msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms // ihr_fwd_fees = ceil((msg_fwd_fees * ihr_price_factor)/2^16) nanograms // bits in the root cell of a message are not included in msg.bits (lump_price pays for them) msg_forward_prices#ea lump_price:uint64 bit_price:uint64 cell_price:uint64 ihr_price_factor:uint32 first_frac:uint16 next_frac:uint16 = MsgForwardPrices; */ /// /// MsgForwardPrices /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct MsgForwardPrices { pub lump_price: u64, pub bit_price: u64, pub cell_price: u64, pub ihr_price_factor: u32, pub first_frac: u16, pub next_frac: u16, } impl MsgForwardPrices { pub fn new() -> Self { Self::default() } } const MSG_FWD_PRICES_TAG: u8 = 0xEA; impl Deserializable for MsgForwardPrices { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if tag != MSG_FWD_PRICES_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.lump_price.read_from(cell)?; self.bit_price.read_from(cell)?; self.cell_price.read_from(cell)?; self.ihr_price_factor.read_from(cell)?; self.first_frac.read_from(cell)?; self.next_frac.read_from(cell)?; Ok(()) } } impl Serializable for MsgForwardPrices { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(MSG_FWD_PRICES_TAG)?; self.lump_price.write_to(cell)?; self.bit_price.write_to(cell)?; self.cell_price.write_to(cell)?; self.ihr_price_factor.write_to(cell)?; self.first_frac.write_to(cell)?; self.next_frac.write_to(cell)?; Ok(()) } } /* // used for messages to/from masterchain config_mc_fwd_prices#_ MsgForwardPrices = ConfigParam 24; // used for all other messages config_fwd_prices#_ MsgForwardPrices = ConfigParam 25; */ /* catchain_config#c1 mc_catchain_lifetime:uint32 shard_catchain_lifetime:uint32 shard_validators_lifetime:uint32 shard_validators_num:uint32 = CatchainConfig; catchain_config_new#c2 flags: (## 7) { flags = 0 } shuffle_mc_validators: Bool mc_catchain_lifetime: uint3 shard_catchain_lifetime: uint32 shard_validators_lifetime: uint32 shard_validators_num: uint32 = CatchainConfig; */ /// /// MsgForwardPrices /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct CatchainConfig { pub isolate_mc_validators: bool, pub shuffle_mc_validators: bool, pub mc_catchain_lifetime: u32, pub shard_catchain_lifetime: u32, pub shard_validators_lifetime: u32, pub shard_validators_num: u32, } impl CatchainConfig { pub fn new() -> Self { Self::default() } } const CATCHAIN_CONFIG_TAG_1: u8 = 0xC1; const CATCHAIN_CONFIG_TAG_2: u8 = 0xC2; impl Deserializable for CatchainConfig { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if (tag != CATCHAIN_CONFIG_TAG_1) && (tag != CATCHAIN_CONFIG_TAG_2) { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } if tag == CATCHAIN_CONFIG_TAG_2 { let flags = u8::construct_from(cell)?; self.isolate_mc_validators = flags & 0b10 != 0; self.shuffle_mc_validators = flags & 0b01 != 0; if flags >> 2 != 0 { fail!(BlockError::InvalidArg("`flags` should be zero".to_string())) } } self.mc_catchain_lifetime.read_from(cell)?; self.shard_catchain_lifetime.read_from(cell)?; self.shard_validators_lifetime.read_from(cell)?; self.shard_validators_num.read_from(cell)?; Ok(()) } } impl Serializable for CatchainConfig { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(CATCHAIN_CONFIG_TAG_2)?; cell.append_bits(0, 6)?; cell.append_bit_bool(self.isolate_mc_validators)?; cell.append_bit_bool(self.shuffle_mc_validators)?; self.mc_catchain_lifetime.write_to(cell)?; self.shard_catchain_lifetime.write_to(cell)?; self.shard_validators_lifetime.write_to(cell)?; self.shard_validators_num.write_to(cell)?; Ok(()) } } /* _ CatchainConfig = ConfigParam 28; */ /* _ fundamental_smc_addr:(HashmapE 256 True) = ConfigParam 31; consensus_config#d6 round_candidates:# { round_candidates >= 1 } next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32 fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32 max_block_bytes:uint32 max_collated_bytes:uint32 = ConsensusConfig; consensus_config_new#d7 flags: (## 7) { flags = 0 } new_catchain_ids: Bool round_candidates: (## 8) { round_candidates >= 1 } next_candidate_delay_ms: uint32 consensus_timeout_ms: uint32 fast_attempts: uint32 attempt_duration: uint32 catchain_max_deps: uint32 max_block_bytes: uint32 max_collated_bytes: uint32 = ConsensusConfig; */ #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConsensusConfig { pub new_catchain_ids: bool, pub round_candidates: u32, pub next_candidate_delay_ms: u32, pub consensus_timeout_ms: u32, pub fast_attempts: u32, pub attempt_duration: u32, pub catchain_max_deps: u32, pub max_block_bytes: u32, pub max_collated_bytes: u32, } impl ConsensusConfig { pub fn new() -> Self { Self::default() } } const CONSENSUS_CONFIG_TAG_1: u8 = 0xD6; const CONSENSUS_CONFIG_TAG_2: u8 = 0xD7; impl Deserializable for ConsensusConfig { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if (tag != CONSENSUS_CONFIG_TAG_1) && (tag != CONSENSUS_CONFIG_TAG_2) { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } if tag == CONSENSUS_CONFIG_TAG_1 { self.round_candidates.read_from(cell)?; } else { let flags = u8::construct_from(cell)?; self.new_catchain_ids = flags == 1; if flags >> 1 != 0 { fail!(BlockError::InvalidArg("`flags` should be zero".to_string())) } self.round_candidates = u8::construct_from(cell)? as u32; if self.round_candidates == 0 { fail!(BlockError::InvalidArg("`round_candidates` should be positive".to_string())) } } self.next_candidate_delay_ms.read_from(cell)?; self.consensus_timeout_ms.read_from(cell)?; self.fast_attempts.read_from(cell)?; self.attempt_duration.read_from(cell)?; self.catchain_max_deps.read_from(cell)?; self.max_block_bytes.read_from(cell)?; self.max_collated_bytes.read_from(cell)?; Ok(()) } } impl Serializable for ConsensusConfig { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { if self.round_candidates == 0 { fail!(BlockError::InvalidArg("`round_candidates` should be positive".to_string())) } cell.append_u8(CONSENSUS_CONFIG_TAG_2)?; cell.append_u8(self.new_catchain_ids as u8)?; (self.round_candidates as u8).write_to(cell)?; self.next_candidate_delay_ms.write_to(cell)?; self.consensus_timeout_ms.write_to(cell)?; self.fast_attempts.write_to(cell)?; self.attempt_duration.write_to(cell)?; self.catchain_max_deps.write_to(cell)?; self.max_block_bytes.write_to(cell)?; self.max_collated_bytes.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam29 { pub consensus_config: ConsensusConfig, } impl ConfigParam29 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam29 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.consensus_config.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam29 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.consensus_config.write_to(cell)?; Ok(()) } } /* _ fundamental_smc_addr:(HashmapE 256 True) = ConfigParam 31; */ define_HashmapE!{FundamentalSmcAddresses, 256, ()} impl IntoIterator for &FundamentalSmcAddresses { type Item = <HashmapIterator<HashmapE> as std::iter::Iterator>::Item; type IntoIter = HashmapIterator<HashmapE>; fn into_iter(self) -> Self::IntoIter { self.0.iter() } } /// /// ConfigParam 30; /// const DELECTOR_PARAMS_TAG: u8 = 0x1; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct DelectorParams { pub delections_step: u32, pub validator_init_code_hash: UInt256, pub staker_init_code_hash: UInt256, } impl Deserializable for DelectorParams { fn construct_from(slice: &mut SliceData) -> Result<Self> { let tag = slice.get_next_byte()?; if tag != DELECTOR_PARAMS_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } let delections_step = Deserializable::construct_from(slice)?; let validator_init_code_hash = Deserializable::construct_from(slice)?; let staker_init_code_hash = Deserializable::construct_from(slice)?; Ok(Self { delections_step, validator_init_code_hash, staker_init_code_hash, }) } } impl Serializable for DelectorParams { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { DELECTOR_PARAMS_TAG.write_to(cell)?; // tag self.delections_step.write_to(cell)?; self.validator_init_code_hash.write_to(cell)?; self.staker_init_code_hash.write_to(cell)?; Ok(()) } } /// /// ConfigParam 31; /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam31 { pub fundamental_smc_addr: FundamentalSmcAddresses, } impl ConfigParam31 { pub fn new() -> Self { Self::default() } pub fn add_address(&mut self, address: UInt256) { self.fundamental_smc_addr.set(&address, &()).unwrap(); } } impl Deserializable for ConfigParam31 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.fundamental_smc_addr.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam31 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.fundamental_smc_addr.write_to(cell)?; Ok(()) } } macro_rules! define_configparams { ( $cpname:ident, $pname:ident ) => { /// /// $cpname structure /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct $cpname { pub $pname: ValidatorSet, } impl $cpname { /// create new instance of $cpname pub fn new() -> Self { Self::default() } } impl Deserializable for $cpname { fn construct_from(slice: &mut SliceData) -> Result<Self> { let $pname = ValidatorSet::construct_from(slice)?; Ok(Self { $pname }) } } impl Serializable for $cpname { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.$pname.write_to(cell)?; Ok(()) } } } } // _ prev_validators:ValidatorSet = ConfigParam 32; define_configparams!(ConfigParam32, prev_validators); // _ prev_temp_validators: ValidatorSet = ConfigParam 33; define_configparams!(ConfigParam33, prev_temp_validators); // _ cur_validators:ValidatorSet = ConfigParam 34; define_configparams!(ConfigParam34, cur_validators); // _ cur_temp_validators: ValidatorSet = ConfigParam 35; define_configparams!(ConfigParam35, cur_temp_validators); //_ next_validators:ValidatorSet = ConfigParam 36; define_configparams!(ConfigParam36, next_validators); // _ next_temp_validators: ValidatorSet = ConfigParam 37; define_configparams!(ConfigParam37, next_temp_validators); #[derive(Clone, Debug, Eq, PartialEq)] pub enum WorkchainFormat { Basic(WorkchainFormat1), Extended(WorkchainFormat0), } impl Default for WorkchainFormat { fn default() -> Self { WorkchainFormat::Basic(WorkchainFormat1::default()) } } impl Deserializable for WorkchainFormat { fn construct_from(slice: &mut SliceData) -> Result<Self> { slice.get_next_bits(3)?; match slice.get_next_bit()? { true => { Ok(WorkchainFormat::Basic(WorkchainFormat1::construct_from(slice)?)) } false => { Ok(WorkchainFormat::Extended(WorkchainFormat0::construct_from(slice)?)) } } } } impl Serializable for WorkchainFormat { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_bits(0, 3)?; match self { WorkchainFormat::Basic(ref val) => { cell.append_bit_one()?; val.write_to(cell)?; }, WorkchainFormat::Extended(val) => { cell.append_bit_zero()?; val.write_to(cell)?; } } Ok(()) } } /* wfmt_basic#1 vm_version:int32 vm_mode:uint64 = WorkchainFormat 1; */ /// /// Workchain format basic /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct WorkchainFormat1 { pub vm_version: i32, pub vm_mode: u64, } impl WorkchainFormat1 { /// /// Create empty intance of WorkchainFormat1 /// pub fn new() -> Self { Self::default() } /// /// Create new instance of WorkchainFormat1 /// pub fn with_params(vm_version: i32, vm_mode: u64) -> Self { WorkchainFormat1 { vm_version, vm_mode } } } impl Deserializable for WorkchainFormat1 { fn construct_from(slice: &mut SliceData) -> Result<Self> { let vm_version = Deserializable::construct_from(slice)?; let vm_mode = Deserializable::construct_from(slice)?; Ok(Self { vm_version, vm_mode }) } } impl Serializable for WorkchainFormat1 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.vm_version.write_to(cell)?; self.vm_mode.write_to(cell)?; Ok(()) } } /* wfmt_ext#0 min_addr_len:(## 12) max_addr_len:(## 12) addr_len_step:(## 12) { min_addr_len >= 64 } { min_addr_len <= max_addr_len } { max_addr_len <= 1023 } { addr_len_step <= 1023 } workchain_type_id:(## 32) { workchain_type_id >= 1 } = WorkchainFormat 0; */ #[derive(Clone, Debug, Eq, PartialEq)] pub struct WorkchainFormat0 { min_addr_len: Number12, max_addr_len: Number12, addr_len_step: Number12, workchain_type_id: Number32, } impl Default for WorkchainFormat0 { fn default() -> Self { Self { min_addr_len: Number12::from(64), max_addr_len: Number12::from(64), addr_len_step: Number12::from(0), workchain_type_id: Number32::from(1) } } } impl WorkchainFormat0 { /// /// Create empty new instance of WorkchainFormat0 /// pub fn new() -> Self { Self::default() } /// /// Create new instance of WorkchainFormat0 /// pub fn with_params(min_addr_len: u16, max_addr_len: u16, addr_len_step: u16, workchain_type_id: u32 ) -> Result<WorkchainFormat0> { if min_addr_len >= 64 && min_addr_len <= max_addr_len && max_addr_len <= 1023 && addr_len_step <= 1023 && workchain_type_id >= 1 { Ok( WorkchainFormat0 { min_addr_len: Number12::new(min_addr_len as u32)?, max_addr_len: Number12::new(max_addr_len as u32)?, addr_len_step: Number12::new(addr_len_step as u32)?, workchain_type_id: Number32::new(workchain_type_id)?, } ) } else { fail!( BlockError::InvalidData( "min_addr_len >= 64 && min_addr_len <= max_addr_len \ && max_addr_len <= 1023 && addr_len_step <= 1023 \ && workchain_type_id >= 1".to_string() ) ) } } /// /// Getter for min_addr_len /// pub fn min_addr_len(&self) -> u16 { self.min_addr_len.as_u16() } /// /// Setter for min_addr_len /// pub fn set_min_addr_len(&mut self, min_addr_len: u16) -> Result<()> { if (64..=1023).contains(&min_addr_len) { self.min_addr_len = Number12::new(min_addr_len as u32)?; Ok(()) } else { fail!( BlockError::InvalidData( "should: min_addr_len >= 64 && min_addr_len <= 1023".to_string() ) ) } } /// /// Getter for min_addr_len /// pub fn max_addr_len(&self) -> u16 { self.max_addr_len.as_u16() } /// /// Setter for max_addr_len /// pub fn set_max_addr_len(&mut self, max_addr_len: u16) -> Result<()> { if (64..=1024).contains(&max_addr_len) && self.min_addr_len <= max_addr_len as u32 { self.max_addr_len = Number12::new(max_addr_len as u32)?; Ok(()) } else { fail!( BlockError::InvalidData( "should: max_addr_len >= 64 && max_addr_len <= 1024 \ && self.min_addr_len <= max_addr_len".to_string() ) ) } } /// /// Getter for addr_len_step /// pub fn addr_len_step(&self) -> u16 { self.addr_len_step.as_u16() } /// /// Setter for min_addr_len /// pub fn set_addr_len_step(&mut self, addr_len_step: u16) -> Result<()> { if addr_len_step <= 1024 { self.addr_len_step = Number12::new(addr_len_step as u32)?; Ok(()) } else { fail!( BlockError::InvalidData("should: addr_len_step <= 1024".to_string()) ) } } /// /// Getter for workchain_type_id /// pub fn workchain_type_id(&self) -> u32 { self.workchain_type_id.as_u32() } /// /// Setter for min_addr_len /// pub fn set_workchain_type_id(&mut self, workchain_type_id: u32) -> Result<()> { if workchain_type_id >= 1 { self.workchain_type_id = Number32::new(workchain_type_id)?; Ok(()) } else { fail!( BlockError::InvalidData("should: workchain_type_id >= 1".to_string()) ) } } } impl Deserializable for WorkchainFormat0 { fn construct_from(slice: &mut SliceData) -> Result<Self> { let min_addr_len = Number12::construct_from(slice)?; let max_addr_len = Number12::construct_from(slice)?; let addr_len_step = Number12::construct_from(slice)?; let workchain_type_id = Number32::construct_from(slice)?; if min_addr_len >= 64 && min_addr_len <= max_addr_len && max_addr_len <= 1023 && addr_len_step <= 1023 && workchain_type_id >= 1 { Ok(Self { min_addr_len, max_addr_len, addr_len_step, workchain_type_id, }) } else { fail!( BlockError::InvalidData( "should: min_addr_len >= 64 && min_addr_len <= max_addr_len \ && max_addr_len <= 1023 && addr_len_step <= 1023".to_string() ) ) } } } impl Serializable for WorkchainFormat0 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { if self.min_addr_len >= 64 && self.min_addr_len <= self.max_addr_len && self.max_addr_len <= 1023 && self.addr_len_step <= 1023 && self.workchain_type_id >= 1 { self.min_addr_len.write_to(cell)?; self.max_addr_len.write_to(cell)?; self.addr_len_step.write_to(cell)?; self.workchain_type_id.write_to(cell)?; Ok(()) } else { fail!( BlockError::InvalidData( "should: min_addr_len >= 64 && min_addr_len <= max_addr_len \ && max_addr_len <= 1023 && addr_len_step <= 1023".to_string() ) ) } } } /* workchain#a5 enabled_since:uint32 min_split:(## 8) max_split:(## 8) { min_split <= max_split } { max_split <= 60 } basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 } zerostate_root_hash:bits256 zerostate_file_hash:bits256 version:uint32 format:(WorkchainFormat basic) = WorkchainDescr; */ /// /// WorkchainDescr structure /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct WorkchainDescr { pub enabled_since: u32, actual_min_split: u8, min_split: u8, max_split: u8, //basic: bool, // depends on format pub active: bool, pub accept_msgs: bool, pub flags: u16, // 13 bit pub zerostate_root_hash: UInt256, pub zerostate_file_hash: UInt256, pub version: u32, pub format: WorkchainFormat } impl WorkchainDescr { /// /// Create empty instance of WorkchainDescr /// pub fn new() -> Self { Self::default() } /// /// Getter for min_split /// pub fn min_split(&self) -> u8 { self.min_split } /// /// Setter for min_split /// pub fn set_min_split(&mut self, min_split: u8) -> Result<()> { if min_split <= 60 { self.min_split = min_split; Ok(()) } else { fail!( BlockError::InvalidData( "should: min_split <= max_split && max_split <= 60".to_string() ) ) } } /// /// Getter for actual_min_split /// pub fn actual_min_split(&self) -> u8 { self.actual_min_split } /// /// Getter for max_split /// pub fn max_split(&self) -> u8 { self.max_split } /// /// Setter for max_split /// pub fn set_max_split(&mut self, max_split: u8) -> Result<()> { if self.min_split <= max_split && max_split <= 60 { self.max_split = max_split; Ok(()) } else { fail!( BlockError::InvalidData( "should: min_split <= max_split && max_split <= 60".to_string() ) ) } } pub fn active(&self) -> bool { self.active } pub fn basic(&self) -> bool { matches!(self.format, WorkchainFormat::Basic(_)) } } const WORKCHAIN_DESCRIPTOR_TAG : u8 = 0xA6; impl Deserializable for WorkchainDescr { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if tag != WORKCHAIN_DESCRIPTOR_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.enabled_since.read_from(cell)?; let mut min = Number8::default(); min.read_from(cell)?; self.actual_min_split = min.as_u8(); let mut min = Number8::default(); min.read_from(cell)?; self.min_split = min.as_u8(); let mut max = Number8::default(); max.read_from(cell)?; self.max_split = max.as_u8(); cell.get_next_bit()?; // basic self.active = cell.get_next_bit()?; self.accept_msgs = cell.get_next_bit()?; let mut flags = Number13::default(); flags.read_from(cell)?; self.flags = flags.as_u16(); self.zerostate_root_hash.read_from(cell)?; self.zerostate_file_hash.read_from(cell)?; self.version.read_from(cell)?; self.format.read_from(cell)?; Ok(()) } } impl Serializable for WorkchainDescr { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { if self.min_split <= self.max_split && self.max_split <= crate::shard::MAX_SPLIT_DEPTH { cell.append_u8(WORKCHAIN_DESCRIPTOR_TAG)?; self.enabled_since.write_to(cell)?; let min = Number8::new(self.actual_min_split as u32)?; min.write_to(cell)?; let min = Number8::new(self.min_split as u32)?; min.write_to(cell)?; let max = Number8::new(self.max_split as u32)?; max.write_to(cell)?; if let WorkchainFormat::Basic(_) = self.format { cell.append_bit_one()?; } else { cell.append_bit_zero()?; } if self.active { cell.append_bit_one()?; } else { cell.append_bit_zero()?; } if self.accept_msgs { cell.append_bit_one()?; } else { cell.append_bit_zero()?; } let flags = Number13::new(self.flags as u32)?; flags.write_to(cell)?; self.zerostate_root_hash.write_to(cell)?; self.zerostate_file_hash.write_to(cell)?; self.version.write_to(cell)?; self.format.write_to(cell)?; Ok(()) } else { fail!( BlockError::InvalidData( "should: min_split <= max_split && max_split <= 60".to_string() ) ) } } } /* cfg_vote_cfg#36 min_tot_rounds: uint8 max_tot_rounds: uint8 min_wins: uint8 max_losses: uint8 min_store_sec: uint32 max_store_sec: uint32 bit_price: uint32 cell_price: uint32 = ConfigProposalSetup; cfg_vote_setup#91 normal_params: ^ConfigProposalSetup critical_params: ^ConfigProposalSetup = ConfigVotingSetup; _ ConfigVotingSetup = ConfigParam 11; */ #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigProposalSetup { pub min_tot_rounds: u8, pub max_tot_rounds: u8, pub min_wins: u8, pub max_losses: u8, pub min_store_sec: u32, pub max_store_sec: u32, pub bit_price: u32, pub cell_price: u32, } const CONFIG_PROPOSAL_SETUP_TAG : u8 = 0x36; impl Deserializable for ConfigProposalSetup { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; if tag != CONFIG_PROPOSAL_SETUP_TAG { fail!(BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() }) } self.min_tot_rounds.read_from(slice)?; self.max_tot_rounds.read_from(slice)?; self.min_wins.read_from(slice)?; self.max_losses.read_from(slice)?; self.min_store_sec.read_from(slice)?; self.max_store_sec.read_from(slice)?; self.bit_price.read_from(slice)?; self.cell_price.read_from(slice)?; Ok(()) } } impl Serializable for ConfigProposalSetup { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(CONFIG_PROPOSAL_SETUP_TAG)?; self.min_tot_rounds.write_to(cell)?; self.max_tot_rounds.write_to(cell)?; self.min_wins.write_to(cell)?; self.max_losses.write_to(cell)?; self.min_store_sec.write_to(cell)?; self.max_store_sec.write_to(cell)?; self.bit_price.write_to(cell)?; self.cell_price.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigVotingSetup { normal_params: ChildCell<ConfigProposalSetup>, critical_params: ChildCell<ConfigProposalSetup>, } impl ConfigVotingSetup { pub fn new(normal_params: &ConfigProposalSetup, critical_params: &ConfigProposalSetup) -> Result<Self> { Ok( ConfigVotingSetup { normal_params: ChildCell::with_struct(normal_params)?, critical_params: ChildCell::with_struct(critical_params)?, } ) } pub fn read_normal_params(&self) -> Result<ConfigProposalSetup> { self.normal_params.read_struct() } pub fn write_normal_params(&mut self, value: &ConfigProposalSetup) -> Result<()> { self.normal_params.write_struct(value) } pub fn normal_params_cell(&self)-> Cell { self.normal_params.cell() } pub fn read_critical_params(&self) -> Result<ConfigProposalSetup> { self.critical_params.read_struct() } pub fn write_critical_params(&mut self, value: &ConfigProposalSetup) -> Result<()> { self.critical_params.write_struct(value) } pub fn critical_params_cell(&self)-> Cell { self.critical_params.cell() } } const CONFIG_VOTING_SETUP_TAG : u8 = 0x91; impl Deserializable for ConfigVotingSetup { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; if tag != CONFIG_VOTING_SETUP_TAG { fail!(BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() }) } self.normal_params.read_from(slice)?; self.critical_params.read_from(slice)?; Ok(()) } } impl Serializable for ConfigVotingSetup { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(CONFIG_VOTING_SETUP_TAG)?; self.normal_params.write_to(cell)?; self.critical_params.write_to(cell)?; Ok(()) } } pub type ConfigParam11 = ConfigVotingSetup; /* _ workchains:(HashmapE 32 WorkchainDescr) = ConfigParam 12; */ define_HashmapE!{Workchains, 32, WorkchainDescr} /// /// ConfigParam 12 struct /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam12 { pub workchains: Workchains, } impl ConfigParam12 { /// new instance of ConfigParam12 pub fn new() -> Self { Self::default() } /// get length pub fn len(&self) -> Result<usize> { self.workchains.len() } /// determine is empty pub fn is_empty(&self) -> bool { self.workchains.is_empty() } /// get value by index pub fn get(&self, workchain_id: i32) -> Result<Option<WorkchainDescr>> { self.workchains.get(&workchain_id) } /// insert value pub fn insert(&mut self, workchain_id: i32, sp: &WorkchainDescr) -> Result<()> { self.workchains.set(&workchain_id, sp) } } impl Deserializable for ConfigParam12 { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { self.workchains.read_from(slice)?; Ok(()) } } impl Serializable for ConfigParam12 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.workchains.write_to(cell)?; Ok(()) } } /// /// ConfigParam 13 struct /// #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam13 { pub cell: Cell, } impl Deserializable for ConfigParam13 { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { self.cell = slice.clone().into_cell(); Ok(()) } } impl Serializable for ConfigParam13 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.checked_append_references_and_data(&SliceData::load_cell_ref(&self.cell)?)?; Ok(()) } } // validator_temp_key#3 // adnl_addr:bits256 // temp_public_key:SigPubKey // seqno:# // valid_until:uint32 // = ValidatorTempKey; const VALIDATOR_TEMP_KEY_TAG: u8 = 0x3; #[derive(Clone, Default, Debug, Eq, PartialEq)] pub struct ValidatorTempKey { adnl_addr: UInt256, temp_public_key: SigPubKey, seqno: u32, valid_until: u32 } impl ValidatorTempKey { /// new instance of ValidatorTempKey pub fn new() -> Self { Self::default() } pub fn with_params(adnl_addr: UInt256, temp_public_key: SigPubKey, seqno: u32, valid_until: u32) -> Self { Self { adnl_addr, temp_public_key, seqno, valid_until } } pub fn set_adnl_addr(&mut self, adnl_addr: UInt256) { self.adnl_addr = adnl_addr } pub fn adnl_addr(&self) -> &UInt256 { &self.adnl_addr } pub fn set_key(&mut self, temp_public_key: SigPubKey) { self.temp_public_key = temp_public_key } pub fn temp_public_key(&self) -> &SigPubKey { &self.temp_public_key } pub fn set_seqno(&mut self, seqno: u32) { self.seqno = seqno } pub fn seqno(&self) -> u32 { self.seqno } pub fn set_valid_until(&mut self, valid_until: u32) { self.valid_until = valid_until } pub fn valid_until(&self) -> u32 { self.valid_until } } impl Deserializable for ValidatorTempKey { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; // TODO what is tag length in bits??? if tag != VALIDATOR_TEMP_KEY_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.adnl_addr.read_from(slice)?; self.temp_public_key.read_from(slice)?; self.seqno.read_from(slice)?; self.valid_until.read_from(slice)?; Ok(()) } } impl Serializable for ValidatorTempKey { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(VALIDATOR_TEMP_KEY_TAG)?; // TODO what is tag length in bits??? self.adnl_addr.write_to(cell)?; self.temp_public_key.write_to(cell)?; self.seqno.write_to(cell)?; self.valid_until.write_to(cell)?; Ok(()) } } // signed_temp_key#4 // key:^ValidatorTempKey // signature:CryptoSignature // = ValidatorSignedTempKey; const VALIDATOR_SIGNED_TEMP_KEY_TAG: u8 = 0x4; #[derive(Clone, Default, Debug, Eq, PartialEq)] pub struct ValidatorSignedTempKey { key: ValidatorTempKey, signature: CryptoSignature } impl ValidatorSignedTempKey { /// new instance of pub fn with_key_and_signature(key: ValidatorTempKey, signature: CryptoSignature) -> Self { Self {key, signature} } pub fn key(&self) -> &ValidatorTempKey { &self.key } pub fn signature(&self) -> &CryptoSignature { &self.signature } } impl Deserializable for ValidatorSignedTempKey { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; // TODO what is tag length in bits??? if tag != VALIDATOR_SIGNED_TEMP_KEY_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.signature.read_from(slice)?; self.key.read_from_cell(slice.checked_drain_reference()?)?; Ok(()) } } impl Serializable for ValidatorSignedTempKey { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(VALIDATOR_SIGNED_TEMP_KEY_TAG)?; // TODO what is tag length in bits??? self.signature.write_to(cell)?; cell.checked_append_reference(self.key.serialize()?)?; Ok(()) } } /// /// ConfigParam 39 struct /// // _ (HashmapE 256 ValidatorSignedTempKey) = ConfigParam 39; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ConfigParam39 { pub validator_keys: ValidatorKeys, } define_HashmapE!(ValidatorKeys, 256, ValidatorSignedTempKey); impl ConfigParam39 { pub fn new() -> Self { Self::default() } /// get length pub fn len(&self) -> Result<usize> { self.validator_keys.len() } /// determine is empty pub fn is_empty(&self) -> bool { self.validator_keys.is_empty() } /// get value by key pub fn get(&self, key: &UInt256) -> Result<ValidatorSignedTempKey> { self .validator_keys .get(key)? .ok_or_else(|| error!(BlockError::InvalidArg(format!("{:x}", key)))) } /// insert value pub fn insert(&mut self, key: &UInt256, validator_key: &ValidatorSignedTempKey) -> Result<()> { self.validator_keys.set(key, validator_key) } } impl Deserializable for ConfigParam39 { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { self.validator_keys.read_from(slice)?; Ok(()) } } impl Serializable for ConfigParam39 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.validator_keys.write_to(cell)?; Ok(()) } } /// /// ConfigParam 40 struct /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigParam40 { pub slashing_config: SlashingConfig, } impl ConfigParam40 { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigParam40 { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { self.slashing_config.read_from(cell)?; Ok(()) } } impl Serializable for ConfigParam40 { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.slashing_config.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Eq, PartialEq)] pub struct SlashingConfig { pub slashing_period_mc_blocks_count : u32, //number of MC blocks for one slashing iteration pub resend_mc_blocks_count : u32, //number of MC blocks to resend slashing messages in case they have not been delivered pub min_samples_count : u32, //minimal number of samples to compute statistics parameters pub collations_score_weight : u32, //weight for collations score in total score pub signing_score_weight : u32, //weight for signing score in total score pub min_slashing_protection_score : u32, //minimal score to protect from any slashing [0..100] pub z_param_numerator : u32, //numerator for Z param of confidence interval pub z_param_denominator : u32, //numerator for Z param of confidence interval } impl SlashingConfig { pub fn new() -> Self { Self::default() } } impl Default for SlashingConfig { fn default() -> SlashingConfig { Self { slashing_period_mc_blocks_count : 100, resend_mc_blocks_count : 4, min_samples_count : 30, collations_score_weight : 0, signing_score_weight : 1, min_slashing_protection_score : 70, z_param_numerator : 2326, //98% confidence z_param_denominator : 1000, } } } const SLASHING_VERSION1_TAG: u8 = 1; impl Deserializable for SlashingConfig { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { match cell.get_next_byte()? { SLASHING_VERSION1_TAG => { self.slashing_period_mc_blocks_count.read_from(cell)?; self.resend_mc_blocks_count.read_from(cell)?; self.min_samples_count.read_from(cell)?; self.collations_score_weight.read_from(cell)?; self.signing_score_weight.read_from(cell)?; self.min_slashing_protection_score.read_from(cell)?; self.z_param_numerator.read_from(cell)?; self.z_param_denominator.read_from(cell)?; } tag => { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } } Ok(()) } } impl Serializable for SlashingConfig { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(SLASHING_VERSION1_TAG)?; self.slashing_period_mc_blocks_count.write_to(cell)?; self.resend_mc_blocks_count.write_to(cell)?; self.min_samples_count.write_to(cell)?; self.collations_score_weight.write_to(cell)?; self.signing_score_weight.write_to(cell)?; self.min_slashing_protection_score.write_to(cell)?; self.z_param_numerator.write_to(cell)?; self.z_param_denominator.write_to(cell)?; Ok(()) } } #[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] pub enum ParamLimitIndex { Underload = 0, Normal, Soft, Medium, Hard } const LIMIT_COUNT: usize = 4; // param_limits#c3 // underload:# // soft_limit:# // { underload <= soft_limit } // hard_limit:# // { soft_limit <= hard_limit } // = ParamLimits; const PARAM_LIMITS_TAG: u8 = 0xc3; #[derive(Clone, Default, Debug, Eq, PartialEq)] pub struct ParamLimits { // [ unerload , soft, (soft+hard)/2, hard ] limits: [u32; LIMIT_COUNT], } impl ParamLimits { pub fn with_limits(underload: u32, soft: u32, hard: u32) -> Result<Self> { let mut limits = [0u32; LIMIT_COUNT]; Self::set_limits(&mut limits, underload, soft, hard)?; Ok(Self{limits}) } pub fn classify(&self, value: u32) -> ParamLimitIndex { if value >= self.medium() { if value >= self.hard_limit() { ParamLimitIndex::Hard } else { ParamLimitIndex::Medium } } else if value >= self.underload() { if value >= self.soft_limit() { ParamLimitIndex::Soft } else { ParamLimitIndex::Normal } } else { ParamLimitIndex::Underload } } pub fn fits(&self, level: ParamLimitIndex, value: u32) -> bool { // *level* *checks* // Underload value < unerload // Normal value < soft // Soft value < medium // Medium value < hard // Hard always true level == ParamLimitIndex::Hard || value < self.limits[level as usize] } pub fn fits_normal(&self, value: u32, percent: u32) -> bool { value * 100 < self.soft_limit() * percent } pub fn underload(&self) -> u32 { self.limits[ParamLimitIndex::Underload as usize] } pub fn soft_limit(&self) -> u32 { self.limits[ParamLimitIndex::Soft as usize - 1] } pub fn medium(&self) -> u32 { self.limits[ParamLimitIndex::Medium as usize - 1] } pub fn hard_limit(&self) -> u32 { self.limits[ParamLimitIndex::Hard as usize - 1] } fn compute_medium_limit(soft: u32, hard: u32) -> u32 { soft + ((hard - soft) >> 1) } fn set_limits( limits: &mut [u32; LIMIT_COUNT], underload: u32, soft: u32, hard: u32 ) -> Result<()> { if underload > soft { fail!( BlockError::InvalidArg( "underload have to be less or equal to soft limit".to_string() ) ) } if soft > hard { fail!( BlockError::InvalidArg( "soft limit have to be less or equal to hard one".to_string() ) ) } limits[ParamLimitIndex::Underload as usize] = underload; limits[ParamLimitIndex::Soft as usize - 1] = soft; limits[ParamLimitIndex::Medium as usize - 1] = Self::compute_medium_limit(soft, hard); limits[ParamLimitIndex::Hard as usize - 1] = hard; Ok(()) } } impl Deserializable for ParamLimits { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; if tag != PARAM_LIMITS_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } let underload = u32::construct_from(slice)?; let soft = u32::construct_from(slice)?; let hard = u32::construct_from(slice)?; Self::set_limits(&mut self.limits, underload, soft, hard) } } impl Serializable for ParamLimits { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(PARAM_LIMITS_TAG)?; self.underload().write_to(cell)?; self.soft_limit().write_to(cell)?; self.hard_limit().write_to(cell)?; Ok(()) } } // block_limits#5d // bytes:ParamLimits // gas:ParamLimits // lt_delta:ParamLimits // = BlockLimits; const BLOCK_LIMITS_TAG: u8 = 0x5d; #[derive(Clone, Default, Debug, Eq, PartialEq)] pub struct BlockLimits { bytes: ParamLimits, gas: ParamLimits, lt_delta: ParamLimits, } impl BlockLimits { pub fn with_limits(bytes: ParamLimits, gas: ParamLimits, lt_delta: ParamLimits) -> Self { Self { bytes, gas, lt_delta } } pub fn bytes(&self) -> &ParamLimits { &self.bytes } pub fn gas(&self) -> &ParamLimits { &self.gas } pub fn lt_delta(&self) -> &ParamLimits { &self.lt_delta } pub fn fits(&self, level: ParamLimitIndex, bytes: u32, gas: u32, lt_delta: u32) -> bool { self.gas.fits(level, gas) && self.bytes.fits(level, bytes) && self.lt_delta.fits(level, lt_delta) } pub fn fits_normal(&self, bytes: u32, gas: u32, lt_delta: u32, percent: u32) -> bool { self.gas.fits_normal(gas, percent) && self.bytes.fits_normal(bytes, percent) && self.lt_delta.fits_normal(lt_delta, percent) } } impl Deserializable for BlockLimits { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; if tag != BLOCK_LIMITS_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.bytes.read_from(slice)?; self.gas.read_from(slice)?; self.lt_delta.read_from(slice)?; Ok(()) } } impl Serializable for BlockLimits { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(BLOCK_LIMITS_TAG)?; self.bytes.write_to(cell)?; self.gas.write_to(cell)?; self.lt_delta.write_to(cell)?; Ok(()) } } type ConfigParam22 = BlockLimits; type ConfigParam23 = BlockLimits; const COPYLEFT_TAG: u8 = 0x9A; /// /// ConfigParam 42 struct /// #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConfigCopyleft { pub copyleft_reward_threshold: Grams, pub license_rates: LicenseRates, } define_HashmapE!(LicenseRates, 8, u8); impl ConfigCopyleft { pub fn new() -> Self { Self::default() } } impl Deserializable for ConfigCopyleft { fn read_from(&mut self, cell: &mut SliceData) -> Result<()> { let tag = cell.get_next_byte()?; if tag != COPYLEFT_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.copyleft_reward_threshold.read_from(cell)?; self.license_rates.read_from(cell)?; Ok(()) } } impl Serializable for ConfigCopyleft { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_u8(COPYLEFT_TAG)?; self.copyleft_reward_threshold.write_to(cell)?; self.license_rates.write_to(cell)?; Ok(()) } } #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct SuspendedAddressesKey { pub workchain_id: i32, pub address: UInt256, } impl SuspendedAddressesKey { pub fn new(workchain_id: i32, address: UInt256) -> Self { Self { workchain_id, address } } } impl Serializable for SuspendedAddressesKey { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { cell.append_i32(self.workchain_id)?; cell.append_raw(self.address.as_slice(), 256)?; Ok(()) } } impl Deserializable for SuspendedAddressesKey { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { self.workchain_id = slice.get_next_i32()?; self.address = UInt256::construct_from(slice)?; Ok(()) } } define_HashmapE!{SuspendedAddresses, 288, ()} impl SuspendedAddresses { pub fn is_suspended(&self, wc: i32, addr: UInt256) -> Result<bool> { let key = SuspendedAddressesKey::new(wc, addr); Ok(self.get(&key)?.is_some()) } pub fn add_suspended_address(&mut self, wc: i32, addr: UInt256) -> Result<()> { let key = SuspendedAddressesKey::new(wc, addr); self.set(&key, &()) } } define_HashmapE!{MeshConfig, 32, ConnectedNwConfig} #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ConnectedNwConfig { // root cell pub zerostate: BlockIdExt, // 1 + 4 + 8 + 4 + 32 + 32 = 81 pub is_active: bool, // 1 pub currency_id: u32, // 4 // 86 // cell1 pub init_block: BlockIdExt, // 81 pub emergency_guard_addr: UInt256, // 32 // 113 // cell2 pub pull_addr: UInt256, // The storage for native tokens of our network, // which are wrapped in the connected network. // 32 pub minter_addr: UInt256,// 32 // 64 // cell3 pub hardforks: Vec<BlockIdExt>, // 81 + chain } const MESH_INFO_TAG: u8 = 0x01; impl Deserializable for ConnectedNwConfig { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { let tag = slice.get_next_byte()?; if tag != MESH_INFO_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } self.zerostate.read_from(slice)?; self.is_active.read_from(slice)?; self.currency_id.read_from(slice)?; let mut slice1 = SliceData::load_cell(slice.checked_drain_reference()?)?; self.init_block.read_from(&mut slice1)?; self.emergency_guard_addr.read_from(&mut slice1)?; let mut slice2 = SliceData::load_cell(slice.checked_drain_reference()?)?; self.pull_addr.read_from(&mut slice2)?; self.minter_addr.read_from(&mut slice2)?; if slice.get_next_bit()? { let mut slice = slice.clone(); while let Ok(ref_cell) = slice.checked_drain_reference() { let mut ref_slice = SliceData::load_cell(ref_cell)?; self.hardforks.push(BlockIdExt::construct_from(&mut ref_slice)?); slice = ref_slice; } } Ok(()) } } impl Serializable for ConnectedNwConfig { fn write_to(&self, builder: &mut BuilderData) -> Result<()> { builder.append_u8(MESH_INFO_TAG)?; self.zerostate.write_to(builder)?; self.is_active.write_to(builder)?; self.currency_id.write_to(builder)?; let mut builder1 = BuilderData::new(); self.init_block.write_to(&mut builder1)?; self.emergency_guard_addr.write_to(&mut builder1)?; builder.checked_append_reference(builder1.into_cell()?)?; let mut builder2 = BuilderData::new(); self.pull_addr.write_to(&mut builder2)?; self.minter_addr.write_to(&mut builder2)?; builder.checked_append_reference(builder2.into_cell()?)?; let mut prev_builder: Option<BuilderData> = None; for hardfork in self.hardforks.iter().rev() { let mut builder = BuilderData::new(); hardfork.write_to(&mut builder)?; if let Some(prev_builder) = prev_builder { builder.checked_append_reference(prev_builder.into_cell()?)?; } prev_builder = Some(builder); } if let Some(prev_builder) = prev_builder { builder.append_bit_one()?; builder.checked_append_reference(prev_builder.into_cell()?)?; } else { builder.append_bit_zero()?; } Ok(()) } } #[cfg(test)] pub(crate) fn dump_config(params: &HashmapE) { params.iterate_slices(|ref mut key, ref mut slice| -> Result<bool> { let key = key.get_next_u32()?; match ConfigParamEnum::construct_from_slice_and_number(&mut SliceData::load_cell(slice.reference(0)?)?, key)? { ConfigParamEnum::ConfigParam31(ref mut cfg) => { println!("\tConfigParam31.fundamental_smc_addr"); cfg.fundamental_smc_addr.iterate_keys(|addr: UInt256| -> Result<bool> { println!("\t\t{}", addr); Ok(true) })?; } ConfigParamEnum::ConfigParam34(ref mut cfg) => { println!("\tConfigParam34.cur_validators"); for validator in cfg.cur_validators.list() { println!("\t\t{:?}", validator); }; } x => println!("\t{:?}", x) } Ok(true) }).unwrap(); } #[derive(Clone, Debug, Eq, PartialEq)] pub struct FastFinalityConfig { pub split_merge_interval: u32, pub collator_range_len: u32, pub lost_collator_timeout: u32, pub mempool_validators_count: u32, pub mempool_rotated_count: u32, // How many validators are changed beetween sessions. // Must be <= mempool_validators_count. pub unreliability_fine: u16, pub unreliability_weak_fading: u16, pub unreliability_strong_fading: u16, pub unreliability_max: u16, pub unreliability_weight: u16, pub familiarity_collator_fine: u16, pub familiarity_msgpool_fine: u16, pub familiarity_fading: u16, pub familiarity_max: u16, pub familiarity_weight: u16, pub busyness_collator_fine: u16, pub busyness_msgpool_fine: u16, pub busyness_weight: u16, pub candidates_percentile: u8, } impl Default for FastFinalityConfig { fn default() -> Self { Self { split_merge_interval: 128, collator_range_len: 5000, lost_collator_timeout: 60, mempool_validators_count: 3, mempool_rotated_count: 1, unreliability_fine: 100, unreliability_weak_fading: 1, unreliability_strong_fading: 10, unreliability_max: u16::MAX, unreliability_weight: 1, familiarity_collator_fine: 2, familiarity_msgpool_fine: 1, familiarity_fading: 1, familiarity_max: u16::MAX, familiarity_weight: 2, busyness_collator_fine: 4, busyness_msgpool_fine: 1, busyness_weight: 1, candidates_percentile: 5, } } } impl Serializable for FastFinalityConfig { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { self.split_merge_interval.write_to(cell)?; self.collator_range_len.write_to(cell)?; self.lost_collator_timeout.write_to(cell)?; self.mempool_validators_count.write_to(cell)?; self.mempool_rotated_count.write_to(cell)?; self.unreliability_fine.write_to(cell)?; self.unreliability_weak_fading.write_to(cell)?; self.unreliability_strong_fading.write_to(cell)?; self.unreliability_max.write_to(cell)?; self.unreliability_weight.write_to(cell)?; self.familiarity_collator_fine.write_to(cell)?; self.familiarity_msgpool_fine.write_to(cell)?; self.familiarity_fading.write_to(cell)?; self.familiarity_max.write_to(cell)?; self.familiarity_weight.write_to(cell)?; self.busyness_collator_fine.write_to(cell)?; self.busyness_msgpool_fine.write_to(cell)?; self.busyness_weight.write_to(cell)?; self.candidates_percentile.write_to(cell)?; Ok(()) } } impl Deserializable for FastFinalityConfig { fn read_from(&mut self, slice: &mut SliceData) -> Result<()> { self.split_merge_interval.read_from(slice)?; self.collator_range_len.read_from(slice)?; self.lost_collator_timeout.read_from(slice)?; self.mempool_validators_count.read_from(slice)?; self.mempool_rotated_count.read_from(slice)?; if self.mempool_rotated_count > self.mempool_validators_count { fail!(BlockError::InvalidData( "mempool_rotated_count must be less or equal to mempool_validators_count".to_string())) } self.unreliability_fine.read_from(slice)?; self.unreliability_weak_fading.read_from(slice)?; self.unreliability_strong_fading.read_from(slice)?; self.unreliability_max.read_from(slice)?; self.unreliability_weight.read_from(slice)?; self.familiarity_collator_fine.read_from(slice)?; self.familiarity_msgpool_fine.read_from(slice)?; self.familiarity_fading.read_from(slice)?; self.familiarity_max.read_from(slice)?; self.familiarity_weight.read_from(slice)?; self.busyness_collator_fine.read_from(slice)?; self.busyness_msgpool_fine.read_from(slice)?; self.busyness_weight.read_from(slice)?; self.candidates_percentile.read_from(slice)?; Ok(()) } } /// /// ConfigParam 62; /// const SMFT_PARAMS_TAG: u8 = 0x2; #[derive(Clone, Debug, Eq, PartialEq)] pub struct SmftParams { pub min_forwarding_neighbours_count: u32, pub max_forwarding_neighbours_count: u32, pub min_far_neighbours_count: u32, pub max_far_neighbours_count: u32, pub min_block_sync_period_ms: u32, pub max_block_sync_period_ms: u32, pub min_far_neighbours_sync_period_ms: u32, pub max_far_neighbours_sync_period_ms: u32, pub far_neighbours_resync_period_ms: u32, pub block_sync_lifetime_period_ms: u32, pub block_lifetime_period_ms: u32, pub verification_obligation_cutoff_numerator: u32, pub verification_obligation_cutoff_denominator: u32, pub delivery_cutoff_numerator: u32, pub delivery_cutoff_denominator: u32, pub manual_candidate_loading_delay_ms: u32, pub mc_allowed_force_delivery_delay_ms: u32, pub mc_force_delivery_duplication_factor_numerator: u32, pub mc_force_delivery_duplication_factor_denominator: u32, pub mc_max_delivery_waiting_timeout_ms: u32, //0 - shadow mode pub use_debug_bls_keys: bool, //true by default for insecure SMFT testing } impl SmftParams { pub const fn new() -> Self { Self { min_forwarding_neighbours_count: 5, max_forwarding_neighbours_count: 32, min_far_neighbours_count: 2, max_far_neighbours_count: 5, min_block_sync_period_ms: 300, max_block_sync_period_ms: 600, min_far_neighbours_sync_period_ms: 1000, max_far_neighbours_sync_period_ms: 2000, far_neighbours_resync_period_ms: 1000, block_sync_lifetime_period_ms: 10000, block_lifetime_period_ms: 240000, verification_obligation_cutoff_numerator: 1, verification_obligation_cutoff_denominator: 5, delivery_cutoff_numerator: 1, delivery_cutoff_denominator: 2, manual_candidate_loading_delay_ms: 4000, mc_allowed_force_delivery_delay_ms: 4000, mc_force_delivery_duplication_factor_numerator: 3, mc_force_delivery_duplication_factor_denominator: 1, mc_max_delivery_waiting_timeout_ms: 0, //by default network is working in shadow SMFT mode use_debug_bls_keys: true, } } } impl Default for SmftParams { fn default() -> SmftParams { Self::new() } } impl Deserializable for SmftParams { fn construct_from(slice: &mut SliceData) -> Result<Self> { let tag = slice.get_next_byte()?; if tag != SMFT_PARAMS_TAG { fail!( BlockError::InvalidConstructorTag { t: tag as u32, s: std::any::type_name::<Self>().to_string() } ) } let min_forwarding_neighbours_count = Deserializable::construct_from(slice)?; let max_forwarding_neighbours_count = Deserializable::construct_from(slice)?; let min_far_neighbours_count = Deserializable::construct_from(slice)?; let max_far_neighbours_count = Deserializable::construct_from(slice)?; let min_block_sync_period_ms = Deserializable::construct_from(slice)?; let max_block_sync_period_ms = Deserializable::construct_from(slice)?; let min_far_neighbours_sync_period_ms = Deserializable::construct_from(slice)?; let max_far_neighbours_sync_period_ms = Deserializable::construct_from(slice)?; let far_neighbours_resync_period_ms = Deserializable::construct_from(slice)?; let block_sync_lifetime_period_ms = Deserializable::construct_from(slice)?; let block_lifetime_period_ms = Deserializable::construct_from(slice)?; let verification_obligation_cutoff_numerator = Deserializable::construct_from(slice)?; let verification_obligation_cutoff_denominator = Deserializable::construct_from(slice)?; let delivery_cutoff_numerator = Deserializable::construct_from(slice)?; let delivery_cutoff_denominator = Deserializable::construct_from(slice)?; let manual_candidate_loading_delay_ms = Deserializable::construct_from(slice)?; let mc_allowed_force_delivery_delay_ms = Deserializable::construct_from(slice)?; let mc_force_delivery_duplication_factor_numerator = Deserializable::construct_from(slice)?; let mc_force_delivery_duplication_factor_denominator = Deserializable::construct_from(slice)?; let mc_max_delivery_waiting_timeout_ms = Deserializable::construct_from(slice)?; let use_debug_bls_keys = Deserializable::construct_from(slice)?; Ok(Self { min_forwarding_neighbours_count, max_forwarding_neighbours_count, min_far_neighbours_count, max_far_neighbours_count, min_block_sync_period_ms, max_block_sync_period_ms, min_far_neighbours_sync_period_ms, max_far_neighbours_sync_period_ms, far_neighbours_resync_period_ms, block_sync_lifetime_period_ms, block_lifetime_period_ms, verification_obligation_cutoff_numerator, verification_obligation_cutoff_denominator, delivery_cutoff_numerator, delivery_cutoff_denominator, manual_candidate_loading_delay_ms, mc_allowed_force_delivery_delay_ms, mc_force_delivery_duplication_factor_numerator, mc_force_delivery_duplication_factor_denominator, mc_max_delivery_waiting_timeout_ms, use_debug_bls_keys, }) } } impl Serializable for SmftParams { fn write_to(&self, cell: &mut BuilderData) -> Result<()> { SMFT_PARAMS_TAG.write_to(cell)?; // tag self.min_forwarding_neighbours_count.write_to(cell)?; self.max_forwarding_neighbours_count.write_to(cell)?; self.min_far_neighbours_count.write_to(cell)?; self.max_far_neighbours_count.write_to(cell)?; self.min_block_sync_period_ms.write_to(cell)?; self.max_block_sync_period_ms.write_to(cell)?; self.min_far_neighbours_sync_period_ms.write_to(cell)?; self.max_far_neighbours_sync_period_ms.write_to(cell)?; self.far_neighbours_resync_period_ms.write_to(cell)?; self.block_sync_lifetime_period_ms.write_to(cell)?; self.block_lifetime_period_ms.write_to(cell)?; self.verification_obligation_cutoff_numerator.write_to(cell)?; self.verification_obligation_cutoff_denominator.write_to(cell)?; self.delivery_cutoff_numerator.write_to(cell)?; self.delivery_cutoff_denominator.write_to(cell)?; self.manual_candidate_loading_delay_ms.write_to(cell)?; self.mc_allowed_force_delivery_delay_ms.write_to(cell)?; self.mc_force_delivery_duplication_factor_numerator.write_to(cell)?; self.mc_force_delivery_duplication_factor_denominator.write_to(cell)?; self.mc_max_delivery_waiting_timeout_ms.write_to(cell)?; self.use_debug_bls_keys.write_to(cell)?; Ok(()) } }