Skip to content

Commit

Permalink
templates: add genesis config presets for minimal/solochain (#5868)
Browse files Browse the repository at this point in the history
# 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 <[email protected]>
  • Loading branch information
iulianbarbu authored Oct 5, 2024
1 parent dada6ce commit f8807d1
Show file tree
Hide file tree
Showing 15 changed files with 197 additions and 130 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 3 additions & 19 deletions templates/minimal/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use minimal_template_runtime::{BalancesConfig, SudoConfig, WASM_BINARY};
use minimal_template_runtime::WASM_BINARY;
use polkadot_sdk::{
sc_service::{ChainType, Properties},
sp_keyring::AccountKeyring,
*,
};
use serde_json::{json, Value};

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

pub fn development_config() -> Result<ChainSpec, String> {
pub fn development_chain_spec() -> Result<ChainSpec, String> {
Ok(ChainSpec::builder(WASM_BINARY.expect("Development wasm not available"), Default::default())
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(testnet_genesis())
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
.with_properties(props())
.build())
}

/// Configure initial storage state for FRAME pallets.
fn testnet_genesis() -> Value {
use minimal_template_runtime::interface::{Balance, MinimumBalance};
use polkadot_sdk::polkadot_sdk_frame::traits::Get;
let endowment = <MinimumBalance as Get<Balance>>::get().max(1) * 1000;
let balances = AccountKeyring::iter()
.map(|a| (a.to_account_id(), endowment))
.collect::<Vec<_>>();
json!({
"balances": BalancesConfig { balances },
"sudo": SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) },
})
}
2 changes: 1 addition & 1 deletion templates/minimal/node/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl SubstrateCli for Cli {

fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_config()?),
"dev" => Box::new(chain_spec::development_chain_spec()?),
path =>
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
Expand Down
2 changes: 2 additions & 0 deletions templates/minimal/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ polkadot-sdk = { workspace = true, features = [
"pallet-transaction-payment-rpc-runtime-api",
"runtime",
] }
serde_json = { workspace = true, default-features = false, features = ["alloc"] }

# local pallet templates
pallet-minimal-template = { workspace = true }
Expand All @@ -37,4 +38,5 @@ std = [
"pallet-minimal-template/std",
"polkadot-sdk/std",
"scale-info/std",
"serde_json/std",
]
54 changes: 51 additions & 3 deletions templates/minimal/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

extern crate alloc;

use alloc::{vec, vec::Vec};
use alloc::vec::Vec;
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use polkadot_sdk::{
polkadot_sdk_frame::{
Expand All @@ -36,6 +36,54 @@ use polkadot_sdk::{
*,
};

/// Provides getters for genesis configuration presets.
pub mod genesis_config_presets {
use crate::{
interface::{Balance, MinimumBalance},
sp_genesis_builder::PresetId,
sp_keyring::AccountKeyring,
BalancesConfig, RuntimeGenesisConfig, SudoConfig,
};

use alloc::{vec, vec::Vec};
use polkadot_sdk::{sp_core::Get, sp_genesis_builder};
use serde_json::Value;

/// Returns a development genesis config preset.
pub fn development_config_genesis() -> Value {
let endowment = <MinimumBalance as Get<Balance>>::get().max(1) * 1000;
let config = RuntimeGenesisConfig {
balances: BalancesConfig {
balances: AccountKeyring::iter()
.map(|a| (a.to_account_id(), endowment))
.collect::<Vec<_>>(),
},
sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) },
..Default::default()
};

serde_json::to_value(config).expect("Could not build genesis config.")
}

/// Get the set of the available genesis config presets.
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
let patch = match id.try_into() {
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)]
}
}

/// The runtime version.
#[runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
Expand Down Expand Up @@ -272,11 +320,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, self::genesis_config_presets::get_preset)
}

fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
vec![]
self::genesis_config_presets::preset_names()
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions templates/parachain/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Extensions {
}
}

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

