Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chain-spec-builder: Add support for codeSubstitutes #4685

Merged
merged 13 commits into from
Jun 25, 2024
17 changes: 15 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ members = [
"bridges/snowbridge/primitives/router",
"bridges/snowbridge/runtime/runtime-common",
"bridges/snowbridge/runtime/test-common",
"cumulus/client/chain-spec-extension",
"cumulus/client/cli",
"cumulus/client/collator",
"cumulus/client/consensus/aura",
Expand Down
14 changes: 14 additions & 0 deletions cumulus/client/chain-spec-extension/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "cumulus-client-chain-spec-extension"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need a new crate for them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was that we can refer to this crate from small tools like chain-spec-builder without pulling in the whole world of dependencies. Which would be the case if I put it in some other bigger crate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be also done with features, one of which could be 'api' exposing necessary types only.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe move it to sc_chain_spec::common, as it is typical/common of parachains?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#4685 (comment) given this, we should revert these changes. Merge the pr with the codeSubstitute support and add a new one that ignores the unknown fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracking of follow up #4873

version = "0.1.0"
authors.workspace = true
edition.workspace = true
description = "Parachain chain-spec extension."
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"

[lints]
workspace = true

[dependencies]
sc-chain-spec = { path = "../../../substrate/client/chain-spec" }
serde = { features = ["derive"], workspace = true, default-features = true }
38 changes: 38 additions & 0 deletions cumulus/client/chain-spec-extension/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Cumulus.

// Cumulus 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.

// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.

//! Chain spec extension for parachains.

use sc_chain_spec::{ChainSpec, ChainSpecExtension, ChainSpecGroup};
use serde::{Deserialize, Serialize};

/// The extensions for the [`ChainSpec`].
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
pub struct Extensions {
/// The relay chain of the Parachain.
#[serde(alias = "relayChain", alias = "RelayChain")]
pub relay_chain: String,
/// The id of the Parachain.
#[serde(alias = "paraId", alias = "ParaId")]
pub para_id: u32,
}

impl Extensions {
/// Try to get the extension from the given `ChainSpec`.
pub fn try_get(chain_spec: &dyn ChainSpec) -> Option<&Self> {
sc_chain_spec::get_extension(chain_spec.extensions())
}
}
1 change: 1 addition & 0 deletions cumulus/polkadot-parachain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ cumulus-primitives-aura = { path = "../primitives/aura" }
cumulus-primitives-core = { path = "../primitives/core" }
cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" }
color-print = "0.3.4"
cumulus-client-chain-spec-extension = { path = "../client/chain-spec-extension" }

[build-dependencies]
substrate-build-script-utils = { path = "../../substrate/utils/build-script-utils" }
Expand Down
21 changes: 1 addition & 20 deletions cumulus/polkadot-parachain/src/chain_spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

use cumulus_client_chain_spec_extension::Extensions;
use parachains_common::{AccountId, Signature};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use serde::{Deserialize, Serialize};
use sp_core::{Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};

Expand All @@ -35,24 +34,6 @@ pub mod shell;
/// The default XCM version to set in genesis config.
const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION;

/// Generic extensions for Parachain ChainSpecs.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
pub struct Extensions {
/// The relay chain of the Parachain.
#[serde(alias = "relayChain", alias = "RelayChain")]
pub relay_chain: String,
/// The id of the Parachain.
#[serde(alias = "paraId", alias = "ParaId")]
pub para_id: u32,
}

impl Extensions {
/// Try to get the extension from the given `ChainSpec`.
pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
sc_chain_spec::get_extension(chain_spec.extensions())
}
}

/// Generic chain spec for all polkadot-parachain runtimes
pub type GenericChainSpec = sc_service::GenericChainSpec<Extensions>;

Expand Down
3 changes: 2 additions & 1 deletion cumulus/polkadot-parachain/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

use cumulus_client_chain_spec_extension::Extensions;
use std::path::PathBuf;

