1mod 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#[derive(Clone, PartialEq, Eq, Serialize, Debug, Default)]
99#[cfg_attr(feature = "datasize", derive(DataSize))]
100#[serde(deny_unknown_fields)]
101pub struct Chainspec {
102 #[serde(rename = "protocol")]
104 pub protocol_config: ProtocolConfig,
105
106 #[serde(rename = "network")]
108 pub network_config: NetworkConfig,
109
110 #[serde(rename = "core")]
112 pub core_config: CoreConfig,
113
114 #[serde(rename = "highway")]
116 pub highway_config: HighwayConfig,
117
118 #[serde(rename = "transactions")]
120 pub transaction_config: TransactionConfig,
121
122 #[serde(rename = "wasm")]
124 pub wasm_config: WasmConfig,
125
126 #[serde(rename = "system_costs")]
128 pub system_costs_config: SystemConfig,
129
130 #[serde(rename = "vacancy")]
132 pub vacancy_config: VacancyConfig,
133
134 pub storage_costs: StorageCosts,
136}
137
138impl Chainspec {
139 pub fn name_hash(&self) -> ChainNameDigest {
141 ChainNameDigest::from_chain_name(&self.network_config.name)
142 }
143
144 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 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 pub fn protocol_version(&self) -> ProtocolVersion {
163 self.protocol_config.version
164 }
165
166 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 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 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 pub fn is_supported(&self, lane: u8) -> bool {
230 self.transaction_config
231 .transaction_v1_config
232 .is_supported(lane)
233 }
234
235 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 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 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 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 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 pub fn with_chain_name(&mut self, chain_name: String) -> &mut Self {
292 self.network_config.name = chain_name;
293 self
294 }
295
296 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 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 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 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
321impl ToBytes for Chainspec {
322 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
323 self.protocol_config.write_bytes(writer)?;
324 self.network_config.write_bytes(writer)?;
325 self.core_config.write_bytes(writer)?;
326 self.highway_config.write_bytes(writer)?;
327 self.transaction_config.write_bytes(writer)?;
328 self.wasm_config.write_bytes(writer)?;
329 self.system_costs_config.write_bytes(writer)?;
330 self.vacancy_config.write_bytes(writer)?;
331 self.storage_costs.write_bytes(writer)
332 }
333
334 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
335 let mut buffer = bytesrepr::allocate_buffer(self)?;
336 self.write_bytes(&mut buffer)?;
337 Ok(buffer)
338 }
339
340 fn serialized_length(&self) -> usize {
341 self.protocol_config.serialized_length()
342 + self.network_config.serialized_length()
343 + self.core_config.serialized_length()
344 + self.highway_config.serialized_length()
345 + self.transaction_config.serialized_length()
346 + self.wasm_config.serialized_length()
347 + self.system_costs_config.serialized_length()
348 + self.vacancy_config.serialized_length()
349 + self.storage_costs.serialized_length()
350 }
351}
352
353impl FromBytes for Chainspec {
354 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
355 let (protocol_config, remainder) = ProtocolConfig::from_bytes(bytes)?;
356 let (network_config, remainder) = NetworkConfig::from_bytes(remainder)?;
357 let (core_config, remainder) = CoreConfig::from_bytes(remainder)?;
358 let (highway_config, remainder) = HighwayConfig::from_bytes(remainder)?;
359 let (transaction_config, remainder) = TransactionConfig::from_bytes(remainder)?;
360 let (wasm_config, remainder) = WasmConfig::from_bytes(remainder)?;
361 let (system_costs_config, remainder) = SystemConfig::from_bytes(remainder)?;
362 let (vacancy_config, remainder) = VacancyConfig::from_bytes(remainder)?;
363 let (storage_costs, remainder) = FromBytes::from_bytes(remainder)?;
364 let chainspec = Chainspec {
365 protocol_config,
366 network_config,
367 core_config,
368 highway_config,
369 transaction_config,
370 wasm_config,
371 system_costs_config,
372 vacancy_config,
373 storage_costs,
374 };
375 Ok((chainspec, remainder))
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382
383 use rand::SeedableRng;
384
385 #[test]
386 fn bytesrepr_roundtrip() {
387 let mut rng = TestRng::from_entropy();
388 let chainspec = Chainspec::random(&mut rng);
389 bytesrepr::test_serialization_roundtrip(&chainspec);
390 }
391}