diff --git a/Cargo.lock b/Cargo.lock index c878bd60cfb7d1e4f1e39f0c9ec3a3a9224e4211..3eaa7c24e30becf7cedbc628df31d6f4f597e707 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12236,6 +12236,7 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", + "serde_json", "smallvec", "sp-api", "sp-block-builder", diff --git a/prdoc/pr_4739.prdoc b/prdoc/pr_4739.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9ca230e3e763ea3aca0ca598187d8e380c038607 --- /dev/null +++ b/prdoc/pr_4739.prdoc @@ -0,0 +1,15 @@ +title: parachain-template - genesis config presets added + +doc: + - audience: Node Dev + description: | + - common DEV_RUNTIME_PRESET ("development") const added to sp-genesis-builder. + - parachain-templates are now using presets. + +crates: + - name: sp-genesis-builder + bump: minor + - name: parachain-template-node + bump: patch + - name: parachain-template-runtime + bump: patch diff --git a/substrate/primitives/genesis-builder/src/lib.rs b/substrate/primitives/genesis-builder/src/lib.rs index 2cbac305b4d97438389b288c804152462769501e..b33609464fc192d69fda8b0d19f6ddc5ed237916 100644 --- a/substrate/primitives/genesis-builder/src/lib.rs +++ b/substrate/primitives/genesis-builder/src/lib.rs @@ -62,6 +62,10 @@ pub type Result = core::result::Result<(), sp_runtime::RuntimeString>; /// The type representing preset ID. pub type PresetId = sp_runtime::RuntimeString; +/// The default `development` preset used to communicate with the runtime via +/// [`GenesisBuilder`] interface. +pub const DEV_RUNTIME_PRESET: &'static str = "development"; + sp_api::decl_runtime_apis! { /// API to interact with RuntimeGenesisConfig for the runtime pub trait GenesisBuilder { diff --git a/templates/parachain/node/src/chain_spec.rs b/templates/parachain/node/src/chain_spec.rs index 3fa91c0261622cd71dbf2b473eb70748f3a29b96..cd02bca466ff2f2fd8e0371f6730877f94e33ade 100644 --- a/templates/parachain/node/src/chain_spec.rs +++ b/templates/parachain/node/src/chain_spec.rs @@ -1,25 +1,11 @@ -use cumulus_primitives_core::ParaId; use parachain_template_runtime as runtime; -use runtime::{AccountId, AuraId, Signature, EXISTENTIAL_DEPOSIT}; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; -use sp_core::{sr25519, Pair, Public}; -use sp_runtime::traits::{IdentifyAccount, Verify}; /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec<Extensions>; -/// The default XCM version to set in genesis config. -const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; - -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - /// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] pub struct Extensions { @@ -38,30 +24,6 @@ impl Extensions { } } -type AccountPublic = <Signature as Verify>::Signer; - -/// Generate collator keys from seed. -/// -/// This function's return type must always match the session keys of the chain in tuple format. -pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { - get_from_seed::<AuraId>(seed) -} - -/// Helper function to generate an account ID from seed -pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId -where - AccountPublic: From<<TPublic::Pair as Pair>::Public>, -{ - AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account() -} - -/// Generate the session keys from individual elements. -/// -/// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn template_session_keys(keys: AuraId) -> runtime::SessionKeys { - runtime::SessionKeys { aura: keys } -} - pub fn development_config() -> ChainSpec { // Give your base currency a unit name and decimal places let mut properties = sc_chain_spec::Properties::new(); @@ -80,35 +42,7 @@ pub fn development_config() -> ChainSpec { .with_name("Development") .with_id("dev") .with_chain_type(ChainType::Development) - .with_genesis_config_patch(testnet_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::<sr25519::Public>("Alice"), - get_collator_keys_from_seed("Alice"), - ), - ( - get_account_id_from_seed::<sr25519::Public>("Bob"), - get_collator_keys_from_seed("Bob"), - ), - ], - vec![ - get_account_id_from_seed::<sr25519::Public>("Alice"), - get_account_id_from_seed::<sr25519::Public>("Bob"), - get_account_id_from_seed::<sr25519::Public>("Charlie"), - get_account_id_from_seed::<sr25519::Public>("Dave"), - get_account_id_from_seed::<sr25519::Public>("Eve"), - get_account_id_from_seed::<sr25519::Public>("Ferdie"), - get_account_id_from_seed::<sr25519::Public>("Alice//stash"), - get_account_id_from_seed::<sr25519::Public>("Bob//stash"), - get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), - get_account_id_from_seed::<sr25519::Public>("Dave//stash"), - get_account_id_from_seed::<sr25519::Public>("Eve//stash"), - get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), - ], - get_account_id_from_seed::<sr25519::Public>("Alice"), - 1000.into(), - )) + .with_genesis_config_preset_name("development") .build() } @@ -131,72 +65,8 @@ pub fn local_testnet_config() -> ChainSpec { .with_name("Local Testnet") .with_id("local_testnet") .with_chain_type(ChainType::Local) - .with_genesis_config_patch(testnet_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::<sr25519::Public>("Alice"), - get_collator_keys_from_seed("Alice"), - ), - ( - get_account_id_from_seed::<sr25519::Public>("Bob"), - get_collator_keys_from_seed("Bob"), - ), - ], - vec![ - get_account_id_from_seed::<sr25519::Public>("Alice"), - get_account_id_from_seed::<sr25519::Public>("Bob"), - get_account_id_from_seed::<sr25519::Public>("Charlie"), - get_account_id_from_seed::<sr25519::Public>("Dave"), - get_account_id_from_seed::<sr25519::Public>("Eve"), - get_account_id_from_seed::<sr25519::Public>("Ferdie"), - get_account_id_from_seed::<sr25519::Public>("Alice//stash"), - get_account_id_from_seed::<sr25519::Public>("Bob//stash"), - get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), - get_account_id_from_seed::<sr25519::Public>("Dave//stash"), - get_account_id_from_seed::<sr25519::Public>("Eve//stash"), - get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), - ], - get_account_id_from_seed::<sr25519::Public>("Alice"), - 1000.into(), - )) + .with_genesis_config_preset_name("local_testnet") .with_protocol_id("template-local") .with_properties(properties) .build() } - -fn testnet_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec<AccountId>, - root: AccountId, - id: ParaId, -) -> serde_json::Value { - serde_json::json!({ - "balances": { - "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(), - "candidacyBond": EXISTENTIAL_DEPOSIT * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - template_session_keys(aura), // session keys - ) - }) - .collect::<Vec<_>>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "sudo": { "key": Some(root) } - }) -} diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 939fa245d2a0c1b6e03ecd0541a2b9aa63af75bd..45c77d18e8167ba2a63e5549e4e8019f0887360d 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -27,6 +27,7 @@ scale-info = { features = [ ], workspace = true } smallvec = { workspace = true, default-features = true } docify = { workspace = true } +serde_json = { workspace = true, default-features = false } # Local pallet-parachain-template = { workspace = true } @@ -126,6 +127,7 @@ std = [ "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", + "serde_json/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs index f5d5d3e63027be2d7cdb20fb24bb4c6dcf3c25c9..243db1b6dde0c27e87b9c4c50dddc5aa2c4c2ef8 100644 --- a/templates/parachain/runtime/src/apis.rs +++ b/templates/parachain/runtime/src/apis.rs @@ -295,11 +295,11 @@ impl_runtime_apis! { } fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> { - get_preset::<RuntimeGenesisConfig>(id, |_| None) + get_preset::<RuntimeGenesisConfig>(id, crate::genesis_config_presets::get_preset) } fn preset_names() -> Vec<sp_genesis_builder::PresetId> { - Default::default() + crate::genesis_config_presets::preset_names() } } } diff --git a/templates/parachain/runtime/src/genesis_config_presets.rs b/templates/parachain/runtime/src/genesis_config_presets.rs new file mode 100644 index 0000000000000000000000000000000000000000..80b763d5bd854c81234645de161982db63e7d299 --- /dev/null +++ b/templates/parachain/runtime/src/genesis_config_presets.rs @@ -0,0 +1,169 @@ +use cumulus_primitives_core::ParaId; + +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; + +use crate::{AccountId, SessionKeys, Signature, EXISTENTIAL_DEPOSIT}; +use alloc::{format, vec, vec::Vec}; +use serde_json::Value; +use sp_core::{sr25519, Pair, Public}; +use sp_genesis_builder::PresetId; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +/// Preset configuration name for a local testnet environment. +pub const PRESET_LOCAL_TESTNET: &str = "local_testnet"; + +type AccountPublic = <Signature as Verify>::Signer; + +/// The default XCM version to set in genesis config. +const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; + +/// Helper function to generate a crypto pair from seed +pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +/// Generate collator keys from seed. +/// +/// This function's return type must always match the session keys of the chain in tuple format. +pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { + get_from_seed::<AuraId>(seed) +} + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId +where + AccountPublic: From<<TPublic::Pair as Pair>::Public>, +{ + AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account() +} + +/// Generate the session keys from individual elements. +/// +/// The input must be a tuple of individual keys (a single arg for now since we have just one key). +pub fn template_session_keys(keys: AuraId) -> SessionKeys { + SessionKeys { aura: keys } +} + +fn testnet_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec<AccountId>, + root: AccountId, + id: ParaId, +) -> Value { + serde_json::json!({ + "balances": { + "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(), + }, + "parachainInfo": { + "parachainId": id, + }, + "collatorSelection": { + "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(), + "candidacyBond": EXISTENTIAL_DEPOSIT * 16, + }, + "session": { + "keys": invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + template_session_keys(aura), // session keys + ) + }) + .collect::<Vec<_>>(), + }, + "polkadotXcm": { + "safeXcmVersion": Some(SAFE_XCM_VERSION), + }, + "sudo": { "key": Some(root) } + }) +} + +fn local_testnet_genesis() -> Value { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_account_id_from_seed::<sr25519::Public>("Charlie"), + get_account_id_from_seed::<sr25519::Public>("Dave"), + get_account_id_from_seed::<sr25519::Public>("Eve"), + get_account_id_from_seed::<sr25519::Public>("Ferdie"), + get_account_id_from_seed::<sr25519::Public>("Alice//stash"), + get_account_id_from_seed::<sr25519::Public>("Bob//stash"), + get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), + get_account_id_from_seed::<sr25519::Public>("Dave//stash"), + get_account_id_from_seed::<sr25519::Public>("Eve//stash"), + get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), + ], + get_account_id_from_seed::<sr25519::Public>("Alice"), + 1000.into(), + ) +} + +fn development_config_genesis() -> Value { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_account_id_from_seed::<sr25519::Public>("Charlie"), + get_account_id_from_seed::<sr25519::Public>("Dave"), + get_account_id_from_seed::<sr25519::Public>("Eve"), + get_account_id_from_seed::<sr25519::Public>("Ferdie"), + get_account_id_from_seed::<sr25519::Public>("Alice//stash"), + get_account_id_from_seed::<sr25519::Public>("Bob//stash"), + get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), + get_account_id_from_seed::<sr25519::Public>("Dave//stash"), + get_account_id_from_seed::<sr25519::Public>("Eve//stash"), + get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), + ], + get_account_id_from_seed::<sr25519::Public>("Alice"), + 1000.into(), + ) +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &PresetId) -> Option<vec::Vec<u8>> { + let patch = match id.try_into() { + Ok(PRESET_LOCAL_TESTNET) => local_testnet_genesis(), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => development_config_genesis(), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec<PresetId> { + vec![ + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(PRESET_LOCAL_TESTNET), + ] +} diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 55714a1248138f64f741caa3c7f4f93d91de7e12..83ae15700a94f0c941420a81f672ce7da224b1f9 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -10,6 +10,7 @@ pub mod apis; #[cfg(feature = "runtime-benchmarks")] mod benchmarks; pub mod configs; +mod genesis_config_presets; mod weights; extern crate alloc;