Skip to content

Commit f8807d1

Browse files
authored
templates: add genesis config presets for minimal/solochain (#5868)
# Description Closes [#5790](#5790). Useful for starting nodes based on minimal/solochain when doing development or for testing omni node with less happy code paths. It is reusing the presets defined for the nodes chain specs. ## Integration Specifically useful for development/testing if generating chain-specs for `minimal` or `solochain` runtimes from `templates` directories. ## Review Notes Added `genesis_config_presets` modules for both minimal/solochain. I reused the presets defined in each node `chain_spec` module correspondingly. ### PRDOC Not sure who uses templates, maybe node devs and runtime devs at start of their learning journey, but happy to get some guidance on how to write the prdoc if needed. ### Thinking out loud I saw concerns around sharing functionality for such genesis config presets between the template chains. I think there might be a case for doing that, on the lines of this comment: #4739 (comment). I would add that `parachains-common::genesis_config_heleper` contains a few methods from those mentioned, but I am unsure if using it as a dependency for templates is correct. Feels like the comment suggests there should be a `commons` crate concerning just `templates`, which I agree with to some degree, if we assume `cumulus` needs might be driven in certain directions that are not relevant to `templates` and vice versa. However I am not so certain about this, so would welcome some thoughts, since I am seeing `parachains-common` being used already in a few runtime implementations: https://crates.io/crates/parachains-common/reverse_dependencies?page=3, so might be a good candidate already for the `common` logic. --------- Signed-off-by: Iulian Barbu <iulian.barbu@parity.io>
1 parent dada6ce commit f8807d1

15 files changed

Lines changed: 197 additions & 130 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

templates/minimal/node/src/chain_spec.rs

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515
// See the License for the specific language governing permissions and
1616
// limitations under the License.
1717

18-
use minimal_template_runtime::{BalancesConfig, SudoConfig, WASM_BINARY};
18+
use minimal_template_runtime::WASM_BINARY;
1919
use polkadot_sdk::{
2020
sc_service::{ChainType, Properties},
21-
sp_keyring::AccountKeyring,
2221
*,
2322
};
24-
use serde_json::{json, Value};
2523

2624
/// This is a specialization of the general Substrate ChainSpec type.
2725
pub type ChainSpec = sc_service::GenericChainSpec;
@@ -33,26 +31,12 @@ fn props() -> Properties {
3331
properties
3432
}
3533

36-
pub fn development_config() -> Result<ChainSpec, String> {
34+
pub fn development_chain_spec() -> Result<ChainSpec, String> {
3735
Ok(ChainSpec::builder(WASM_BINARY.expect("Development wasm not available"), Default::default())
3836
.with_name("Development")
3937
.with_id("dev")
4038
.with_chain_type(ChainType::Development)
41-
.with_genesis_config_patch(testnet_genesis())
39+
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
4240
.with_properties(props())
4341
.build())
4442
}
45-
46-
/// Configure initial storage state for FRAME pallets.
47-
fn testnet_genesis() -> Value {
48-
use minimal_template_runtime::interface::{Balance, MinimumBalance};
49-
use polkadot_sdk::polkadot_sdk_frame::traits::Get;
50-
let endowment = <MinimumBalance as Get<Balance>>::get().max(1) * 1000;
51-
let balances = AccountKeyring::iter()
52-
.map(|a| (a.to_account_id(), endowment))
53-
.collect::<Vec<_>>();
54-
json!({
55-
"balances": BalancesConfig { balances },
56-
"sudo": SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) },
57-
})
58-
}

