casper_types/
chainspec.rs

1//! The chainspec is a set of configuration options for the network.  All validators must apply the
2//! same set of options in order to join and act as a peer in a given network.
3
4mod accounts_config;
5mod activation_point;
6mod chainspec_raw_bytes;
7mod core_config;
8mod fee_handling;
9pub mod genesis_config;
10mod global_state_update;
11mod highway_config;
12mod hold_balance_handling;
13mod network_config;
14mod next_upgrade;
15mod pricing_handling;
16mod protocol_config;
17mod refund_handling;
18mod transaction_config;
19mod upgrade_config;
20mod vacancy_config;
21mod vm_config;
22
23#[cfg(any(feature = "std", test))]
24use std::{fmt::Debug, sync::Arc};
25
26#[cfg(feature = "datasize")]
27use datasize::DataSize;
28#[cfg(any(feature = "testing", test))]
29use rand::Rng;
30use serde::Serialize;
31use tracing::error;
32
33#[cfg(any(feature = "testing", test))]
34use crate::testing::TestRng;
35use crate::{
36    bytesrepr::{self, FromBytes, ToBytes},
37    ChainNameDigest, Digest, EraId, ProtocolVersion, Timestamp,
38};
39pub use accounts_config::{
40    AccountConfig, AccountsConfig, AdministratorAccount, DelegatorConfig, GenesisAccount,
41    GenesisValidator, ValidatorConfig,
42};
43pub use activation_point::ActivationPoint;
44pub use chainspec_raw_bytes::ChainspecRawBytes;
45pub use core_config::{
46    ConsensusProtocolName, CoreConfig, LegacyRequiredFinality, DEFAULT_GAS_HOLD_INTERVAL,
47    DEFAULT_MINIMUM_BID_AMOUNT,
48};
49#[cfg(any(feature = "std", test))]
50pub use core_config::{
51    DEFAULT_BASELINE_MOTES_AMOUNT, DEFAULT_FEE_HANDLING, DEFAULT_REFUND_HANDLING,
52};
53pub use fee_handling::FeeHandling;
54#[cfg(any(feature = "std", test))]
55pub use genesis_config::GenesisConfig;
56pub use global_state_update::{GlobalStateUpdate, GlobalStateUpdateConfig, GlobalStateUpdateError};
57pub use highway_config::HighwayConfig;
58pub use hold_balance_handling::HoldBalanceHandling;
59pub use network_config::NetworkConfig;
60pub use next_upgrade::NextUpgrade;
61pub use pricing_handling::PricingHandling;
62pub use protocol_config::ProtocolConfig;
63pub use refund_handling::RefundHandling;
64pub use transaction_config::{
65    DeployConfig, TransactionConfig, TransactionLaneDefinition, TransactionV1Config,
66};
67#[cfg(any(feature = "testing", test))]
68pub use transaction_config::{
69    DEFAULT_LARGE_TRANSACTION_GAS_LIMIT, DEFAULT_MAX_PAYMENT_MOTES, DEFAULT_MIN_TRANSFER_MOTES,
70};
71pub use upgrade_config::ProtocolUpgradeConfig;
72pub use vacancy_config::VacancyConfig;
73pub use vm_config::{
74    AuctionCosts, BrTableCost, ChainspecRegistry, ControlFlowCosts, HandlePaymentCosts,
75    HostFunction, HostFunctionCost, HostFunctionCostsV1, HostFunctionCostsV2, HostFunctionV2,
76    MessageLimits, MintCosts, OpcodeCosts, StandardPaymentCosts, StorageCosts, SystemConfig,
77    WasmConfig, WasmV1Config, WasmV2Config, DEFAULT_HOST_FUNCTION_NEW_DICTIONARY,
78};
79#[cfg(any(feature = "testing", test))]
80pub use vm_config::{
81    DEFAULT_ADD_BID_COST, DEFAULT_ADD_COST, DEFAULT_BIT_COST, DEFAULT_CONST_COST,
82    DEFAULT_CONTROL_FLOW_BLOCK_OPCODE, DEFAULT_CONTROL_FLOW_BR_IF_OPCODE,
83    DEFAULT_CONTROL_FLOW_BR_OPCODE, DEFAULT_CONTROL_FLOW_BR_TABLE_MULTIPLIER,
84    DEFAULT_CONTROL_FLOW_BR_TABLE_OPCODE, DEFAULT_CONTROL_FLOW_CALL_INDIRECT_OPCODE,
85    DEFAULT_CONTROL_FLOW_CALL_OPCODE, DEFAULT_CONTROL_FLOW_DROP_OPCODE,
86    DEFAULT_CONTROL_FLOW_ELSE_OPCODE, DEFAULT_CONTROL_FLOW_END_OPCODE,
87    DEFAULT_CONTROL_FLOW_IF_OPCODE, DEFAULT_CONTROL_FLOW_LOOP_OPCODE,
88    DEFAULT_CONTROL_FLOW_RETURN_OPCODE, DEFAULT_CONTROL_FLOW_SELECT_OPCODE,
89    DEFAULT_CONVERSION_COST, DEFAULT_CURRENT_MEMORY_COST, DEFAULT_DELEGATE_COST, DEFAULT_DIV_COST,
90    DEFAULT_GLOBAL_COST, DEFAULT_GROW_MEMORY_COST, DEFAULT_INTEGER_COMPARISON_COST,
91    DEFAULT_LOAD_COST, DEFAULT_LOCAL_COST, DEFAULT_MAX_STACK_HEIGHT, DEFAULT_MUL_COST,
92    DEFAULT_NEW_DICTIONARY_COST, DEFAULT_NOP_COST, DEFAULT_STORE_COST, DEFAULT_TRANSFER_COST,
93    DEFAULT_UNREACHABLE_COST, DEFAULT_WASM_MAX_MEMORY,
94};
95
96/// A collection of configuration settings describing the state of the system at genesis and after
97/// upgrades to basic system functionality occurring after genesis.
98#[derive(Clone, PartialEq, Eq, Serialize, Debug, Default)]
99#[cfg_attr(feature = "datasize", derive(DataSize))]
100#[serde(deny_unknown_fields)]
101pub struct Chainspec {
102    /// Protocol config.
103    #[serde(rename = "protocol")]
104    pub protocol_config: ProtocolConfig,
105
106    /// Network config.
107    #[serde(rename = "network")]
108    pub network_config: NetworkConfig,
109
110    /// Core config.
111    #[serde(rename = "core")]
112    pub core_config: CoreConfig,
113
114    /// Highway config.
115    #[serde(rename = "highway")]
116    pub highway_config: HighwayConfig,
117
118    /// Transaction Config.
119    #[serde(rename = "transactions")]
120    pub transaction_config: TransactionConfig,
121
122    /// Wasm config.
123    #[serde(rename = "wasm")]
124    pub wasm_config: WasmConfig,
125
126    /// System costs config.
127    #[serde(rename = "system_costs")]
128    pub system_costs_config: SystemConfig,
129
130    /// Vacancy behavior config
131    #[serde(rename = "vacancy")]
132    pub vacancy_config: VacancyConfig,
133
134    /// Storage costs.
135    pub storage_costs: StorageCosts,
136}
137
138impl Chainspec {
139    /// Returns the hash of the chainspec's name.
140    pub fn name_hash(&self) -> ChainNameDigest {
141        ChainNameDigest::from_chain_name(&self.network_config.name)
142    }
143
144    /// Serializes `self` and hashes the resulting bytes.
145    pub fn hash(&self) -> Digest {
146        let serialized_chainspec = self.to_bytes().unwrap_or_else(|error| {
147            error!(%error, "failed to serialize chainspec");
148            vec![]
149        });
150        Digest::hash(serialized_chainspec)
151    }
152
153    /// Serializes `self` and hashes the resulting bytes, if able.
154    pub fn try_hash(&self) -> Result<Digest, String> {
155        let arr = self
156            .to_bytes()
157            .map_err(|_| "failed to serialize chainspec".to_string())?;
158        Ok(Digest::hash(arr))
159    }
160
161    /// Returns the protocol version of the chainspec.
162    pub fn protocol_version(&self) -> ProtocolVersion {
163        self.protocol_config.version
164    }
165
166    /// Returns the era ID of where we should reset back to.  This means stored blocks in that and
167    /// subsequent eras are deleted from storage.
168    pub fn hard_reset_to_start_of_era(&self) -> Option<EraId> {
169        self.protocol_config
170            .hard_reset
171            .then(|| self.protocol_config.activation_point.era_id())
172    }
173
174    /// Creates an upgrade config instance from parts.
175    pub fn upgrade_config_from_parts(
176        &self,
177        pre_state_hash: Digest,
178        current_protocol_version: ProtocolVersion,
179        era_id: EraId,
180        chainspec_raw_bytes: Arc<ChainspecRawBytes>,
181    ) -> Result<ProtocolUpgradeConfig, String> {
182        let chainspec_registry = ChainspecRegistry::new_with_optional_global_state(
183            chainspec_raw_bytes.chainspec_bytes(),
184            chainspec_raw_bytes.maybe_global_state_bytes(),
185        );
186        let global_state_update = match self.protocol_config.get_update_mapping() {
187            Ok(global_state_update) => global_state_update,
188            Err(err) => {
189                return Err(format!("failed to generate global state update: {}", err));
190            }
191        };
192        let fee_handling = self.core_config.fee_handling;
193        let validator_minimum_bid_amount = self.core_config.minimum_bid_amount;
194        let maximum_delegation_amount = self.core_config.maximum_delegation_amount;
195        let minimum_delegation_amount = self.core_config.minimum_delegation_amount;
196        let enable_addressable_entity = self.core_config.enable_addressable_entity;
197
198        Ok(ProtocolUpgradeConfig::new(
199            pre_state_hash,
200            current_protocol_version,
201            self.protocol_config.version,
202            Some(era_id),
203            Some(self.core_config.gas_hold_balance_handling),
204            Some(self.core_config.gas_hold_interval.millis()),
205            Some(self.core_config.validator_slots),
206            Some(self.core_config.auction_delay),
207            Some(self.core_config.locked_funds_period.millis()),
208            Some(self.core_config.round_seigniorage_rate),
209            Some(self.core_config.unbonding_delay),
210            global_state_update,
211            chainspec_registry,
212            fee_handling,
213            validator_minimum_bid_amount,
214            maximum_delegation_amount,
215            minimum_delegation_amount,
216            enable_addressable_entity,
217        ))
218    }
219
220    /// Returns balance hold epoch based upon configured hold interval, calculated from the imputed
221    /// timestamp.
222    pub fn balance_holds_epoch(&self, timestamp: Timestamp) -> u64 {
223        timestamp
224            .millis()
225            .saturating_sub(self.core_config.gas_hold_interval.millis())
226    }
227
228    /// Is the given transaction lane supported.
229    pub fn is_supported(&self, lane: u8) -> bool {
230        self.transaction_config
231            .transaction_v1_config
232            .is_supported(lane)
233    }
234
235    /// Returns the max serialized for the given category.
236    pub fn get_max_serialized_length_by_category(&self, lane: u8) -> u64 {
237        self.transaction_config
238            .transaction_v1_config
239            .get_max_serialized_length(lane)
240    }
241
242    /// Returns the max args length for the given category.
243    pub fn get_max_args_length_by_category(&self, lane: u8) -> u64 {
244        self.transaction_config
245            .transaction_v1_config
246            .get_max_args_length(lane)
247    }
248
249    /// Returns the max gas limit for the given category.
250    pub fn get_max_gas_limit_by_category(&self, lane: u8) -> u64 {
251        self.transaction_config
252            .transaction_v1_config
253            .get_max_transaction_gas_limit(lane)
254    }
255
256    /// Returns the max transaction count for the given category.
257    pub fn get_max_transaction_count_by_category(&self, lane: u8) -> u64 {
258        self.transaction_config
259            .transaction_v1_config
260            .get_max_transaction_count(lane)
261    }
262}
263
264#[cfg(any(feature = "testing", test))]
265impl Chainspec {
266    /// Generates a random instance using a `TestRng`.
267    pub fn random(rng: &mut TestRng) -> Self {
268        let protocol_config = ProtocolConfig::random(rng);
269        let network_config = NetworkConfig::random(rng);
270        let core_config = CoreConfig::random(rng);
271        let highway_config = HighwayConfig::random(rng);
272        let transaction_config = TransactionConfig::random(rng);
273        let wasm_config = rng.gen();
274        let system_costs_config = SystemConfig::random(rng);
275        let vacancy_config = VacancyConfig::random(rng);
276
277        Chainspec {
278            protocol_config,
279            network_config,
280            core_config,
281            highway_config,
282            transaction_config,
283            wasm_config,
284            system_costs_config,
285            vacancy_config,
286            storage_costs: rng.gen(),
287        }
288    }
289
290    /// Set the chain name;
291    pub fn with_chain_name(&mut self, chain_name: String) -> &mut Self {
292        self.network_config.name = chain_name;
293        self
294    }
295
296    /// Set max associated keys.
297    pub fn with_max_associated_keys(&mut self, max_associated_keys: u32) -> &mut Self {
298        self.core_config.max_associated_keys = max_associated_keys;
299        self
300    }
301
302    /// Set pricing handling.
303    pub fn with_pricing_handling(&mut self, pricing_handling: PricingHandling) -> &mut Self {
304        self.core_config.pricing_handling = pricing_handling;
305        self
306    }
307
308    /// Set allow prepaid.
309    pub fn with_allow_prepaid(&mut self, allow_prepaid: bool) -> &mut Self {
310        self.core_config.allow_prepaid = allow_prepaid;
311        self
312    }
313
314    /// Set block gas limit.
315    pub fn with_block_gas_limit(&mut self, block_gas_limit: u64) -> &mut Self {
316        self.transaction_config.block_gas_limit = block_gas_limit;
317        self
318    }
319
320    /// Set vm2 casper wasm.
321    pub fn with_vm_casper_v2(&mut self, vm_casper_v2: bool) -> &mut Self {
322        self.transaction_config.runtime_config.vm_casper_v2 = vm_casper_v2;
323        self
324    }
325}
326
327impl ToBytes for Chainspec {
328    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
329        self.protocol_config.write_bytes(writer)?;
330        self.network_config.write_bytes(writer)?;
331        self.core_config.write_bytes(writer)?;
332        self.highway_config.write_bytes(writer)?;
333        self.transaction_config.write_bytes(writer)?;
334        self.wasm_config.write_bytes(writer)?;
335        self.system_costs_config.write_bytes(writer)?;
336        self.vacancy_config.write_bytes(writer)?;
337        self.storage_costs.write_bytes(writer)
338    }
339
340    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
341        let mut buffer = bytesrepr::allocate_buffer(self)?;
342        self.write_bytes(&mut buffer)?;
343        Ok(buffer)
344    }
345
346    fn serialized_length(&self) -> usize {
347        self.protocol_config.serialized_length()
348            + self.network_config.serialized_length()
349            + self.core_config.serialized_length()
350            + self.highway_config.serialized_length()
351            + self.transaction_config.serialized_length()
352            + self.wasm_config.serialized_length()
353            + self.system_costs_config.serialized_length()
354            + self.vacancy_config.serialized_length()
355            + self.storage_costs.serialized_length()
356    }
357}
358
359impl FromBytes for Chainspec {
360    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
361        let (protocol_config, remainder) = ProtocolConfig::from_bytes(bytes)?;
362        let (network_config, remainder) = NetworkConfig::from_bytes(remainder)?;
363        let (core_config, remainder) = CoreConfig::from_bytes(remainder)?;
364        let (highway_config, remainder) = HighwayConfig::from_bytes(remainder)?;
365        let (transaction_config, remainder) = TransactionConfig::from_bytes(remainder)?;
366        let (wasm_config, remainder) = WasmConfig::from_bytes(remainder)?;
367        let (system_costs_config, remainder) = SystemConfig::from_bytes(remainder)?;
368        let (vacancy_config, remainder) = VacancyConfig::from_bytes(remainder)?;
369        let (storage_costs, remainder) = FromBytes::from_bytes(remainder)?;
370        let chainspec = Chainspec {
371            protocol_config,
372            network_config,
373            core_config,
374            highway_config,
375            transaction_config,
376            wasm_config,
377            system_costs_config,
378            vacancy_config,
379            storage_costs,
380        };
381        Ok((chainspec, remainder))
382    }
383}
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    use rand::SeedableRng;
390
391    #[test]
392    fn bytesrepr_roundtrip() {
393        let mut rng = TestRng::from_entropy();
394        let chainspec = Chainspec::random(&mut rng);
395        bytesrepr::test_serialization_roundtrip(&chainspec);
396    }
397}