Skip to content

Commit

Permalink
Merge pull request #265 from paritytech/runtime-presets
Browse files Browse the repository at this point in the history
  • Loading branch information
Moliholy authored Feb 3, 2025
2 parents 5758237 + 9c8ee37 commit 98b625b
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 8 deletions.
4 changes: 3 additions & 1 deletion Cargo.lock

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

22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,28 @@ In case the script fails to fetch the relay chain runtimes they can also be buil
./zombienet.sh build
```

### Notes regarding presets

Presets are predefined configurations that simplify initializing a chain’s genesis state. They
establish key parameters like balances, collator sets, council members, and the sudo (root) account.
By using presets, you can quickly spin up a network for testing or specialized use without manually
defining every genesis detail.

#### dev

- Minimal, local-friendly preset with default collators (e.g., “Alith” and “Balthasar”).
- Distributes tokens across several accounts for testing.
- Sets a small council and a single sudo key for convenient local control.

#### muse/mythos

- Uses two specific collators.
- Assigns different account balances for a more structured distribution.
- No council members; includes one sudo key for administration.

These presets are especially useful for quickly preparing Zombienet-based test setups or any local
development scenario without manually customizing every detail.

### Notes regarding Polkadot.js and Ethereum accounts

On Polkadot.js, when bootstraping the local network with zombienet, the normal accounts are not derived from a seed.
Expand Down
4 changes: 2 additions & 2 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ sp-runtime = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }
sp-std = { workspace = true, default-features = false }
pallet-balances = { workspace = true, default-features = false }
pallet-treasury = { workspace = true, default-features = false }

xcm = { workspace = true, default-features = false }

parachains-common = { workspace = true, default-features = false }
polkadot-primitives = { workspace = true, default-features = false }
Expand All @@ -45,6 +44,7 @@ std = [
"sp-std/std",
"account/std",
"pallet-balances/std",
"xcm/std",
]

runtime-benchmarks = [
Expand Down
31 changes: 30 additions & 1 deletion runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_core::U256;
use sp_core::{Pair, Public, U256};

use sp_runtime::{
traits::{IdentifyAccount, Verify},
Expand All @@ -17,6 +17,8 @@ use frame_support::traits::Incrementable;
//https://github.com/paritytech/cumulus/tree/master/parachains/common
pub use parachains_common::{AuraId, Balance, Block, BlockNumber, Hash};

extern crate alloc;

pub type Signature = EthereumSignature;

/// Use AccountId20 for Ethereum address
Expand Down Expand Up @@ -78,3 +80,30 @@ impl From<u16> for IncrementableU256 {
IncrementableU256(U256::from(value))
}
}

/// The default XCM version to set in genesis config.
pub 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(&alloc::format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}

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

/// 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 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)
}
2 changes: 2 additions & 0 deletions runtime/mainnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
substrate-wasm-builder = { workspace = true, optional = true }

[dependencies]
serde_json = { workspace = true }
hex-literal = { workspace = true }
log = { workspace = true, default-features = false }
parity-scale-codec = { workspace = true, default-features = false, features = [
Expand Down Expand Up @@ -102,6 +103,7 @@ polkadot-primitives = { workspace = true, default-features = false }
[features]
default = ["std"]
std = [
"serde_json/std",
"parity-scale-codec/std",
"log/std",
"scale-info/std",
Expand Down
159 changes: 157 additions & 2 deletions runtime/mainnet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,161 @@ mod benches {
);
}

pub mod genesis_config_presets {
use super::*;
use frame_support::build_struct_json_patch;
use hex_literal::hex;
use runtime_common::{get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION};
use serde_json::{to_string, Value};
use sp_core::{crypto::UncheckedInto, ecdsa};
use sp_genesis_builder::{PresetId, DEV_RUNTIME_PRESET};
use sp_runtime::Percent;

pub const MYTHOS_RUNTIME_PRESET: &str = "mythos";
pub const PARA_ID: u32 = 3369;

fn create_preset(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<(AccountId, Balance)>,
council: Vec<AccountId>,
root_key: AccountId,
id: ParaId,
) -> Value {
build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig { balances: endowed_accounts },
parachain_info: ParachainInfoConfig { parachain_id: id },
collator_staking: CollatorStakingConfig {
invulnerables: invulnerables
.iter()
.cloned()
.map(|(acc, _)| acc)
.collect::<Vec<_>>(),
min_candidacy_bond: 50 * MYTH,
min_stake: 10 * MYTH,
desired_candidates: 6,
collator_reward_percentage: Percent::from_parts(10),
extra_reward: 0,
},
council: CouncilConfig { members: council },
session: SessionConfig {
keys: invulnerables
.into_iter()
.map(|(acc, aura)| {
(
acc, // account id
acc, // validator id
SessionKeys { aura }, // session keys
)
})
.collect::<Vec<_>>(),
},
sudo: SudoConfig { key: Some(root_key) },
polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) },
})
}

pub fn get_builtin_preset(id: &PresetId) -> Option<Vec<u8>> {
let preset = match id.as_ref() {
DEV_RUNTIME_PRESET => {
let balance_per_account = (1_000_000_000 * MYTH).saturating_div(6);
create_preset(
vec![
(
get_account_id_from_seed::<ecdsa::Public>("Alice"),
get_collator_keys_from_seed("Alice"),
),
(
get_account_id_from_seed::<ecdsa::Public>("Bob"),
get_collator_keys_from_seed("Bob"),
),
],
vec![
(
AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")),
balance_per_account,
), // Alith
(
AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")),
balance_per_account,
), // Baltathar
(
AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")),
balance_per_account,
), // Charleth
(
AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")),
balance_per_account,
), // Dorothy
(
AccountId::from(hex!("Ff64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB")),
balance_per_account,
), // Ethan
(
AccountId::from(hex!("C0F0f4ab324C46e55D02D0033343B4Be8A55532d")),
balance_per_account,
), // Faith
],
vec![
AccountId::from(hex!("3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0")), // Baltathar
AccountId::from(hex!("798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc")), // Charleth
AccountId::from(hex!("773539d4Ac0e786233D90A233654ccEE26a613D9")), // Dorothy
],
AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")),
PARA_ID.into(),
)
},
MYTHOS_RUNTIME_PRESET => create_preset(
vec![
(
hex!("65c39EB8DDC9EA6F2135A28Ea670E97bc3CCc012").into(),
hex!("d609c361de761b4bf8ba1ae4f8e436e74e1324b0a9eac08b34e31413bbd3f27f")
.unchecked_into(),
),
(
hex!("B9717024eB621a7AE331F92C3dC63a0aB60031c5").into(),
hex!("8abe92437bf6690bc8f75cea612a5898cd2823c23681b346f776337660316979")
.unchecked_into(),
),
(
hex!("F4d1C38f3Be73d7cD2123968141Aec3AbB393153").into(),
hex!("86360126eb30d60c9232206ba78a9fafb2322958bb3a021fa88ba09dfc753802")
.unchecked_into(),
),
(
hex!("E4f607AB7fA6b5Fd4f8127E051f151DaBb7279c6").into(),
hex!("b0909f6832d2f5120b874b3e1cbe1b72fb5ccdbc268ba79bebdd8e71ab41e334")
.unchecked_into(),
),
],
vec![
(
AccountId::from(hex!("742c722892976C23A3919ADC7A4B562169B91E41")),
1_000 * MYTH,
),
(
AccountId::from(hex!("f476dA221b07135b106d923b8884b76b09982B4F")),
150_000_000 * MYTH,
),
],
vec![],
AccountId::from(hex!("742c722892976C23A3919ADC7A4B562169B91E41")),
PARA_ID.into(),
),
_ => return None,
};

Some(
to_string(&preset)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}

pub fn preset_names() -> Vec<PresetId> {
vec![PresetId::from(DEV_RUNTIME_PRESET), PresetId::from(MYTHOS_RUNTIME_PRESET)]
}
}

impl_runtime_apis! {
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
Expand Down Expand Up @@ -1172,11 +1327,11 @@ impl_runtime_apis! {
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {

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_builtin_preset)
}

fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
vec![]
crate::genesis_config_presets::preset_names()
}

fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
Expand Down
2 changes: 2 additions & 0 deletions runtime/testnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
substrate-wasm-builder = { workspace = true, optional = true }

[dependencies]
serde_json = { workspace = true }
hex-literal = { workspace = true }
log = { workspace = true, default-features = false }
parity-scale-codec = { workspace = true, default-features = false, features = ["derive"]}
Expand Down Expand Up @@ -98,6 +99,7 @@ polkadot-primitives = { workspace = true, default-features = false }
[features]
default = ["std"]
std = [
"serde_json/std",
"parity-scale-codec/std",
"log/std",
"scale-info/std",
Expand Down
Loading

0 comments on commit 98b625b

Please sign in to comment.