templates/minimal/node/src/command.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl SubstrateCli for Cli {
4949

5050
fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
5151
Ok(match id {
52-
"dev" => Box::new(chain_spec::development_config()?),
52+
"dev" => Box::new(chain_spec::development_chain_spec()?),
5353
path =>
5454
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
5555
})

templates/minimal/runtime/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ polkadot-sdk = { workspace = true, features = [
2121
"pallet-transaction-payment-rpc-runtime-api",
2222
"runtime",
2323
] }
24+
serde_json = { workspace = true, default-features = false, features = ["alloc"] }
2425

2526
# local pallet templates
2627
pallet-minimal-template = { workspace = true }
@@ -37,4 +38,5 @@ std = [
3738
"pallet-minimal-template/std",
3839
"polkadot-sdk/std",
3940
"scale-info/std",
41+
"serde_json/std",
4042
]

templates/minimal/runtime/src/lib.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
2525

2626
extern crate alloc;
2727

28-
use alloc::{vec, vec::Vec};
28+
use alloc::vec::Vec;
2929
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
3030
use polkadot_sdk::{
3131
polkadot_sdk_frame::{
@@ -36,6 +36,54 @@ use polkadot_sdk::{
3636
*,
3737
};
3838

39+
/// Provides getters for genesis configuration presets.
40+
pub mod genesis_config_presets {
41+
use crate::{
42+
interface::{Balance, MinimumBalance},
43+
sp_genesis_builder::PresetId,
44+
sp_keyring::AccountKeyring,
45+
BalancesConfig, RuntimeGenesisConfig, SudoConfig,
46+
};
47+
48+
use alloc::{vec, vec::Vec};
49+
use polkadot_sdk::{sp_core::Get, sp_genesis_builder};
50+
use serde_json::Value;
51+
52+
/// Returns a development genesis config preset.
53+
pub fn development_config_genesis() -> Value {
54+
let endowment = <MinimumBalance as Get<Balance>>::get().max(1) * 1000;
55+
let config = RuntimeGenesisConfig {
56+
balances: BalancesConfig {
57+
balances: AccountKeyring::iter()
58+
.map(|a| (a.to_account_id(), endowment))
59+
.collect::<Vec<_>>(),
60+
},
61+
sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) },
62+
..Default::default()
63+
};
64+
65+
serde_json::to_value(config).expect("Could not build genesis config.")
66+
}
67+
68+
/// Get the set of the available genesis config presets.
69+
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
70+
let patch = match id.try_into() {
71+
Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => development_config_genesis(),
72+
_ => return None,
73+
};
74+
Some(
75+
serde_json::to_string(&patch)
76+
.expect("serialization to json is expected to work. qed.")
77+
.into_bytes(),
78+
)
79+
}
80+
81+
/// List of supported presets.
82+
pub fn preset_names() -> Vec<PresetId> {
83+
vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
84+
}
85+
}
86+
3987
/// The runtime version.
4088
#[runtime_version]
4189
pub const VERSION: RuntimeVersion = RuntimeVersion {
@@ -272,11 +320,11 @@ impl_runtime_apis! {
272320
}
273321

274322
fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
275-
get_preset::<RuntimeGenesisConfig>(id, |_| None)
323+
get_preset::<RuntimeGenesisConfig>(id, self::genesis_config_presets::get_preset)
276324
}
277325

278326
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
279-
vec![]
327+
self::genesis_config_presets::preset_names()
280328
}
281329
}
282330
}

templates/parachain/node/src/chain_spec.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl Extensions {
2424
}
2525
}
2626

27-
pub fn development_config() -> ChainSpec {
27+
pub fn development_chain_spec() -> ChainSpec {
2828
// Give your base currency a unit name and decimal places
2929
let mut properties = sc_chain_spec::Properties::new();
3030
properties.insert("tokenSymbol".into(), "UNIT".into());
@@ -46,7 +46,7 @@ pub fn development_config() -> ChainSpec {
4646
.build()
4747
}
4848

49-
pub fn local_testnet_config() -> ChainSpec {
49+
pub fn local_chain_spec() -> ChainSpec {
5050
// Give your base currency a unit name and decimal places
5151
let mut properties = sc_chain_spec::Properties::new();
5252
properties.insert("tokenSymbol".into(), "UNIT".into());

templates/parachain/node/src/command.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use crate::{
1717

1818
fn load_spec(id: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
1919
Ok(match id {
20-
"dev" => Box::new(chain_spec::development_config()),
21-
"template-rococo" => Box::new(chain_spec::local_testnet_config()),
22-
"" | "local" => Box::new(chain_spec::local_testnet_config()),
20+
"dev" => Box::new(chain_spec::development_chain_spec()),
21+
"template-rococo" => Box::new(chain_spec::local_chain_spec()),
22+
"" | "local" => Box::new(chain_spec::local_chain_spec()),
2323
path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
2424
})
2525
}

templates/parachain/runtime/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ scale-info = { features = [
2727
], workspace = true }
2828
smallvec = { workspace = true, default-features = true }
2929
docify = { workspace = true }
30-
serde_json = { workspace = true, default-features = false }
30+
serde_json = { workspace = true, default-features = false, features = ["alloc"] }
3131

3232
# Local
3333
pallet-parachain-template = { workspace = true }

templates/solochain/node/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ sp-consensus-aura = { workspace = true, default-features = true }
3535
sc-consensus = { workspace = true, default-features = true }
3636
sc-consensus-grandpa = { workspace = true, default-features = true }
3737
sp-consensus-grandpa = { workspace = true, default-features = true }
38+
sp-genesis-builder = { workspace = true, default-features = true }
3839
sc-client-api = { workspace = true, default-features = true }
3940
sc-basic-authorship = { workspace = true, default-features = true }
4041

@@ -66,9 +67,7 @@ substrate-build-script-utils = { workspace = true, default-features = true }
6667

6768
[features]
6869
default = ["std"]
69-
std = [
70-
"solochain-template-runtime/std",
71-
]
70+
std = ["solochain-template-runtime/std"]
7271
# Dependencies that are only required if runtime benchmarking should be build.
7372
runtime-benchmarks = [
7473
"frame-benchmarking-cli/runtime-benchmarks",
Lines changed: 5 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,29 @@
11
use sc_service::ChainType;
2-
use solochain_template_runtime::{AccountId, Signature, WASM_BINARY};
3-
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
4-
use sp_consensus_grandpa::AuthorityId as GrandpaId;
5-
use sp_core::{sr25519, Pair, Public};
6-
use sp_runtime::traits::{IdentifyAccount, Verify};
7-
8-
// The URL for the telemetry server.
9-
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
2+
use solochain_template_runtime::WASM_BINARY;
103

114
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
125
pub type ChainSpec = sc_service::GenericChainSpec;
136

14-
/// Generate a crypto pair from seed.
15-
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
16-
TPublic::Pair::from_string(&format!("//{}", seed), None)
17-
.expect("static values are valid; qed")
18-
.public()
19-
}
20-
21-
type AccountPublic = <Signature as Verify>::Signer;
22-
23-
/// Generate an account ID from seed.
24-
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
25-
where
26-
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
27-
{
28-
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
29-
}
30-
31-
/// Generate an Aura authority key.
32-
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
33-
(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
34-
}
35-
36-
pub fn development_config() -> Result<ChainSpec, String> {
7+
pub fn development_chain_spec() -> Result<ChainSpec, String> {
378
Ok(ChainSpec::builder(
389
WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
3910
None,
4011
)
4112
.with_name("Development")
4213
.with_id("dev")
4314
.with_chain_type(ChainType::Development)
44-
.with_genesis_config_patch(testnet_genesis(
45-
// Initial PoA authorities
46-
vec![authority_keys_from_seed("Alice")],
47-
// Sudo account
48-
get_account_id_from_seed::<sr25519::Public>("Alice"),
49-
// Pre-funded accounts
50-
vec![
51-
get_account_id_from_seed::<sr25519::Public>("Alice"),
52-
get_account_id_from_seed::<sr25519::Public>("Bob"),
53-
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
54-
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
55-
],
56-
true,
57-
))
15+
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
5816
.build())
5917
}
6018

61-
pub fn local_testnet_config() -> Result<ChainSpec, String> {
19+
pub fn local_chain_spec() -> Result<ChainSpec, String> {
6220
Ok(ChainSpec::builder(
6321
WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
6422
None,
6523
)
6624
.with_name("Local Testnet")
6725
.with_id("local_testnet")
6826
.with_chain_type(ChainType::Local)
69-
.with_genesis_config_patch(testnet_genesis(
70-
// Initial PoA authorities
71-
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
72-
// Sudo account
73-
get_account_id_from_seed::<sr25519::Public>("Alice"),
74-
// Pre-funded accounts
75-
vec![
76-
get_account_id_from_seed::<sr25519::Public>("Alice"),
77-
get_account_id_from_seed::<sr25519::Public>("Bob"),
78-
get_account_id_from_seed::<sr25519::Public>("Charlie"),
79-
get_account_id_from_seed::<sr25519::Public>("Dave"),
80-
get_account_id_from_seed::<sr25519::Public>("Eve"),
81-
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
82-
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
83-
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
84-
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
85-
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
86-
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
87-
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
88-
],
89-
true,
90-
))
27+
.with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
9128
.build())
9229
}
93-
94-
/// Configure initial storage state for FRAME modules.
95-
fn testnet_genesis(
96-
initial_authorities: Vec<(AuraId, GrandpaId)>,
97-
root_key: AccountId,
98-
endowed_accounts: Vec<AccountId>,
99-
_enable_println: bool,
100-
) -> serde_json::Value {
101-
serde_json::json!({
102-
"balances": {
103-
// Configure endowed accounts with initial balance of 1 << 60.
104-
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
105-
},
106-
"aura": {
107-
"authorities": initial_authorities.iter().map(|x| (x.0.clone())).collect::<Vec<_>>(),
108-
},
109-
"grandpa": {
110-
"authorities": initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::<Vec<_>>(),
111-
},
112-
"sudo": {
113-
// Assign network admin rights.
114-
"key": Some(root_key),
115-
},
116-
})
117-
}

0 commit comments

Comments
 (0)