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 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}