Skip to main content

pop_chains/up/
chains.rs

1// SPDX-License-Identifier: GPL-3.0
2
3use super::{Binary, Relay, chain_specs::chain_spec_generator};
4use crate::{Error, registry, registry::System, traits::Binary as BinaryT};
5use pop_common::sourcing::{filters::prefix, traits::*};
6use std::path::Path;
7
8/// Initializes the configuration required to launch a system parachain.
9///
10/// # Arguments
11/// * `id` - The parachain identifier.
12/// * `command` - The command specified.
13/// * `version` - The version of the parachain binary to be used.
14/// * `runtime_version` - The version of the runtime to be used.
15/// * `relay_chain_version` - The version of the relay chain binary being used.
16/// * `chain` - The chain specified.
17/// * `cache` - The cache to be used.
18pub(super) async fn system(
19	id: u32,
20	command: &str,
21	version: Option<&str>,
22	runtime_version: Option<&str>,
23	relay_chain_version: &str,
24	chain: Option<&str>,
25	cache: &Path,
26) -> Result<Option<super::Chain>, Error> {
27	let para = &System;
28	let name = para.binary().to_string();
29	if command != name {
30		return Ok(None);
31	}
32	// Default to the same version as the relay chain when not explicitly specified
33	let source = para
34		.source()?
35		.resolve(&name, version.or(Some(relay_chain_version)), cache, |f| prefix(f, &name))
36		.await
37		.into();
38	let binary = Binary::Source { name, source, cache: cache.to_path_buf() };
39	let chain_spec_generator = match chain {
40		Some(chain) => chain_spec_generator(chain, runtime_version, cache).await?,
41		None => None,
42	};
43	Ok(Some(super::Chain { id, binary, chain: chain.map(|c| c.to_string()), chain_spec_generator }))
44}
45
46/// Initializes the configuration required to launch a parachain.
47///
48/// # Arguments
49/// * `id` - The parachain identifier.
50/// * `command` - The command specified.
51/// * `version` - The version of the parachain binary to be used.
52/// * `chain` - The chain specified.
53/// * `cache` - The cache to be used.
54pub(super) async fn from(
55	relay: &Relay,
56	id: u32,
57	command: &str,
58	version: Option<&str>,
59	chain: Option<&str>,
60	cache: &Path,
61) -> Result<Option<super::Chain>, Error> {
62	if let Some(para) = registry::chains(relay).iter().find(|p| p.binary() == command) {
63		let name = para.binary().to_string();
64		let source =
65			para.source()?.resolve(&name, version, cache, |f| prefix(f, &name)).await.into();
66		let binary = Binary::Source { name, source, cache: cache.to_path_buf() };
67		return Ok(Some(super::Chain {
68			id,
69			binary,
70			chain: chain.map(|c| c.to_string()),
71			chain_spec_generator: None,
72		}));
73	}
74	Ok(None)
75}
76
77#[cfg(test)]
78mod tests {
79	use super::*;
80	use crate::up::tests::{FALLBACK, RELAY_BINARY_VERSION, SYSTEM_PARA_BINARY_VERSION};
81	use pop_common::{
82		polkadot_sdk::{sort_by_latest_semantic_version, sort_by_latest_stable_version},
83		sourcing::{ArchiveFileSpec, GitHub::ReleaseArchive, Source},
84		target,
85	};
86	use std::path::PathBuf;
87	use tempfile::tempdir;
88
89	#[tokio::test]
90	async fn system_matches_command() -> anyhow::Result<()> {
91		assert!(
92			system(
93				1000,
94				"polkadot",
95				None,
96				None,
97				RELAY_BINARY_VERSION,
98				Some("asset-hub-paseo-local"),
99				tempdir()?.path()
100			)
101			.await?
102			.is_none()
103		);
104		Ok(())
105	}
106
107	#[tokio::test]
108	async fn system_using_relay_version() -> anyhow::Result<()> {
109		let expected = &System;
110		let para_id = 1000;
111
112		let temp_dir = tempdir()?;
113		let parachain = system(
114			para_id,
115			expected.binary(),
116			None,
117			None,
118			RELAY_BINARY_VERSION,
119			None,
120			temp_dir.path(),
121		)
122		.await?
123		.unwrap();
124		assert_eq!(para_id, parachain.id);
125		assert!(matches!(parachain.binary, Binary::Source { name, source, cache }
126			if name == expected.binary() && source == Source::GitHub(ReleaseArchive {
127					owner: "r0gue-io".to_string(),
128					repository: "polkadot".to_string(),
129					tag: Some(format!("polkadot-{RELAY_BINARY_VERSION}")),
130					tag_pattern: Some("polkadot-{version}".into()),
131					prerelease: false,
132					version_comparator: sort_by_latest_stable_version,
133					fallback: FALLBACK.into(),
134					archive: format!("{name}-{}.tar.gz", target()?),
135					contents: vec![ArchiveFileSpec::new(expected.binary().into(), None, true)],
136					latest: parachain.binary.latest().map(|l| l.to_string()),
137				}).into() && cache == temp_dir.path()
138		));
139		Ok(())
140	}
141
142	#[tokio::test]
143	async fn system_works() -> anyhow::Result<()> {
144		let expected = &System;
145		let para_id = 1000;
146
147		let temp_dir = tempdir()?;
148		let parachain = system(
149			para_id,
150			expected.binary(),
151			Some(SYSTEM_PARA_BINARY_VERSION),
152			None,
153			RELAY_BINARY_VERSION,
154			None,
155			temp_dir.path(),
156		)
157		.await?
158		.unwrap();
159		assert_eq!(para_id, parachain.id);
160		assert!(matches!(parachain.binary, Binary::Source { name, source, cache }
161			if name == expected.binary() && source == Source::GitHub(ReleaseArchive {
162					owner: "r0gue-io".to_string(),
163					repository: "polkadot".to_string(),
164					tag: Some(format!("polkadot-{SYSTEM_PARA_BINARY_VERSION}")),
165					tag_pattern: Some("polkadot-{version}".into()),
166					prerelease: false,
167					version_comparator: sort_by_latest_stable_version,
168					fallback: FALLBACK.into(),
169					archive: format!("{name}-{}.tar.gz", target()?),
170					contents: vec![ArchiveFileSpec::new(expected.binary().into(), None, true)],
171					latest: parachain.binary.latest().map(|l| l.to_string()),
172				}).into() && cache == temp_dir.path()
173		));
174		Ok(())
175	}
176
177	#[tokio::test]
178	async fn system_with_chain_spec_generator_works() -> anyhow::Result<()> {
179		let expected = System;
180		let runtime_version = "v1.3.3";
181		let para_id = 1000;
182
183		let temp_dir = tempdir()?;
184		let parachain = system(
185			para_id,
186			expected.binary(),
187			None,
188			Some(runtime_version),
189			RELAY_BINARY_VERSION,
190			Some("asset-hub-paseo-local"),
191			temp_dir.path(),
192		)
193		.await?
194		.unwrap();
195		assert_eq!(parachain.id, para_id);
196		assert_eq!(parachain.chain.unwrap(), "asset-hub-paseo-local");
197		let chain_spec_generator = parachain.chain_spec_generator.unwrap();
198		assert!(matches!(chain_spec_generator, Binary::Source { name, source, cache }
199			if name == "paseo-chain-spec-generator" && source == Source::GitHub(ReleaseArchive {
200					owner: "r0gue-io".to_string(),
201					repository: "paseo-runtimes".to_string(),
202					tag: Some(runtime_version.to_string()),
203					tag_pattern: None,
204					prerelease: false,
205					version_comparator: sort_by_latest_semantic_version,
206					fallback: "v1.4.1".into(),
207					archive: format!("chain-spec-generator-{}.tar.gz", target()?),
208					contents: [ArchiveFileSpec::new("chain-spec-generator".into(), Some("paseo-chain-spec-generator".into()), true)].to_vec(),
209					latest: chain_spec_generator.latest().map(|l| l.to_string()),
210				}).into() && cache == temp_dir.path()
211		));
212		Ok(())
213	}
214
215	#[tokio::test]
216	async fn pop_works() -> anyhow::Result<()> {
217		let version = "v0.3.0";
218		let expected = "pop-node";
219		let para_id = 2000;
220
221		let temp_dir = tempdir()?;
222		let parachain =
223			from(&Relay::Paseo, para_id, expected, Some(version), None, temp_dir.path())
224				.await?
225				.unwrap();
226		assert_eq!(para_id, parachain.id);
227		assert!(matches!(parachain.binary, Binary::Source { name, source, cache }
228			if name == expected && source == Source::GitHub(ReleaseArchive {
229					owner: "r0gue-io".to_string(),
230					repository: "pop-node".to_string(),
231					tag: Some(format!("node-{version}")),
232					tag_pattern: Some("node-{version}".into()),
233					prerelease: false,
234					version_comparator: sort_by_latest_semantic_version,
235					fallback: "v0.3.0".into(),
236					archive: format!("{name}-{}.tar.gz", target()?),
237					contents: vec![ArchiveFileSpec::new(expected.into(), None, true)],
238					latest: parachain.binary.latest().map(|l| l.to_string()),
239				}).into() && cache == temp_dir.path()
240		));
241		Ok(())
242	}
243
244	#[tokio::test]
245	async fn from_handles_unsupported_command() -> anyhow::Result<()> {
246		assert!(
247			from(&Relay::Paseo, 2000, "none", None, None, &PathBuf::default())
248				.await?
249				.is_none()
250		);
251		Ok(())
252	}
253}