pub fn local_testnet_config() -> ChainSpec {
pub fn local_chain_spec() -> ChainSpec {
// Give your base currency a unit name and decimal places
let mut properties = sc_chain_spec::Properties::new();
properties.insert("tokenSymbol".into(), "UNIT".into());
Expand Down
6 changes: 3 additions & 3 deletions templates/parachain/node/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use crate::{

fn load_spec(id: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_config()),
"template-rococo" => Box::new(chain_spec::local_testnet_config()),
"" | "local" => Box::new(chain_spec::local_testnet_config()),
"dev" => Box::new(chain_spec::development_chain_spec()),
"template-rococo" => Box::new(chain_spec::local_chain_spec()),
"" | "local" => Box::new(chain_spec::local_chain_spec()),
path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
Expand Down
2 changes: 1 addition & 1 deletion templates/parachain/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ scale-info = { features = [
], workspace = true }
smallvec = { workspace = true, default-features = true }
docify = { workspace = true }
serde_json = { workspace = true, default-features = false }
serde_json = { workspace = true, default-features = false, features = ["alloc"] }

# Local
pallet-parachain-template = { workspace = true }
Expand Down
5 changes: 2 additions & 3 deletions templates/solochain/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ sp-consensus-aura = { workspace = true, default-features = true }
sc-consensus = { workspace = true, default-features = true }
sc-consensus-grandpa = { workspace = true, default-features = true }
sp-consensus-grandpa = { workspace = true, default-features = true }
sp-genesis-builder = { workspace = true, default-features = true }
sc-client-api = { workspace = true, default-features = true }
sc-basic-authorship = { workspace = true, default-features = true }

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

[features]
default = ["std"]
std = [
"solochain-template-runtime/std",
]
std = ["solochain-template-runtime/std"]
# Dependencies that are only required if runtime benchmarking should be build.
runtime-benchmarks = [
"frame-benchmarking-cli/runtime-benchmarks",
Expand Down
98 changes: 5 additions & 93 deletions templates/solochain/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
@@ -1,117 +1,29 @@
use sc_service::ChainType;
use solochain_template_runtime::{AccountId, Signature, WASM_BINARY};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};

// The URL for the telemetry server.
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
use solochain_template_runtime::WASM_BINARY;

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

/// 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()
}

type AccountPublic = <Signature as Verify>::Signer;

/// 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 an Aura authority key.
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
}

pub fn development_config() -> Result<ChainSpec, String> {
pub fn development_chain_spec() -> Result<ChainSpec, String> {
Ok(ChainSpec::builder(
WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
None,
)
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(testnet_genesis(
// Initial PoA authorities
vec![authority_keys_from_seed("Alice")],
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
],
true,
))
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
.build())
}

pub fn local_testnet_config() -> Result<ChainSpec, String> {
pub fn local_chain_spec() -> Result<ChainSpec, String> {
Ok(ChainSpec::builder(
WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
None,
)
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(testnet_genesis(
// Initial PoA authorities
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
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"),
],
true,
))
.with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
.build())
}

/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
initial_authorities: Vec<(AuraId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool,
) -> serde_json::Value {
serde_json::json!({
"balances": {
// Configure endowed accounts with initial balance of 1 << 60.
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
"aura": {
"authorities": initial_authorities.iter().map(|x| (x.0.clone())).collect::<Vec<_>>(),
},
"grandpa": {
"authorities": initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::<Vec<_>>(),
},
"sudo": {
// Assign network admin rights.
"key": Some(root_key),
},
})
}
4 changes: 2 additions & 2 deletions templates/solochain/node/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ impl SubstrateCli for Cli {

fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_config()?),
"" | "local" => Box::new(chain_spec::local_testnet_config()?),
"dev" => Box::new(chain_spec::development_chain_spec()?),
"" | "local" => Box::new(chain_spec::local_chain_spec()?),
path =>
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
Expand Down
4 changes: 4 additions & 0 deletions templates/solochain/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ scale-info = { features = [
"derive",
"serde",
], workspace = true }
serde_json = { workspace = true, default-features = false, features = ["alloc"] }

# frame
frame-support = { features = ["experimental"], workspace = true }
Expand All @@ -45,6 +46,7 @@ sp-consensus-aura = { features = [
sp-consensus-grandpa = { features = [
"serde",
], workspace = true }
sp-keyring = { workspace = true }
sp-core = { features = [
"serde",
], workspace = true }
Expand Down Expand Up @@ -114,6 +116,8 @@ std = [
"sp-transaction-pool/std",
"sp-version/std",

"serde_json/std",
"sp-keyring/std",
"substrate-wasm-builder",
]

Expand Down
Loading

0 comments on commit f8807d1

Please sign in to comment.