/// Sub-commands supported by the collator.
Expand Down Expand Up @@ -113,7 +114,7 @@ impl RelayChainCli {
para_config: &sc_service::Configuration,
relay_chain_args: impl Iterator<Item = &'a String>,
) -> Self {
let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec);
let extension = Extensions::try_get(&*para_config.chain_spec);
let chain_id = extension.map(|e| e.relay_chain.clone());
let base_path = para_config.base_path.path().join("polkadot");
Self {
Expand Down
2 changes: 1 addition & 1 deletion cumulus/polkadot-parachain/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ pub fn run() -> Result<()> {
sc_sysinfo::gather_hwbench(Some(database_path))
})).flatten();

let para_id = chain_spec::Extensions::try_get(&*config.chain_spec)
let para_id = cumulus_client_chain_spec_extension::Extensions::try_get(&*config.chain_spec)
.map(|e| e.para_id)
.ok_or("Could not find parachain extension in chain-spec.")?;

Expand Down
2 changes: 1 addition & 1 deletion cumulus/test/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ codec = { package = "parity-scale-codec", version = "3.6.12" }
criterion = { version = "0.5.1", features = ["async_tokio"] }
jsonrpsee = { version = "0.22", features = ["server"] }
rand = "0.8.5"
serde = { features = ["derive"], workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
tokio = { version = "1.32.0", features = ["macros"] }
tracing = "0.1.37"
Expand Down Expand Up @@ -88,6 +87,7 @@ cumulus-test-relay-sproof-builder = { path = "../relay-sproof-builder" }
cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false }
cumulus-primitives-storage-weight-reclaim = { path = "../../primitives/storage-weight-reclaim" }
pallet-timestamp = { path = "../../../substrate/frame/timestamp" }
cumulus-client-chain-spec-extension = { path = "../../client/chain-spec-extension" }

[dev-dependencies]
futures = "0.3.28"
Expand Down
23 changes: 5 additions & 18 deletions cumulus/test/service/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@

#![allow(missing_docs)]

use cumulus_client_chain_spec_extension::Extensions;
use cumulus_primitives_core::ParaId;
use cumulus_test_runtime::{AccountId, Signature};
use parachains_common::AuraId;
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};

Expand All @@ -35,21 +34,6 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
.public()
}

/// The extensions for the [`ChainSpec`].
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
#[serde(deny_unknown_fields)]
pub struct Extensions {
/// The id of the Parachain.
pub para_id: u32,
}

impl Extensions {
/// Try to get the extension from the given `ChainSpec`.
pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
sc_chain_spec::get_extension(chain_spec.extensions())
}
}

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

/// Helper function to generate an account ID from seed.
Expand All @@ -69,7 +53,10 @@ pub fn get_chain_spec_with_extra_endowed(
) -> ChainSpec {
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() },
Extensions {
para_id: id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()).into(),
relay_chain: "rococo-local".to_string(),
},
)
.with_name("Local Testnet")
.with_id("local_testnet")
Expand Down
9 changes: 5 additions & 4 deletions cumulus/test/service/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::sync::Arc;

use cli::{RelayChainCli, Subcommand, TestCollatorCli};
use cumulus_primitives_core::relay_chain::CollatorPair;
use cumulus_test_service::{chain_spec, new_partial, AnnounceBlockFn};
use cumulus_test_service::{new_partial, AnnounceBlockFn};
use sc_cli::{CliConfiguration, SubstrateCli};
use sp_core::Pair;

Expand Down Expand Up @@ -77,9 +77,10 @@ fn main() -> Result<(), sc_cli::Error> {
SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
.map_err(|err| format!("Relay chain argument error: {}", err))?;

let parachain_id = chain_spec::Extensions::try_get(&*config.chain_spec)
.map(|e| e.para_id)
.ok_or("Could not find parachain extension in chain-spec.")?;
let parachain_id =
cumulus_client_chain_spec_extension::Extensions::try_get(&*config.chain_spec)
.map(|e| e.para_id)
.ok_or("Could not find parachain extension in chain-spec.")?;

tracing::info!("Parachain id: {:?}", parachain_id);
tracing::info!(
Expand Down
16 changes: 16 additions & 0 deletions prdoc/pr_4685.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.github.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Chain-spec-builder supports parachain chain-specs and `codeSubstitutes`.

doc:
- audience: Node Operator
description: |
Chain-spec-builder now supports parachain chain-specs. Parachain chain-specs have the `relay_chain` and `para_id` fields.
Before this change, the fields would get silently removed when using the chain-spec-builder.
In addition, a new subcommand `add-code-substitute` is available. It allows users to provide a runtime that should be used from a given
block onwards.

crates:
- name: staging-chain-spec-builder
bump: minor
4 changes: 4 additions & 0 deletions substrate/bin/utils/chain-spec-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ log = { workspace = true, default-features = true }
sc-chain-spec = { path = "../../../client/chain-spec", features = ["clap"] }
serde_json = { workspace = true, default-features = true }
sp-tracing = { path = "../../../primitives/tracing" }
sp-runtime = { path = "../../../primitives/runtime" }
sp-core = { path = "../../../primitives/core" }
sc-service = { path = "../../../client/service", default-features = false }
cumulus-client-chain-spec-extension = { path = "../../../../cumulus/client/chain-spec-extension" }
37 changes: 31 additions & 6 deletions substrate/bin/utils/chain-spec-builder/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use chain_spec_builder::{
generate_chain_spec_for_runtime, ChainSpecBuilder, ChainSpecBuilderCmd, ConvertToRawCmd,
DisplayPresetCmd, ListPresetsCmd, UpdateCodeCmd, VerifyCmd,
generate_chain_spec_for_runtime, AddCodeSubstituteCmd, ChainSpecBuilder, ChainSpecBuilderCmd,
ConvertToRawCmd, DisplayPresetCmd, ListPresetsCmd, UpdateCodeCmd, VerifyCmd,
};
use clap::Parser;
use cumulus_client_chain_spec_extension::Extensions;
use sc_chain_spec::{
update_code_in_json_chain_spec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller,
set_code_substitute_in_json_chain_spec, update_code_in_json_chain_spec, GenericChainSpec,
GenesisConfigBuilderRuntimeCaller,
};
use staging_chain_spec_builder as chain_spec_builder;
use std::fs;

type ChainSpec = GenericChainSpec<Option<Extensions>, ()>;

//avoid error message escaping
fn main() {
match inner_main() {
Expand All @@ -50,7 +54,7 @@ fn inner_main() -> Result<(), String> {
ref input_chain_spec,
ref runtime_wasm_path,
}) => {
let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?;
let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?;

let mut chain_spec_json =
serde_json::from_str::<serde_json::Value>(&chain_spec.as_json(false)?)
Expand All @@ -65,8 +69,29 @@ fn inner_main() -> Result<(), String> {
.map_err(|e| format!("to pretty failed: {e}"))?;
fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?;
},
ChainSpecBuilderCmd::AddCodeSubstitute(AddCodeSubstituteCmd {
ref input_chain_spec,
ref runtime_wasm_path,
block_height,
}) => {
let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?;

let mut chain_spec_json =
serde_json::from_str::<serde_json::Value>(&chain_spec.as_json(false)?)
.map_err(|e| format!("Conversion to json failed: {e}"))?;

set_code_substitute_in_json_chain_spec(
&mut chain_spec_json,
&fs::read(runtime_wasm_path.as_path())
.map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..],
block_height,
);
let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json)
.map_err(|e| format!("to pretty failed: {e}"))?;
fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?;
},
Copy link
Contributor

@michalkucharczyk michalkucharczyk Jun 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: to avoid code duplication in UpdateCode and AddCodeSubstitute match arms we could add a function update_chain_spec_file_in_place which could take a closure that modifies &mut chain_spec_json provided as its input.

ChainSpecBuilderCmd::ConvertToRaw(ConvertToRawCmd { ref input_chain_spec }) => {
let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?;
let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?;

let chain_spec_json =
serde_json::from_str::<serde_json::Value>(&chain_spec.as_json(true)?)
Expand All @@ -77,7 +102,7 @@ fn inner_main() -> Result<(), String> {
fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?;
},
ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec }) => {
let chain_spec = GenericChainSpec::<()>::from_json_file(input_chain_spec.clone())?;
let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?;
let _ = serde_json::from_str::<serde_json::Value>(&chain_spec.as_json(true)?)
.map_err(|e| format!("Conversion to json failed: {e}"))?;
},
Expand Down
Loading
Loading