referrerpolicy=no-referrer-when-downgrade

polkadot_parachain/chain_spec/
mod.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use cumulus_primitives_core::ParaId;
18use polkadot_omni_node_lib::{
19	chain_spec::{GenericChainSpec, LoadSpec},
20	runtime::{
21		AuraConsensusId, BlockNumber, Consensus, Runtime, RuntimeResolver as RuntimeResolverT,
22	},
23};
24use sc_chain_spec::{ChainSpec, ChainType};
25use yet_another_parachain::yet_another_parachain_config;
26
27pub mod asset_hubs;
28pub mod bridge_hubs;
29pub mod collectives;
30pub mod coretime;
31pub mod glutton;
32pub mod penpal;
33pub mod people;
34pub mod rococo_parachain;
35pub mod yet_another_parachain;
36
37/// Extracts the normalized chain id and parachain id from the input chain id.
38/// (H/T to Phala for the idea)
39/// E.g. "penpal-kusama-2004" yields ("penpal-kusama", Some(2004))
40fn extract_parachain_id<'a>(
41	id: &'a str,
42	para_prefixes: &[&str],
43) -> (&'a str, &'a str, Option<ParaId>) {
44	for para_prefix in para_prefixes {
45		if let Some(suffix) = id.strip_prefix(para_prefix) {
46			let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix");
47			return (&id[..para_prefix.len() - 1], id, Some(para_id.into()));
48		}
49	}
50
51	(id, id, None)
52}
53
54#[derive(Debug)]
55pub(crate) struct ChainSpecLoader;
56
57impl LoadSpec for ChainSpecLoader {
58	fn load_spec(&self, id: &str) -> Result<Box<dyn ChainSpec>, String> {
59		Ok(match id {
60			// - Default-like
61			"staging" => Box::new(rococo_parachain::staging_rococo_parachain_local_config()),
62			"tick" => Box::new(GenericChainSpec::from_json_bytes(
63				&include_bytes!("../../chain-specs/tick.json")[..],
64			)?),
65			"trick" => Box::new(GenericChainSpec::from_json_bytes(
66				&include_bytes!("../../chain-specs/trick.json")[..],
67			)?),
68			"track" => Box::new(GenericChainSpec::from_json_bytes(
69				&include_bytes!("../../chain-specs/track.json")[..],
70			)?),
71
72			// -- Asset Hub Polkadot
73			"asset-hub-polkadot" | "statemint" => Box::new(GenericChainSpec::from_json_bytes(
74				&include_bytes!("../../chain-specs/asset-hub-polkadot.json")[..],
75			)?),
76
77			// -- Asset Hub Kusama
78			"asset-hub-kusama" | "statemine" => Box::new(GenericChainSpec::from_json_bytes(
79				&include_bytes!("../../chain-specs/asset-hub-kusama.json")[..],
80			)?),
81
82			// -- Asset Hub Rococo
83			"asset-hub-rococo-dev" => Box::new(asset_hubs::asset_hub_rococo_development_config()),
84			"asset-hub-rococo-local" => Box::new(asset_hubs::asset_hub_rococo_local_config()),
85			// the chain spec as used for generating the upgrade genesis values
86			"asset-hub-rococo-genesis" => Box::new(asset_hubs::asset_hub_rococo_genesis_config()),
87			"asset-hub-rococo" => Box::new(GenericChainSpec::from_json_bytes(
88				&include_bytes!("../../chain-specs/asset-hub-rococo.json")[..],
89			)?),
90
91			// -- Asset Hub Westend
92			"asset-hub-westend-dev" | "westmint-dev" =>
93				Box::new(asset_hubs::asset_hub_westend_development_config()),
94			"asset-hub-westend-local" | "westmint-local" =>
95				Box::new(asset_hubs::asset_hub_westend_local_config()),
96			// the chain spec as used for generating the upgrade genesis values
97			"asset-hub-westend-genesis" | "westmint-genesis" =>
98				Box::new(asset_hubs::asset_hub_westend_config()),
99			// the shell-based chain spec as used for syncing
100			"asset-hub-westend" | "westmint" => Box::new(GenericChainSpec::from_json_bytes(
101				&include_bytes!("../../chain-specs/asset-hub-westend.json")[..],
102			)?),
103
104			// -- Polkadot Collectives
105			"collectives-polkadot" => Box::new(GenericChainSpec::from_json_bytes(
106				&include_bytes!("../../chain-specs/collectives-polkadot.json")[..],
107			)?),
108
109			// -- Westend Collectives
110			"collectives-westend-dev" =>
111				Box::new(collectives::collectives_westend_development_config()),
112			"collectives-westend-local" =>
113				Box::new(collectives::collectives_westend_local_config()),
114			"collectives-westend" => Box::new(GenericChainSpec::from_json_bytes(
115				&include_bytes!("../../chain-specs/collectives-westend.json")[..],
116			)?),
117
118			// -- BridgeHub
119			bridge_like_id
120				if bridge_like_id.starts_with(bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) =>
121				bridge_like_id
122					.parse::<bridge_hubs::BridgeHubRuntimeType>()
123					.expect("invalid value")
124					.load_config()?,
125
126			// -- Coretime
127			coretime_like_id
128				if coretime_like_id.starts_with(coretime::CoretimeRuntimeType::ID_PREFIX) =>
129				coretime_like_id
130					.parse::<coretime::CoretimeRuntimeType>()
131					.expect("invalid value")
132					.load_config()?,
133
134			// -- Penpal
135			id if id.starts_with("penpal-rococo") => {
136				let (_, _, para_id) = extract_parachain_id(&id, &["penpal-rococo-"]);
137				Box::new(penpal::get_penpal_chain_spec(
138					para_id.expect("Must specify parachain id"),
139					"rococo-local",
140				))
141			},
142			id if id.starts_with("penpal-westend") => {
143				let (_, _, para_id) = extract_parachain_id(&id, &["penpal-westend-"]);
144				Box::new(penpal::get_penpal_chain_spec(
145					para_id.expect("Must specify parachain id"),
146					"westend-local",
147				))
148			},
149
150			// -- Glutton Westend
151			id if id.starts_with("glutton-westend-dev") => {
152				let (_, _, para_id) = extract_parachain_id(&id, &["glutton-westend-dev-"]);
153				Box::new(glutton::glutton_westend_config(
154					para_id.expect("Must specify parachain id"),
155					ChainType::Development,
156					"westend-dev",
157				))
158			},
159			id if id.starts_with("glutton-westend-local") => {
160				let (_, _, para_id) = extract_parachain_id(&id, &["glutton-westend-local-"]);
161				Box::new(glutton::glutton_westend_config(
162					para_id.expect("Must specify parachain id"),
163					ChainType::Local,
164					"westend-local",
165				))
166			},
167			// the chain spec as used for generating the upgrade genesis values
168			id if id.starts_with("glutton-westend-genesis") => {
169				let (_, _, para_id) = extract_parachain_id(&id, &["glutton-westend-genesis-"]);
170				Box::new(glutton::glutton_westend_config(
171					para_id.expect("Must specify parachain id"),
172					ChainType::Live,
173					"westend",
174				))
175			},
176
177			id if id.starts_with("yap-") => {
178				let tok: Vec<String> = id.split('-').map(|s| s.to_owned()).collect();
179				assert!(
180					tok.len() == 4,
181					"Invalid YAP chain id, should be 'yap-<relay>-<chaintype>-<para-id>'"
182				);
183				let relay = if &tok[2] == "live" { tok[1].clone() } else { tok[1..=2].join("-") };
184				let chain_type = match tok[2].as_str() {
185					"local" => ChainType::Local,
186					"dev" => ChainType::Development,
187					"live" => ChainType::Live,
188					_ => unimplemented!("Unknown chain type {}", tok[2]),
189				};
190				let para_id: u32 =
191					tok[3].parse().expect(&format!("Illegal para id '{}' provided", tok[3]));
192
193				Box::new(yet_another_parachain_config(relay, chain_type, para_id))
194			},
195
196			// -- People
197			people_like_id if people_like_id.starts_with(people::PeopleRuntimeType::ID_PREFIX) =>
198				people_like_id
199					.parse::<people::PeopleRuntimeType>()
200					.expect("invalid value")
201					.load_config()?,
202
203			// -- Fallback (generic chainspec)
204			"" => {
205				log::warn!("No ChainSpec.id specified, so using default one, based on rococo-parachain runtime");
206				Box::new(rococo_parachain::rococo_parachain_local_config())
207			},
208
209			// -- Loading a specific spec from disk
210			path => Box::new(GenericChainSpec::from_json_file(path.into())?),
211		})
212	}
213}
214
215/// Helper enum that is used for better distinction of different parachain/runtime configuration
216/// (it is based/calculated on ChainSpec's ID attribute)
217#[derive(Debug, PartialEq)]
218enum LegacyRuntime {
219	Omni,
220	AssetHubPolkadot,
221	AssetHub,
222	Penpal,
223	Collectives,
224	Glutton,
225	BridgeHub(bridge_hubs::BridgeHubRuntimeType),
226	Coretime(coretime::CoretimeRuntimeType),
227	People(people::PeopleRuntimeType),
228}
229
230impl LegacyRuntime {
231	fn from_id(id: &str) -> LegacyRuntime {
232		let id = id.replace('_', "-");
233
234		if id.starts_with("asset-hub-polkadot") | id.starts_with("statemint") {
235			LegacyRuntime::AssetHubPolkadot
236		} else if id.starts_with("asset-hub-kusama") |
237			id.starts_with("statemine") |
238			id.starts_with("asset-hub-rococo") |
239			id.starts_with("rockmine") |
240			id.starts_with("asset-hub-westend") |
241			id.starts_with("westmint")
242		{
243			LegacyRuntime::AssetHub
244		} else if id.starts_with("penpal") {
245			LegacyRuntime::Penpal
246		} else if id.starts_with("collectives-polkadot") || id.starts_with("collectives-westend") {
247			LegacyRuntime::Collectives
248		} else if id.starts_with(bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) {
249			LegacyRuntime::BridgeHub(
250				id.parse::<bridge_hubs::BridgeHubRuntimeType>().expect("Invalid value"),
251			)
252		} else if id.starts_with(coretime::CoretimeRuntimeType::ID_PREFIX) {
253			LegacyRuntime::Coretime(
254				id.parse::<coretime::CoretimeRuntimeType>().expect("Invalid value"),
255			)
256		} else if id.starts_with("glutton") {
257			LegacyRuntime::Glutton
258		} else if id.starts_with(people::PeopleRuntimeType::ID_PREFIX) {
259			LegacyRuntime::People(id.parse::<people::PeopleRuntimeType>().expect("Invalid value"))
260		} else {
261			log::warn!(
262				"No specific runtime was recognized for ChainSpec's id: '{}', \
263				so Runtime::Omni(Consensus::Aura) will be used",
264				id
265			);
266			LegacyRuntime::Omni
267		}
268	}
269}
270
271#[derive(Debug)]
272pub(crate) struct RuntimeResolver;
273
274impl RuntimeResolverT for RuntimeResolver {
275	fn runtime(&self, chain_spec: &dyn ChainSpec) -> sc_cli::Result<Runtime> {
276		let legacy_runtime = LegacyRuntime::from_id(chain_spec.id());
277		Ok(match legacy_runtime {
278			LegacyRuntime::AssetHubPolkadot =>
279				Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Ed25519)),
280			LegacyRuntime::AssetHub |
281			LegacyRuntime::BridgeHub(_) |
282			LegacyRuntime::Collectives |
283			LegacyRuntime::Coretime(_) |
284			LegacyRuntime::People(_) |
285			LegacyRuntime::Glutton |
286			LegacyRuntime::Penpal |
287			LegacyRuntime::Omni =>
288				Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519)),
289		})
290	}
291}
292
293#[cfg(test)]
294mod tests {
295	use super::*;
296	use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, ChainType, Extension};
297	use serde::{Deserialize, Serialize};
298
299	#[derive(
300		Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default,
301	)]
302	#[serde(deny_unknown_fields)]
303	pub struct Extensions1 {
304		pub attribute1: String,
305		pub attribute2: u32,
306	}
307
308	#[derive(
309		Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default,
310	)]
311	#[serde(deny_unknown_fields)]
312	pub struct Extensions2 {
313		pub attribute_x: String,
314		pub attribute_y: String,
315		pub attribute_z: u32,
316	}
317
318	pub type DummyChainSpec<E> = sc_service::GenericChainSpec<E>;
319
320	pub fn create_default_with_extensions<E: Extension>(
321		id: &str,
322		extension: E,
323	) -> DummyChainSpec<E> {
324		DummyChainSpec::builder(
325			rococo_parachain_runtime::WASM_BINARY
326				.expect("WASM binary was not built, please build it!"),
327			extension,
328		)
329		.with_name("Dummy local testnet")
330		.with_id(id)
331		.with_chain_type(ChainType::Local)
332		.with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
333		.build()
334	}
335
336	#[test]
337	fn test_legacy_runtime_for_different_chain_specs() {
338		let chain_spec =
339			create_default_with_extensions("penpal-rococo-1000", Extensions2::default());
340		assert_eq!(LegacyRuntime::Penpal, LegacyRuntime::from_id(chain_spec.id()));
341
342		let chain_spec = crate::chain_spec::rococo_parachain::rococo_parachain_local_config();
343		assert_eq!(LegacyRuntime::Omni, LegacyRuntime::from_id(chain_spec.id()));
344	}
345}