chain-spec: getting ready for native-runtime-free world (#1256)

This PR prepares chains specs for _native-runtime-free_  world.

This PR has following changes:
- `substrate`:
  - adds support for:
- JSON based `GenesisConfig` to `ChainSpec` allowing interaction with
runtime `GenesisBuilder` API.
- interacting with arbitrary runtime wasm blob to[
`chain-spec-builder`](https://github.com/paritytech/substrate/blob/3ef576eaeb3f42610e85daecc464961cf1295570/bin/utils/chain-spec-builder/src/lib.rs#L46)
command line util,
- removes
[`code`](https://github.com/paritytech/substrate/blob/3ef576eaeb3f42610e85daecc464961cf1295570/frame/system/src/lib.rs#L660)
from `system_pallet`
  - adds `code` to the `ChainSpec`
- deprecates
[`ChainSpec::from_genesis`](https://github.com/paritytech/substrate/blob/3ef576eaeb3f42610e85daecc464961cf1295570/client/chain-spec/src/chain_spec.rs#L263),
but also changes the signature of this method extending it with `code`
argument.
[`ChainSpec::builder()`](https://github.com/paritytech/substrate/blob/20bee680ed098be7239cf7a6b804cd4de267983e/client/chain-spec/src/chain_spec.rs#L507)
should be used instead.
- `polkadot`:
- all references to `RuntimeGenesisConfig` in `node/service` are
removed,
- all
`(kusama|polkadot|versi|rococo|wococo)_(staging|dev)_genesis_config`
functions now return the JSON patch for default runtime `GenesisConfig`,
  - `ChainSpecBuilder` is used, `ChainSpec::from_genesis` is removed,

- `cumulus`:
  - `ChainSpecBuilder` is used, `ChainSpec::from_genesis` is removed,
- _JSON_ patch configuration used instead of `RuntimeGenesisConfig
struct` in all chain specs.
  
---------

Co-authored-by: command-bot <>
Co-authored-by: Javier Viola <javier@parity.io>
Co-authored-by: Davide Galassi <davxy@datawok.net>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Kevin Krone <kevin@parity.io>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Michal Kucharczyk
2023-11-05 15:19:23 +01:00
committed by GitHub
parent c46a7dbb61
commit 8ba7a6aba8
90 changed files with 4833 additions and 3059 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ variables:
RUSTY_CACHIER_COMPRESSION_METHOD: zstd
NEXTEST_FAILURE_OUTPUT: immediate-final
NEXTEST_SUCCESS_OUTPUT: final
ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.75"
ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.79"
DOCKER_IMAGES_VERSION: "${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}"
default:
Generated
+29
View File
@@ -965,6 +965,7 @@ dependencies = [
"sp-block-builder",
"sp-consensus-aura",
"sp-core",
"sp-genesis-builder",
"sp-inherents",
"sp-offchain",
"sp-runtime",
@@ -4222,6 +4223,7 @@ dependencies = [
"sp-api",
"sp-block-builder",
"sp-core",
"sp-genesis-builder",
"sp-inherents",
"sp-io",
"sp-offchain",
@@ -4288,6 +4290,7 @@ dependencies = [
"sc-transaction-pool",
"sc-transaction-pool-api",
"serde",
"serde_json",
"sp-api",
"sp-arithmetic",
"sp-authority-discovery",
@@ -6738,7 +6741,9 @@ dependencies = [
"polkadot-service",
"rococo-runtime",
"rococo-runtime-constants",
"sc-chain-spec",
"sc-consensus-grandpa",
"serde_json",
"sp-authority-discovery",
"sp-consensus-babe",
"sp-consensus-beefy",
@@ -7159,6 +7164,7 @@ dependencies = [
"parity-scale-codec",
"primitive-types",
"scale-info",
"serde_json",
"sp-api",
"sp-authority-discovery",
"sp-block-builder",
@@ -8199,6 +8205,7 @@ dependencies = [
"sc-telemetry",
"sc-transaction-pool",
"sc-transaction-pool-api",
"serde_json",
"sp-api",
"sp-block-builder",
"sp-blockchain",
@@ -8215,6 +8222,7 @@ name = "minimal-runtime"
version = "0.1.0"
dependencies = [
"frame",
"frame-support",
"pallet-balances",
"pallet-sudo",
"pallet-timestamp",
@@ -8222,6 +8230,7 @@ dependencies = [
"pallet-transaction-payment-rpc-runtime-api",
"parity-scale-codec",
"scale-info",
"sp-genesis-builder",
"substrate-wasm-builder",
]
@@ -8679,6 +8688,7 @@ dependencies = [
"sc-telemetry",
"sc-transaction-pool",
"sc-transaction-pool-api",
"serde_json",
"sp-api",
"sp-block-builder",
"sp-blockchain",
@@ -8730,6 +8740,7 @@ dependencies = [
"pallet-transaction-payment-rpc-runtime-api",
"parity-scale-codec",
"scale-info",
"serde_json",
"sp-api",
"sp-block-builder",
"sp-consensus-aura",
@@ -11168,6 +11179,7 @@ dependencies = [
"sc-transaction-pool",
"sc-transaction-pool-api",
"serde",
"serde_json",
"sp-api",
"sp-block-builder",
"sp-blockchain",
@@ -12743,6 +12755,7 @@ dependencies = [
"sp-runtime",
"sp-session",
"sp-timestamp",
"sp-tracing 10.0.0",
"sp-transaction-pool",
"staging-xcm",
"substrate-build-script-utils",
@@ -14783,7 +14796,11 @@ dependencies = [
name = "sc-chain-spec"
version = "4.0.0-dev"
dependencies = [
"array-bytes 6.1.0",
"docify",
"log",
"memmap2",
"parity-scale-codec",
"sc-chain-spec-derive",
"sc-client-api",
"sc-executor",
@@ -14791,10 +14808,16 @@ dependencies = [
"sc-telemetry",
"serde",
"serde_json",
"sp-application-crypto",
"sp-blockchain",
"sp-consensus-babe",
"sp-core",
"sp-genesis-builder",
"sp-io",
"sp-keyring",
"sp-runtime",
"sp-state-machine",
"substrate-test-runtime",
]
[[package]]
@@ -17986,11 +18009,15 @@ version = "2.0.0"
dependencies = [
"ansi_term",
"clap 4.4.6",
"kitchensink-runtime",
"log",
"rand 0.8.5",
"sc-chain-spec",
"sc-keystore",
"serde_json",
"sp-core",
"sp-keystore",
"sp-tracing 10.0.0",
"staging-node-cli",
]
@@ -18110,6 +18137,7 @@ dependencies = [
"parity-scale-codec",
"sc-executor",
"scale-info",
"serde_json",
"sp-application-crypto",
"sp-consensus-babe",
"sp-core",
@@ -18339,6 +18367,7 @@ name = "substrate"
version = "1.0.0"
dependencies = [
"frame-support",
"sc-chain-spec",
"sc-cli",
"sc-consensus-aura",
"sc-consensus-babe",
@@ -17,6 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" }
serde = { version = "1.0.188", features = ["derive"] }
jsonrpsee = { version = "0.16.2", features = ["server"] }
futures = "0.3.28"
serde_json = "1.0.104"
# Local
parachain-template-runtime = { path = "../runtime" }
+96 -125
View File
@@ -7,8 +7,7 @@ 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<parachain_template_runtime::RuntimeGenesisConfig, Extensions>;
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;
@@ -68,53 +67,48 @@ pub fn development_config() -> ChainSpec {
properties.insert("tokenDecimals".into(), 12.into());
properties.insert("ss58Format".into(), 42.into());
ChainSpec::from_genesis(
// Name
"Development",
// ID
"dev",
ChainType::Development,
move || {
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(),
)
},
Vec::new(),
None,
None,
None,
None,
ChainSpec::builder(
parachain_template_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
relay_chain: "rococo-local".into(),
// You MUST set this to the correct network!
para_id: 1000,
},
)
.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(),
))
.build()
}
pub fn local_testnet_config() -> ChainSpec {
@@ -124,59 +118,51 @@ pub fn local_testnet_config() -> ChainSpec {
properties.insert("tokenDecimals".into(), 12.into());
properties.insert("ss58Format".into(), 42.into());
ChainSpec::from_genesis(
// Name
"Local Testnet",
// ID
"local_testnet",
ChainType::Local,
move || {
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(),
)
},
// Bootnodes
Vec::new(),
// Telemetry
None,
// Protocol ID
Some("template-local"),
// Fork ID
None,
// Properties
Some(properties),
// Extensions
#[allow(deprecated)]
ChainSpec::builder(
parachain_template_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
relay_chain: "rococo-local".into(),
// You MUST set this to the correct network!
para_id: 1000,
},
)
.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_protocol_id("template-local")
.with_properties(properties)
.build()
}
fn testnet_genesis(
@@ -184,28 +170,20 @@ fn testnet_genesis(
endowed_accounts: Vec<AccountId>,
root: AccountId,
id: ParaId,
) -> parachain_template_runtime::RuntimeGenesisConfig {
parachain_template_runtime::RuntimeGenesisConfig {
system: parachain_template_runtime::SystemConfig {
code: parachain_template_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
balances: parachain_template_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
"parachainInfo": {
"parachainId": id,
},
parachain_info: parachain_template_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": EXISTENTIAL_DEPOSIT * 16,
},
collator_selection: parachain_template_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: EXISTENTIAL_DEPOSIT * 16,
..Default::default()
},
session: parachain_template_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -214,18 +192,11 @@ fn testnet_genesis(
template_session_keys(aura), // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
// no need to pass anything to aura, in fact it will panic if we do. Session will take care
// of this.
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: parachain_template_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
transaction_payment: Default::default(),
sudo: parachain_template_runtime::SudoConfig { key: Some(root) },
}
"sudo": { "key": Some(root) }
})
}
@@ -10,6 +10,7 @@ publish = false
[dependencies]
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false }
paste = "1.0.14"
serde_json = "1.0.104"
# Substrate
grandpa = { package = "sc-consensus-grandpa", path = "../../../../../substrate/client/consensus/grandpa" }
@@ -24,6 +25,7 @@ pallet-staking = { path = "../../../../../substrate/frame/staking", default-feat
pallet-message-queue = { path = "../../../../../substrate/frame/message-queue", default-features = false}
pallet-im-online = { path = "../../../../../substrate/frame/im-online", default-features = false}
beefy-primitives = { package = "sp-consensus-beefy", path = "../../../../../substrate/primitives/consensus/beefy" }
sc-chain-spec = { path = "../../../../../substrate/client/chain-spec", default-features = false }
# Polkadot
polkadot-core-primitives = { path = "../../../../../polkadot/core-primitives", default-features = false}
File diff suppressed because it is too large Load Diff
@@ -45,6 +45,7 @@ sp-block-builder = { path = "../../../../../substrate/primitives/block-builder",
sp-consensus-aura = { path = "../../../../../substrate/primitives/consensus/aura", default-features = false}
sp-core = { path = "../../../../../substrate/primitives/core", default-features = false}
sp-inherents = { path = "../../../../../substrate/primitives/inherents", default-features = false}
sp-genesis-builder = { path = "../../../../../substrate/primitives/genesis-builder", default-features = false }
sp-offchain = { path = "../../../../../substrate/primitives/offchain", default-features = false}
sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false}
sp-session = { path = "../../../../../substrate/primitives/session", default-features = false}
@@ -230,6 +231,7 @@ std = [
"sp-block-builder/std",
"sp-consensus-aura/std",
"sp-core/std",
"sp-genesis-builder/std",
"sp-inherents/std",
"sp-offchain/std",
"sp-runtime/std",
@@ -60,6 +60,7 @@ use cumulus_primitives_core::ParaId;
use frame_support::{
construct_runtime,
dispatch::DispatchClass,
genesis_builder_helper::{build_config, create_default_config},
ord_parameter_types, parameter_types,
traits::{
AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse,
@@ -1568,6 +1569,16 @@ impl_runtime_apis! {
Ok(batches)
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn create_default_config() -> Vec<u8> {
create_default_config::<RuntimeGenesisConfig>()
}
fn build_config(config: Vec<u8>) -> sp_genesis_builder::Result {
build_config::<RuntimeGenesisConfig>(config)
}
}
}
cumulus_pallet_parachain_system::register_validate_block! {
+1
View File
@@ -48,6 +48,7 @@ sp-io = { path = "../../substrate/primitives/io" }
sp-core = { path = "../../substrate/primitives/core" }
sp-session = { path = "../../substrate/primitives/session" }
sc-consensus = { path = "../../substrate/client/consensus/common" }
sp-tracing = { path = "../../substrate/primitives/tracing" }
sc-cli = { path = "../../substrate/client/cli" }
sc-client-api = { path = "../../substrate/client/api" }
sc-executor = { path = "../../substrate/client/executor" }
File diff suppressed because it is too large Load Diff
@@ -215,8 +215,7 @@ pub mod rococo {
parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT;
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type BridgeHubChainSpec =
sc_service::GenericChainSpec<bridge_hub_rococo_runtime::RuntimeGenesisConfig, Extensions>;
pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub type RuntimeApi = bridge_hub_rococo_runtime::RuntimeApi;
@@ -235,52 +234,47 @@ pub mod rococo {
properties.insert("tokenDecimals".into(), 12.into());
modify_props(&mut properties);
BridgeHubChainSpec::from_genesis(
// Name
chain_name,
// ID
super::ensure_id(id).expect("invalid id"),
ChainType::Local,
move || {
genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
bridges_pallet_owner_seed
.as_ref()
.map(|seed| get_account_id_from_seed::<sr25519::Public>(seed)),
)
},
Vec::new(),
None,
None,
None,
Some(properties),
BridgeHubChainSpec::builder(
bridge_hub_rococo_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() },
)
.with_name(chain_name)
.with_id(super::ensure_id(id).expect("invalid id"))
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
bridges_pallet_owner_seed
.as_ref()
.map(|seed| get_account_id_from_seed::<sr25519::Public>(seed)),
))
.with_properties(properties)
.build()
}
fn genesis(
@@ -288,28 +282,20 @@ pub mod rococo {
endowed_accounts: Vec<AccountId>,
id: ParaId,
bridges_pallet_owner: Option<AccountId>,
) -> bridge_hub_rococo_runtime::RuntimeGenesisConfig {
bridge_hub_rococo_runtime::RuntimeGenesisConfig {
system: bridge_hub_rococo_runtime::SystemConfig {
code: bridge_hub_rococo_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
balances: bridge_hub_rococo_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
"parachainInfo": {
"parachainId": id,
},
parachain_info: bridge_hub_rococo_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": BRIDGE_HUB_ROCOCO_ED * 16,
},
collator_selection: bridge_hub_rococo_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: BRIDGE_HUB_ROCOCO_ED * 16,
..Default::default()
},
session: bridge_hub_rococo_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -318,40 +304,31 @@ pub mod rococo {
bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
bridge_wococo_grandpa: bridge_hub_rococo_runtime::BridgeWococoGrandpaConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeWococoGrandpa": {
"owner": bridges_pallet_owner.clone(),
},
bridge_westend_grandpa: bridge_hub_rococo_runtime::BridgeWestendGrandpaConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeWestendGrandpa": {
"owner": bridges_pallet_owner.clone(),
},
bridge_rococo_grandpa: bridge_hub_rococo_runtime::BridgeRococoGrandpaConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeRococoGrandpa": {
"owner": bridges_pallet_owner.clone(),
},
bridge_rococo_messages: bridge_hub_rococo_runtime::BridgeRococoMessagesConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeRococoMessages": {
"owner": bridges_pallet_owner.clone(),
},
bridge_wococo_messages: bridge_hub_rococo_runtime::BridgeWococoMessagesConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeWococoMessages": {
"owner": bridges_pallet_owner.clone(),
},
bridge_westend_messages: bridge_hub_rococo_runtime::BridgeWestendMessagesConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeWestendMessages": {
"owner": bridges_pallet_owner.clone(),
},
}
})
}
}
@@ -403,8 +380,7 @@ pub mod kusama {
parachains_common::kusama::currency::EXISTENTIAL_DEPOSIT;
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type BridgeHubChainSpec =
sc_service::GenericChainSpec<bridge_hub_kusama_runtime::RuntimeGenesisConfig, Extensions>;
pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub type RuntimeApi = bridge_hub_kusama_runtime::RuntimeApi;
pub fn local_config(
@@ -418,81 +394,68 @@ pub mod kusama {
properties.insert("tokenSymbol".into(), "KSM".into());
properties.insert("tokenDecimals".into(), 12.into());
BridgeHubChainSpec::from_genesis(
// Name
chain_name,
// ID
super::ensure_id(id).expect("invalid id"),
ChainType::Local,
move || {
genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
)
},
Vec::new(),
None,
None,
None,
Some(properties),
BridgeHubChainSpec::builder(
bridge_hub_kusama_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() },
)
.with_name(chain_name)
.with_id(super::ensure_id(id).expect("invalid id"))
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
))
.with_properties(properties)
.build()
}
fn genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> bridge_hub_kusama_runtime::RuntimeGenesisConfig {
bridge_hub_kusama_runtime::RuntimeGenesisConfig {
system: bridge_hub_kusama_runtime::SystemConfig {
code: bridge_hub_kusama_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
},
balances: bridge_hub_kusama_runtime::BalancesConfig {
balances: endowed_accounts
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.cloned()
.map(|k| (k, BRIDGE_HUB_KUSAMA_ED * 524_288))
.collect(),
.collect::<Vec<_>>(),
},
parachain_info: bridge_hub_kusama_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"parachainInfo": {
"parachainId": id,
},
collator_selection: bridge_hub_kusama_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: BRIDGE_HUB_KUSAMA_ED * 16,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": BRIDGE_HUB_KUSAMA_ED * 16,
},
session: bridge_hub_kusama_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -501,16 +464,12 @@ pub mod kusama {
bridge_hub_kusama_runtime::SessionKeys { aura }, // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: bridge_hub_kusama_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
},
}
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
}
})
}
}
@@ -545,52 +504,47 @@ pub mod westend {
properties.insert("tokenSymbol".into(), "WND".into());
properties.insert("tokenDecimals".into(), 12.into());
BridgeHubChainSpec::from_genesis(
// Name
chain_name,
// ID
super::ensure_id(id).expect("invalid id"),
ChainType::Local,
move || {
genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
bridges_pallet_owner_seed
.as_ref()
.map(|seed| get_account_id_from_seed::<sr25519::Public>(seed)),
)
},
Vec::new(),
None,
None,
None,
Some(properties),
BridgeHubChainSpec::builder(
bridge_hub_westend_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!"),
Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() },
)
.with_name(chain_name)
.with_id(super::ensure_id(id).expect("invalid id"))
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
bridges_pallet_owner_seed
.as_ref()
.map(|seed| get_account_id_from_seed::<sr25519::Public>(seed)),
))
.with_properties(properties)
.build()
}
fn genesis(
@@ -598,28 +552,20 @@ pub mod westend {
endowed_accounts: Vec<AccountId>,
id: ParaId,
bridges_pallet_owner: Option<AccountId>,
) -> bridge_hub_westend_runtime::RuntimeGenesisConfig {
bridge_hub_westend_runtime::RuntimeGenesisConfig {
system: bridge_hub_westend_runtime::SystemConfig {
code: bridge_hub_westend_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
balances: bridge_hub_westend_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
"parachainInfo": {
"parachainId": id,
},
parachain_info: bridge_hub_westend_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": BRIDGE_HUB_WESTEND_ED * 16,
},
collator_selection: bridge_hub_westend_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: BRIDGE_HUB_WESTEND_ED * 16,
..Default::default()
},
session: bridge_hub_westend_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -628,24 +574,18 @@ pub mod westend {
bridge_hub_westend_runtime::SessionKeys { aura }, // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: bridge_hub_westend_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
bridge_rococo_grandpa: bridge_hub_westend_runtime::BridgeRococoGrandpaConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
"bridgeRococoGrandpa": {
"owner": bridges_pallet_owner.clone(),
},
bridge_rococo_messages: bridge_hub_westend_runtime::BridgeRococoMessagesConfig {
owner: bridges_pallet_owner.clone(),
..Default::default()
},
}
"bridgeRococoMessages": {
"owner": bridges_pallet_owner.clone(),
}
})
}
}
@@ -666,8 +606,7 @@ pub mod polkadot {
parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT;
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type BridgeHubChainSpec =
sc_service::GenericChainSpec<bridge_hub_polkadot_runtime::RuntimeGenesisConfig, Extensions>;
pub type BridgeHubChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub type RuntimeApi = bridge_hub_polkadot_runtime::RuntimeApi;
pub fn local_config(
@@ -681,81 +620,68 @@ pub mod polkadot {
properties.insert("tokenSymbol".into(), "DOT".into());
properties.insert("tokenDecimals".into(), 10.into());
BridgeHubChainSpec::from_genesis(
// Name
chain_name,
// ID
super::ensure_id(id).expect("invalid id"),
ChainType::Local,
move || {
genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
)
},
Vec::new(),
None,
None,
None,
Some(properties),
BridgeHubChainSpec::builder(
bridge_hub_polkadot_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: relay_chain.to_string(), para_id: para_id.into() },
)
.with_name(chain_name)
.with_id(super::ensure_id(id).expect("invalid id"))
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
para_id,
))
.with_properties(properties)
.build()
}
fn genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> bridge_hub_polkadot_runtime::RuntimeGenesisConfig {
bridge_hub_polkadot_runtime::RuntimeGenesisConfig {
system: bridge_hub_polkadot_runtime::SystemConfig {
code: bridge_hub_polkadot_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
},
balances: bridge_hub_polkadot_runtime::BalancesConfig {
balances: endowed_accounts
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.cloned()
.map(|k| (k, BRIDGE_HUB_POLKADOT_ED * 4096))
.collect(),
.collect::<Vec<_>>(),
},
parachain_info: bridge_hub_polkadot_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"parachainInfo": {
"parachainId": id,
},
collator_selection: bridge_hub_polkadot_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: BRIDGE_HUB_POLKADOT_ED * 16,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": BRIDGE_HUB_POLKADOT_ED * 16,
},
session: bridge_hub_polkadot_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -764,15 +690,11 @@ pub mod polkadot {
bridge_hub_polkadot_runtime::SessionKeys { aura }, // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: bridge_hub_polkadot_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
},
}
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
}
})
}
}
@@ -22,8 +22,7 @@ use parachains_common::{AccountId, AuraId, Balance as CollectivesBalance};
use sc_service::ChainType;
use sp_core::sr25519;
pub type CollectivesPolkadotChainSpec =
sc_service::GenericChainSpec<collectives_polkadot_runtime::RuntimeGenesisConfig, Extensions>;
pub type CollectivesPolkadotChainSpec = sc_service::GenericChainSpec<(), Extensions>;
const COLLECTIVES_POLKADOT_ED: CollectivesBalance =
parachains_common::polkadot::currency::EXISTENTIAL_DEPOSIT;
@@ -43,37 +42,33 @@ pub fn collectives_polkadot_development_config() -> CollectivesPolkadotChainSpec
properties.insert("tokenSymbol".into(), "DOT".into());
properties.insert("tokenDecimals".into(), 10.into());
CollectivesPolkadotChainSpec::from_genesis(
// Name
"Polkadot Collectives Development",
// ID
"collectives_polkadot_dev",
ChainType::Local,
move || {
collectives_polkadot_genesis(
// initial collators.
vec![(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
)],
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"),
],
// 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever
// be a collective para on Kusama.
1002.into(),
)
},
Vec::new(),
None,
None,
None,
Some(properties),
CollectivesPolkadotChainSpec::builder(
collectives_polkadot_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "polkadot-dev".into(), para_id: 1002 },
)
.with_name("Polkadot Collectives Development")
.with_id("collectives_polkadot_dev")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(collectives_polkadot_genesis(
// initial collators.
vec![(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
)],
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"),
],
// 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever
// be a collective para on Kusama.
1002.into(),
))
.with_boot_nodes(Vec::new())
.with_properties(properties)
.build()
}
/// Collectives Polkadot Local Config.
@@ -83,81 +78,69 @@ pub fn collectives_polkadot_local_config() -> CollectivesPolkadotChainSpec {
properties.insert("tokenSymbol".into(), "DOT".into());
properties.insert("tokenDecimals".into(), 10.into());
CollectivesPolkadotChainSpec::from_genesis(
// Name
"Polkadot Collectives Local",
// ID
"collectives_polkadot_local",
ChainType::Local,
move || {
collectives_polkadot_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
1002.into(),
)
},
Vec::new(),
None,
None,
None,
Some(properties),
CollectivesPolkadotChainSpec::builder(
collectives_polkadot_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "polkadot-local".into(), para_id: 1002 },
)
.with_name("Polkadot Collectives Local")
.with_id("collectives_polkadot_local")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(collectives_polkadot_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
1002.into(),
))
.with_boot_nodes(Vec::new())
.with_properties(properties)
.build()
}
fn collectives_polkadot_genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> collectives_polkadot_runtime::RuntimeGenesisConfig {
collectives_polkadot_runtime::RuntimeGenesisConfig {
system: collectives_polkadot_runtime::SystemConfig {
code: collectives_polkadot_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
},
balances: collectives_polkadot_runtime::BalancesConfig {
balances: endowed_accounts
) -> serde_json::Value {
serde_json::json!( {
"balances": {
"balances": endowed_accounts
.iter()
.cloned()
.map(|k| (k, COLLECTIVES_POLKADOT_ED * 4096))
.collect(),
.collect::<Vec<_>>(),
},
parachain_info: collectives_polkadot_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"parachainInfo": {
"parachainId": id,
},
collator_selection: collectives_polkadot_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: COLLECTIVES_POLKADOT_ED * 16,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": COLLECTIVES_POLKADOT_ED * 16,
},
session: collectives_polkadot_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -166,18 +149,12 @@ fn collectives_polkadot_genesis(
collectives_polkadot_session_keys(aura), // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
// no need to pass anything to aura, in fact it will panic if we do. Session will take care
// of this.
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: collectives_polkadot_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
alliance: Default::default(),
alliance_motion: Default::default(),
}
})
}
@@ -23,8 +23,7 @@ use parachains_common::{AccountId, AuraId};
use sc_service::ChainType;
use sp_core::{crypto::UncheckedInto, sr25519};
pub type ContractsRococoChainSpec =
sc_service::GenericChainSpec<contracts_rococo_runtime::RuntimeGenesisConfig, Extensions>;
pub type ContractsRococoChainSpec = sc_service::GenericChainSpec<(), Extensions>;
/// No relay chain suffix because the id is the same over all relay chains.
const CONTRACTS_PARACHAIN_ID: u32 = 1002;
@@ -38,52 +37,46 @@ pub fn contracts_rococo_development_config() -> ContractsRococoChainSpec {
properties.insert("tokenSymbol".into(), "ROC".into());
properties.insert("tokenDecimals".into(), 12.into());
ContractsRococoChainSpec::from_genesis(
// Name
"Contracts on Rococo Development",
// ID
"contracts-rococo-dev",
ChainType::Development,
move || {
contracts_rococo_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("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"),
],
CONTRACTS_PARACHAIN_ID.into(),
)
},
Vec::new(),
None,
None,
None,
None,
ContractsRococoChainSpec::builder(
contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
para_id: CONTRACTS_PARACHAIN_ID,
},
)
.with_name("Contracts on Rococo Development")
.with_id("contracts-rococo-dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(contracts_rococo_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("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"),
],
CONTRACTS_PARACHAIN_ID.into(),
))
.with_boot_nodes(Vec::new())
.build()
}
pub fn contracts_rococo_local_config() -> ContractsRococoChainSpec {
@@ -91,58 +84,46 @@ pub fn contracts_rococo_local_config() -> ContractsRococoChainSpec {
properties.insert("tokenSymbol".into(), "ROC".into());
properties.insert("tokenDecimals".into(), 12.into());
ContractsRococoChainSpec::from_genesis(
// Name
"Contracts on Rococo",
// ID
"contracts-rococo-local",
ChainType::Local,
move || {
contracts_rococo_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("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"),
],
CONTRACTS_PARACHAIN_ID.into(),
)
},
// Bootnodes
Vec::new(),
// Telemetry
None,
// Protocol ID
None,
// Fork ID
None,
// Properties
Some(properties),
// Extensions
ContractsRococoChainSpec::builder(
contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: "rococo-local".into(), // You MUST set this to the correct network!
para_id: CONTRACTS_PARACHAIN_ID,
},
)
.with_name("Contracts on Rococo")
.with_id("contracts-rococo-local")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(contracts_rococo_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<contracts_rococo_runtime::AuraId>("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"),
],
CONTRACTS_PARACHAIN_ID.into(),
))
.with_properties(properties)
.build()
}
pub fn contracts_rococo_config() -> ContractsRococoChainSpec {
@@ -151,111 +132,92 @@ pub fn contracts_rococo_config() -> ContractsRococoChainSpec {
properties.insert("tokenSymbol".into(), "ROC".into());
properties.insert("tokenDecimals".into(), 12.into());
ContractsRococoChainSpec::from_genesis(
// Name
"Contracts on Rococo",
// ID
"contracts-rococo",
ChainType::Live,
move || {
contracts_rococo_genesis(
vec![
// 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26
(
hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"]
.into(),
hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"]
.unchecked_into(),
),
// 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2
(
hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"]
.into(),
hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"]
.unchecked_into(),
),
// 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM
(
hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"]
.into(),
hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"]
.unchecked_into(),
),
// 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF
(
hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"]
.into(),
hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"]
.unchecked_into(),
),
],
// Warning: The configuration for a production chain should not contain
// any endowed accounts here, otherwise it'll be minting extra native tokens
// from the relay chain on the parachain.
vec![
// NOTE: Remove endowed accounts if deployed on other relay chains.
// Endowed accounts
hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(),
// AccountId of an account which `ink-waterfall` uses for automated testing
hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(),
],
CONTRACTS_PARACHAIN_ID.into(),
)
},
// Bootnodes
vec![
ContractsRococoChainSpec::builder(
contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID }
)
.with_name("Contracts on Rococo")
.with_id("contracts-rococo")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(contracts_rococo_genesis(
vec![
// 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26
(
hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"]
.into(),
hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"]
.unchecked_into(),
),
// 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2
(
hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"]
.into(),
hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"]
.unchecked_into(),
),
// 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM
(
hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"]
.into(),
hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"]
.unchecked_into(),
),
// 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF
(
hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"]
.into(),
hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"]
.unchecked_into(),
),
],
// Warning: The configuration for a production chain should not contain
// any endowed accounts here, otherwise it'll be minting extra native tokens
// from the relay chain on the parachain.
vec![
// NOTE: Remove endowed accounts if deployed on other relay chains.
// Endowed accounts
hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(),
// AccountId of an account which `ink-waterfall` uses for automated testing
hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(),
],
CONTRACTS_PARACHAIN_ID.into(),
))
.with_boot_nodes(vec![
"/dns/contracts-collator-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj"
.parse()
.expect("MultiaddrWithPeerId"),
.parse()
.expect("MultiaddrWithPeerId"),
"/dns/contracts-collator-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh"
.parse()
.expect("MultiaddrWithPeerId"),
.parse()
.expect("MultiaddrWithPeerId"),
"/dns/contracts-collator-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk"
.parse()
.expect("MultiaddrWithPeerId"),
.parse()
.expect("MultiaddrWithPeerId"),
"/dns/contracts-collator-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX"
.parse()
.expect("MultiaddrWithPeerId"),
],
// Telemetry
None,
// Protocol ID
None,
// Fork ID
None,
// Properties
Some(properties),
// Extensions
Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID },
)
.parse()
.expect("MultiaddrWithPeerId"),
])
.with_properties(properties)
.build()
}
fn contracts_rococo_genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> contracts_rococo_runtime::RuntimeGenesisConfig {
contracts_rococo_runtime::RuntimeGenesisConfig {
system: contracts_rococo_runtime::SystemConfig {
code: contracts_rococo_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
) -> serde_json::Value {
serde_json::json!( {
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
balances: contracts_rococo_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
"parachainInfo": {
"parachainId": id,
},
parachain_info: contracts_rococo_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": CONTRACTS_ROCOCO_ED * 16,
},
collator_selection: contracts_rococo_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: CONTRACTS_ROCOCO_ED * 16,
..Default::default()
},
session: contracts_rococo_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -264,21 +226,17 @@ fn contracts_rococo_genesis(
contracts_rococo_runtime::SessionKeys { aura }, // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
// no need to pass anything to aura, in fact it will panic if we do. Session will take care
// of this.
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: contracts_rococo_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
sudo: contracts_rococo_runtime::SudoConfig {
key: Some(
hex!["2681a28014e7d3a5bfb32a003b3571f53c408acbc28d351d6bf58f5028c4ef14"].into(),
),
"sudo": {
"key": Some(sp_runtime::AccountId32::from(hex![
"2681a28014e7d3a5bfb32a003b3571f53c408acbc28d351d6bf58f5028c4ef14"
])),
},
}
})
}
@@ -23,103 +23,72 @@ use sp_core::sr25519;
use super::get_collator_keys_from_seed;
/// Specialized `ChainSpec` for the Glutton parachain runtime.
pub type GluttonChainSpec =
sc_service::GenericChainSpec<glutton_runtime::RuntimeGenesisConfig, Extensions>;
pub type GluttonChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub fn glutton_development_config(para_id: ParaId) -> GluttonChainSpec {
GluttonChainSpec::from_genesis(
// Name
"Glutton Development",
// ID
"glutton_dev",
ChainType::Local,
move || glutton_genesis(para_id, vec![get_collator_keys_from_seed::<AuraId>("Alice")]),
Vec::new(),
None,
None,
None,
None,
GluttonChainSpec::builder(
glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "kusama-dev".into(), para_id: para_id.into() },
)
.with_name("Glutton Development")
.with_id("glutton_dev")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(glutton_genesis(
para_id,
vec![get_collator_keys_from_seed::<AuraId>("Alice")],
))
.build()
}
pub fn glutton_local_config(para_id: ParaId) -> GluttonChainSpec {
GluttonChainSpec::from_genesis(
// Name
"Glutton Local",
// ID
"glutton_local",
ChainType::Local,
move || {
glutton_genesis(
para_id,
vec![
get_collator_keys_from_seed::<AuraId>("Alice"),
get_collator_keys_from_seed::<AuraId>("Bob"),
],
)
},
Vec::new(),
None,
None,
None,
None,
GluttonChainSpec::builder(
glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "kusama-local".into(), para_id: para_id.into() },
)
.with_name("Glutton Local")
.with_id("glutton_local")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(glutton_genesis(
para_id,
vec![
get_collator_keys_from_seed::<AuraId>("Alice"),
get_collator_keys_from_seed::<AuraId>("Bob"),
],
))
.build()
}
pub fn glutton_config(para_id: ParaId) -> GluttonChainSpec {
let mut properties = sc_chain_spec::Properties::new();
properties.insert("ss58Format".into(), 2.into());
GluttonChainSpec::from_genesis(
// Name
format!("Glutton {}", para_id).as_str(),
// ID
format!("glutton-kusama-{}", para_id).as_str(),
ChainType::Live,
move || {
glutton_genesis(
para_id,
vec![
get_collator_keys_from_seed::<AuraId>("Alice"),
get_collator_keys_from_seed::<AuraId>("Bob"),
],
)
},
Vec::new(),
None,
// Protocol ID
Some(format!("glutton-kusama-{}", para_id).as_str()),
None,
Some(properties),
GluttonChainSpec::builder(
glutton_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "kusama".into(), para_id: para_id.into() },
)
.with_name(format!("Glutton {}", para_id).as_str())
.with_id(format!("glutton-kusama-{}", para_id).as_str())
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(glutton_genesis(
para_id,
vec![
get_collator_keys_from_seed::<AuraId>("Alice"),
get_collator_keys_from_seed::<AuraId>("Bob"),
],
))
.with_protocol_id(format!("glutton-kusama-{}", para_id).as_str())
.with_properties(properties)
.build()
}
fn glutton_genesis(
parachain_id: ParaId,
collators: Vec<AuraId>,
) -> glutton_runtime::RuntimeGenesisConfig {
glutton_runtime::RuntimeGenesisConfig {
system: glutton_runtime::SystemConfig {
code: glutton_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
fn glutton_genesis(parachain_id: ParaId, collators: Vec<AuraId>) -> serde_json::Value {
serde_json::json!( {
"parachainInfo": {
"parachainId": parachain_id
},
parachain_info: glutton_runtime::ParachainInfoConfig { parachain_id, ..Default::default() },
parachain_system: Default::default(),
glutton: glutton_runtime::GluttonConfig {
compute: Default::default(),
storage: Default::default(),
trash_data_count: Default::default(),
..Default::default()
"sudo": {
"key": Some(get_account_id_from_seed::<sr25519::Public>("Alice")),
},
aura: glutton_runtime::AuraConfig { authorities: collators },
aura_ext: Default::default(),
sudo: glutton_runtime::SudoConfig {
key: Some(get_account_id_from_seed::<sr25519::Public>("Alice")),
},
}
"aura": { "authorities": collators },
})
}
@@ -22,8 +22,7 @@ use parachains_common::{AccountId, AuraId};
use sc_service::ChainType;
use sp_core::sr25519;
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type PenpalChainSpec =
sc_service::GenericChainSpec<penpal_runtime::RuntimeGenesisConfig, Extensions>;
pub type PenpalChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> PenpalChainSpec {
// Give your base currency a unit name and decimal places
@@ -32,84 +31,69 @@ pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> PenpalChainSpec {
properties.insert("tokenDecimals".into(), 12u32.into());
properties.insert("ss58Format".into(), 42u32.into());
PenpalChainSpec::from_genesis(
// Name
"Penpal Parachain",
// ID
&format!("penpal-{}", relay_chain.replace("-local", "")),
ChainType::Development,
move || {
penpal_testnet_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
id,
)
},
Vec::new(),
None,
None,
None,
None,
PenpalChainSpec::builder(
penpal_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: relay_chain.into(), // You MUST set this to the correct network!
para_id: id.into(),
},
)
.with_name("Penpal Parachain")
.with_id(&format!("penpal-{}", relay_chain.replace("-local", "")))
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(penpal_testnet_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_collator_keys_from_seed::<AuraId>("Alice"),
),
(
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_collator_keys_from_seed::<AuraId>("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"),
],
id,
))
.build()
}
fn penpal_testnet_genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> penpal_runtime::RuntimeGenesisConfig {
penpal_runtime::RuntimeGenesisConfig {
system: penpal_runtime::SystemConfig {
code: penpal_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
},
balances: penpal_runtime::BalancesConfig {
balances: endowed_accounts
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.cloned()
.map(|k| (k, penpal_runtime::EXISTENTIAL_DEPOSIT * 4096))
.collect(),
.collect::<Vec<_>>(),
},
parachain_info: penpal_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"parachainInfo": {
"parachainId": id,
},
collator_selection: penpal_runtime::CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(),
candidacy_bond: penpal_runtime::EXISTENTIAL_DEPOSIT * 16,
..Default::default()
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": penpal_runtime::EXISTENTIAL_DEPOSIT * 16,
},
session: penpal_runtime::SessionConfig {
keys: invulnerables
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
@@ -118,21 +102,15 @@ fn penpal_testnet_genesis(
penpal_session_keys(aura), // session keys
)
})
.collect(),
.collect::<Vec<_>>(),
},
// no need to pass anything to aura, in fact it will panic if we do. Session will take care
// of this.
aura: Default::default(),
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: penpal_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
sudo: penpal_runtime::SudoConfig {
key: Some(get_account_id_from_seed::<sr25519::Public>("Alice")),
"sudo": {
"key": Some(get_account_id_from_seed::<sr25519::Public>("Alice")),
},
}
})
}
/// Generate the session keys from individual elements.
@@ -25,73 +25,61 @@ use rococo_parachain_runtime::AuraId;
use sc_chain_spec::ChainType;
use sp_core::{crypto::UncheckedInto, sr25519};
pub type RococoParachainChainSpec =
sc_service::GenericChainSpec<rococo_parachain_runtime::RuntimeGenesisConfig, Extensions>;
pub type RococoParachainChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub fn rococo_parachain_local_config() -> RococoParachainChainSpec {
RococoParachainChainSpec::from_genesis(
"Rococo Parachain Local",
"local_testnet",
ChainType::Local,
move || {
testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![get_from_seed::<AuraId>("Alice"), get_from_seed::<AuraId>("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"),
],
1000.into(),
)
},
Vec::new(),
None,
None,
None,
None,
RococoParachainChainSpec::builder(
rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "rococo-local".into(), para_id: 1000 },
)
.with_name("Rococo Parachain Local")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![get_from_seed::<AuraId>("Alice"), get_from_seed::<AuraId>("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"),
],
1000.into(),
))
.build()
}
pub fn staging_rococo_parachain_local_config() -> RococoParachainChainSpec {
RococoParachainChainSpec::from_genesis(
"Staging Rococo Parachain Local",
"staging_testnet",
ChainType::Live,
move || {
testnet_genesis(
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
vec![
// $secret//one
hex!["aad9fa2249f87a210a0f93400b7f90e47b810c6d65caa0ca3f5af982904c2a33"]
.unchecked_into(),
// $secret//two
hex!["d47753f0cca9dd8da00c70e82ec4fc5501a69c49a5952a643d18802837c88212"]
.unchecked_into(),
],
vec![
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()
],
1000.into(),
)
},
Vec::new(),
None,
None,
None,
None,
#[allow(deprecated)]
RococoParachainChainSpec::builder(
rococo_parachain_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "rococo-local".into(), para_id: 1000 },
)
.with_name("Staging Rococo Parachain Local")
.with_id("staging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(testnet_genesis(
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
vec![
// $secret//one
hex!["aad9fa2249f87a210a0f93400b7f90e47b810c6d65caa0ca3f5af982904c2a33"]
.unchecked_into(),
// $secret//two
hex!["d47753f0cca9dd8da00c70e82ec4fc5501a69c49a5952a643d18802837c88212"]
.unchecked_into(),
],
vec![hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()],
1000.into(),
))
.build()
}
pub(crate) fn testnet_genesis(
@@ -99,28 +87,18 @@ pub(crate) fn testnet_genesis(
initial_authorities: Vec<AuraId>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> rococo_parachain_runtime::RuntimeGenesisConfig {
rococo_parachain_runtime::RuntimeGenesisConfig {
system: rococo_parachain_runtime::SystemConfig {
code: rococo_parachain_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
balances: rococo_parachain_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
"sudo": { "key": Some(root_key) },
"parachainInfo": {
"parachainId": id,
},
sudo: rococo_parachain_runtime::SudoConfig { key: Some(root_key) },
parachain_info: rococo_parachain_runtime::ParachainInfoConfig {
parachain_id: id,
..Default::default()
"aura": { "authorities": initial_authorities },
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
aura: rococo_parachain_runtime::AuraConfig { authorities: initial_authorities },
aura_ext: Default::default(),
parachain_system: Default::default(),
polkadot_xcm: rococo_parachain_runtime::PolkadotXcmConfig {
safe_xcm_version: Some(SAFE_XCM_VERSION),
..Default::default()
},
}
})
}
@@ -23,49 +23,35 @@ use sp_core::sr25519;
use super::get_collator_keys_from_seed;
/// Specialized `ChainSpec` for the seedling parachain runtime.
pub type SeedlingChainSpec =
sc_service::GenericChainSpec<seedling_runtime::RuntimeGenesisConfig, Extensions>;
pub type SeedlingChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub fn get_seedling_chain_spec() -> SeedlingChainSpec {
SeedlingChainSpec::from_genesis(
"Seedling Local Testnet",
"seedling_local_testnet",
ChainType::Local,
move || {
seedling_testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
2000.into(),
vec![get_collator_keys_from_seed::<AuraId>("Alice")],
)
},
Vec::new(),
None,
None,
None,
None,
SeedlingChainSpec::builder(
seedling_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "westend".into(), para_id: 2000 },
)
.with_name("Seedling Local Testnet")
.with_id("seedling_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(seedling_testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
2000.into(),
vec![get_collator_keys_from_seed::<AuraId>("Alice")],
))
.with_boot_nodes(Vec::new())
.build()
}
fn seedling_testnet_genesis(
root_key: AccountId,
parachain_id: ParaId,
collators: Vec<AuraId>,
) -> seedling_runtime::RuntimeGenesisConfig {
seedling_runtime::RuntimeGenesisConfig {
system: seedling_runtime::SystemConfig {
code: seedling_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
) -> serde_json::Value {
serde_json::json!({
"sudo": { "key": Some(root_key) },
"parachainInfo": {
"parachainId": parachain_id,
},
sudo: seedling_runtime::SudoConfig { key: Some(root_key) },
parachain_info: seedling_runtime::ParachainInfoConfig {
parachain_id,
..Default::default()
},
parachain_system: Default::default(),
aura: seedling_runtime::AuraConfig { authorities: collators },
aura_ext: Default::default(),
}
"aura": { "authorities": collators },
})
}
@@ -22,40 +22,27 @@ use sc_service::ChainType;
use super::get_collator_keys_from_seed;
/// Specialized `ChainSpec` for the shell parachain runtime.
pub type ShellChainSpec =
sc_service::GenericChainSpec<shell_runtime::RuntimeGenesisConfig, Extensions>;
pub type ShellChainSpec = sc_service::GenericChainSpec<(), Extensions>;
pub fn get_shell_chain_spec() -> ShellChainSpec {
ShellChainSpec::from_genesis(
"Shell Local Testnet",
"shell_local_testnet",
ChainType::Local,
move || {
shell_testnet_genesis(1000.into(), vec![get_collator_keys_from_seed::<AuraId>("Alice")])
},
Vec::new(),
None,
None,
None,
None,
ShellChainSpec::builder(
shell_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: "westend".into(), para_id: 1000 },
)
.with_name("Shell Local Testnet")
.with_id("shell_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(shell_testnet_genesis(
1000.into(),
vec![get_collator_keys_from_seed::<AuraId>("Alice")],
))
.with_boot_nodes(Vec::new())
.build()
}
fn shell_testnet_genesis(
parachain_id: ParaId,
collators: Vec<AuraId>,
) -> shell_runtime::RuntimeGenesisConfig {
shell_runtime::RuntimeGenesisConfig {
system: shell_runtime::SystemConfig {
code: shell_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
},
parachain_info: shell_runtime::ParachainInfoConfig { parachain_id, ..Default::default() },
parachain_system: Default::default(),
aura: shell_runtime::AuraConfig { authorities: collators },
aura_ext: Default::default(),
}
fn shell_testnet_genesis(parachain_id: ParaId, collators: Vec<AuraId>) -> serde_json::Value {
serde_json::json!({
"parachainInfo": { "parachainId": parachain_id},
"aura": { "authorities": collators },
})
}
+17 -22
View File
@@ -1200,35 +1200,30 @@ mod tests {
cfg_file_path
}
pub type DummyChainSpec<E> =
sc_service::GenericChainSpec<rococo_parachain_runtime::RuntimeGenesisConfig, E>;
pub type DummyChainSpec<E> = sc_service::GenericChainSpec<(), E>;
pub fn create_default_with_extensions<E: Extension>(
id: &str,
extension: E,
) -> DummyChainSpec<E> {
DummyChainSpec::from_genesis(
"Dummy local testnet",
id,
ChainType::Local,
move || {
crate::chain_spec::rococo_parachain::testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![
get_from_seed::<rococo_parachain_runtime::AuraId>("Alice"),
get_from_seed::<rococo_parachain_runtime::AuraId>("Bob"),
],
vec![get_account_id_from_seed::<sr25519::Public>("Alice")],
1000.into(),
)
},
Vec::new(),
None,
None,
None,
None,
DummyChainSpec::builder(
rococo_parachain_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
extension,
)
.with_name("Dummy local testnet")
.with_id(id)
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(crate::chain_spec::rococo_parachain::testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![
get_from_seed::<rococo_parachain_runtime::AuraId>("Alice"),
get_from_seed::<rococo_parachain_runtime::AuraId>("Bob"),
],
vec![get_account_id_from_seed::<sr25519::Public>("Alice")],
1000.into(),
))
.build()
}
#[test]
+9 -18
View File
@@ -19,13 +19,13 @@
mod block_builder;
use codec::{Decode, Encode};
use runtime::{
Balance, Block, BlockHashCount, Runtime, RuntimeCall, RuntimeGenesisConfig, Signature,
SignedExtra, SignedPayload, UncheckedExtrinsic, VERSION,
Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload,
UncheckedExtrinsic, VERSION,
};
use sc_executor::HeapAllocStrategy;
use sc_executor_common::runtime_blob::RuntimeBlob;
use sp_blockchain::HeaderBackend;
use sp_core::{sr25519, Pair};
use sp_core::Pair;
use sp_io::TestExternalities;
use sp_runtime::{generic::Era, BuildStorage, SaturatedConversion};
@@ -84,17 +84,12 @@ pub struct GenesisParameters {
impl substrate_test_client::GenesisInit for GenesisParameters {
fn genesis_storage(&self) -> Storage {
if self.endowed_accounts.is_empty() {
genesis_config().build_storage().unwrap()
} else {
cumulus_test_service::testnet_genesis(
cumulus_test_service::get_account_id_from_seed::<sr25519::Public>("Alice"),
self.endowed_accounts.clone(),
None,
)
.build_storage()
.unwrap()
}
cumulus_test_service::chain_spec::get_chain_spec_with_extra_endowed(
None,
self.endowed_accounts.clone(),
)
.build_storage()
.expect("Builds test runtime genesis storage")
}
}
@@ -127,10 +122,6 @@ impl DefaultTestClientBuilderExt for TestClientBuilder {
}
}
fn genesis_config() -> RuntimeGenesisConfig {
cumulus_test_service::testnet_genesis_with_default_endowed(Default::default(), None)
}
/// Create an unsigned extrinsic from a runtime call.
pub fn generate_unsigned(function: impl Into<RuntimeCall>) -> UncheckedExtrinsic {
UncheckedExtrinsic::new_unsigned(function.into())
+2
View File
@@ -23,6 +23,7 @@ pallet-transaction-payment = { path = "../../../substrate/frame/transaction-paym
sp-api = { path = "../../../substrate/primitives/api", default-features = false}
sp-block-builder = { path = "../../../substrate/primitives/block-builder", default-features = false}
sp-core = { path = "../../../substrate/primitives/core", default-features = false}
sp-genesis-builder = { path = "../../../substrate/primitives/genesis-builder", default-features = false}
sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false}
sp-io = { path = "../../../substrate/primitives/io", default-features = false}
sp-offchain = { path = "../../../substrate/primitives/offchain", default-features = false}
@@ -59,6 +60,7 @@ std = [
"sp-api/std",
"sp-block-builder/std",
"sp-core/std",
"sp-genesis-builder/std",
"sp-inherents/std",
"sp-io/std",
"sp-offchain/std",
+11
View File
@@ -47,6 +47,7 @@ use sp_version::RuntimeVersion;
pub use frame_support::{
construct_runtime,
dispatch::DispatchClass,
genesis_builder_helper::{build_config, create_default_config},
parameter_types,
traits::{ConstU8, Randomness},
weights::{
@@ -473,6 +474,16 @@ impl_runtime_apis! {
ParachainSystem::collect_collation_info(header)
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn create_default_config() -> Vec<u8> {
create_default_config::<RuntimeGenesisConfig>()
}
fn build_config(config: Vec<u8>) -> sp_genesis_builder::Result {
build_config::<RuntimeGenesisConfig>(config)
}
}
}
cumulus_pallet_parachain_system::register_validate_block! {
+1
View File
@@ -17,6 +17,7 @@ criterion = { version = "0.5.1", features = [ "async_tokio" ] }
jsonrpsee = { version = "0.16.2", features = ["server"] }
rand = "0.8.5"
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107"
tokio = { version = "1.32.0", features = ["macros"] }
tracing = "0.1.37"
url = "2.4.0"
+20 -29
View File
@@ -63,25 +63,25 @@ where
/// The given accounts are initialized with funds in addition
/// to the default known accounts.
pub fn get_chain_spec_with_extra_endowed(
id: ParaId,
id: Option<ParaId>,
extra_endowed_accounts: Vec<AccountId>,
) -> ChainSpec {
ChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
ChainType::Local,
move || testnet_genesis_with_default_endowed(extra_endowed_accounts.clone(), Some(id)),
Vec::new(),
None,
None,
None,
None,
Extensions { para_id: id.into() },
ChainSpec::builder(
cumulus_test_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { para_id: id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()).into() },
)
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(testnet_genesis_with_default_endowed(
extra_endowed_accounts.clone(),
id,
))
.build()
}
/// Get the chain spec for a specific parachain ID.
pub fn get_chain_spec(id: ParaId) -> ChainSpec {
pub fn get_chain_spec(id: Option<ParaId>) -> ChainSpec {
get_chain_spec_with_extra_endowed(id, Default::default())
}
@@ -89,7 +89,7 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec {
pub fn testnet_genesis_with_default_endowed(
mut extra_endowed_accounts: Vec<AccountId>,
self_para_id: Option<ParaId>,
) -> cumulus_test_runtime::RuntimeGenesisConfig {
) -> serde_json::Value {
let mut endowed = vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
@@ -114,21 +114,12 @@ pub fn testnet_genesis(
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
self_para_id: Option<ParaId>,
) -> cumulus_test_runtime::RuntimeGenesisConfig {
cumulus_test_runtime::RuntimeGenesisConfig {
system: cumulus_test_runtime::SystemConfig {
code: cumulus_test_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
..Default::default()
},
glutton: Default::default(),
parachain_system: Default::default(),
balances: cumulus_test_runtime::BalancesConfig {
) -> serde_json::Value {
serde_json::json!({
"balances": cumulus_test_runtime::BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
},
sudo: cumulus_test_runtime::SudoConfig { key: Some(root_key) },
transaction_payment: Default::default(),
test_pallet: cumulus_test_runtime::TestPalletConfig { self_para_id, ..Default::default() },
}
"sudo": cumulus_test_runtime::SudoConfig { key: Some(root_key) },
"testPallet": cumulus_test_runtime::TestPalletConfig { self_para_id, ..Default::default() }
})
}
+3 -2
View File
@@ -287,8 +287,9 @@ impl SubstrateCli for TestCollatorCli {
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"" => Box::new(cumulus_test_service::get_chain_spec(ParaId::from(self.parachain_id)))
as Box<_>,
"" => Box::new(cumulus_test_service::get_chain_spec(Some(ParaId::from(
self.parachain_id,
)))) as Box<_>,
path => {
let chain_spec =
cumulus_test_service::chain_spec::ChainSpec::from_json_file(path.into())?;
+1 -1
View File
@@ -23,7 +23,7 @@ use sp_runtime::traits::Block as BlockT;
/// Returns the initial head data for a parachain ID.
pub fn initial_head_data(para_id: ParaId) -> HeadData {
let spec = crate::chain_spec::get_chain_spec(para_id);
let spec = crate::chain_spec::get_chain_spec(Some(para_id));
let block: Block = generate_genesis_block(&spec, sp_runtime::StateVersion::V1).unwrap();
let genesis_state = block.header().encode();
genesis_state.into()
+1 -1
View File
@@ -719,7 +719,7 @@ pub fn node_config(
let role = if is_collator { Role::Authority } else { Role::Full };
let key_seed = key.to_seed();
let mut spec =
Box::new(chain_spec::get_chain_spec_with_extra_endowed(para_id, endowed_accounts));
Box::new(chain_spec::get_chain_spec_with_extra_endowed(Some(para_id), endowed_accounts));
let mut storage = spec.as_storage_builder().build_storage().expect("could not build storage");
+1 -1
View File
@@ -73,7 +73,7 @@ fn main() -> Result<(), sc_cli::Error> {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|_config| {
let parachain_id = ParaId::from(cmd.parachain_id);
let spec = cumulus_test_service::get_chain_spec(parachain_id);
let spec = cumulus_test_service::get_chain_spec(Some(parachain_id));
cmd.base.run(&spec)
})
},
@@ -4,7 +4,7 @@ default_command = "polkadot"
chain = "rococo-local"
[relaychain.genesis.runtime.configuration.config]
[relaychain.genesis.runtimeGenesis.patch.configuration.config]
# set parameters such that collators only connect to 1 validator as a backing group
max_validators_per_core = 1
group_rotation_frequency = 100 # 10 mins
@@ -32,7 +32,7 @@ cumulus_based = true
add_to_genesis = false
register_para = false
# Set some random value in the genesis state to create a different genesis hash.
[parachains.genesis.runtime.sudo]
[parachains.genesis.runtimeGenesis.patch.sudo]
key = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
# run the parachain that will be used to return the header of the solo chain.
+199 -337
View File
@@ -75,7 +75,7 @@ pub type GenericChainSpec = service::GenericChainSpec<(), Extensions>;
/// The `ChainSpec` parameterized for the westend runtime.
#[cfg(feature = "westend-native")]
pub type WestendChainSpec = service::GenericChainSpec<westend::RuntimeGenesisConfig, Extensions>;
pub type WestendChainSpec = service::GenericChainSpec<(), Extensions>;
/// The `ChainSpec` parameterized for the westend runtime.
// Dummy chain spec, but that is fine when we don't have the native runtime.
@@ -84,12 +84,7 @@ pub type WestendChainSpec = GenericChainSpec;
/// The `ChainSpec` parameterized for the rococo runtime.
#[cfg(feature = "rococo-native")]
pub type RococoChainSpec = service::GenericChainSpec<rococo::RuntimeGenesisConfig, Extensions>;
/// The `ChainSpec` parameterized for the `versi` runtime.
///
/// As of now `Versi` will just be a clone of `Rococo`, until we need it to differ.
pub type VersiChainSpec = RococoChainSpec;
pub type RococoChainSpec = service::GenericChainSpec<(), Extensions>;
/// The `ChainSpec` parameterized for the rococo runtime.
// Dummy chain spec, but that is fine when we don't have the native runtime.
@@ -206,7 +201,7 @@ fn rococo_session_keys(
}
#[cfg(feature = "westend-native")]
fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig {
fn westend_staging_testnet_config_genesis() -> serde_json::Value {
use hex_literal::hex;
use sp_core::crypto::UncheckedInto;
@@ -344,19 +339,16 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim
const ENDOWMENT: u128 = 1_000_000 * WND;
const STASH: u128 = 100 * WND;
westend::RuntimeGenesisConfig {
system: westend::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() },
balances: westend::BalancesConfig {
balances: endowed_accounts
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.map(|k: &AccountId| (k.clone(), ENDOWMENT))
.chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
.collect(),
.collect::<Vec<_>>(),
},
beefy: Default::default(),
indices: westend::IndicesConfig { indices: vec![] },
session: westend::SessionConfig {
keys: initial_authorities
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
@@ -375,51 +367,32 @@ fn westend_staging_testnet_config_genesis(wasm_binary: &[u8]) -> westend::Runtim
})
.collect::<Vec<_>>(),
},
staking: westend::StakingConfig {
validator_count: 50,
minimum_validator_count: 4,
stakers: initial_authorities
"staking": {
"validatorCount": 50,
"minimumValidatorCount": 4,
"stakers": initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::Validator))
.collect(),
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
force_era: Forcing::ForceNone,
slash_reward_fraction: Perbill::from_percent(10),
..Default::default()
.map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::<AccountId>::Validator))
.collect::<Vec<_>>(),
"invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
"forceEra": Forcing::ForceNone,
"slashRewardFraction": Perbill::from_percent(10),
},
babe: westend::BabeConfig {
authorities: Default::default(),
epoch_config: Some(westend::BABE_GENESIS_EPOCH_CONFIG),
..Default::default()
"babe": {
"epochConfig": Some(westend::BABE_GENESIS_EPOCH_CONFIG),
},
grandpa: Default::default(),
im_online: Default::default(),
authority_discovery: westend::AuthorityDiscoveryConfig {
keys: vec![],
..Default::default()
"sudo": { "key": Some(endowed_accounts[0].clone()) },
"configuration": {
"config": default_parachains_host_configuration(),
},
vesting: westend::VestingConfig { vesting: vec![] },
sudo: westend::SudoConfig { key: Some(endowed_accounts[0].clone()) },
hrmp: Default::default(),
treasury: Default::default(),
configuration: westend::ConfigurationConfig {
config: default_parachains_host_configuration(),
"registrar": {
"nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID,
},
paras: Default::default(),
registrar: westend_runtime::RegistrarConfig {
next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID,
..Default::default()
},
xcm_pallet: Default::default(),
nomination_pools: Default::default(),
assigned_slots: Default::default(),
}
})
}
#[cfg(feature = "rococo-native")]
fn rococo_staging_testnet_config_genesis(
wasm_binary: &[u8],
) -> rococo_runtime::RuntimeGenesisConfig {
fn rococo_staging_testnet_config_genesis() -> serde_json::Value {
use hex_literal::hex;
use sp_core::crypto::UncheckedInto;
@@ -662,19 +635,16 @@ fn rococo_staging_testnet_config_genesis(
const ENDOWMENT: u128 = 1_000_000 * ROC;
const STASH: u128 = 100 * ROC;
rococo_runtime::RuntimeGenesisConfig {
system: rococo_runtime::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() },
balances: rococo_runtime::BalancesConfig {
balances: endowed_accounts
serde_json::json!({
"balances": {
"balances": endowed_accounts
.iter()
.map(|k: &AccountId| (k.clone(), ENDOWMENT))
.chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
.collect(),
.collect::<Vec<_>>(),
},
beefy: Default::default(),
indices: rococo_runtime::IndicesConfig { indices: vec![] },
session: rococo_runtime::SessionConfig {
keys: initial_authorities
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
@@ -693,80 +663,55 @@ fn rococo_staging_testnet_config_genesis(
})
.collect::<Vec<_>>(),
},
babe: rococo_runtime::BabeConfig {
authorities: Default::default(),
epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG),
..Default::default()
"babe": {
"epochConfig": Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG),
},
grandpa: Default::default(),
im_online: Default::default(),
treasury: Default::default(),
authority_discovery: rococo_runtime::AuthorityDiscoveryConfig {
keys: vec![],
..Default::default()
"sudo": { "key": Some(endowed_accounts[0].clone()) },
"configuration": {
"config": default_parachains_host_configuration(),
},
claims: rococo::ClaimsConfig { claims: vec![], vesting: vec![] },
vesting: rococo::VestingConfig { vesting: vec![] },
sudo: rococo_runtime::SudoConfig { key: Some(endowed_accounts[0].clone()) },
paras: rococo_runtime::ParasConfig { paras: vec![], ..Default::default() },
hrmp: Default::default(),
configuration: rococo_runtime::ConfigurationConfig {
config: default_parachains_host_configuration(),
"registrar": {
"nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID,
},
registrar: rococo_runtime::RegistrarConfig {
next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID,
..Default::default()
},
xcm_pallet: Default::default(),
nis_counterpart_balances: Default::default(),
assigned_slots: Default::default(),
}
})
}
/// Westend staging testnet config.
#[cfg(feature = "westend-native")]
pub fn westend_staging_testnet_config() -> Result<WestendChainSpec, String> {
let wasm_binary = westend::WASM_BINARY.ok_or("Westend development wasm not available")?;
let boot_nodes = vec![];
Ok(WestendChainSpec::from_genesis(
"Westend Staging Testnet",
"westend_staging_testnet",
ChainType::Live,
move || westend_staging_testnet_config_genesis(wasm_binary),
boot_nodes,
Some(
TelemetryEndpoints::new(vec![(WESTEND_STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Westend Staging telemetry url is valid; qed"),
),
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(WestendChainSpec::builder(
westend::WASM_BINARY.ok_or("Westend development wasm not available")?,
Default::default(),
))
)
.with_name("Westend Staging Testnet")
.with_id("westend_staging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(westend_staging_testnet_config_genesis())
.with_telemetry_endpoints(
TelemetryEndpoints::new(vec![(WESTEND_STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Westend Staging telemetry url is valid; qed"),
)
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
/// Rococo staging testnet config.
#[cfg(feature = "rococo-native")]
pub fn rococo_staging_testnet_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?;
let boot_nodes = vec![];
Ok(RococoChainSpec::from_genesis(
"Rococo Staging Testnet",
"rococo_staging_testnet",
ChainType::Live,
move || rococo_staging_testnet_config_genesis(wasm_binary),
boot_nodes,
Some(
TelemetryEndpoints::new(vec![(ROCOCO_STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Rococo Staging telemetry url is valid; qed"),
),
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?,
Default::default(),
))
)
.with_name("Rococo Staging Testnet")
.with_id("rococo_staging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(rococo_staging_testnet_config_genesis())
.with_telemetry_endpoints(
TelemetryEndpoints::new(vec![(ROCOCO_STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Rococo Staging telemetry url is valid; qed"),
)
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
pub fn versi_chain_spec_properties() -> serde_json::map::Map<String, serde_json::Value> {
@@ -783,24 +728,21 @@ pub fn versi_chain_spec_properties() -> serde_json::map::Map<String, serde_json:
/// Versi staging testnet config.
#[cfg(feature = "rococo-native")]
pub fn versi_staging_testnet_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Versi development wasm not available")?;
let boot_nodes = vec![];
Ok(RococoChainSpec::from_genesis(
"Versi Staging Testnet",
"versi_staging_testnet",
ChainType::Live,
move || rococo_staging_testnet_config_genesis(wasm_binary),
boot_nodes,
Some(
TelemetryEndpoints::new(vec![(VERSI_STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Versi Staging telemetry url is valid; qed"),
),
Some("versi"),
None,
Some(versi_chain_spec_properties()),
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Versi development wasm not available")?,
Default::default(),
))
)
.with_name("Versi Staging Testnet")
.with_id("versi_staging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(rococo_staging_testnet_config_genesis())
.with_telemetry_endpoints(
TelemetryEndpoints::new(vec![(VERSI_STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Versi Staging telemetry url is valid; qed"),
)
.with_protocol_id("versi")
.with_properties(versi_chain_spec_properties())
.build())
}
/// Helper function to generate a crypto pair from seed
@@ -879,10 +821,9 @@ fn testnet_accounts() -> Vec<AccountId> {
]
}
/// Helper function to create westend `RuntimeGenesisConfig` for testing
/// Helper function to create westend runtime `GenesisConfig` patch for testing
#[cfg(feature = "westend-native")]
pub fn westend_testnet_genesis(
wasm_binary: &[u8],
initial_authorities: Vec<(
AccountId,
AccountId,
@@ -896,21 +837,18 @@ pub fn westend_testnet_genesis(
)>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
) -> westend::RuntimeGenesisConfig {
) -> serde_json::Value {
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(testnet_accounts);
const ENDOWMENT: u128 = 1_000_000 * WND;
const STASH: u128 = 100 * WND;
westend::RuntimeGenesisConfig {
system: westend::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() },
indices: westend::IndicesConfig { indices: vec![] },
balances: westend::BalancesConfig {
balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(),
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::<Vec<_>>(),
},
beefy: Default::default(),
session: westend::SessionConfig {
keys: initial_authorities
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
@@ -929,51 +867,33 @@ pub fn westend_testnet_genesis(
})
.collect::<Vec<_>>(),
},
staking: westend::StakingConfig {
minimum_validator_count: 1,
validator_count: initial_authorities.len() as u32,
stakers: initial_authorities
"staking": {
"minimumValidatorCount": 1,
"validatorCount": initial_authorities.len() as u32,
"stakers": initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::Validator))
.collect(),
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
force_era: Forcing::NotForcing,
slash_reward_fraction: Perbill::from_percent(10),
..Default::default()
.map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::<AccountId>::Validator))
.collect::<Vec<_>>(),
"invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
"forceEra": Forcing::NotForcing,
"slashRewardFraction": Perbill::from_percent(10),
},
babe: westend::BabeConfig {
authorities: Default::default(),
epoch_config: Some(westend::BABE_GENESIS_EPOCH_CONFIG),
..Default::default()
"babe": {
"epochConfig": Some(westend::BABE_GENESIS_EPOCH_CONFIG),
},
grandpa: Default::default(),
im_online: Default::default(),
authority_discovery: westend::AuthorityDiscoveryConfig {
keys: vec![],
..Default::default()
"sudo": { "key": Some(root_key) },
"configuration": {
"config": default_parachains_host_configuration(),
},
vesting: westend::VestingConfig { vesting: vec![] },
sudo: westend::SudoConfig { key: Some(root_key) },
hrmp: Default::default(),
treasury: Default::default(),
configuration: westend::ConfigurationConfig {
config: default_parachains_host_configuration(),
"registrar": {
"nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID,
},
paras: Default::default(),
registrar: westend_runtime::RegistrarConfig {
next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID,
..Default::default()
},
xcm_pallet: Default::default(),
nomination_pools: Default::default(),
assigned_slots: Default::default(),
}
})
}
/// Helper function to create rococo `RuntimeGenesisConfig` for testing
/// Helper function to create rococo runtime `GenesisConfig` patch for testing
#[cfg(feature = "rococo-native")]
pub fn rococo_testnet_genesis(
wasm_binary: &[u8],
initial_authorities: Vec<(
AccountId,
AccountId,
@@ -987,20 +907,17 @@ pub fn rococo_testnet_genesis(
)>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
) -> rococo_runtime::RuntimeGenesisConfig {
) -> serde_json::Value {
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(testnet_accounts);
const ENDOWMENT: u128 = 1_000_000 * ROC;
rococo_runtime::RuntimeGenesisConfig {
system: rococo_runtime::SystemConfig { code: wasm_binary.to_vec(), ..Default::default() },
beefy: Default::default(),
indices: rococo_runtime::IndicesConfig { indices: vec![] },
balances: rococo_runtime::BalancesConfig {
balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(),
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::<Vec<_>>(),
},
session: rococo_runtime::SessionConfig {
keys: initial_authorities
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
@@ -1019,43 +936,25 @@ pub fn rococo_testnet_genesis(
})
.collect::<Vec<_>>(),
},
babe: rococo_runtime::BabeConfig {
authorities: Default::default(),
epoch_config: Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG),
..Default::default()
"babe": {
"epochConfig": Some(rococo_runtime::BABE_GENESIS_EPOCH_CONFIG),
},
grandpa: Default::default(),
im_online: Default::default(),
treasury: Default::default(),
claims: rococo::ClaimsConfig { claims: vec![], vesting: vec![] },
vesting: rococo::VestingConfig { vesting: vec![] },
authority_discovery: rococo_runtime::AuthorityDiscoveryConfig {
keys: vec![],
..Default::default()
},
sudo: rococo_runtime::SudoConfig { key: Some(root_key.clone()) },
hrmp: Default::default(),
configuration: rococo_runtime::ConfigurationConfig {
config: polkadot_runtime_parachains::configuration::HostConfiguration {
"sudo": { "key": Some(root_key.clone()) },
"configuration": {
"config": polkadot_runtime_parachains::configuration::HostConfiguration {
max_validators_per_core: Some(1),
..default_parachains_host_configuration()
},
},
paras: rococo_runtime::ParasConfig { paras: vec![], ..Default::default() },
registrar: rococo_runtime::RegistrarConfig {
next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID,
..Default::default()
},
xcm_pallet: Default::default(),
nis_counterpart_balances: Default::default(),
assigned_slots: Default::default(),
}
"registrar": {
"nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID,
}
})
}
#[cfg(feature = "westend-native")]
fn westend_development_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig {
fn westend_development_config_genesis() -> serde_json::Value {
westend_testnet_genesis(
wasm_binary,
vec![get_authority_keys_from_seed("Alice")],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
@@ -1063,9 +962,8 @@ fn westend_development_config_genesis(wasm_binary: &[u8]) -> westend::RuntimeGen
}
#[cfg(feature = "rococo-native")]
fn rococo_development_config_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig {
fn rococo_development_config_genesis() -> serde_json::Value {
rococo_testnet_genesis(
wasm_binary,
vec![get_authority_keys_from_seed("Alice")],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
@@ -1075,84 +973,67 @@ fn rococo_development_config_genesis(wasm_binary: &[u8]) -> rococo_runtime::Runt
/// Westend development config (single validator Alice)
#[cfg(feature = "westend-native")]
pub fn westend_development_config() -> Result<WestendChainSpec, String> {
let wasm_binary = westend::WASM_BINARY.ok_or("Westend development wasm not available")?;
Ok(WestendChainSpec::from_genesis(
"Development",
"westend_dev",
ChainType::Development,
move || westend_development_config_genesis(wasm_binary),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(WestendChainSpec::builder(
westend::WASM_BINARY.ok_or("Westend development wasm not available")?,
Default::default(),
))
)
.with_name("Development")
.with_id("westend_dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(westend_development_config_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
/// Rococo development config (single validator Alice)
#[cfg(feature = "rococo-native")]
pub fn rococo_development_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?;
Ok(RococoChainSpec::from_genesis(
"Development",
"rococo_dev",
ChainType::Development,
move || rococo_development_config_genesis(wasm_binary),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?,
Default::default(),
))
)
.with_name("Development")
.with_id("rococo_dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(rococo_development_config_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
/// `Versi` development config (single validator Alice)
#[cfg(feature = "rococo-native")]
pub fn versi_development_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Versi development wasm not available")?;
Ok(RococoChainSpec::from_genesis(
"Development",
"versi_dev",
ChainType::Development,
move || rococo_development_config_genesis(wasm_binary),
vec![],
None,
Some("versi"),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Versi development wasm not available")?,
Default::default(),
))
)
.with_name("Development")
.with_id("versi_dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(rococo_development_config_genesis())
.with_protocol_id("versi")
.build())
}
/// Wococo development config (single validator Alice)
#[cfg(feature = "rococo-native")]
pub fn wococo_development_config() -> Result<RococoChainSpec, String> {
const WOCOCO_DEV_PROTOCOL_ID: &str = "woco";
let wasm_binary = rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?;
Ok(RococoChainSpec::from_genesis(
"Development",
"wococo_dev",
ChainType::Development,
move || rococo_development_config_genesis(wasm_binary),
vec![],
None,
Some(WOCOCO_DEV_PROTOCOL_ID),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?,
Default::default(),
))
)
.with_name("Development")
.with_id("wococo_dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(rococo_development_config_genesis())
.with_protocol_id(WOCOCO_DEV_PROTOCOL_ID)
.build())
}
#[cfg(feature = "westend-native")]
fn westend_local_testnet_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisConfig {
fn westend_local_testnet_genesis() -> serde_json::Value {
westend_testnet_genesis(
wasm_binary,
vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
@@ -1162,26 +1043,21 @@ fn westend_local_testnet_genesis(wasm_binary: &[u8]) -> westend::RuntimeGenesisC
/// Westend local testnet config (multivalidator Alice + Bob)
#[cfg(feature = "westend-native")]
pub fn westend_local_testnet_config() -> Result<WestendChainSpec, String> {
let wasm_binary = westend::WASM_BINARY.ok_or("Westend development wasm not available")?;
Ok(WestendChainSpec::from_genesis(
"Westend Local Testnet",
"westend_local_testnet",
ChainType::Local,
move || westend_local_testnet_genesis(wasm_binary),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(WestendChainSpec::builder(
westend::WASM_BINARY.ok_or("Westend development wasm not available")?,
Default::default(),
))
)
.with_name("Westend Local Testnet")
.with_id("westend_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(westend_local_testnet_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
#[cfg(feature = "rococo-native")]
fn rococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig {
fn rococo_local_testnet_genesis() -> serde_json::Value {
rococo_testnet_genesis(
wasm_binary,
vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
@@ -1191,27 +1067,22 @@ fn rococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGe
/// Rococo local testnet config (multivalidator Alice + Bob)
#[cfg(feature = "rococo-native")]
pub fn rococo_local_testnet_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?;
Ok(RococoChainSpec::from_genesis(
"Rococo Local Testnet",
"rococo_local_testnet",
ChainType::Local,
move || rococo_local_testnet_genesis(wasm_binary),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Rococo development wasm not available")?,
Default::default(),
))
)
.with_name("Rococo Local Testnet")
.with_id("rococo_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(rococo_local_testnet_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
/// Wococo is a temporary testnet that uses almost the same runtime as rococo.
#[cfg(feature = "rococo-native")]
fn wococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig {
fn wococo_local_testnet_genesis() -> serde_json::Value {
rococo_testnet_genesis(
wasm_binary,
vec![
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
@@ -1226,27 +1097,22 @@ fn wococo_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGe
/// Wococo local testnet config (multivalidator Alice + Bob + Charlie + Dave)
#[cfg(feature = "rococo-native")]
pub fn wococo_local_testnet_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?;
Ok(RococoChainSpec::from_genesis(
"Wococo Local Testnet",
"wococo_local_testnet",
ChainType::Local,
move || wococo_local_testnet_genesis(wasm_binary),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Rococo development wasm (used for wococo) not available")?,
Default::default(),
))
)
.with_name("Wococo Local Testnet")
.with_id("wococo_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(wococo_local_testnet_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.build())
}
/// `Versi` is a temporary testnet that uses the same runtime as rococo.
#[cfg(feature = "rococo-native")]
fn versi_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGenesisConfig {
fn versi_local_testnet_genesis() -> serde_json::Value {
rococo_testnet_genesis(
wasm_binary,
vec![
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
@@ -1261,18 +1127,14 @@ fn versi_local_testnet_genesis(wasm_binary: &[u8]) -> rococo_runtime::RuntimeGen
/// `Versi` local testnet config (multivalidator Alice + Bob + Charlie + Dave)
#[cfg(feature = "rococo-native")]
pub fn versi_local_testnet_config() -> Result<RococoChainSpec, String> {
let wasm_binary = rococo::WASM_BINARY.ok_or("Versi development wasm not available")?;
Ok(RococoChainSpec::from_genesis(
"Versi Local Testnet",
"versi_local_testnet",
ChainType::Local,
move || versi_local_testnet_genesis(wasm_binary),
vec![],
None,
Some("versi"),
None,
None,
Ok(RococoChainSpec::builder(
rococo::WASM_BINARY.ok_or("Rococo development wasm (used for versi) not available")?,
Default::default(),
))
)
.with_name("Versi Local Testnet")
.with_id("versi_local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(versi_local_testnet_genesis())
.with_protocol_id("versi")
.build())
}
+1 -1
View File
@@ -51,7 +51,7 @@ pub struct GenesisParameters;
impl substrate_test_client::GenesisInit for GenesisParameters {
fn genesis_storage(&self) -> Storage {
polkadot_test_service::chain_spec::polkadot_local_testnet_genesis()
polkadot_test_service::chain_spec::polkadot_local_testnet_config()
.build_storage()
.expect("Builds test runtime genesis storage")
}
-1
View File
@@ -59,7 +59,6 @@ substrate-test-client = { path = "../../../../substrate/test-utils/client" }
[dev-dependencies]
pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false }
serde_json = "1.0.107"
substrate-test-utils = { path = "../../../../substrate/test-utils" }
tokio = { version = "1.24.2", features = ["macros"] }
+33 -50
View File
@@ -31,8 +31,7 @@ use test_runtime_constants::currency::DOTS;
const DEFAULT_PROTOCOL_ID: &str = "dot";
/// The `ChainSpec` parameterized for polkadot test runtime.
pub type PolkadotChainSpec =
sc_service::GenericChainSpec<polkadot_test_runtime::RuntimeGenesisConfig, Extensions>;
pub type PolkadotChainSpec = sc_service::GenericChainSpec<(), Extensions>;
/// Returns the properties for the [`PolkadotChainSpec`].
pub fn polkadot_chain_spec_properties() -> serde_json::map::Map<String, serde_json::Value> {
@@ -46,22 +45,21 @@ pub fn polkadot_chain_spec_properties() -> serde_json::map::Map<String, serde_js
/// Local testnet config (multivalidator Alice + Bob)
pub fn polkadot_local_testnet_config() -> PolkadotChainSpec {
PolkadotChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
ChainType::Local,
|| polkadot_local_testnet_genesis(),
vec![],
None,
Some(DEFAULT_PROTOCOL_ID),
None,
Some(polkadot_chain_spec_properties()),
PolkadotChainSpec::builder(
polkadot_test_runtime::WASM_BINARY.expect("Wasm binary must be built for testing"),
Default::default(),
)
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(polkadot_local_testnet_genesis())
.with_protocol_id(DEFAULT_PROTOCOL_ID)
.with_properties(polkadot_chain_spec_properties())
.build()
}
/// Local testnet genesis config (multivalidator Alice + Bob)
pub fn polkadot_local_testnet_genesis() -> polkadot_test_runtime::RuntimeGenesisConfig {
pub fn polkadot_local_testnet_genesis() -> serde_json::Value {
polkadot_testnet_genesis(
vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")],
get_account_id_from_seed::<sr25519::Public>("Alice"),
@@ -114,7 +112,7 @@ fn polkadot_testnet_genesis(
)>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
) -> polkadot_test_runtime::RuntimeGenesisConfig {
) -> serde_json::Value {
use polkadot_test_runtime as runtime;
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(testnet_accounts);
@@ -122,17 +120,12 @@ fn polkadot_testnet_genesis(
const ENDOWMENT: u128 = 1_000_000 * DOTS;
const STASH: u128 = 100 * DOTS;
runtime::RuntimeGenesisConfig {
system: runtime::SystemConfig {
code: runtime::WASM_BINARY.expect("Wasm binary must be built for testing").to_vec(),
..Default::default()
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::<Vec<_>>(),
},
indices: runtime::IndicesConfig { indices: vec![] },
balances: runtime::BalancesConfig {
balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(),
},
session: runtime::SessionConfig {
keys: initial_authorities
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
@@ -149,33 +142,23 @@ fn polkadot_testnet_genesis(
})
.collect::<Vec<_>>(),
},
staking: runtime::StakingConfig {
minimum_validator_count: 1,
validator_count: 2,
stakers: initial_authorities
"staking": {
"minimumValidatorCount": 1,
"validatorCount": 2,
"stakers": initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), STASH, runtime::StakerStatus::Validator))
.collect(),
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
force_era: Forcing::NotForcing,
slash_reward_fraction: Perbill::from_percent(10),
..Default::default()
.map(|x| (x.0.clone(), x.0.clone(), STASH, runtime::StakerStatus::<AccountId>::Validator))
.collect::<Vec<_>>(),
"invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
"forceEra": Forcing::NotForcing,
"slashRewardFraction": Perbill::from_percent(10),
},
babe: runtime::BabeConfig {
authorities: vec![],
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
..Default::default()
"babe": {
"epochConfig": Some(BABE_GENESIS_EPOCH_CONFIG),
},
grandpa: Default::default(),
authority_discovery: runtime::AuthorityDiscoveryConfig {
keys: vec![],
..Default::default()
},
claims: runtime::ClaimsConfig { claims: vec![], vesting: vec![] },
vesting: runtime::VestingConfig { vesting: vec![] },
sudo: runtime::SudoConfig { key: Some(root_key) },
configuration: runtime::ConfigurationConfig {
config: polkadot_runtime_parachains::configuration::HostConfiguration {
"sudo": { "key": Some(root_key) },
"configuration": {
"config": polkadot_runtime_parachains::configuration::HostConfiguration {
validation_upgrade_cooldown: 10u32,
validation_upgrade_delay: 5,
code_retention_period: 1200,
@@ -188,8 +171,8 @@ fn polkadot_testnet_genesis(
minimum_validation_upgrade_delay: 5,
..Default::default()
},
},
}
}
})
}
/// Can be called for a `Configuration` to check if it is a configuration for the `Test` network.
+4 -1
View File
@@ -246,7 +246,8 @@ impl sp_runtime::traits::Convert<sp_core::U256, Balance> for U256ToBalance {
}
/// Macro to set a value (e.g. when using the `parameter_types` macro) to either a production value
/// or to an environment variable or testing value (in case the `fast-runtime` feature is selected).
/// or to an environment variable or testing value (in case the `fast-runtime` feature is selected)
/// or one of two testing values depending on feature.
/// Note that the environment variable is evaluated _at compile time_.
///
/// Usage:
@@ -255,6 +256,8 @@ impl sp_runtime::traits::Convert<sp_core::U256, Balance> for U256ToBalance {
/// // Note that the env variable version parameter cannot be const.
/// pub LaunchPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1, "KSM_LAUNCH_PERIOD");
/// pub const VotingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1 * MINUTES);
/// pub const EpochDuration: BlockNumber =
/// prod_or_fast!(1 * HOURS, "fast-runtime", 1 * MINUTES, "fast-runtime-10m", 10 * MINUTES);
/// }
/// ```
#[macro_export]
@@ -56,6 +56,7 @@ const LOG_TARGET: &str = "runtime::configuration";
serde::Serialize,
serde::Deserialize,
)]
#[serde(deny_unknown_fields)]
pub struct HostConfiguration<BlockNumber> {
// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct
// requires special treatment.
+1 -1
View File
@@ -313,7 +313,7 @@ try-runtime = [
]
# Set timing constants (e.g. session period) to faster versions to speed up testing.
fast-runtime = []
fast-runtime = [ "rococo-runtime-constants/fast-runtime" ]
runtime-metrics = [ "runtime-parachains/runtime-metrics", "sp-io/with-tracing" ]
@@ -29,3 +29,6 @@ std = [
"sp-weights/std",
"xcm/std",
]
# Set timing constants (e.g. session period) to faster versions to speed up testing.
fast-runtime = []
@@ -1,7 +1,7 @@
[settings]
timeout = 1000
[relaychain.genesis.runtime.configuration.config]
[relaychain.genesis.runtimeGenesis.patch.configuration.config]
max_validators_per_core = 5
needed_approvals = 8
@@ -2,7 +2,7 @@
timeout = 1000
bootnode = true
[relaychain.genesis.runtime.configuration.config]
[relaychain.genesis.runtimeGenesis.patch.configuration.config]
max_validators_per_core = 1
needed_approvals = 2
@@ -2,7 +2,7 @@
timeout = 1000
bootnode = true
[relaychain.genesis.runtime.configuration.config]
[relaychain.genesis.runtimeGenesis.patch.configuration.config]
max_validators_per_core = 1
needed_approvals = 2
group_rotation_frequency = 2
@@ -2,7 +2,7 @@
timeout = 1000
bootnode = true
[relaychain.genesis.runtime.configuration.config]
[relaychain.genesis.runtimeGenesis.patch.configuration.config]
max_validators_per_core = 1
needed_approvals = 3
+19
View File
@@ -0,0 +1,19 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
title: "`chain-spec`: getting ready for native-runtime-free world"
doc:
- audience: Node Dev
description: |
- [`ChainSpec::from_genesis`](https://github.com/paritytech/polkadot-sdk/blob/3df6b4d00eb310900de6f4858114baf68239412c/substrate/client/chain-spec/src/chain_spec.rs#L525) becomes deprecated in favor of [`ChainSpec::builder()`](https://github.com/paritytech/polkadot-sdk/blob/3df6b4d00eb310900de6f4858114baf68239412c/substrate/client/chain-spec/src/chain_spec.rs#L432),
- The signature of [`ChainSpec::from_genesis`] method was changed by extending it with `code` argument.
migrations:
db: []
runtime: []
crates: []
host_functions: []
+1
View File
@@ -17,6 +17,7 @@ subkey = { path = "bin/utils/subkey" }
chain-spec-builder = { package = "staging-chain-spec-builder", path = "bin/utils/chain-spec-builder" }
sc-service = { path = "client/service" }
sc-chain-spec = { path = "client/chain-spec" }
sc-cli = { path = "client/cli" }
sc-consensus-aura = { path = "client/consensus/aura" }
sc-consensus-babe = { path = "client/consensus/babe" }
+1
View File
@@ -21,6 +21,7 @@ clap = { version = "4.0.9", features = ["derive"] }
futures = { version = "0.3.21", features = ["thread-pool"] }
futures-timer = "3.0.1"
jsonrpsee = { version = "0.16.2", features = ["server"] }
serde_json = "1.0.107"
sc-cli = { path = "../../../client/cli" }
sc-executor = { path = "../../../client/executor" }
+15 -26
View File
@@ -15,12 +15,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use runtime::{BalancesConfig, RuntimeGenesisConfig, SudoConfig, SystemConfig, WASM_BINARY};
use runtime::{BalancesConfig, SudoConfig, WASM_BINARY};
use sc_service::{ChainType, Properties};
use serde_json::{json, Value};
use sp_keyring::AccountKeyring;
/// This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec<RuntimeGenesisConfig>;
pub type ChainSpec = sc_service::GenericChainSpec<()>;
fn props() -> Properties {
let mut properties = Properties::new();
@@ -30,37 +31,25 @@ fn props() -> Properties {
}
pub fn development_config() -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;
Ok(ChainSpec::from_genesis(
"Development",
"dev",
ChainType::Development,
move || testnet_genesis(wasm_binary),
vec![],
None,
None,
None,
Some(props()),
None,
))
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_properties(props())
.build())
}
/// Configure initial storage state for FRAME pallets.
fn testnet_genesis(wasm_binary: &[u8]) -> RuntimeGenesisConfig {
fn testnet_genesis() -> Value {
use frame::traits::Get;
use runtime::interface::{Balance, MinimumBalance};
let endowment = <MinimumBalance as Get<Balance>>::get().max(1) * 1000;
let balances = AccountKeyring::iter()
.map(|a| (a.to_account_id(), endowment))
.collect::<Vec<_>>();
RuntimeGenesisConfig {
system: SystemConfig {
// Add Wasm runtime to storage.
code: wasm_binary.to_vec(),
_config: Default::default(),
},
balances: BalancesConfig { balances },
sudo: SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) },
..Default::default()
}
json!({
"balances": BalancesConfig { balances },
"sudo": SudoConfig { key: Some(AccountKeyring::Alice.to_account_id()) },
})
}
+4
View File
@@ -9,6 +9,7 @@ scale-info = { version = "2.6.0", default-features = false }
# this is a frame-based runtime, thus importing `frame` with runtime feature enabled.
frame = { path = "../../../frame", default-features = false, features = ["runtime", "experimental"] }
frame-support = { path = "../../../frame/support", default-features = false}
# pallets that we want to use
pallet-balances = { path = "../../../frame/balances", default-features = false }
@@ -17,6 +18,9 @@ pallet-timestamp = { path = "../../../frame/timestamp", default-features = false
pallet-transaction-payment = { path = "../../../frame/transaction-payment", default-features = false }
pallet-transaction-payment-rpc-runtime-api = { path = "../../../frame/transaction-payment/rpc/runtime-api", default-features = false }
# genesis builder that allows us to interacto with runtime genesis config
sp-genesis-builder = { path = "../../../primitives/genesis-builder", default-features = false}
[build-dependencies]
substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true }
+11
View File
@@ -31,6 +31,7 @@ use frame::{
prelude::*,
},
};
use frame_support::genesis_builder_helper::{build_config, create_default_config};
#[runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
@@ -210,6 +211,16 @@ impl_runtime_apis! {
TransactionPayment::length_to_fee(length)
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn create_default_config() -> Vec<u8> {
create_default_config::<RuntimeGenesisConfig>()
}
fn build_config(config: Vec<u8>) -> sp_genesis_builder::Result {
build_config::<RuntimeGenesisConfig>(config)
}
}
}
/// Some re-exports that the node side code needs to know. Some are useful in this context as well.
@@ -19,6 +19,7 @@ name = "node-template"
[dependencies]
clap = { version = "4.4.6", features = ["derive"] }
futures = { version = "0.3.21", features = ["thread-pool"]}
serde_json = "1.0.85"
sc-cli = { path = "../../../client/cli" }
sp-core = { path = "../../../primitives/core" }
@@ -1,7 +1,4 @@
use node_template_runtime::{
AccountId, AuraConfig, BalancesConfig, GrandpaConfig, RuntimeGenesisConfig, Signature,
SudoConfig, SystemConfig, WASM_BINARY,
};
use node_template_runtime::{AccountId, RuntimeGenesisConfig, Signature, WASM_BINARY};
use sc_service::ChainType;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
@@ -37,122 +34,84 @@ pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
}
pub fn development_config() -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;
Ok(ChainSpec::from_genesis(
// Name
"Development",
// ID
"dev",
ChainType::Development,
move || {
testnet_genesis(
wasm_binary,
// 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,
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
None,
// Properties
None,
// Extensions
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,
))
.build())
}
pub fn local_testnet_config() -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;
Ok(ChainSpec::from_genesis(
// Name
"Local Testnet",
// ID
"local_testnet",
ChainType::Local,
move || {
testnet_genesis(
wasm_binary,
// 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,
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
// Properties
None,
None,
// Extensions
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,
))
.build())
}
/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
wasm_binary: &[u8],
initial_authorities: Vec<(AuraId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool,
) -> RuntimeGenesisConfig {
RuntimeGenesisConfig {
system: SystemConfig {
// Add Wasm runtime to storage.
code: wasm_binary.to_vec(),
..Default::default()
},
balances: BalancesConfig {
) -> serde_json::Value {
serde_json::json!({
"balances": {
// Configure endowed accounts with initial balance of 1 << 60.
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
aura: AuraConfig {
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
"aura": {
"authorities": initial_authorities.iter().map(|x| (x.0.clone())).collect::<Vec<_>>(),
},
grandpa: GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(),
..Default::default()
"grandpa": {
"authorities": initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::<Vec<_>>(),
},
sudo: SudoConfig {
"sudo": {
// Assign network admin rights.
key: Some(root_key),
"key": Some(root_key),
},
transaction_payment: Default::default(),
}
})
}
@@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] }
pallet-aura = { path = "../../../frame/aura", default-features = false}
pallet-balances = { path = "../../../frame/balances", default-features = false}
@@ -28,17 +28,18 @@ pallet-transaction-payment = { path = "../../../frame/transaction-payment", defa
frame-executive = { path = "../../../frame/executive", default-features = false}
sp-api = { path = "../../../primitives/api", default-features = false}
sp-block-builder = { path = "../../../primitives/block-builder", default-features = false}
sp-consensus-aura = { path = "../../../primitives/consensus/aura", default-features = false}
sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false}
sp-core = { path = "../../../primitives/core", default-features = false}
sp-consensus-aura = { path = "../../../primitives/consensus/aura", default-features = false, features = ["serde"] }
sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features = ["serde"] }
sp-core = { path = "../../../primitives/core", default-features = false, features = ["serde"]}
sp-inherents = { path = "../../../primitives/inherents", default-features = false}
sp-offchain = { path = "../../../primitives/offchain", default-features = false}
sp-runtime = { path = "../../../primitives/runtime", default-features = false}
sp-runtime = { path = "../../../primitives/runtime", default-features = false, features = ["serde"] }
sp-session = { path = "../../../primitives/session", default-features = false}
sp-std = { path = "../../../primitives/std", default-features = false}
sp-storage = { path = "../../../primitives/storage", default-features = false}
sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false}
sp-version = { path = "../../../primitives/version", default-features = false}
sp-version = { path = "../../../primitives/version", default-features = false, features = ["serde"] }
serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] }
sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" }
# Used for the node template's RPCs
@@ -75,6 +76,7 @@ std = [
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-transaction-payment/std",
"scale-info/std",
"serde_json/std",
"sp-api/std",
"sp-block-builder/std",
"sp-consensus-aura/std",
-1
View File
@@ -124,7 +124,6 @@ futures = "0.3.21"
tempfile = "3.1.0"
assert_cmd = "2.0.2"
nix = { version = "0.26.1", features = ["signal"] }
serde_json = "1.0"
regex = "1.6.0"
platforms = "3.0"
soketto = "0.7.1"
+109 -137
View File
@@ -20,10 +20,7 @@
use grandpa_primitives::AuthorityId as GrandpaId;
use kitchensink_runtime::{
constants::currency::*, wasm_binary_unwrap, BabeConfig, BalancesConfig, Block, CouncilConfig,
DemocracyConfig, ElectionsConfig, ImOnlineConfig, IndicesConfig, MaxNominations,
NominationPoolsConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus, StakingConfig,
SudoConfig, SystemConfig, TechnicalCommitteeConfig,
constants::currency::*, wasm_binary_unwrap, Block, MaxNominations, SessionKeys, StakerStatus,
};
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use sc_chain_spec::ChainSpecExtension;
@@ -45,6 +42,8 @@ pub use node_primitives::{AccountId, Balance, Signature};
type AccountPublic = <Signature as Verify>::Signer;
const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
const ENDOWMENT: Balance = 10_000_000 * DOLLARS;
const STASH: Balance = ENDOWMENT / 1000;
/// Node `ChainSpec` extensions.
///
@@ -78,7 +77,11 @@ fn session_keys(
SessionKeys { grandpa, babe, im_online, authority_discovery, mixnet }
}
fn staging_testnet_config_genesis() -> RuntimeGenesisConfig {
fn configure_accounts_for_staging_testnet() -> (
Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId)>,
AccountId,
Vec<AccountId>,
) {
#[rustfmt::skip]
// stash, controller, session-key
// generated with secret:
@@ -190,28 +193,27 @@ fn staging_testnet_config_genesis() -> RuntimeGenesisConfig {
);
let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
(initial_authorities, root_key, endowed_accounts)
}
fn staging_testnet_config_genesis() -> serde_json::Value {
let (initial_authorities, root_key, endowed_accounts) =
configure_accounts_for_staging_testnet();
testnet_genesis(initial_authorities, vec![], root_key, Some(endowed_accounts))
}
/// Staging testnet config.
pub fn staging_testnet_config() -> ChainSpec {
let boot_nodes = vec![];
ChainSpec::from_genesis(
"Staging Testnet",
"staging_testnet",
ChainType::Live,
staging_testnet_config_genesis,
boot_nodes,
Some(
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Staging Testnet")
.with_id("staging_testnet")
.with_chain_type(ChainType::Live)
.with_genesis_config_patch(staging_testnet_config_genesis())
.with_telemetry_endpoints(
TelemetryEndpoints::new(vec![(STAGING_TELEMETRY_URL.to_string(), 0)])
.expect("Staging telemetry url is valid; qed"),
),
None,
None,
None,
Default::default(),
)
)
.build()
}
/// Helper function to generate a crypto pair from seed.
@@ -244,8 +246,7 @@ pub fn authority_keys_from_seed(
)
}
/// Helper function to create RuntimeGenesisConfig for testing.
pub fn testnet_genesis(
fn configure_accounts(
initial_authorities: Vec<(
AccountId,
AccountId,
@@ -256,9 +257,14 @@ pub fn testnet_genesis(
MixnetId,
)>,
initial_nominators: Vec<AccountId>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
) -> RuntimeGenesisConfig {
stash: Balance,
) -> (
Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId)>,
Vec<AccountId>,
usize,
Vec<(AccountId, AccountId, Balance, StakerStatus<AccountId>)>,
) {
let mut endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
@@ -290,7 +296,7 @@ pub fn testnet_genesis(
let mut rng = rand::thread_rng();
let stakers = initial_authorities
.iter()
.map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::Validator))
.map(|x| (x.0.clone(), x.0.clone(), stash, StakerStatus::Validator))
.chain(initial_nominators.iter().map(|x| {
use rand::{seq::SliceRandom, Rng};
let limit = (MaxNominations::get() as usize).min(initial_authorities.len());
@@ -301,23 +307,39 @@ pub fn testnet_genesis(
.into_iter()
.map(|choice| choice.0.clone())
.collect::<Vec<_>>();
(x.clone(), x.clone(), STASH, StakerStatus::Nominator(nominations))
(x.clone(), x.clone(), stash, StakerStatus::Nominator(nominations))
}))
.collect::<Vec<_>>();
let num_endowed_accounts = endowed_accounts.len();
const ENDOWMENT: Balance = 10_000_000 * DOLLARS;
const STASH: Balance = ENDOWMENT / 1000;
(initial_authorities, endowed_accounts, num_endowed_accounts, stakers)
}
RuntimeGenesisConfig {
system: SystemConfig { code: wasm_binary_unwrap().to_vec(), ..Default::default() },
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
/// Helper function to create RuntimeGenesisConfig json patch for testing.
pub fn testnet_genesis(
initial_authorities: Vec<(
AccountId,
AccountId,
GrandpaId,
BabeId,
ImOnlineId,
AuthorityDiscoveryId,
MixnetId,
)>,
initial_nominators: Vec<AccountId>,
root_key: AccountId,
endowed_accounts: Option<Vec<AccountId>>,
) -> serde_json::Value {
let (initial_authorities, endowed_accounts, num_endowed_accounts, stakers) =
configure_accounts(initial_authorities, initial_nominators, endowed_accounts, STASH);
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect::<Vec<_>>(),
},
indices: IndicesConfig { indices: vec![] },
session: SessionConfig {
keys: initial_authorities
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
(
@@ -334,67 +356,45 @@ pub fn testnet_genesis(
})
.collect::<Vec<_>>(),
},
staking: StakingConfig {
validator_count: initial_authorities.len() as u32,
minimum_validator_count: initial_authorities.len() as u32,
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
slash_reward_fraction: Perbill::from_percent(10),
stakers,
..Default::default()
"staking": {
"validatorCount": initial_authorities.len() as u32,
"minimumValidatorCount": initial_authorities.len() as u32,
"invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::<Vec<_>>(),
"slashRewardFraction": Perbill::from_percent(10),
"stakers": stakers.clone(),
},
democracy: DemocracyConfig::default(),
elections: ElectionsConfig {
members: endowed_accounts
"elections": {
"members": endowed_accounts
.iter()
.take((num_endowed_accounts + 1) / 2)
.cloned()
.map(|member| (member, STASH))
.collect(),
.collect::<Vec<_>>(),
},
council: CouncilConfig::default(),
technical_committee: TechnicalCommitteeConfig {
members: endowed_accounts
"technicalCommittee": {
"members": endowed_accounts
.iter()
.take((num_endowed_accounts + 1) / 2)
.cloned()
.collect(),
phantom: Default::default(),
.collect::<Vec<_>>(),
},
sudo: SudoConfig { key: Some(root_key) },
babe: BabeConfig {
epoch_config: Some(kitchensink_runtime::BABE_GENESIS_EPOCH_CONFIG),
..Default::default()
"sudo": { "key": Some(root_key.clone()) },
"babe": {
"epochConfig": Some(kitchensink_runtime::BABE_GENESIS_EPOCH_CONFIG),
},
im_online: ImOnlineConfig { keys: vec![] },
authority_discovery: Default::default(),
grandpa: Default::default(),
technical_membership: Default::default(),
treasury: Default::default(),
society: SocietyConfig { pot: 0 },
vesting: Default::default(),
assets: pallet_assets::GenesisConfig {
"society": { "pot": 0 },
"assets": {
// This asset is used by the NIS pallet as counterpart currency.
assets: vec![(9, get_account_id_from_seed::<sr25519::Public>("Alice"), true, 1)],
..Default::default()
"assets": vec![(9, get_account_id_from_seed::<sr25519::Public>("Alice"), true, 1)],
},
pool_assets: Default::default(),
transaction_storage: Default::default(),
transaction_payment: Default::default(),
alliance: Default::default(),
safe_mode: Default::default(),
tx_pause: Default::default(),
alliance_motion: Default::default(),
nomination_pools: NominationPoolsConfig {
min_create_bond: 10 * DOLLARS,
min_join_bond: 1 * DOLLARS,
..Default::default()
"nominationPools": {
"minCreateBond": 10 * DOLLARS,
"minJoinBond": 1 * DOLLARS,
},
glutton: Default::default(),
mixnet: Default::default(),
}
})
}
fn development_config_genesis() -> RuntimeGenesisConfig {
fn development_config_genesis_json() -> serde_json::Value {
testnet_genesis(
vec![authority_keys_from_seed("Alice")],
vec![],
@@ -405,21 +405,15 @@ fn development_config_genesis() -> RuntimeGenesisConfig {
/// Development config (single validator Alice).
pub fn development_config() -> ChainSpec {
ChainSpec::from_genesis(
"Development",
"dev",
ChainType::Development,
development_config_genesis,
vec![],
None,
None,
None,
None,
Default::default(),
)
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(development_config_genesis_json())
.build()
}
fn local_testnet_genesis() -> RuntimeGenesisConfig {
fn local_testnet_genesis() -> serde_json::Value {
testnet_genesis(
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
vec![],
@@ -430,18 +424,12 @@ fn local_testnet_genesis() -> RuntimeGenesisConfig {
/// Local testnet config (multivalidator Alice + Bob).
pub fn local_testnet_config() -> ChainSpec {
ChainSpec::from_genesis(
"Local Testnet",
"local_testnet",
ChainType::Local,
local_testnet_genesis,
vec![],
None,
None,
None,
None,
Default::default(),
)
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(local_testnet_genesis())
.build()
}
#[cfg(test)]
@@ -451,45 +439,29 @@ pub(crate) mod tests {
use sc_service_test;
use sp_runtime::BuildStorage;
fn local_testnet_genesis_instant_single() -> RuntimeGenesisConfig {
testnet_genesis(
vec![authority_keys_from_seed("Alice")],
vec![],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
)
}
/// Local testnet config (single validator - Alice).
pub fn integration_test_config_with_single_authority() -> ChainSpec {
ChainSpec::from_genesis(
"Integration Test",
"test",
ChainType::Development,
local_testnet_genesis_instant_single,
vec![],
None,
None,
None,
None,
Default::default(),
)
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Integration Test")
.with_id("test")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(testnet_genesis(
vec![authority_keys_from_seed("Alice")],
vec![],
get_account_id_from_seed::<sr25519::Public>("Alice"),
None,
))
.build()
}
/// Local testnet config (multivalidator Alice + Bob).
pub fn integration_test_config_with_two_authorities() -> ChainSpec {
ChainSpec::from_genesis(
"Integration Test",
"test",
ChainType::Development,
local_testnet_genesis,
vec![],
None,
None,
None,
None,
Default::default(),
)
ChainSpec::builder(wasm_binary_unwrap(), Default::default())
.with_name("Integration Test")
.with_id("test")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(local_testnet_genesis())
.build()
}
#[test]
+4 -3
View File
@@ -14,17 +14,17 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.1" }
scale-info = { version = "2.10.0", features = ["derive"] }
scale-info = { version = "2.10.0", features = ["derive", "serde"] }
frame-benchmarking = { path = "../../../frame/benchmarking" }
node-primitives = { path = "../primitives" }
kitchensink-runtime = { path = "../runtime" }
sc-executor = { path = "../../../client/executor" }
sp-core = { path = "../../../primitives/core" }
sp-core = { path = "../../../primitives/core", features=["serde"] }
sp-keystore = { path = "../../../primitives/keystore" }
sp-state-machine = { path = "../../../primitives/state-machine" }
sp-tracing = { path = "../../../primitives/tracing" }
sp-trie = { path = "../../../primitives/trie" }
sp-statement-store = { path = "../../../primitives/statement-store" }
sp-statement-store = { path = "../../../primitives/statement-store", features=["serde"] }
[dev-dependencies]
criterion = "0.4.0"
@@ -47,6 +47,7 @@ sp-consensus-babe = { path = "../../../primitives/consensus/babe" }
sp-externalities = { path = "../../../primitives/externalities" }
sp-keyring = { path = "../../../primitives/keyring" }
sp-runtime = { path = "../../../primitives/runtime" }
serde_json = "1.0.85"
[features]
stress-test = []
+1 -1
View File
@@ -190,7 +190,7 @@ fn bench_execute_block(c: &mut Criterion) {
for strategy in execution_methods {
group.bench_function(format!("{:?}", strategy), |b| {
let genesis_config = node_testing::genesis::config(Some(compact_code_unwrap()));
let genesis_config = node_testing::genesis::config();
let use_native = match strategy {
ExecutionMethod::Native => true,
ExecutionMethod::Wasm(..) => false,
@@ -857,3 +857,19 @@ fn should_import_block_with_test_client() {
futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap();
}
#[test]
fn default_config_as_json_works() {
let mut t = new_test_ext(compact_code_unwrap());
let r = executor_call(&mut t, "GenesisBuilder_create_default_config", &vec![], false)
.0
.unwrap();
let r = Vec::<u8>::decode(&mut &r[..]).unwrap();
let json = String::from_utf8(r.into()).expect("returned value is json. qed.");
let expected = include_str!("res/default_genesis_config.json").to_string();
assert_eq!(
serde_json::from_str::<serde_json::Value>(&expected).unwrap(),
serde_json::from_str::<serde_json::Value>(&json).unwrap()
);
}
+1 -1
View File
@@ -124,7 +124,7 @@ pub fn executor_call(
pub fn new_test_ext(code: &[u8]) -> TestExternalities<BlakeTwo256> {
let ext = TestExternalities::new_with_code(
code,
node_testing::genesis::config(Some(code)).build_storage().unwrap(),
node_testing::genesis::config().build_storage().unwrap(),
);
ext
}
@@ -0,0 +1,108 @@
{
"system": {},
"babe": {
"authorities": [],
"epochConfig": null
},
"indices": {
"indices": []
},
"balances": {
"balances": []
},
"transactionPayment": {
"multiplier": "1000000000000000000"
},
"staking": {
"validatorCount": 0,
"minimumValidatorCount": 0,
"invulnerables": [],
"forceEra": "NotForcing",
"slashRewardFraction": 0,
"canceledPayout": 0,
"stakers": [],
"minNominatorBond": 0,
"minValidatorBond": 0,
"maxValidatorCount": null,
"maxNominatorCount": null
},
"session": {
"keys": []
},
"democracy": {},
"council": {
"members": []
},
"technicalCommittee": {
"members": []
},
"elections": {
"members": []
},
"technicalMembership": {
"members": []
},
"grandpa": {
"authorities": []
},
"treasury": {},
"sudo": {
"key": null
},
"imOnline": {
"keys": []
},
"authorityDiscovery": {
"keys": []
},
"society": {
"pot": 0
},
"vesting": {
"vesting": []
},
"glutton": {
"compute": "0",
"storage": "0",
"trashDataCount": 0
},
"assets": {
"assets": [],
"metadata": [],
"accounts": []
},
"poolAssets": {
"assets": [],
"metadata": [],
"accounts": []
},
"transactionStorage": {
"byteFee": 10,
"entryFee": 1000,
"storagePeriod": 100800
},
"allianceMotion": {
"members": []
},
"alliance": {
"fellows": [],
"allies": []
},
"mixnet": {
"mixnodes": []
},
"nominationPools": {
"minJoinBond": 0,
"minCreateBond": 0,
"maxPools": 16,
"maxMembersPerPool": 32,
"maxMembers": 512,
"globalMaxCommission": null
},
"txPause": {
"paused": []
},
"safeMode": {
"enteredUntil": null
}
}
+11 -9
View File
@@ -20,33 +20,34 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features =
"derive",
"max-encoded-len",
] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] }
static_assertions = "1.1.0"
log = { version = "0.4.17", default-features = false }
serde_json = { version = "1.0.85", default-features = false, features = ["alloc", "arbitrary_precision"] }
# pallet-asset-conversion: turn on "num-traits" feature
primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info", "num-traits"] }
# primitives
sp-authority-discovery = { path = "../../../primitives/authority-discovery", default-features = false}
sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false}
sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false}
sp-authority-discovery = { path = "../../../primitives/authority-discovery", default-features = false, features=["serde"] }
sp-consensus-babe = { path = "../../../primitives/consensus/babe", default-features = false, features=["serde"] }
sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa", default-features = false, features=["serde"] }
sp-block-builder = { path = "../../../primitives/block-builder", default-features = false}
sp-genesis-builder = { default-features = false, path = "../../../primitives/genesis-builder" }
sp-inherents = { path = "../../../primitives/inherents", default-features = false}
node-primitives = { path = "../primitives", default-features = false}
sp-mixnet = { path = "../../../primitives/mixnet", default-features = false }
sp-offchain = { path = "../../../primitives/offchain", default-features = false}
sp-core = { path = "../../../primitives/core", default-features = false}
sp-core = { path = "../../../primitives/core", default-features = false, features=["serde"] }
sp-std = { path = "../../../primitives/std", default-features = false}
sp-api = { path = "../../../primitives/api", default-features = false}
sp-runtime = { path = "../../../primitives/runtime", default-features = false}
sp-staking = { path = "../../../primitives/staking", default-features = false}
sp-runtime = { path = "../../../primitives/runtime", default-features = false, features=["serde"] }
sp-staking = { path = "../../../primitives/staking", default-features = false, features=["serde"] }
sp-storage = { path = "../../../primitives/storage", default-features = false}
sp-session = { path = "../../../primitives/session", default-features = false}
sp-transaction-pool = { path = "../../../primitives/transaction-pool", default-features = false}
sp-statement-store = { path = "../../../primitives/statement-store", default-features = false}
sp-version = { path = "../../../primitives/version", default-features = false}
sp-statement-store = { path = "../../../primitives/statement-store", default-features = false, features=["serde"] }
sp-version = { path = "../../../primitives/version", default-features = false, features=["serde"] }
sp-io = { path = "../../../primitives/io", default-features = false}
# frame dependencies
@@ -230,6 +231,7 @@ std = [
"pallet-whitelist/std",
"primitive-types/std",
"scale-info/std",
"serde_json/std",
"sp-api/std",
"sp-authority-discovery/std",
"sp-block-builder/std",
+15 -7
View File
@@ -398,7 +398,7 @@ impl BenchDb {
let client_config = sc_service::ClientConfig::default();
let genesis_block_builder = sc_service::GenesisBlockBuilder::new(
&keyring.generate_genesis(),
keyring.as_storage_builder(),
!client_config.no_genesis,
backend.clone(),
executor.clone(),
@@ -590,12 +590,20 @@ impl BenchKeyring {
}
}
/// Generate genesis with accounts from this keyring endowed with some balance.
pub fn generate_genesis(&self) -> kitchensink_runtime::RuntimeGenesisConfig {
crate::genesis::config_endowed(
Some(kitchensink_runtime::wasm_binary_unwrap()),
self.collect_account_ids(),
)
/// Generate genesis with accounts from this keyring endowed with some balance and
/// kitchensink_runtime code blob.
pub fn as_storage_builder(&self) -> &dyn sp_runtime::BuildStorage {
self
}
}
impl sp_runtime::BuildStorage for BenchKeyring {
fn assimilate_storage(&self, storage: &mut sp_core::storage::Storage) -> Result<(), String> {
storage.top.insert(
sp_core::storage::well_known_keys::CODE.to_vec(),
kitchensink_runtime::wasm_binary_unwrap().into(),
);
crate::genesis::config_endowed(self.collect_account_ids()).assimilate_storage(storage)
}
}
+6 -1
View File
@@ -42,7 +42,12 @@ pub struct GenesisParameters;
impl substrate_test_client::GenesisInit for GenesisParameters {
fn genesis_storage(&self) -> Storage {
crate::genesis::config(None).build_storage().unwrap()
let mut storage = crate::genesis::config().build_storage().unwrap();
storage.top.insert(
sp_core::storage::well_known_keys::CODE.to_vec(),
kitchensink_runtime::wasm_binary_unwrap().into(),
);
storage
}
}
+7 -11
View File
@@ -20,22 +20,21 @@
use crate::keyring::*;
use kitchensink_runtime::{
constants::currency::*, wasm_binary_unwrap, AccountId, AssetsConfig, BabeConfig,
BalancesConfig, GluttonConfig, GrandpaConfig, IndicesConfig, RuntimeGenesisConfig,
SessionConfig, SocietyConfig, StakerStatus, StakingConfig, SystemConfig,
BABE_GENESIS_EPOCH_CONFIG,
constants::currency::*, AccountId, AssetsConfig, BabeConfig, BalancesConfig, GluttonConfig,
GrandpaConfig, IndicesConfig, RuntimeGenesisConfig, SessionConfig, SocietyConfig, StakerStatus,
StakingConfig, BABE_GENESIS_EPOCH_CONFIG,
};
use sp_keyring::{Ed25519Keyring, Sr25519Keyring};
use sp_runtime::Perbill;
/// Create genesis runtime configuration for tests.
pub fn config(code: Option<&[u8]>) -> RuntimeGenesisConfig {
config_endowed(code, Default::default())
pub fn config() -> RuntimeGenesisConfig {
config_endowed(Default::default())
}
/// Create genesis runtime configuration for tests with some extra
/// endowed accounts.
pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec<AccountId>) -> RuntimeGenesisConfig {
pub fn config_endowed(extra_endowed: Vec<AccountId>) -> RuntimeGenesisConfig {
let mut endowed = vec![
(alice(), 111 * DOLLARS),
(bob(), 100 * DOLLARS),
@@ -48,10 +47,7 @@ pub fn config_endowed(code: Option<&[u8]>, extra_endowed: Vec<AccountId>) -> Run
endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS)));
RuntimeGenesisConfig {
system: SystemConfig {
code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()),
..Default::default()
},
system: Default::default(),
indices: IndicesConfig { indices: vec![] },
balances: BalancesConfig { balances: endowed },
session: SessionConfig {
@@ -23,8 +23,12 @@ crate-type = ["rlib"]
ansi_term = "0.12.1"
clap = { version = "4.4.6", features = ["derive"] }
rand = "0.8"
kitchensink-runtime = { version = "3.0.0-dev", path = "../../node/runtime" }
log = "0.4.17"
node-cli = { package = "staging-node-cli", path = "../../node/cli" }
sc-chain-spec = { path = "../../../client/chain-spec" }
sc-keystore = { path = "../../../client/keystore" }
serde_json = "1.0.100"
sp-core = { path = "../../../primitives/core" }
sp-keystore = { path = "../../../primitives/keystore" }
sp-tracing = { version = "10.0.0", path = "../../../primitives/tracing" }
@@ -17,28 +17,40 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use chain_spec_builder::{
generate_authority_keys_and_store, generate_chain_spec, print_seeds, ChainSpecBuilder,
generate_authority_keys_and_store, generate_chain_spec, generate_chain_spec_for_runtime,
print_seeds, ChainSpecBuilder, ChainSpecBuilderCmd, EditCmd, GenerateCmd, NewCmd, VerifyCmd,
};
use clap::Parser;
use node_cli::chain_spec;
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
use sc_chain_spec::{update_code_in_json_chain_spec, GenericChainSpec};
use sp_core::{crypto::Ss58Codec, sr25519};
use staging_chain_spec_builder as chain_spec_builder;
use std::fs;
fn main() -> Result<(), String> {
#[cfg(build_type = "debug")]
println!(
"The chain spec builder builds a chain specification that includes a Substrate runtime \
compiled as WASM. To ensure proper functioning of the included runtime compile (or run) \
the chain spec builder binary in `--release` mode.\n",
);
sp_tracing::try_init_simple();
let builder = ChainSpecBuilder::parse();
let chain_spec_path = builder.chain_spec_path().to_path_buf();
#[cfg(build_type = "debug")]
if matches!(builder.command, ChainSpecBuilderCmd::Generate(_) | ChainSpecBuilderCmd::New(_)) {
println!(
"The chain spec builder builds a chain specification that includes a Substrate runtime \
compiled as WASM. To ensure proper functioning of the included runtime compile (or run) \
the chain spec builder binary in `--release` mode.\n",
);
}
let (authority_seeds, nominator_accounts, endowed_accounts, sudo_account) = match builder {
ChainSpecBuilder::Generate { authorities, nominators, endowed, keystore_path, .. } => {
let chain_spec_path = builder.chain_spec_path.to_path_buf();
let mut write_chain_spec = true;
let chain_spec_json = match builder.command {
ChainSpecBuilderCmd::Generate(GenerateCmd {
authorities,
nominators,
endowed,
keystore_path,
}) => {
let authorities = authorities.max(1);
let rand_str = || -> String {
OsRng.sample_iter(&Alphanumeric).take(32).map(char::from).collect()
@@ -72,19 +84,58 @@ fn main() -> Result<(), String> {
let sudo_account =
chain_spec::get_account_id_from_seed::<sr25519::Public>(&sudo_seed).to_ss58check();
(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)
generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)
},
ChainSpecBuilder::New {
ChainSpecBuilderCmd::New(NewCmd {
authority_seeds,
nominator_accounts,
endowed_accounts,
sudo_account,
..
} => (authority_seeds, nominator_accounts, endowed_accounts, sudo_account),
};
}) =>
generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account),
ChainSpecBuilderCmd::Runtime(cmd) => generate_chain_spec_for_runtime(&cmd),
ChainSpecBuilderCmd::Edit(EditCmd {
ref input_chain_spec,
ref runtime_wasm_path,
convert_to_raw,
}) => {
let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?;
let json =
generate_chain_spec(authority_seeds, nominator_accounts, endowed_accounts, sudo_account)?;
let mut chain_spec_json =
serde_json::from_str::<serde_json::Value>(&chain_spec.as_json(convert_to_raw)?)
.map_err(|e| format!("Conversion to json failed: {e}"))?;
if let Some(path) = runtime_wasm_path {
update_code_in_json_chain_spec(
&mut chain_spec_json,
&fs::read(path.as_path())
.map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..],
);
}
fs::write(chain_spec_path, json).map_err(|err| err.to_string())
serde_json::to_string_pretty(&chain_spec_json)
.map_err(|e| format!("to pretty failed: {e}"))
},
ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec, ref runtime_wasm_path }) => {
write_chain_spec = false;
let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?;
let mut chain_spec_json =
serde_json::from_str::<serde_json::Value>(&chain_spec.as_json(true)?)
.map_err(|e| format!("Conversion to json failed: {e}"))?;
if let Some(path) = runtime_wasm_path {
update_code_in_json_chain_spec(
&mut chain_spec_json,
&fs::read(path.as_path())
.map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..],
);
};
serde_json::to_string_pretty(&chain_spec_json)
.map_err(|e| format!("to pretty failed: {e}"))
},
}?;
if write_chain_spec {
fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())
} else {
Ok(())
}
}
+215 -94
View File
@@ -29,96 +29,169 @@
//! [`sc-chain-spec`]: ../sc_chain_spec/index.html
//! [`node-cli`]: ../node_cli/index.html
use std::path::{Path, PathBuf};
use std::{
fs,
path::{Path, PathBuf},
};
use ansi_term::Style;
use clap::Parser;
use clap::{Parser, Subcommand};
use sc_chain_spec::GenesisConfigBuilderRuntimeCaller;
use node_cli::chain_spec::{self, AccountId};
use sc_keystore::LocalKeystore;
use serde_json::Value;
use sp_core::crypto::{ByteArray, Ss58Codec};
use sp_keystore::KeystorePtr;
/// A utility to easily create a testnet chain spec definition with a given set
/// of authorities and endowed accounts and/or generate random accounts.
#[derive(Parser)]
#[derive(Debug, Parser)]
#[command(rename_all = "kebab-case")]
pub enum ChainSpecBuilder {
/// Create a new chain spec with the given authorities, endowed and sudo
/// accounts.
New {
/// Authority key seed.
#[arg(long, short, required = true)]
authority_seeds: Vec<String>,
/// Active nominators (SS58 format), each backing a random subset of the aforementioned
/// authorities.
#[arg(long, short, default_value = "0")]
nominator_accounts: Vec<String>,
/// Endowed account address (SS58 format).
#[arg(long, short)]
endowed_accounts: Vec<String>,
/// Sudo account address (SS58 format).
#[arg(long, short)]
sudo_account: String,
/// The path where the chain spec should be saved.
#[arg(long, short, default_value = "./chain_spec.json")]
chain_spec_path: PathBuf,
},
/// Create a new chain spec with the given number of authorities and endowed
/// accounts. Random keys will be generated as required.
Generate {
/// The number of authorities.
#[arg(long, short)]
authorities: usize,
/// The number of nominators backing the aforementioned authorities.
///
/// Will nominate a random subset of `authorities`.
#[arg(long, short, default_value_t = 0)]
nominators: usize,
/// The number of endowed accounts.
#[arg(long, short, default_value_t = 0)]
endowed: usize,
/// The path where the chain spec should be saved.
#[arg(long, short, default_value = "./chain_spec.json")]
chain_spec_path: PathBuf,
/// Path to use when saving generated keystores for each authority.
///
/// At this path, a new folder will be created for each authority's
/// keystore named `auth-$i` where `i` is the authority index, i.e.
/// `auth-0`, `auth-1`, etc.
#[arg(long, short)]
keystore_path: Option<PathBuf>,
},
pub struct ChainSpecBuilder {
#[command(subcommand)]
pub command: ChainSpecBuilderCmd,
/// The path where the chain spec should be saved.
#[arg(long, short, default_value = "./chain_spec.json")]
pub chain_spec_path: PathBuf,
}
impl ChainSpecBuilder {
/// Returns the path where the chain spec should be saved.
pub fn chain_spec_path(&self) -> &Path {
match self {
ChainSpecBuilder::New { chain_spec_path, .. } => chain_spec_path.as_path(),
ChainSpecBuilder::Generate { chain_spec_path, .. } => chain_spec_path.as_path(),
}
}
#[derive(Debug, Subcommand)]
#[command(rename_all = "kebab-case")]
pub enum ChainSpecBuilderCmd {
New(NewCmd),
Generate(GenerateCmd),
Runtime(RuntimeCmd),
Edit(EditCmd),
Verify(VerifyCmd),
}
fn genesis_constructor(
authority_seeds: &[String],
nominator_accounts: &[AccountId],
endowed_accounts: &[AccountId],
sudo_account: &AccountId,
) -> chain_spec::RuntimeGenesisConfig {
let authorities = authority_seeds
.iter()
.map(AsRef::as_ref)
.map(chain_spec::authority_keys_from_seed)
.collect::<Vec<_>>();
/// Create a new chain spec with the given authorities, endowed and sudo
/// accounts. Only works for kitchen-sink runtime
#[derive(Parser, Debug)]
#[command(rename_all = "kebab-case")]
pub struct NewCmd {
/// Authority key seed.
#[arg(long, short, required = true)]
pub authority_seeds: Vec<String>,
/// Active nominators (SS58 format), each backing a random subset of the aforementioned
/// authorities.
#[arg(long, short, default_value = "0")]
pub nominator_accounts: Vec<String>,
/// Endowed account address (SS58 format).
#[arg(long, short)]
pub endowed_accounts: Vec<String>,
/// Sudo account address (SS58 format).
#[arg(long, short)]
pub sudo_account: String,
}
chain_spec::testnet_genesis(
authorities,
nominator_accounts.to_vec(),
sudo_account.clone(),
Some(endowed_accounts.to_vec()),
)
/// Create a new chain spec with the given number of authorities and endowed
/// accounts. Random keys will be generated as required.
#[derive(Parser, Debug)]
pub struct GenerateCmd {
/// The number of authorities.
#[arg(long, short)]
pub authorities: usize,
/// The number of nominators backing the aforementioned authorities.
///
/// Will nominate a random subset of `authorities`.
#[arg(long, short, default_value_t = 0)]
pub nominators: usize,
/// The number of endowed accounts.
#[arg(long, short, default_value_t = 0)]
pub endowed: usize,
/// Path to use when saving generated keystores for each authority.
///
/// At this path, a new folder will be created for each authority's
/// keystore named `auth-$i` where `i` is the authority index, i.e.
/// `auth-0`, `auth-1`, etc.
#[arg(long, short)]
pub keystore_path: Option<PathBuf>,
}
/// Create a new chain spec by interacting with the provided runtime wasm blob.
#[derive(Parser, Debug)]
pub struct RuntimeCmd {
/// The name of chain
#[arg(long, short = 'n', default_value = "Custom")]
chain_name: String,
/// The chain id
#[arg(long, short = 'i', default_value = "custom")]
chain_id: String,
/// The path to runtime wasm blob
#[arg(long, short)]
runtime_wasm_path: PathBuf,
/// Export chainspec as raw storage
#[arg(long, short = 's')]
raw_storage: bool,
/// Verify the genesis config. This silently generates the raw storage from genesis config. Any
/// errors will be reported.
#[arg(long, short = 'v')]
verify: bool,
#[command(subcommand)]
action: GenesisBuildAction,
}
#[derive(Subcommand, Debug, Clone)]
enum GenesisBuildAction {
Patch(PatchCmd),
Full(FullCmd),
Default(DefaultCmd),
}
/// Patches the runtime's default genesis config with provided patch.
#[derive(Parser, Debug, Clone)]
struct PatchCmd {
/// The path to the runtime genesis config patch.
#[arg(long, short)]
patch_path: PathBuf,
}
/// Build the genesis config for runtime using provided json file. No defaults will be used.
#[derive(Parser, Debug, Clone)]
struct FullCmd {
/// The path to the full runtime genesis config json file.
#[arg(long, short)]
config_path: PathBuf,
}
/// Gets the default genesis config for the runtime and uses it in ChainSpec. Please note that
/// default genesis config may not be valid. For some runtimes initial values should be added there
/// (e.g. session keys, babe epoch).
#[derive(Parser, Debug, Clone)]
struct DefaultCmd {
/// If provided stores the default genesis config json file at given path (in addition to
/// chain-spec).
#[arg(long, short)]
default_config_path: Option<PathBuf>,
}
/// Edits provided input chain spec. Input can be converted into raw storage chain-spec. The code
/// can be updated with the runtime provided in the command line.
#[derive(Parser, Debug, Clone)]
pub struct EditCmd {
/// Chain spec to be edited
#[arg(long, short)]
pub input_chain_spec: PathBuf,
/// The path to new runtime wasm blob to be stored into chain-spec
#[arg(long, short = 'r')]
pub runtime_wasm_path: Option<PathBuf>,
/// Convert genesis spec to raw format
#[arg(long, short = 's')]
pub convert_to_raw: bool,
}
/// Verifies provided input chain spec. If the runtime is provided verification is performed against
/// new runtime.
#[derive(Parser, Debug, Clone)]
pub struct VerifyCmd {
/// Chain spec to be edited
#[arg(long, short)]
pub input_chain_spec: PathBuf,
/// The path to new runtime wasm blob to be stored into chain-spec
#[arg(long, short = 'r')]
pub runtime_wasm_path: Option<PathBuf>,
}
/// Generate the chain spec using the given seeds and accounts.
@@ -145,27 +218,24 @@ pub fn generate_chain_spec(
let sudo_account = parse_account(sudo_account)?;
let chain_spec = chain_spec::ChainSpec::from_genesis(
"Custom",
"custom",
sc_chain_spec::ChainType::Live,
move || {
genesis_constructor(
&authority_seeds,
&nominator_accounts,
&endowed_accounts,
&sudo_account,
)
},
vec![],
None,
None,
None,
None,
Default::default(),
);
let authorities = authority_seeds
.iter()
.map(AsRef::as_ref)
.map(chain_spec::authority_keys_from_seed)
.collect::<Vec<_>>();
chain_spec.as_json(false)
chain_spec::ChainSpec::builder(kitchensink_runtime::wasm_binary_unwrap(), Default::default())
.with_name("Custom")
.with_id("custom")
.with_chain_type(sc_chain_spec::ChainType::Live)
.with_genesis_config_patch(chain_spec::testnet_genesis(
authorities,
nominator_accounts,
sudo_account,
Some(endowed_accounts),
))
.build()
.as_json(false)
}
/// Generate the authority keys and store them in the given `keystore_path`.
@@ -241,3 +311,54 @@ pub fn print_seeds(
println!("{}", header.paint("Sudo seed"));
println!("//{}", sudo_seed);
}
/// Processes `RuntimeCmd` and returns JSON version of `ChainSpec`
pub fn generate_chain_spec_for_runtime(cmd: &RuntimeCmd) -> Result<String, String> {
let code = fs::read(cmd.runtime_wasm_path.as_path())
.map_err(|e| format!("wasm blob shall be readable {e}"))?;
let builder = chain_spec::ChainSpec::builder(&code[..], Default::default())
.with_name(&cmd.chain_name[..])
.with_id(&cmd.chain_id[..])
.with_chain_type(sc_chain_spec::ChainType::Live);
let builder = match cmd.action {
GenesisBuildAction::Patch(PatchCmd { ref patch_path }) => {
let patch = fs::read(patch_path.as_path())
.map_err(|e| format!("patch file {patch_path:?} shall be readable: {e}"))?;
builder.with_genesis_config_patch(serde_json::from_slice::<Value>(&patch[..]).map_err(
|e| format!("patch file {patch_path:?} shall contain a valid json: {e}"),
)?)
},
GenesisBuildAction::Full(FullCmd { ref config_path }) => {
let config = fs::read(config_path.as_path())
.map_err(|e| format!("config file {config_path:?} shall be readable: {e}"))?;
builder.with_genesis_config(serde_json::from_slice::<Value>(&config[..]).map_err(
|e| format!("config file {config_path:?} shall contain a valid json: {e}"),
)?)
},
GenesisBuildAction::Default(DefaultCmd { ref default_config_path }) => {
let caller = GenesisConfigBuilderRuntimeCaller::new(&code[..]);
let default_config = caller
.get_default_config()
.map_err(|e| format!("getting default config from runtime should work: {e}"))?;
default_config_path.clone().map(|path| {
fs::write(path.as_path(), serde_json::to_string_pretty(&default_config).unwrap())
.map_err(|err| err.to_string())
});
builder.with_genesis_config(default_config)
},
};
let chain_spec = builder.build();
match (cmd.verify, cmd.raw_storage) {
(_, true) => chain_spec.as_json(true),
(true, false) => {
chain_spec.as_json(true)?;
println!("Genesis config verification: OK");
chain_spec.as_json(false)
},
(false, false) => chain_spec.as_json(false),
}
}
+12
View File
@@ -13,15 +13,27 @@ readme = "README.md"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] }
memmap2 = "0.5.0"
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107"
sc-client-api = { path = "../api" }
sc-chain-spec-derive = { path = "derive" }
sc-executor = { path = "../executor" }
sp-io = { default-features = false, path = "../../primitives/io" }
sc-network = { path = "../network" }
sc-telemetry = { path = "../telemetry" }
sp-blockchain = { path = "../../primitives/blockchain" }
sp-core = { path = "../../primitives/core" }
sp-genesis-builder = { path = "../../primitives/genesis-builder" }
sp-runtime = { path = "../../primitives/runtime" }
sp-state-machine = { path = "../../primitives/state-machine" }
log = { version = "0.4.17", default-features = false }
array-bytes = { version = "6.1" }
docify = "0.2.0"
[dev-dependencies]
substrate-test-runtime = { path = "../../test-utils/runtime" }
sp-keyring = { path = "../../primitives/keyring" }
sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto", features = ["serde"] }
sp-consensus-babe = { default-features = false, path = "../../primitives/consensus/babe", features = ["serde"] }
+2 -88
View File
@@ -1,92 +1,6 @@
Substrate chain configurations.
This crate contains structs and utilities to declare
a runtime-specific configuration file (a.k.a chain spec).
Basic chain spec type containing all required parameters is
[`ChainSpec`](https://docs.rs/sc-chain-spec/latest/sc_chain_spec/struct.GenericChainSpec.html). It can be extended with
additional options that contain configuration specific to your chain.
Usually the extension is going to be an amalgamate of types exposed
by Substrate core modules. To allow the core modules to retrieve
their configuration from your extension you should use `ChainSpecExtension`
macro exposed by this crate.
```rust
use std::collections::HashMap;
use sc_chain_spec::{GenericChainSpec, ChainSpecExtension};
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
pub struct MyExtension {
pub known_blocks: HashMap<u64, String>,
}
pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
```
Some parameters may require different values depending on the
current blockchain height (a.k.a. forks). You can use `ChainSpecGroup`
macro and provided [`Forks`](https://docs.rs/sc-chain-spec/latest/sc_chain_spec/struct.Forks.html) structure to put
such parameters to your chain spec.
This will allow to override a single parameter starting at specific
block number.
```rust
use sc_chain_spec::{Forks, ChainSpecGroup, ChainSpecExtension, GenericChainSpec};
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
pub struct ClientParams {
max_block_size: usize,
max_extrinsic_size: usize,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup)]
pub struct PoolParams {
max_transaction_size: usize,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecGroup, ChainSpecExtension)]
pub struct Extension {
pub client: ClientParams,
pub pool: PoolParams,
}
pub type BlockNumber = u64;
/// A chain spec supporting forkable `ClientParams`.
pub type MyChainSpec1<G> = GenericChainSpec<G, Forks<BlockNumber, ClientParams>>;
/// A chain spec supporting forkable `Extension`.
pub type MyChainSpec2<G> = GenericChainSpec<G, Forks<BlockNumber, Extension>>;
```
It's also possible to have a set of parameters that is allowed to change
with block numbers (i.e. is forkable), and another set that is not subject to changes.
This is also possible by declaring an extension that contains `Forks` within it.
```rust
use serde::{Serialize, Deserialize};
use sc_chain_spec::{Forks, GenericChainSpec, ChainSpecGroup, ChainSpecExtension};
#[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
pub struct ClientParams {
max_block_size: usize,
max_extrinsic_size: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize, ChainSpecGroup)]
pub struct PoolParams {
max_transaction_size: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize, ChainSpecExtension)]
pub struct Extension {
pub client: ClientParams,
#[forks]
pub pool: Forks<u64, PoolParams>,
}
pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
```
This crate contains structs and utilities to declare a runtime-specific configuration file (a.k.a chain spec).
Refer to crate documentation for details.
License: GPL-3.0-or-later WITH Classpath-exception-2.0
@@ -0,0 +1,18 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"raw": {
"top": {
"0x3a636f6465": "0x010101"
},
"childrenDefault": {}
}
}
}
@@ -0,0 +1,19 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"raw": {
"top": {
"0x3a636f6465": "0x010101"
},
"childrenDefault": {}
}
},
"code": "0x060708"
}
@@ -0,0 +1,128 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"runtimeGenesis": {
"config": {
"babe": {
"authorities": [
[
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
1
],
[
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
1
],
[
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
1
]
],
"epochConfig": {
"allowed_slots": "PrimaryAndSecondaryPlainSlots",
"c": [
3,
10
]
}
},
"balances": {
"balances": [
[
"5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH",
100000000000000000
],
[
"5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o",
100000000000000000
],
[
"5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9",
100000000000000000
],
[
"5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK",
100000000000000000
],
[
"5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW",
100000000000000000
],
[
"5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR",
100000000000000000
],
[
"5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY",
100000000000000000
],
[
"5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ",
100000000000000000
],
[
"5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX",
100000000000000000
],
[
"5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q",
100000000000000000
],
[
"5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz",
100000000000000000
],
[
"5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf",
100000000000000000
],
[
"5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz",
100000000000000000
],
[
"5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC",
100000000000000000
],
[
"5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51",
100000000000000000
],
[
"5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e",
100000000000000000
],
[
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
100000000000000000
],
[
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
100000000000000000
],
[
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
100000000000000000
]
]
},
"substrateTest": {
"authorities": [
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y"
]
},
"system": {}
},
"code": "0x0"
}
}
}
@@ -0,0 +1,53 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"raw": {
"top": {
"0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
"0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22",
"0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
"0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48010000000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe220100000000000000",
"0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000",
"0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48010000000000000090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe220100000000000000",
"0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x03000000000000000a0000000000000001",
"0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
"0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01",
"0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545",
"0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545",
"0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901cae4e3edfbb32c91ed3f01ab964f4eeeab50338d8e5176d3141802d7b010a55dadcd5f23cf8aaafa724627e967e90e": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da91b614bd4a126f2d5d294e9a8af9da25248d7e931307afb4b68d8d565d4c66e00d856c6d65f5fed6bb82dcfb60e936c67": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94b21aff9fe1e8b2fc4b0775b8cbeff28ba8e2c7594dd74730f3ca835e95455d199261897edc9735d602ea29615e2b10b": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95786a2916fcb81e1bd5dcd81e0d2452884617f575372edb5a36d85c04cdf2e4699f96fe33eb5f94a28c041b88e398d0c": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95b8542d9672c7b7e779cc7c1e6b605691c2115d06120ea2bee32dd601d02f36367564e7ddf84ae2717ca3f097459652e": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da996c30bdbfab640838e6b6d3c33ab4adb4211b79e34ee8072eab506edd4b93a7b85a14c9a05e5cdd056d98e7dbca87730": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99dc65b1339ec388fbf2ca0cdef51253512c6cfd663203ea16968594f24690338befd906856c4d2f4ef32dad578dba20c": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99e6eb5abd62f5fd54793da91a47e6af6125d57171ff9241f07acaa1bb6a6103517965cf2cd00e643b27e7599ebccba70": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d0052993b6f3bd0544fd1f5e4125b9fbde3e789ecd53431fe5c06c12b72137153496dace35c695b5f4d7b41f7ed5763b": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d6b7e9a5f12bc571053265dade10d3b4b606fc73f57f03cdb4c932d475ab426043e429cecc2ffff0d2672b0df8398c48": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e1a35f56ee295d39287cbffcfc60c4b346f136b564e1fad55031404dd84e5cd3fa76bfe7cc7599b39d38fd06663bbc0a": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e2c1dc507e2035edbbd8776c440d870460c57f0008067cc01c5ff9eb2e2f9b3a94299a915a91198bd1021a6c55596f57": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9eca0e653a94f4080f6311b4e7b6934eb2afba9278e30ccf6a6ceb3a8b6e336b70068f045c666f2e7f4f9cc5f47db8972": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9ee8bf7ef90fc56a8aa3b90b344c599550c29b161e27ff8ba45bf6bad4711f326fc506a8803453a4d7e3158e993495f10": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9f5d6f1c082fe63eec7a71fcad00f4a892e3d43b7b0d04e776e69e7be35247cecdac65504c579195731eaf64b7940966e": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9fbf0818841edf110e05228a6379763c4fc3c37459d9bdc61f58a5ebc01e9e2305a19d390c0543dc733861ec3cf1de01f": "0x000000000000000000000000010000000000000000008a5d784563010000000000000000000000000000000000000000000000000000000000000080",
"0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000",
"0x3a636f6465": "0x0",
"0x3a65787472696e7369635f696e646578": "0x00000000",
"0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100",
"0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00003ef1ee275e1a"
},
"childrenDefault": {}
}
}
}
@@ -0,0 +1,32 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"runtimeGenesis": {
"patch": {
"babe": {
"epochConfig": {
"allowed_slots": "PrimaryAndSecondaryPlainSlots",
"c": [
7,
10
]
}
},
"substrateTest": {
"authorities": [
"5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
]
}
},
"code": "0x0"
}
}
}
@@ -0,0 +1,32 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"raw": {
"top": {
"0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
"0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x081cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
"0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
"0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000",
"0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x07000000000000000a0000000000000001",
"0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000",
"0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01",
"0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545",
"0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545",
"0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01",
"0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000",
"0x3a636f6465": "0x0",
"0x3a65787472696e7369635f696e646578": "0x00000000",
"0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100",
"0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0000000000000000"
},
"childrenDefault": {}
}
}
}
+768 -62
View File
@@ -18,8 +18,10 @@
//! Substrate chain configurations.
#![warn(missing_docs)]
use crate::{extension::GetExtension, ChainType, Properties, RuntimeGenesis};
use crate::{
extension::GetExtension, ChainType, GenesisConfigBuilderRuntimeCaller as RuntimeCaller,
Properties, RuntimeGenesis,
};
use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints;
use serde::{Deserialize, Serialize};
@@ -29,13 +31,32 @@ use sp_core::{
Bytes,
};
use sp_runtime::BuildStorage;
use std::{borrow::Cow, collections::BTreeMap, fs::File, path::PathBuf, sync::Arc};
use std::{
borrow::Cow,
collections::{BTreeMap, VecDeque},
fs::File,
marker::PhantomData,
path::PathBuf,
sync::Arc,
};
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
enum GenesisBuildAction {
Patch(json::Value),
Full(json::Value),
}
#[allow(deprecated)]
enum GenesisSource<G> {
File(PathBuf),
Binary(Cow<'static, [u8]>),
Factory(Arc<dyn Fn() -> G + Send + Sync>),
/// factory function + code
//Factory and G type parameter shall be removed togheter with `ChainSpec::from_genesis`
Factory(Arc<dyn Fn() -> G + Send + Sync>, Vec<u8>),
Storage(Storage),
/// build action + code
GenesisBuilderApi(GenesisBuildAction, Vec<u8>),
}
impl<G> Clone for GenesisSource<G> {
@@ -43,14 +64,17 @@ impl<G> Clone for GenesisSource<G> {
match *self {
Self::File(ref path) => Self::File(path.clone()),
Self::Binary(ref d) => Self::Binary(d.clone()),
Self::Factory(ref f) => Self::Factory(f.clone()),
Self::Factory(ref f, ref c) => Self::Factory(f.clone(), c.clone()),
Self::Storage(ref s) => Self::Storage(s.clone()),
Self::GenesisBuilderApi(ref s, ref c) => Self::GenesisBuilderApi(s.clone(), c.clone()),
}
}
}
impl<G: RuntimeGenesis> GenesisSource<G> {
fn resolve(&self) -> Result<Genesis<G>, String> {
/// helper container for deserializing genesis from the JSON file (ChainSpec JSON file is
/// also supported here)
#[derive(Serialize, Deserialize)]
struct GenesisContainer<G> {
genesis: Genesis<G>,
@@ -79,31 +103,21 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
.map_err(|e| format!("Error parsing embedded file: {}", e))?;
Ok(genesis.genesis)
},
Self::Factory(f) => Ok(Genesis::Runtime(f())),
Self::Storage(storage) => {
let top = storage
.top
.iter()
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
.collect();
let children_default = storage
.children_default
.iter()
.map(|(k, child)| {
(
StorageKey(k.clone()),
child
.data
.iter()
.map(|(k, v)| (StorageKey(k.clone()), StorageData(v.clone())))
.collect(),
)
})
.collect();
Ok(Genesis::Raw(RawGenesis { top, children_default }))
},
Self::Factory(f, code) => Ok(Genesis::RuntimeAndCode(RuntimeInnerWrapper {
runtime: f(),
code: code.clone(),
})),
Self::Storage(storage) => Ok(Genesis::Raw(RawGenesis::from(storage.clone()))),
Self::GenesisBuilderApi(GenesisBuildAction::Full(config), code) =>
Ok(Genesis::RuntimeGenesis(RuntimeGenesisInner {
json_blob: RuntimeGenesisConfigJson::Config(config.clone()),
code: code.clone(),
})),
Self::GenesisBuilderApi(GenesisBuildAction::Patch(patch), code) =>
Ok(Genesis::RuntimeGenesis(RuntimeGenesisInner {
json_blob: RuntimeGenesisConfigJson::Patch(patch.clone()),
code: code.clone(),
})),
}
}
}
@@ -111,7 +125,18 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
match self.genesis.resolve()? {
Genesis::Runtime(gc) => gc.assimilate_storage(storage),
#[allow(deprecated)]
Genesis::Runtime(runtime_genesis_config) => {
runtime_genesis_config.assimilate_storage(storage)?;
},
#[allow(deprecated)]
Genesis::RuntimeAndCode(RuntimeInnerWrapper {
runtime: runtime_genesis_config,
code,
}) => {
runtime_genesis_config.assimilate_storage(storage)?;
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code);
},
Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => {
storage.top.extend(map.into_iter().map(|(k, v)| (k.0, v.0)));
children_map.into_iter().for_each(|(k, v)| {
@@ -123,13 +148,37 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
.data
.extend(v.into_iter().map(|(k, v)| (k.0, v.0)));
});
Ok(())
},
// The `StateRootHash` variant exists as a way to keep note that other clients support
// it, but Substrate itself isn't capable of loading chain specs with just a hash at the
// moment.
Genesis::StateRootHash(_) => Err("Genesis storage in hash format not supported".into()),
}
Genesis::StateRootHash(_) =>
return Err("Genesis storage in hash format not supported".into()),
Genesis::RuntimeGenesis(RuntimeGenesisInner {
json_blob: RuntimeGenesisConfigJson::Config(config),
code,
}) => {
RuntimeCaller::new(&code[..])
.get_storage_for_config(config)?
.assimilate_storage(storage)?;
storage
.top
.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone());
},
Genesis::RuntimeGenesis(RuntimeGenesisInner {
json_blob: RuntimeGenesisConfigJson::Patch(patch),
code,
}) => {
RuntimeCaller::new(&code[..])
.get_storage_for_patch(patch)?
.assimilate_storage(storage)?;
storage
.top
.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone());
},
};
Ok(())
}
}
@@ -144,20 +193,98 @@ pub struct RawGenesis {
pub children_default: BTreeMap<StorageKey, GenesisStorage>,
}
impl From<sp_core::storage::Storage> for RawGenesis {
fn from(value: sp_core::storage::Storage) -> Self {
Self {
top: value.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect(),
children_default: value
.children_default
.into_iter()
.map(|(sk, child)| {
(
StorageKey(sk),
child
.data
.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect(),
)
})
.collect(),
}
}
}
/// Inner representation of [`Genesis<G>::RuntimeGenesis`] format
#[derive(Serialize, Deserialize, Debug)]
struct RuntimeGenesisInner {
/// Runtime wasm code, expected to be hex-encoded in JSON.
/// The code shall be capable of parsing `json_blob`.
#[serde(default, with = "sp_core::bytes")]
code: Vec<u8>,
/// The patch or full representation of runtime's `RuntimeGenesisConfig` struct.
#[serde(flatten)]
json_blob: RuntimeGenesisConfigJson,
}
/// Represents two possible variants of the contained JSON blob for the
/// [`Genesis<G>::RuntimeGenesis`] format.
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
enum RuntimeGenesisConfigJson {
/// Represents the explicit and comprehensive runtime genesis config in JSON format.
/// The contained object is a JSON blob that can be parsed by a compatible runtime.
///
/// Using a full config is useful for when someone wants to ensure that a change in the runtime
/// makes the deserialization fail and not silently add some default values.
Config(json::Value),
/// Represents a patch for the default runtime genesis config in JSON format which is
/// essentially a list of keys that are to be customized in runtime genesis config.
/// The contained value is a JSON blob that can be parsed by a compatible runtime.
Patch(json::Value),
}
/// Inner variant wrapper for deprecated runtime.
#[derive(Serialize, Deserialize, Debug)]
struct RuntimeInnerWrapper<G> {
/// The native `RuntimeGenesisConfig` struct.
runtime: G,
/// Runtime code.
#[serde(with = "sp_core::bytes")]
code: Vec<u8>,
}
/// Represents the different formats of the genesis state within chain spec JSON blob.
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
enum Genesis<G> {
/// (Deprecated) Contains the JSON representation of G (the native type representing the
/// runtime's `RuntimeGenesisConfig` struct) (will be removed with `ChainSpec::from_genesis`)
/// without the runtime code. It is required to deserialize the legacy chainspecs genereted
/// with `ChainsSpec::from_genesis` method.
Runtime(G),
/// (Deprecated) Contains the JSON representation of G (the native type representing the
/// runtime's `RuntimeGenesisConfig` struct) (will be removed with `ChainSpec::from_genesis`)
/// and the runtime code. It is required to create and deserialize JSON chainspecs created with
/// deprecated `ChainSpec::from_genesis` method.
RuntimeAndCode(RuntimeInnerWrapper<G>),
/// The genesis storage as raw data. Typically raw key-value entries in state.
Raw(RawGenesis),
/// State root hash of the genesis storage.
StateRootHash(StorageData),
/// Represents the runtime genesis config in JSON format toghether with runtime code.
RuntimeGenesis(RuntimeGenesisInner),
}
/// A configuration of a client. Does not include runtime storage initialization.
/// Note: `genesis` field is ignored due to way how the chain specification is serialized into
/// JSON file. Refer to [`ChainSpecJsonContainer`], which flattens [`ClientSpec`] and denies uknown
/// fields.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
// we cannot #[serde(deny_unknown_fields)]. Otherwise chain-spec-builder will fail on any
// non-standard spec
struct ClientSpec<E> {
name: String,
id: String,
@@ -194,6 +321,137 @@ struct ClientSpec<E> {
/// We use `Option` here since `()` is not flattenable by serde.
pub type NoExtension = Option<()>;
/// Builder for creating [`ChainSpec`] instances.
pub struct ChainSpecBuilder<G, E = NoExtension> {
code: Vec<u8>,
extensions: E,
name: String,
id: String,
chain_type: ChainType,
genesis_build_action: GenesisBuildAction,
boot_nodes: Option<Vec<MultiaddrWithPeerId>>,
telemetry_endpoints: Option<TelemetryEndpoints>,
protocol_id: Option<String>,
fork_id: Option<String>,
properties: Option<Properties>,
_genesis: PhantomData<G>,
}
impl<G, E> ChainSpecBuilder<G, E> {
/// Creates a new builder instance with no defaults.
pub fn new(code: &[u8], extensions: E) -> Self {
Self {
code: code.into(),
extensions,
name: "Development".to_string(),
id: "dev".to_string(),
chain_type: ChainType::Local,
genesis_build_action: GenesisBuildAction::Patch(Default::default()),
boot_nodes: None,
telemetry_endpoints: None,
protocol_id: None,
fork_id: None,
properties: None,
_genesis: Default::default(),
}
}
/// Sets the spec name.
pub fn with_name(mut self, name: &str) -> Self {
self.name = name.into();
self
}
/// Sets the spec ID.
pub fn with_id(mut self, id: &str) -> Self {
self.id = id.into();
self
}
/// Sets the type of the chain.
pub fn with_chain_type(mut self, chain_type: ChainType) -> Self {
self.chain_type = chain_type;
self
}
/// Sets a list of bootnode addresses.
pub fn with_boot_nodes(mut self, boot_nodes: Vec<MultiaddrWithPeerId>) -> Self {
self.boot_nodes = Some(boot_nodes);
self
}
/// Sets telemetry endpoints.
pub fn with_telemetry_endpoints(mut self, telemetry_endpoints: TelemetryEndpoints) -> Self {
self.telemetry_endpoints = Some(telemetry_endpoints);
self
}
/// Sets the network protocol ID.
pub fn with_protocol_id(mut self, protocol_id: &str) -> Self {
self.protocol_id = Some(protocol_id.into());
self
}
/// Sets an optional network fork identifier.
pub fn with_fork_id(mut self, fork_id: &str) -> Self {
self.fork_id = Some(fork_id.into());
self
}
/// Sets additional loosely-typed properties of the chain.
pub fn with_properties(mut self, properties: Properties) -> Self {
self.properties = Some(properties);
self
}
/// Sets chain spec extensions.
pub fn with_extensions(mut self, extensions: E) -> Self {
self.extensions = extensions;
self
}
/// Sets the code.
pub fn with_code(mut self, code: &[u8]) -> Self {
self.code = code.into();
self
}
/// Sets the JSON patch for runtime's GenesisConfig.
pub fn with_genesis_config_patch(mut self, patch: json::Value) -> Self {
self.genesis_build_action = GenesisBuildAction::Patch(patch);
self
}
/// Sets the full runtime's GenesisConfig JSON.
pub fn with_genesis_config(mut self, config: json::Value) -> Self {
self.genesis_build_action = GenesisBuildAction::Full(config);
self
}
/// Builds a [`ChainSpec`] instance using the provided settings.
pub fn build(self) -> ChainSpec<G, E> {
let client_spec = ClientSpec {
name: self.name,
id: self.id,
chain_type: self.chain_type,
boot_nodes: self.boot_nodes.unwrap_or_default(),
telemetry_endpoints: self.telemetry_endpoints,
protocol_id: self.protocol_id,
fork_id: self.fork_id,
properties: self.properties,
extensions: self.extensions,
consensus_engine: (),
genesis: Default::default(),
code_substitutes: BTreeMap::new(),
};
ChainSpec {
client_spec,
genesis: GenesisSource::GenesisBuilderApi(self.genesis_build_action, self.code.into()),
}
}
}
/// A configuration of a chain. Can be used to build a genesis block.
pub struct ChainSpec<G, E = NoExtension> {
client_spec: ClientSpec<E>,
@@ -260,6 +518,10 @@ impl<G, E> ChainSpec<G, E> {
}
/// Create hardcoded spec.
#[deprecated(
note = "`from_genesis` is planned to be removed in May 2024. Use `builder()` instead."
)]
// deprecated note: Genesis<G>::Runtime + GenesisSource::Factory shall also be removed
pub fn from_genesis<F: Fn() -> G + 'static + Send + Sync>(
name: &str,
id: &str,
@@ -271,6 +533,7 @@ impl<G, E> ChainSpec<G, E> {
fork_id: Option<&str>,
properties: Option<Properties>,
extensions: E,
code: &[u8],
) -> Self {
let client_spec = ClientSpec {
name: name.to_owned(),
@@ -287,21 +550,30 @@ impl<G, E> ChainSpec<G, E> {
code_substitutes: BTreeMap::new(),
};
ChainSpec { client_spec, genesis: GenesisSource::Factory(Arc::new(constructor)) }
ChainSpec {
client_spec,
genesis: GenesisSource::Factory(Arc::new(constructor), code.into()),
}
}
/// Type of the chain.
fn chain_type(&self) -> ChainType {
self.client_spec.chain_type.clone()
}
/// Provides a `ChainSpec` builder.
pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder<G, E> {
ChainSpecBuilder::new(code, extensions)
}
}
impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
impl<G: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
/// Parse json content into a `ChainSpec`
pub fn from_json_bytes(json: impl Into<Cow<'static, [u8]>>) -> Result<Self, String> {
let json = json.into();
let client_spec = json::from_slice(json.as_ref())
.map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) })
}
@@ -318,50 +590,74 @@ impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
memmap2::Mmap::map(&file)
.map_err(|e| format!("Error mmaping spec file `{}`: {}", path.display(), e))?
};
let client_spec =
json::from_slice(&bytes).map_err(|e| format!("Error parsing spec file: {}", e))?;
Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) })
}
}
/// Helper structure for serializing (and only serializing) the ChainSpec into JSON file. It
/// represents the layout of `ChainSpec` JSON file.
#[derive(Serialize, Deserialize)]
struct JsonContainer<G, E> {
// we cannot #[serde(deny_unknown_fields)]. Otherwise chain-spec-builder will fail on any
// non-standard spec.
struct ChainSpecJsonContainer<G, E> {
#[serde(flatten)]
client_spec: ClientSpec<E>,
genesis: Genesis<G>,
}
impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
fn json_container(&self, raw: bool) -> Result<JsonContainer<G, E>, String> {
let genesis = match (raw, self.genesis.resolve()?) {
fn json_container(&self, raw: bool) -> Result<ChainSpecJsonContainer<G, E>, String> {
let raw_genesis = match (raw, self.genesis.resolve()?) {
(
true,
Genesis::RuntimeGenesis(RuntimeGenesisInner {
json_blob: RuntimeGenesisConfigJson::Config(config),
code,
}),
) => {
let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_config(config)?;
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code);
RawGenesis::from(storage)
},
(
true,
Genesis::RuntimeGenesis(RuntimeGenesisInner {
json_blob: RuntimeGenesisConfigJson::Patch(patch),
code,
}),
) => {
let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_patch(patch)?;
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code);
RawGenesis::from(storage)
},
#[allow(deprecated)]
(true, Genesis::RuntimeAndCode(RuntimeInnerWrapper { runtime: g, code })) => {
let mut storage = g.build_storage()?;
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code);
RawGenesis::from(storage)
},
#[allow(deprecated)]
(true, Genesis::Runtime(g)) => {
let storage = g.build_storage()?;
let top =
storage.top.into_iter().map(|(k, v)| (StorageKey(k), StorageData(v))).collect();
let children_default = storage
.children_default
.into_iter()
.map(|(sk, child)| {
(
StorageKey(sk),
child
.data
.into_iter()
.map(|(k, v)| (StorageKey(k), StorageData(v)))
.collect(),
)
})
.collect();
Genesis::Raw(RawGenesis { top, children_default })
RawGenesis::from(storage)
},
(_, genesis) => genesis,
(true, Genesis::Raw(raw)) => raw,
(_, genesis) =>
return Ok(ChainSpecJsonContainer { client_spec: self.client_spec.clone(), genesis }),
};
Ok(JsonContainer { client_spec: self.client_spec.clone(), genesis })
Ok(ChainSpecJsonContainer {
client_spec: self.client_spec.clone(),
genesis: Genesis::Raw(raw_genesis),
})
}
/// Dump to json string.
/// Dump the chain specification to JSON string.
pub fn as_json(&self, raw: bool) -> Result<String, String> {
let container = self.json_container(raw)?;
json::to_string_pretty(&container).map_err(|e| format!("Error generating spec json: {}", e))
@@ -442,9 +738,87 @@ where
}
}
/// The `fun` will be called with the value at `path`.
///
/// If exists, the value at given `path` will be passed to the `fun` and the result of `fun`
/// call will be returned. Otherwise false is returned.
/// `path` will be modified.
///
/// # Examples
/// ```ignore
/// use serde_json::{from_str, json, Value};
/// let doc = json!({"a":{"b":{"c":"5"}}});
/// let mut path = ["a", "b", "c"].into();
/// assert!(json_eval_value_at_key(&doc, &mut path, &|v| { assert_eq!(v,"5"); true }));
/// ```
fn json_eval_value_at_key(
doc: &json::Value,
path: &mut VecDeque<&str>,
fun: &dyn Fn(&json::Value) -> bool,
) -> bool {
let Some(key) = path.pop_front() else {
return false;
};
if path.is_empty() {
doc.as_object().map_or(false, |o| o.get(key).map_or(false, |v| fun(v)))
} else {
doc.as_object()
.map_or(false, |o| o.get(key).map_or(false, |v| json_eval_value_at_key(v, path, fun)))
}
}
macro_rules! json_path {
[ $($x:expr),+ ] => {
VecDeque::<&str>::from([$($x),+])
};
}
fn json_contains_path(doc: &json::Value, path: &mut VecDeque<&str>) -> bool {
json_eval_value_at_key(doc, path, &|_| true)
}
/// This function updates the code in given chain spec.
///
/// Function support updating the runtime code in provided JSON chain spec blob. `Genesis<G>::Raw`
/// and `Genesis<G>::RuntimeGenesis` formats are supported.
///
/// If update was successful `true` is returned, otherwise `false`. Chain spec JSON is modified in
/// place.
pub fn update_code_in_json_chain_spec(chain_spec: &mut json::Value, code: &[u8]) -> bool {
let mut path = json_path!["genesis", "runtimeGenesis", "code"];
let mut raw_path = json_path!["genesis", "raw", "top"];
if json_contains_path(&chain_spec, &mut path) {
#[derive(Serialize)]
struct Container<'a> {
#[serde(with = "sp_core::bytes")]
code: &'a [u8],
}
let code_patch = json::json!({"genesis":{"runtimeGenesis": Container { code }}});
crate::json_patch::merge(chain_spec, code_patch);
true
} else if json_contains_path(&chain_spec, &mut raw_path) {
#[derive(Serialize)]
struct Container<'a> {
#[serde(with = "sp_core::bytes", rename = "0x3a636f6465")]
code: &'a [u8],
}
let code_patch = json::json!({"genesis":{"raw":{"top": Container { code }}}});
crate::json_patch::merge(chain_spec, code_patch);
true
} else {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{from_str, json, Value};
use sp_application_crypto::Ss58Codec;
use sp_core::storage::well_known_keys;
use sp_keyring::AccountKeyring;
#[derive(Debug, Serialize, Deserialize)]
struct Genesis(BTreeMap<String, String>);
@@ -536,4 +910,336 @@ mod tests {
);
}
}
#[test]
// some tests for json path utils
fn test_json_eval_value_at_key() {
let doc = json!({"a":{"b1":"20","b":{"c":{"d":"10"}}}});
assert!(json_eval_value_at_key(&doc, &mut json_path!["a", "b1"], &|v| { *v == "20" }));
assert!(json_eval_value_at_key(&doc, &mut json_path!["a", "b", "c", "d"], &|v| {
*v == "10"
}));
assert!(!json_eval_value_at_key(&doc, &mut json_path!["a", "c", "d"], &|_| { true }));
assert!(!json_eval_value_at_key(&doc, &mut json_path!["d"], &|_| { true }));
assert!(json_contains_path(&doc, &mut json_path!["a", "b1"]));
assert!(json_contains_path(&doc, &mut json_path!["a", "b"]));
assert!(json_contains_path(&doc, &mut json_path!["a", "b", "c"]));
assert!(json_contains_path(&doc, &mut json_path!["a", "b", "c", "d"]));
assert!(!json_contains_path(&doc, &mut json_path!["a", "b", "c", "d", "e"]));
assert!(!json_contains_path(&doc, &mut json_path!["a", "b", "b1"]));
assert!(!json_contains_path(&doc, &mut json_path!["d"]));
}
fn zeroize_code_key_in_json(encoded: bool, json: &str) -> Value {
let mut json = from_str::<Value>(json).unwrap();
let (zeroing_patch, mut path) = if encoded {
(
json!({"genesis":{"raw":{"top":{"0x3a636f6465":"0x0"}}}}),
json_path!["genesis", "raw", "top", "0x3a636f6465"],
)
} else {
(
json!({"genesis":{"runtimeGenesis":{"code":"0x0"}}}),
json_path!["genesis", "runtimeGenesis", "code"],
)
};
assert!(json_contains_path(&json, &mut path));
crate::json_patch::merge(&mut json, zeroing_patch);
json
}
#[docify::export]
#[test]
fn build_chain_spec_with_patch_works() {
let output: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(json!({
"babe": {
"epochConfig": {
"c": [
7,
10
],
"allowed_slots": "PrimaryAndSecondaryPlainSlots"
}
},
"substrateTest": {
"authorities": [
AccountKeyring::Ferdie.public().to_ss58check(),
AccountKeyring::Alice.public().to_ss58check()
],
}
}))
.build();
let raw_chain_spec = output.as_json(true);
assert!(raw_chain_spec.is_ok());
}
#[docify::export]
#[test]
fn generate_chain_spec_with_patch_works() {
let output: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(json!({
"babe": {
"epochConfig": {
"c": [
7,
10
],
"allowed_slots": "PrimaryAndSecondaryPlainSlots"
}
},
"substrateTest": {
"authorities": [
AccountKeyring::Ferdie.public().to_ss58check(),
AccountKeyring::Alice.public().to_ss58check()
],
}
}))
.build();
let actual = output.as_json(false).unwrap();
let actual_raw = output.as_json(true).unwrap();
let expected =
from_str::<Value>(include_str!("../res/substrate_test_runtime_from_patch.json"))
.unwrap();
let expected_raw =
from_str::<Value>(include_str!("../res/substrate_test_runtime_from_patch_raw.json"))
.unwrap();
//wasm blob may change overtime so let's zero it. Also ensure it is there:
let actual = zeroize_code_key_in_json(false, actual.as_str());
let actual_raw = zeroize_code_key_in_json(true, actual_raw.as_str());
assert_eq!(actual, expected);
assert_eq!(actual_raw, expected_raw);
}
#[test]
fn generate_chain_spec_with_full_config_works() {
let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json");
let output: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config(from_str(j).unwrap())
.build();
let actual = output.as_json(false).unwrap();
let actual_raw = output.as_json(true).unwrap();
let expected =
from_str::<Value>(include_str!("../res/substrate_test_runtime_from_config.json"))
.unwrap();
let expected_raw =
from_str::<Value>(include_str!("../res/substrate_test_runtime_from_config_raw.json"))
.unwrap();
//wasm blob may change overtime so let's zero it. Also ensure it is there:
let actual = zeroize_code_key_in_json(false, actual.as_str());
let actual_raw = zeroize_code_key_in_json(true, actual_raw.as_str());
assert_eq!(actual, expected);
assert_eq!(actual_raw, expected_raw);
}
#[test]
fn chain_spec_as_json_fails_with_invalid_config() {
let j =
include_str!("../../../test-utils/runtime/res/default_genesis_config_invalid_2.json");
let output: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config(from_str(j).unwrap())
.build();
assert_eq!(
output.as_json(true),
Err("Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 1 column 8".to_string())
);
}
#[test]
fn chain_spec_as_json_fails_with_invalid_patch() {
let output: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(json!({
"invalid_pallet": {},
"substrateTest": {
"authorities": [
AccountKeyring::Ferdie.public().to_ss58check(),
AccountKeyring::Alice.public().to_ss58check()
],
}
}))
.build();
assert!(output.as_json(true).unwrap_err().contains("Invalid JSON blob: unknown field `invalid_pallet`, expected one of `system`, `babe`, `substrateTest`, `balances`"));
}
#[test]
fn check_if_code_is_valid_for_raw_without_code() {
let spec = ChainSpec::<()>::from_json_bytes(Cow::Owned(
include_bytes!("../res/raw_no_code.json").to_vec(),
))
.unwrap();
let j = from_str::<Value>(&spec.as_json(true).unwrap()).unwrap();
assert!(json_eval_value_at_key(
&j,
&mut json_path!["genesis", "raw", "top", "0x3a636f6465"],
&|v| { *v == "0x010101" }
));
assert!(!json_contains_path(&j, &mut json_path!["code"]));
}
#[test]
fn check_code_in_assimilated_storage_for_raw_without_code() {
let spec = ChainSpec::<()>::from_json_bytes(Cow::Owned(
include_bytes!("../res/raw_no_code.json").to_vec(),
))
.unwrap();
let storage = spec.build_storage().unwrap();
assert!(storage
.top
.get(&well_known_keys::CODE.to_vec())
.map(|v| *v == vec![1, 1, 1])
.unwrap())
}
#[test]
fn update_code_works_with_runtime_genesis_config() {
let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json");
let chain_spec: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config(from_str(j).unwrap())
.build();
let mut chain_spec_json = from_str::<Value>(&chain_spec.as_json(false).unwrap()).unwrap();
assert!(update_code_in_json_chain_spec(&mut chain_spec_json, &[0, 1, 2, 4, 5, 6]));
assert!(json_eval_value_at_key(
&chain_spec_json,
&mut json_path!["genesis", "runtimeGenesis", "code"],
&|v| { *v == "0x000102040506" }
));
}
#[test]
fn update_code_works_for_raw() {
let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json");
let chain_spec: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config(from_str(j).unwrap())
.build();
let mut chain_spec_json = from_str::<Value>(&chain_spec.as_json(true).unwrap()).unwrap();
assert!(update_code_in_json_chain_spec(&mut chain_spec_json, &[0, 1, 2, 4, 5, 6]));
assert!(json_eval_value_at_key(
&chain_spec_json,
&mut json_path!["genesis", "raw", "top", "0x3a636f6465"],
&|v| { *v == "0x000102040506" }
));
}
#[test]
fn update_code_works_with_runtime_genesis_patch() {
let chain_spec: ChainSpec<()> = ChainSpec::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
.with_name("TestName")
.with_id("test_id")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(json!({}))
.build();
let mut chain_spec_json = from_str::<Value>(&chain_spec.as_json(false).unwrap()).unwrap();
assert!(update_code_in_json_chain_spec(&mut chain_spec_json, &[0, 1, 2, 4, 5, 6]));
assert!(json_eval_value_at_key(
&chain_spec_json,
&mut json_path!["genesis", "runtimeGenesis", "code"],
&|v| { *v == "0x000102040506" }
));
}
#[test]
fn generate_from_genesis_is_still_supported() {
#[allow(deprecated)]
let chain_spec: ChainSpec<substrate_test_runtime::RuntimeGenesisConfig> = ChainSpec::from_genesis(
"TestName",
"test",
ChainType::Local,
move || substrate_test_runtime::RuntimeGenesisConfig {
babe: substrate_test_runtime::BabeConfig {
epoch_config: Some(
substrate_test_runtime::TEST_RUNTIME_BABE_EPOCH_CONFIGURATION,
),
..Default::default()
},
..Default::default()
},
Vec::new(),
None,
None,
None,
None,
Default::default(),
&vec![0, 1, 2, 4, 5, 6],
);
let chain_spec_json = from_str::<Value>(&chain_spec.as_json(false).unwrap()).unwrap();
assert!(json_eval_value_at_key(
&chain_spec_json,
&mut json_path!["genesis", "runtimeAndCode", "code"],
&|v| { *v == "0x000102040506" }
));
let chain_spec_json = from_str::<Value>(&chain_spec.as_json(true).unwrap()).unwrap();
assert!(json_eval_value_at_key(
&chain_spec_json,
&mut json_path!["genesis", "raw", "top", "0x3a636f6465"],
&|v| { *v == "0x000102040506" }
));
}
}
@@ -0,0 +1,183 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! A helper module for calling the GenesisBuilder API from arbitrary runtime wasm blobs.
use codec::{Decode, Encode};
use sc_executor::{error::Result, WasmExecutor};
use serde_json::{from_slice, Value};
use sp_core::{
storage::Storage,
traits::{CallContext, CodeExecutor, Externalities, FetchRuntimeCode, RuntimeCode},
};
use sp_genesis_builder::Result as BuildResult;
use sp_state_machine::BasicExternalities;
use std::borrow::Cow;
/// A utility that facilitates calling the GenesisBuilder API from the runtime wasm code blob.
pub struct GenesisConfigBuilderRuntimeCaller<'a> {
code: Cow<'a, [u8]>,
code_hash: Vec<u8>,
executor: WasmExecutor<sp_io::SubstrateHostFunctions>,
}
impl<'a> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a> {
fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
Some(self.code.as_ref().into())
}
}
impl<'a> GenesisConfigBuilderRuntimeCaller<'a> {
/// Creates new instance using the provided code blob.
///
/// This code is later referred to as `runtime`.
pub fn new(code: &'a [u8]) -> Self {
GenesisConfigBuilderRuntimeCaller {
code: code.into(),
code_hash: sp_core::blake2_256(code).to_vec(),
executor: WasmExecutor::<sp_io::SubstrateHostFunctions>::builder()
.with_allow_missing_host_functions(true)
.build(),
}
}
fn call(&self, ext: &mut dyn Externalities, method: &str, data: &[u8]) -> Result<Vec<u8>> {
self.executor
.call(
ext,
&RuntimeCode { heap_pages: None, code_fetcher: self, hash: self.code_hash.clone() },
method,
data,
false,
CallContext::Offchain,
)
.0
}
/// Returns the default `GenesisConfig` provided by the `runtime`.
///
/// Calls [`GenesisBuilder::create_default_config`](sp_genesis_builder::GenesisBuilder::create_default_config) in the `runtime`.
pub fn get_default_config(&self) -> core::result::Result<Value, String> {
let mut t = BasicExternalities::new_empty();
let call_result = self
.call(&mut t, "GenesisBuilder_create_default_config", &[])
.map_err(|e| format!("wasm call error {e}"))?;
let default_config = Vec::<u8>::decode(&mut &call_result[..])
.map_err(|e| format!("scale codec error: {e}"))?;
Ok(from_slice(&default_config[..]).expect("returned value is json. qed."))
}
/// Build the given `GenesisConfig` and returns the genesis state.
///
/// Calls [`GenesisBuilder::build_config`](sp_genesis_builder::GenesisBuilder::build_config)
/// provided by the `runtime`.
pub fn get_storage_for_config(&self, config: Value) -> core::result::Result<Storage, String> {
let mut ext = BasicExternalities::new_empty();
let call_result = self
.call(&mut ext, "GenesisBuilder_build_config", &config.to_string().encode())
.map_err(|e| format!("wasm call error {e}"))?;
BuildResult::decode(&mut &call_result[..])
.map_err(|e| format!("scale codec error: {e}"))??;
Ok(ext.into_storages())
}
/// Creates the genesis state by patching the default `GenesisConfig` and applying it.
///
/// This function generates the `GenesisConfig` for the runtime by applying a provided JSON
/// patch. The patch modifies the default `GenesisConfig` allowing customization of the specific
/// keys. The resulting `GenesisConfig` is then deserialized from the patched JSON
/// representation and stored in the storage.
///
/// If the provided JSON patch is incorrect or the deserialization fails the error will be
/// returned.
///
/// The patching process modifies the default `GenesisConfig` according to the following rules:
/// 1. Existing keys in the default configuration will be overridden by the corresponding values
/// in the patch.
/// 2. If a key exists in the patch but not in the default configuration, it will be added to
/// the resulting `GenesisConfig`.
/// 3. Keys in the default configuration that have null values in the patch will be removed from
/// the resulting `GenesisConfig`. This is helpful for changing enum variant value.
///
/// Please note that the patch may contain full `GenesisConfig`.
pub fn get_storage_for_patch(&self, patch: Value) -> core::result::Result<Storage, String> {
let mut config = self.get_default_config()?;
crate::json_patch::merge(&mut config, patch);
self.get_storage_for_config(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{from_str, json};
pub use sp_consensus_babe::{AllowedSlots, BabeEpochConfiguration, Slot};
#[test]
fn get_default_config_works() {
let config =
GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap())
.get_default_config()
.unwrap();
let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#;
assert_eq!(from_str::<Value>(expected).unwrap(), config);
}
#[test]
fn get_storage_for_patch_works() {
let patch = json!({
"babe": {
"epochConfig": {
"c": [
69,
696
],
"allowed_slots": "PrimaryAndSecondaryPlainSlots"
}
},
});
let storage =
GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap())
.get_storage_for_patch(patch)
.unwrap();
//Babe|Authorities
let value: Vec<u8> = storage
.top
.get(
&array_bytes::hex2bytes(
"1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef",
)
.unwrap(),
)
.unwrap()
.clone();
assert_eq!(
BabeEpochConfiguration::decode(&mut &value[..]).unwrap(),
BabeEpochConfiguration {
c: (69, 696),
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots
}
);
}
}
@@ -0,0 +1,191 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! A helper module providing json patching functions.
use serde_json::Value;
/// Recursively merges two JSON objects, `a` and `b`, into a single object.
///
/// If a key exists in both objects, the value from `b` will override the value from `a`.
/// If a key exists in `b` with a `null` value, it will be removed from `a`.
/// If a key exists only in `b` and not in `a`, it will be added to `a`.
///
/// # Arguments
///
/// * `a` - A mutable reference to the target JSON object to merge into.
/// * `b` - The JSON object to merge with `a`.
pub fn merge(a: &mut Value, b: Value) {
match (a, b) {
(Value::Object(a), Value::Object(b)) =>
for (k, v) in b {
if v.is_null() {
a.remove(&k);
} else {
merge(a.entry(k).or_insert(Value::Null), v);
}
},
(a, b) => *a = b,
};
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test1_simple_merge() {
let mut j1 = json!({ "a":123 });
merge(&mut j1, json!({ "b":256 }));
assert_eq!(j1, json!({ "a":123, "b":256 }));
}
#[test]
fn test2_patch_simple_merge_nested() {
let mut j1 = json!({
"a": {
"name": "xxx",
"value": 123
},
"b": { "c" : { "inner_name": "yyy" } }
});
let j2 = json!({
"a": {
"keys": ["a", "b", "c" ]
}
});
merge(&mut j1, j2);
assert_eq!(
j1,
json!({"a":{"keys":["a","b","c"],"name":"xxx","value":123}, "b": { "c" : { "inner_name": "yyy" } }})
);
}
#[test]
fn test3_patch_overrides_existing_keys() {
let mut j1 = json!({
"a": {
"name": "xxx",
"value": 123,
"keys": ["d"]
}
});
let j2 = json!({
"a": {
"keys": ["a", "b", "c" ]
}
});
merge(&mut j1, j2);
assert_eq!(j1, json!({"a":{"keys":["a","b","c"],"name":"xxx","value":123}}));
}
#[test]
fn test4_patch_overrides_existing_keys() {
let mut j1 = json!({
"a": {
"name": "xxx",
"value": 123,
"b" : {
"inner_name": "yyy"
}
}
});
let j2 = json!({
"a": {
"name": "new_name",
"b" : {
"inner_name": "inner_new_name"
}
}
});
merge(&mut j1, j2);
assert_eq!(
j1,
json!({ "a": {"name":"new_name", "value":123, "b" : { "inner_name": "inner_new_name" }} })
);
}
#[test]
fn test5_patch_overrides_existing_nested_keys() {
let mut j1 = json!({
"a": {
"name": "xxx",
"value": 123,
"b": {
"c": {
"d": {
"name": "yyy",
"value": 256
}
}
}
},
});
let j2 = json!({
"a": {
"value": 456,
"b": {
"c": {
"d": {
"name": "new_name"
}
}
}
}
});
merge(&mut j1, j2);
assert_eq!(
j1,
json!({ "a": {"name":"xxx", "value":456, "b": { "c": { "d": { "name": "new_name", "value": 256 }}}}})
);
}
#[test]
fn test6_patch_removes_keys_if_null() {
let mut j1 = json!({
"a": {
"name": "xxx",
"value": 123,
"enum_variant_1": {
"name": "yyy",
}
},
});
let j2 = json!({
"a": {
"value": 456,
"enum_variant_1": null,
"enum_variant_2": 32,
}
});
merge(&mut j1, j2);
assert_eq!(j1, json!({ "a": {"name":"xxx", "value":456, "enum_variant_2": 32 }}));
}
}
+246 -106
View File
@@ -16,38 +16,253 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Substrate chain configurations.
//! This crate includes structs and utilities for defining configuration files (known as chain
//! specification) for both runtime and node.
//!
//! This crate contains structs and utilities to declare
//! a runtime-specific configuration file (a.k.a chain spec).
//! # Intro: Chain Specification
//!
//! Basic chain spec type containing all required parameters is
//! [`GenericChainSpec`]. It can be extended with
//! additional options that contain configuration specific to your chain.
//! Usually the extension is going to be an amalgamate of types exposed
//! by Substrate core modules. To allow the core modules to retrieve
//! their configuration from your extension you should use `ChainSpecExtension`
//! macro exposed by this crate.
//! The chain specification comprises parameters and settings that define the properties and an
//! initial state of a chain. Users typically interact with the JSON representation of the chain
//! spec. Internally, the chain spec is embodied by the [`GenericChainSpec`] struct, and specific
//! properties can be accessed using the [`ChainSpec`] trait.
//!
//! In summary, although not restricted to, the primary role of the chain spec is to provide a list
//! of well-known boot nodes for the blockchain network and the means for initializing the genesis
//! storage. This initialization is necessary for creating a genesis block upon which subsequent
//! blocks are built. When the node is launched for the first time, it reads the chain spec,
//! initializes the genesis block, and establishes connections with the boot nodes.
//!
//! The JSON chain spec is divided into two main logical sections:
//! - one section details general chain properties,
//! - second explicitly or indirectly defines the genesis storage, which, in turn, determines the
//! genesis hash of the chain,
//!
//! The chain specification consists of the following fields:
//!
//! <table>
//! <thead>
//! <tr>
//! <th>Chain spec key</th>
//! <th>Description</th>
//! </tr>
//! </thead>
//! <tbody>
//! <tr>
//! <td>name</td>
//! <td>The human readable name of the chain.</td>
//! </tr>
//! <tr>
//! <td>id</td>
//! <td>The id of the chain.</td>
//! </tr>
//! <tr>
//! <td>chainType</td>
//! <td>The chain type of this chain
//! (refer to
//! <a href="enum.ChainType.html" title="enum sc_chain_spec::ChainType">
//! <code>ChainType</code>
//! </a>).
//! </td>
//! </tr>
//! <tr>
//! <td>bootNodes</td>
//! <td>A list of
//! <a href="https://github.com/multiformats/multiaddr">multi addresses</a>
//! that belong to boot nodes of the chain.</td>
//! </tr>
//! <tr>
//! <td>telemetryEndpoints</td>
//! <td>Optional list of <code>multi address, verbosity</code> of telemetry endpoints. The
//! verbosity goes from 0 to 9. With 0 being the mode with the lowest verbosity.</td>
//! </tr>
//! <tr>
//! <td>protocolId</td>
//! <td>Optional networking protocol id that identifies the chain.</td>
//! </tr>
//! <tr>
//! <td>forkId</td>
//! <td>Optional fork id. Should most likely be left empty. Can be used to signal a fork on
//! the network level when two chains have the same genesis hash.</td>
//! </tr>
//! <tr>
//! <td>properties</td>
//! <td>Custom properties. Shall be provided in the form of
//! <code>key</code>-<code>value</code> json object.
//! </td>
//! </tr>
//! <tr>
//! <td>consensusEngine</td>
//! <td>Deprecated field. Should be ignored.</td>
//! </tr>
//! <tr>
//! <td>codeSubstitutes</td>
//! <td>Optional map of <code>block_number</code> to <code>wasm_code</code>. More details in
//! material to follow.</td>
//! </tr>
//! <tr>
//! <td>genesis</td>
//! <td>Defines the initial state of the runtime. More details in material to follow.</td>
//! </tr>
//! </tbody>
//! </table>
//!
//! # `genesis`: Initial Runtime State
//!
//! All nodes in the network must build subsequent blocks upon exactly the same genesis block.
//!
//! The information configured in the `genesis` section of a chain specification is used to build
//! the genesis storage, which is essential for creating the genesis block, since the block header
//! includes the storage root hash.
//!
//! The `genesis` key of the chain specification definition describes the
//! initial state of the runtime. For example, it may contain:
//! - an initial list of funded accounts,
//! - the administrative account that controls the sudo key,
//! - an initial authorities set for consensus, etc.
//!
//! As the compiled WASM blob of the runtime code is stored in the chain's state, the initial
//! runtime must also be provided within the chain specification.
//!
//! In essence, the most important formats of genesis initial state are:
//!
//! <table>
//! <thead>
//! <tr>
//! <th>Format</th>
//! <th>Description</th>
//! </tr>
//! </thead>
//! <tbody>
//! <tr>
//! <td>
//! <code>runtime / full config</code>
//! </td>
//! <td>A JSON object that provides an explicit and comprehensive representation of the
//! <code>RuntimeGenesisConfig</code> struct, which is generated by <a
//! href="../frame_support_procedural/macro.construct_runtime.html"
//! ><code>frame::runtime::prelude::construct_runtime</code></a> macro (<a
//! href="../substrate_test_runtime/struct.RuntimeGenesisConfig.html#"
//! >example of generated struct</a>). Must contain all the keys of
//! the genesis config, no defaults will be used.
//!
//! This format explicitly provides the code of the runtime.
//! </td></tr>
//! <tr>
//! <td>
//! <code>patch</code>
//! </td>
//! <td>A JSON object that offers a partial representation of the
//! <code>RuntimeGenesisConfig</code> provided by the runtime. It contains a patch, which is
//! essentially a list of key-value pairs to customize in the default runtime's
//! <code>RuntimeGenesisConfig</code>.
//! This format explicitly provides the code of the runtime.
//! </td></tr>
//! <tr>
//! <td>
//! <code>raw</code>
//! </td>
//! <td>A JSON object with two fields: <code>top</code> and <code>children_default</code>.
//! Each field is a map of <code>key => value</code> pairs representing entries in a genesis storage
//! trie. The runtime code is one of such entries.</td>
//! </tr>
//! </tbody>
//! </table>
//!
//! For production or long-lasting blockchains, using the `raw` format in the chain specification is
//! recommended. Only the `raw` format guarantees that storage root hash will remain unchanged when
//! the `RuntimeGenesisConfig` format changes due to software upgrade.
//!
//! JSON examples in the [following section](#json-chain-specification-example) illustrate the `raw`
//! `patch` and full genesis fields.
//!
//! # From Initial State to Raw Genesis.
//!
//! To generate a raw genesis storage from the JSON representation of the runtime genesis config,
//! the node needs to interact with the runtime.
//!
//! This interaction involves passing the runtime genesis config JSON blob to the runtime using the
//! [`sp_genesis_builder::GenesisBuilder::build_config`] function. During this operation, the
//! runtime converts the JSON representation of the genesis config into [`sp_io::storage`] items. It
//! is a crucial step for computing the storage root hash, which is a key component in determining
//! the genesis hash.
//!
//! Consequently, the runtime must support the [`sp_genesis_builder::GenesisBuilder`] API to
//! utilize either `patch` or `full` formats.
//!
//! This entire process is encapsulated within the implementation of the [`BuildStorage`] trait,
//! which can be accessed through the [`ChainSpec::as_storage_builder`] method. There is an
//! intermediate internal helper that facilitates this interaction,
//! [`GenesisConfigBuilderRuntimeCaller`], which serves as a straightforward wrapper for
//! [`sc_executor::WasmExecutor`].
//!
//! In case of `raw` genesis state the node does not interact with the runtime regarding the
//! computation of initial state.
//!
//! The plain and `raw` chain specification JSON blobs can be found in
//! [JSON examples](#json-chain-specification-example) section.
//!
//! # Optional Code Mapping
//!
//! Optional map of `block_number` to `wasm_code`.
//!
//! The given `wasm_code` will be used to substitute the on-chain wasm code starting with the
//! given block number until the `spec_version` on-chain changes. The given `wasm_code` should
//! be as close as possible to the on-chain wasm code. A substitute should be used to fix a bug
//! that cannot be fixed with a runtime upgrade, if for example the runtime is constantly
//! panicking. Introducing new runtime APIs isn't supported, because the node
//! will read the runtime version from the on-chain wasm code.
//!
//! Use this functionality only when there is no other way around it, and only patch the problematic
//! bug; the rest should be done with an on-chain runtime upgrade.
//!
//! # Building a Chain Specification
//!
//! The [`ChainSpecBuilder`] should be used to create an instance of a chain specification. Its API
//! allows configuration of all fields of the chain spec. To generate a JSON representation of the
//! specification, use [`ChainSpec::as_json`].
//!
//! The sample code to generate a chain spec is as follows:
#![doc = docify::embed!("src/chain_spec.rs", build_chain_spec_with_patch_works)]
//! # JSON chain specification example
//!
//! The following are the plain and `raw` versions of the chain specification JSON files, resulting
//! from executing of the above [example](#building-a-chain-specification):
//! ```ignore
#![doc = include_str!("../res/substrate_test_runtime_from_patch.json")]
//! ```
//! ```ignore
#![doc = include_str!("../res/substrate_test_runtime_from_patch_raw.json")]
//! ```
//! The following example shows the plain full config version of chain spec:
//! ```ignore
#![doc = include_str!("../res/substrate_test_runtime_from_config.json")]
//! ```
//! The [`ChainSpec`] trait represents the API to access values defined in the JSON chain specification.
//!
//!
//! # Custom Chain Spec Extensions
//!
//! The basic chain spec type containing all required parameters is [`GenericChainSpec`]. It can be
//! extended with additional options containing configuration specific to your chain. Usually, the
//! extension will be a combination of types exposed by Substrate core modules.
//!
//! To allow the core modules to retrieve their configuration from your extension, you should use
//! `ChainSpecExtension` macro exposed by this crate.
//! ```rust
//! use std::collections::HashMap;
//! use sc_chain_spec::{GenericChainSpec, ChainSpecExtension};
//!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
//! pub struct MyExtension {
//! pub known_blocks: HashMap<u64, String>,
//! pub known_blocks: HashMap<u64, String>,
//! }
//!
//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
//! ```
//!
//! Some parameters may require different values depending on the
//! current blockchain height (a.k.a. forks). You can use `ChainSpecGroup`
//! macro and provided [`Forks`](./struct.Forks.html) structure to put
//! such parameters to your chain spec.
//! This will allow to override a single parameter starting at specific
//! block number.
//!
//! Some parameters may require different values depending on the current blockchain height (a.k.a.
//! forks). You can use the [`ChainSpecGroup`](macro@ChainSpecGroup) macro and the provided [`Forks`]
//! structure to add such parameters to your chain spec. This will allow overriding a single
//! parameter starting at a specific block number.
//! ```rust
//! use sc_chain_spec::{Forks, ChainSpecGroup, ChainSpecExtension, GenericChainSpec};
//!
@@ -76,12 +291,9 @@
//! /// A chain spec supporting forkable `Extension`.
//! pub type MyChainSpec2<G> = GenericChainSpec<G, Forks<BlockNumber, Extension>>;
//! ```
//!
//! It's also possible to have a set of parameters that is allowed to change
//! with block numbers (i.e. is forkable), and another set that is not subject to changes.
//! This is also possible by declaring an extension that contains `Forks` within it.
//!
//!
//! It's also possible to have a set of parameters that are allowed to change with block numbers
//! (i.e., they are forkable), and another set that is not subject to changes. This can also be
//! achieved by declaring an extension that contains [`Forks`] within it.
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use sc_chain_spec::{Forks, GenericChainSpec, ChainSpecGroup, ChainSpecExtension};
@@ -106,98 +318,26 @@
//!
//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
//! ```
//!
//! # Substrate chain specification format
//!
//! The Substrate chain specification is a `json` file that describes the basics of a chain. Most
//! importantly it lays out the genesis storage which leads to the genesis hash. The default
//! Substrate chain specification format is the following:
//!
//! ```json
//! // The human readable name of the chain.
//! "name": "Flaming Fir",
//!
//! // The id of the chain.
//! "id": "flamingfir9",
//!
//! // The chain type of this chain.
//! // Possible values are `Live`, `Development`, `Local`.
//! "chainType": "Live",
//!
//! // A list of multi addresses that belong to boot nodes of the chain.
//! "bootNodes": [
//! "/dns/0.flamingfir.paritytech.net/tcp/30333/p2p/12D3KooWLK2gMLhWsYJzjW3q35zAs9FDDVqfqVfVuskiGZGRSMvR",
//! ],
//!
//! // Optional list of "multi address, verbosity" of telemetry endpoints.
//! // The verbosity goes from `0` to `9`. With `0` being the mode with the lowest verbosity.
//! "telemetryEndpoints": [
//! [
//! "/dns/telemetry.polkadot.io/tcp/443/x-parity-wss/%2Fsubmit%2F",
//! 0
//! ]
//! ],
//!
//! // Optional networking protocol id that identifies the chain.
//! "protocolId": "fir9",
//!
//! // Optional fork id. Should most likely be left empty.
//! // Can be used to signal a fork on the network level when two chains have the
//! // same genesis hash.
//! "forkId": "random_fork",
//!
//! // Custom properties.
//! "properties": {
//! "tokenDecimals": 15,
//! "tokenSymbol": "FIR"
//! },
//!
//! // Deprecated field. Should be ignored.
//! "consensusEngine": null,
//!
//! // The genesis declaration of the chain.
//! //
//! // `runtime`, `raw`, `stateRootHash` denote the type of the genesis declaration.
//! //
//! // These declarations are in the following formats:
//! // - `runtime` is a `json` object that can be parsed by a compatible `GenesisConfig`. This
//! // `GenesisConfig` is declared by a runtime and opaque to the node.
//! // - `raw` is a `json` object with two fields `top` and `children_default`. Each of these
//! // fields is a map of `key => value`. These key/value pairs represent the genesis storage.
//! // - `stateRootHash` is a single hex encoded hash that represents the genesis hash. The hash
//! // type depends on the hash used by the chain.
//! //
//! "genesis": { "runtime": {} },
//!
//! /// Optional map of `block_number` to `wasm_code`.
//! ///
//! /// The given `wasm_code` will be used to substitute the on-chain wasm code starting with the
//! /// given block number until the `spec_version` on-chain changes. The given `wasm_code` should
//! /// be as close as possible to the on-chain wasm code. A substitute should be used to fix a bug
//! /// that can not be fixed with a runtime upgrade, if for example the runtime is constantly
//! /// panicking. Introducing new runtime apis isn't supported, because the node
//! /// will read the runtime version from the on-chain wasm code. Use this functionality only when
//! /// there is no other way around it and only patch the problematic bug, the rest should be done
//! /// with a on-chain runtime upgrade.
//! "codeSubstitutes": [],
//! ```
//!
//! See [`ChainSpec`] for a trait representation of the above.
//!
//! The chain spec can be extended with other fields that are opaque to the default chain spec.
//! Specific node implementations will need to be able to deserialize these extensions.
mod chain_spec;
mod extension;
mod genesis;
mod genesis_block;
mod genesis_config_builder;
mod json_patch;
pub use self::{
chain_spec::{ChainSpec as GenericChainSpec, NoExtension},
chain_spec::{
update_code_in_json_chain_spec, ChainSpec as GenericChainSpec, ChainSpecBuilder,
NoExtension,
},
extension::{get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group},
genesis::{
genesis_block::{
construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock,
GenesisBlockBuilder,
},
genesis_config_builder::GenesisConfigBuilderRuntimeCaller,
};
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
@@ -126,18 +126,14 @@ mod tests {
}
fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
Ok(Box::new(GenericChainSpec::from_genesis(
"test",
"test_id",
ChainType::Development,
|| unimplemented!("Not required in tests"),
Vec::new(),
None,
None,
None,
None,
NoExtension::None,
)))
Ok(Box::new(
GenericChainSpec::<()>::builder(Default::default(), NoExtension::None)
.with_name("test")
.with_id("test_id")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(Default::default())
.build(),
))
}
}
+8 -12
View File
@@ -251,18 +251,14 @@ mod tests {
trie_cache_maximum_size: None,
state_pruning: None,
blocks_pruning: sc_client_db::BlocksPruning::KeepAll,
chain_spec: Box::new(GenericChainSpec::from_genesis(
"test",
"test_id",
ChainType::Development,
|| unimplemented!("Not required in tests"),
Vec::new(),
None,
None,
None,
None,
NoExtension::None,
)),
chain_spec: Box::new(
GenericChainSpec::<()>::builder(Default::default(), NoExtension::None)
.with_name("test")
.with_id("test_id")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(Default::default())
.build(),
),
wasm_method: Default::default(),
wasm_runtime_overrides: None,
rpc_addr: None,
-3
View File
@@ -724,8 +724,6 @@ pub mod pallet {
#[derive(frame_support::DefaultNoBound)]
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
#[serde(with = "sp_core::bytes")]
pub code: Vec<u8>,
#[serde(skip)]
pub _config: sp_std::marker::PhantomData<T>,
}
@@ -739,7 +737,6 @@ pub mod pallet {
<UpgradedToU32RefCount<T>>::put(true);
<UpgradedToTripleRefCount<T>>::put(true);
sp_io::storage::set(well_known_keys::CODE, &self.code);
sp_io::storage::set(well_known_keys::EXTRINSIC_INDEX, &0u32.encode());
}
}
+6 -2
View File
@@ -141,8 +141,9 @@
//! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the
//! modules that are provided with `FRAME`. This node and runtime is only used for testing and
//! demonstration.
//! * [`chain-spec-builder`]: Utility to build more detailed chain-specs for the aforementioned
//! node. Other projects typically contain a `build-spec` subcommand that does the same.
//! * [`chain-spec-builder`]: Utility to build more detailed [chain-spec][`sc-chain-spec`] for the
//! aforementioned node. Other projects typically contain a `build-spec` subcommand that does the
//! same.
//! * [`node-template`]: a template node that contains a minimal set of features and can act as a
//! starting point of a project.
//! * [`subkey`]: Substrate's key management utility.
@@ -177,6 +178,8 @@
//!
//! Additional noteworthy crates within substrate:
//!
//! - Chain specification of a Substrate node:
//! - [`sc-chain-spec`]
//! - RPC APIs of a Substrate node: [`sc-rpc-api`]/[`sc-rpc`]
//! - CLI Options of a Substrate node: [`sc-cli`]
//! - All of the consensus related crates provided by Substrate:
@@ -217,6 +220,7 @@
//! [`sp-api`]: ../sp_api/index.html
//! [`sp-api`]: ../sp_api/index.html
//! [`sc-client-db`]: ../sc_client_db/index.html
//! [`sc-chain-spec`]: ../sc_chain_spec/index.html
//! [`sc-network`]: ../sc_network/index.html
//! [`sc-rpc-api`]: ../sc_rpc_api/index.html
//! [`sc-rpc`]: ../sc_rpc/index.html
+2 -2
View File
@@ -48,8 +48,6 @@ sp-externalities = { path = "../../primitives/externalities", default-features =
# 3rd party
array-bytes = { version = "6.1", optional = true }
log = { version = "0.4.17", default-features = false }
serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false }
serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] }
[dev-dependencies]
futures = "0.3.21"
@@ -60,6 +58,8 @@ sp-consensus = { path = "../../primitives/consensus/common" }
substrate-test-runtime-client = { path = "client" }
sp-tracing = { path = "../../primitives/tracing" }
json-patch = { version = "1.0.0", default-features = false }
serde = { version = "1.0.188", features = ["alloc", "derive"], default-features = false }
serde_json = { version = "1.0.107", default-features = false, features = ["alloc"] }
[build-dependencies]
substrate-wasm-builder = { path = "../../utils/wasm-builder", optional = true }
@@ -1,7 +1,5 @@
{
"system": {
"code": "0x52"
},
"system": {},
"babe": {
"authorities": [
[
@@ -1,7 +1,5 @@
{
"system": {
"code": "0x52"
},
"system": {},
"babe": {
"epochConfig": {
"c": [
@@ -1,7 +1,5 @@
{
"system": {
"code": "0x52"
},
"system": {},
"babe": {
"renamed_authorities": [
[
@@ -0,0 +1,113 @@
{
"system": {},
"babex": {
"authorities": [
[
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
1
],
[
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
1
],
[
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
1
]
],
"epochConfig": {
"c": [
3,
10
],
"allowed_slots": "PrimaryAndSecondaryPlainSlots"
}
},
"substrateTest": {
"authorities": [
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y"
]
},
"balances": {
"balances": [
[
"5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH",
100000000000000000
],
[
"5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o",
100000000000000000
],
[
"5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9",
100000000000000000
],
[
"5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK",
100000000000000000
],
[
"5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW",
100000000000000000
],
[
"5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR",
100000000000000000
],
[
"5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY",
100000000000000000
],
[
"5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ",
100000000000000000
],
[
"5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX",
100000000000000000
],
[
"5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q",
100000000000000000
],
[
"5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz",
100000000000000000
],
[
"5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf",
100000000000000000
],
[
"5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz",
100000000000000000
],
[
"5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC",
100000000000000000
],
[
"5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51",
100000000000000000
],
[
"5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e",
100000000000000000
],
[
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
100000000000000000
],
[
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
100000000000000000
],
[
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
100000000000000000
]
]
}
}
@@ -117,10 +117,7 @@ impl GenesisStorageBuilder {
.collect();
RuntimeGenesisConfig {
system: frame_system::GenesisConfig {
code: self.wasm_code.clone().unwrap_or(wasm_binary_unwrap().to_vec()),
..Default::default()
},
system: Default::default(),
babe: pallet_babe::GenesisConfig {
authorities: authorities_sr25519
.clone()
@@ -149,6 +146,11 @@ impl GenesisStorageBuilder {
storage.top.insert(well_known_keys::HEAP_PAGES.into(), heap_pages.encode());
}
storage.top.insert(
well_known_keys::CODE.into(),
self.wasm_code.clone().unwrap_or(wasm_binary_unwrap().to_vec()),
);
storage.top.extend(self.extra_storage.top.clone());
storage.children_default.extend(self.extra_storage.children_default.clone());
+32 -19
View File
@@ -464,11 +464,10 @@ impl_opaque_keys! {
}
}
pub(crate) const TEST_RUNTIME_BABE_EPOCH_CONFIGURATION: BabeEpochConfiguration =
BabeEpochConfiguration {
c: (3, 10),
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
};
pub const TEST_RUNTIME_BABE_EPOCH_CONFIGURATION: BabeEpochConfiguration = BabeEpochConfiguration {
c: (3, 10),
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
};
impl_runtime_apis! {
impl sp_api::Core<Block> for Runtime {
@@ -1237,7 +1236,7 @@ mod tests {
#[test]
fn build_minimal_genesis_config_works() {
sp_tracing::try_init_simple();
let default_minimal_json = r#"{"system":{"code":"0x"},"babe":{"authorities":[],"epochConfig":{"c": [ 3, 10 ],"allowed_slots":"PrimaryAndSecondaryPlainSlots"}},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#;
let default_minimal_json = r#"{"system":{},"babe":{"authorities":[],"epochConfig":{"c": [ 3, 10 ],"allowed_slots":"PrimaryAndSecondaryPlainSlots"}},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#;
let mut t = BasicExternalities::new_empty();
executor_call(&mut t, "GenesisBuilder_build_config", &default_minimal_json.encode())
@@ -1264,8 +1263,6 @@ mod tests {
// System|LastRuntimeUpgrade
"26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8",
// :code
"3a636f6465",
// :extrinsic_index
"3a65787472696e7369635f696e646578",
// Balances|TotalIssuance
@@ -1294,35 +1291,55 @@ mod tests {
let r = Vec::<u8>::decode(&mut &r[..]).unwrap();
let json = String::from_utf8(r.into()).expect("returned value is json. qed.");
let expected = r#"{"system":{"code":"0x"},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#;
let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#;
assert_eq!(expected.to_string(), json);
}
#[test]
fn build_config_from_json_works() {
sp_tracing::try_init_simple();
let j = include_str!("test_json/default_genesis_config.json");
let j = include_str!("../res/default_genesis_config.json");
let mut t = BasicExternalities::new_empty();
let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap();
let r = BuildResult::decode(&mut &r[..]);
assert!(r.is_ok());
let keys = t.into_storages().top.keys().cloned().map(hex).collect::<Vec<String>>();
let mut keys = t.into_storages().top.keys().cloned().map(hex).collect::<Vec<String>>();
// following keys are not placed during `<RuntimeGenesisConfig as GenesisBuild>::build`
// process, add them `keys` to assert against known keys.
keys.push(hex(b":code"));
keys.sort();
assert_eq!(keys, storage_key_generator::get_expected_storage_hashed_keys(false));
}
#[test]
fn build_config_from_invalid_json_fails() {
sp_tracing::try_init_simple();
let j = include_str!("test_json/default_genesis_config_invalid.json");
let j = include_str!("../res/default_genesis_config_invalid.json");
let mut t = BasicExternalities::new_empty();
let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap();
let r = BuildResult::decode(&mut &r[..]).unwrap();
log::info!("result: {:#?}", r);
assert_eq!(r, Err(
sp_runtime::RuntimeString::Owned(
"Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 6 column 25".to_string(),
"Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 4 column 25".to_string(),
))
);
}
#[test]
fn build_config_from_invalid_json_fails_2() {
sp_tracing::try_init_simple();
let j = include_str!("../res/default_genesis_config_invalid_2.json");
let mut t = BasicExternalities::new_empty();
let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap();
let r = BuildResult::decode(&mut &r[..]).unwrap();
assert_eq!(r, Err(
sp_runtime::RuntimeString::Owned(
"Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 3 column 9".to_string(),
))
);
}
@@ -1330,7 +1347,7 @@ mod tests {
#[test]
fn build_config_from_incomplete_json_fails() {
sp_tracing::try_init_simple();
let j = include_str!("test_json/default_genesis_config_incomplete.json");
let j = include_str!("../res/default_genesis_config_incomplete.json");
let mut t = BasicExternalities::new_empty();
let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap();
@@ -1339,7 +1356,7 @@ mod tests {
assert_eq!(
r,
Err(sp_runtime::RuntimeString::Owned(
"Invalid JSON blob: missing field `authorities` at line 13 column 3"
"Invalid JSON blob: missing field `authorities` at line 11 column 3"
.to_string()
))
);
@@ -1438,10 +1455,6 @@ mod tests {
);
assert_eq!(u64::decode(&mut &value[..]).unwrap(), 0);
// :code
let value: Vec<u8> = get_from_storage("3a636f6465");
assert!(Vec::<u8>::decode(&mut &value[..]).is_err());
//System|ParentHash
let value: Vec<u8> = get_from_storage(
"26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc",