From 2d3a6932de35fc53da4e4b6bc195b1cc69550300 Mon Sep 17 00:00:00 2001
From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com>
Date: Mon, 27 May 2024 23:29:50 +0200
Subject: [PATCH] `sc-chain-spec`: deprecated code removed (#4410)

This PR removes deprecated code:
- The `RuntimeGenesisConfig` generic type parameter in
`GenericChainSpec` struct.
- `ChainSpec::from_genesis` method allowing to create chain-spec using
closure providing runtime genesis struct
- `GenesisSource::Factory` variant together with no longer needed
`GenesisSource`'s generic parameter `G` (which was intended to be a
runtime genesis struct).


https://github.com/paritytech/polkadot-sdk/blob/17b56fae2d976a3df87f34076875de8c26da0355/substrate/client/chain-spec/src/chain_spec.rs#L559-L563
---
 Cargo.lock                                    |   1 +
 .../polkadot-parachain/src/chain_spec/mod.rs  |   2 +-
 cumulus/polkadot-parachain/src/command.rs     |   2 +-
 cumulus/test/service/src/chain_spec.rs        |   4 +-
 polkadot/node/service/src/chain_spec.rs       |   6 +-
 polkadot/node/service/src/lib.rs              |   4 +-
 polkadot/node/test/service/src/chain_spec.rs  |   2 +-
 prdoc/pr_4410.prdoc                           |  37 +++
 substrate/bin/node/cli/src/chain_spec.rs      |   2 +-
 substrate/client/chain-spec/Cargo.toml        |   1 +
 ...spec_as_json_fails_with_invalid_config.err | 114 ---------
 substrate/client/chain-spec/src/chain_spec.rs | 229 ++++--------------
 substrate/client/chain-spec/src/lib.rs        |  13 +-
 .../client/cli/src/commands/insert_key.rs     |   4 +-
 substrate/client/cli/src/runner.rs            |  15 +-
 .../grandpa/src/communication/tests.rs        |  25 +-
 substrate/client/service/src/lib.rs           |   2 +-
 substrate/client/service/test/src/lib.rs      |  37 ++-
 templates/minimal/node/src/chain_spec.rs      |   2 +-
 templates/parachain/node/src/chain_spec.rs    |   2 +-
 templates/solochain/node/src/chain_spec.rs    |   4 +-
 21 files changed, 143 insertions(+), 365 deletions(-)
 create mode 100644 prdoc/pr_4410.prdoc
 delete mode 100644 substrate/client/chain-spec/res/chain_spec_as_json_fails_with_invalid_config.err

diff --git a/Cargo.lock b/Cargo.lock
index acbda4f0326..3d6cbc9e83f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -16702,6 +16702,7 @@ dependencies = [
  "log",
  "memmap2 0.9.3",
  "parity-scale-codec",
+ "regex",
  "sc-chain-spec-derive",
  "sc-client-api",
  "sc-executor",
diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs
index 136a19e3166..19047b073b0 100644
--- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs
+++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs
@@ -54,7 +54,7 @@ impl Extensions {
 }
 
 /// Generic chain spec for all polkadot-parachain runtimes
-pub type GenericChainSpec = sc_service::GenericChainSpec<(), Extensions>;
+pub type GenericChainSpec = sc_service::GenericChainSpec<Extensions>;
 
 /// Helper function to generate a crypto pair from seed
 pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs
index 041187de488..653ea3281f0 100644
--- a/cumulus/polkadot-parachain/src/command.rs
+++ b/cumulus/polkadot-parachain/src/command.rs
@@ -1017,7 +1017,7 @@ mod tests {
 		cfg_file_path
 	}
 
-	pub type DummyChainSpec<E> = sc_service::GenericChainSpec<(), E>;
+	pub type DummyChainSpec<E> = sc_service::GenericChainSpec<E>;
 
 	pub fn create_default_with_extensions<E: Extension>(
 		id: &str,
diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs
index 4db2513e2b6..28faba7377e 100644
--- a/cumulus/test/service/src/chain_spec.rs
+++ b/cumulus/test/service/src/chain_spec.rs
@@ -17,7 +17,7 @@
 #![allow(missing_docs)]
 
 use cumulus_primitives_core::ParaId;
-use cumulus_test_runtime::{AccountId, RuntimeGenesisConfig, Signature};
+use cumulus_test_runtime::{AccountId, Signature};
 use parachains_common::AuraId;
 use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
 use sc_service::ChainType;
@@ -26,7 +26,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<RuntimeGenesisConfig, Extensions>;
+pub type ChainSpec = sc_service::GenericChainSpec<Extensions>;
 
 /// Helper function to generate a crypto pair from seed
 pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs
index 1b990af2394..c7019e3f0b2 100644
--- a/polkadot/node/service/src/chain_spec.rs
+++ b/polkadot/node/service/src/chain_spec.rs
@@ -70,11 +70,11 @@ pub struct Extensions {
 }
 
 // Generic chain spec, in case when we don't have the native runtime.
-pub type GenericChainSpec = service::GenericChainSpec<(), Extensions>;
+pub type GenericChainSpec = service::GenericChainSpec<Extensions>;
 
 /// The `ChainSpec` parameterized for the westend runtime.
 #[cfg(feature = "westend-native")]
-pub type WestendChainSpec = service::GenericChainSpec<(), 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.
@@ -83,7 +83,7 @@ pub type WestendChainSpec = GenericChainSpec;
 
 /// The `ChainSpec` parameterized for the rococo runtime.
 #[cfg(feature = "rococo-native")]
-pub type RococoChainSpec = service::GenericChainSpec<(), Extensions>;
+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.
diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs
index 6d365b93ac7..f50b9770b41 100644
--- a/polkadot/node/service/src/lib.rs
+++ b/polkadot/node/service/src/lib.rs
@@ -100,8 +100,8 @@ pub use sc_executor::NativeExecutionDispatch;
 use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY};
 pub use service::{
 	config::{DatabaseSource, PrometheusConfig},
-	ChainSpec, Configuration, Error as SubstrateServiceError, PruningMode, Role, RuntimeGenesis,
-	TFullBackend, TFullCallExecutor, TFullClient, TaskManager, TransactionPoolOptions,
+	ChainSpec, Configuration, Error as SubstrateServiceError, PruningMode, Role, TFullBackend,
+	TFullCallExecutor, TFullClient, TaskManager, TransactionPoolOptions,
 };
 pub use sp_api::{ApiRef, ConstructRuntimeApi, Core as CoreApi, ProvideRuntimeApi};
 pub use sp_runtime::{
diff --git a/polkadot/node/test/service/src/chain_spec.rs b/polkadot/node/test/service/src/chain_spec.rs
index f14fa9fde58..e6a1229caf8 100644
--- a/polkadot/node/test/service/src/chain_spec.rs
+++ b/polkadot/node/test/service/src/chain_spec.rs
@@ -33,7 +33,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<(), 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> {
diff --git a/prdoc/pr_4410.prdoc b/prdoc/pr_4410.prdoc
new file mode 100644
index 00000000000..1dc1d4c1f87
--- /dev/null
+++ b/prdoc/pr_4410.prdoc
@@ -0,0 +1,37 @@
+title: "[sc-chain-spec] Remove deprecated code"
+
+doc:
+  - audience: Node Dev
+    description: |
+      The RuntimeGenesisConfig generic type parameter was removed from GenericChainSpec struct.
+      ChainSpec::from_genesis method was removed.
+      Removed related deprecated code from `sc-chain-spec`.
+      This change simplifies the codebase and ensures the use of up-to-date definitions.
+
+crates:
+  - name: sc-service
+    bump: minor
+  - name: minimal-template-node
+    bump: minor
+  - name: sc-cli
+    bump: patch
+  - name: polkadot-test-service
+    bump: major
+  - name: sc-service-test
+    bump: major
+  - name: staging-node-cli
+    bump: major
+  - name: parachain-template-node
+    bump: minor
+  - name: solochain-template-node
+    bump: minor
+  - name: polkadot-parachain-bin
+    bump: major
+  - name: polkadot-service
+    bump: major
+  - name: sc-consensus-grandpa
+    bump: patch
+  - name: cumulus-test-service
+    bump: minor
+  - name: sc-chain-spec
+    bump: major
diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs
index a3b536e5434..bc7821bfcf3 100644
--- a/substrate/bin/node/cli/src/chain_spec.rs
+++ b/substrate/bin/node/cli/src/chain_spec.rs
@@ -64,7 +64,7 @@ pub struct Extensions {
 }
 
 /// Specialized `ChainSpec`.
-pub type ChainSpec = sc_service::GenericChainSpec<RuntimeGenesisConfig, Extensions>;
+pub type ChainSpec = sc_service::GenericChainSpec<Extensions>;
 /// Flaming Fir testnet generator
 pub fn flaming_fir_config() -> Result<ChainSpec, String> {
 	ChainSpec::from_json_bytes(&include_bytes!("../res/flaming-fir.json")[..])
diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml
index 84ef89783ad..9028a2c49ee 100644
--- a/substrate/client/chain-spec/Cargo.toml
+++ b/substrate/client/chain-spec/Cargo.toml
@@ -42,3 +42,4 @@ 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"] }
+regex = "1.6.0"
diff --git a/substrate/client/chain-spec/res/chain_spec_as_json_fails_with_invalid_config.err b/substrate/client/chain-spec/res/chain_spec_as_json_fails_with_invalid_config.err
deleted file mode 100644
index c545b53b2ba..00000000000
--- a/substrate/client/chain-spec/res/chain_spec_as_json_fails_with_invalid_config.err
+++ /dev/null
@@ -1,114 +0,0 @@
-Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, `substrateTest`, `balances` at line 3 column 9 for blob:
-{
-  "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
-      ]
-    ]
-  }
-}
\ No newline at end of file
diff --git a/substrate/client/chain-spec/src/chain_spec.rs b/substrate/client/chain-spec/src/chain_spec.rs
index a9cdce4bf95..883cd19adfd 100644
--- a/substrate/client/chain-spec/src/chain_spec.rs
+++ b/substrate/client/chain-spec/src/chain_spec.rs
@@ -20,7 +20,7 @@
 #![warn(missing_docs)]
 use crate::{
 	extension::GetExtension, genesis_config_builder::HostFunctions, ChainType,
-	GenesisConfigBuilderRuntimeCaller as RuntimeCaller, Properties, RuntimeGenesis,
+	GenesisConfigBuilderRuntimeCaller as RuntimeCaller, Properties,
 };
 use sc_network::config::MultiaddrWithPeerId;
 use sc_telemetry::TelemetryEndpoints;
@@ -37,7 +37,6 @@ use std::{
 	fs::File,
 	marker::PhantomData,
 	path::PathBuf,
-	sync::Arc,
 };
 
 #[derive(Serialize, Deserialize)]
@@ -58,37 +57,33 @@ impl<EHF> Clone for GenesisBuildAction<EHF> {
 	}
 }
 
-#[allow(deprecated)]
-enum GenesisSource<G, EHF> {
+enum GenesisSource<EHF> {
 	File(PathBuf),
 	Binary(Cow<'static, [u8]>),
 	/// factory function + code
-	//Factory and G type parameter shall be removed together with `ChainSpec::from_genesis`
-	Factory(Arc<dyn Fn() -> G + Send + Sync>, Vec<u8>),
 	Storage(Storage),
 	/// build action + code
 	GenesisBuilderApi(GenesisBuildAction<EHF>, Vec<u8>),
 }
 
-impl<G, EHF> Clone for GenesisSource<G, EHF> {
+impl<EHF> Clone for GenesisSource<EHF> {
 	fn clone(&self) -> Self {
 		match *self {
 			Self::File(ref path) => Self::File(path.clone()),
 			Self::Binary(ref d) => Self::Binary(d.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, EHF: HostFunctions> GenesisSource<G, EHF> {
-	fn resolve(&self) -> Result<Genesis<G>, String> {
+impl<EHF: HostFunctions> GenesisSource<EHF> {
+	fn resolve(&self) -> Result<Genesis, 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>,
+		struct GenesisContainer {
+			genesis: Genesis,
 		}
 
 		match self {
@@ -105,19 +100,15 @@ impl<G: RuntimeGenesis, EHF: HostFunctions> GenesisSource<G, EHF> {
 					})?
 				};
 
-				let genesis: GenesisContainer<G> = json::from_slice(&bytes)
+				let genesis: GenesisContainer = json::from_slice(&bytes)
 					.map_err(|e| format!("Error parsing spec file: {}", e))?;
 				Ok(genesis.genesis)
 			},
 			Self::Binary(buf) => {
-				let genesis: GenesisContainer<G> = json::from_reader(buf.as_ref())
+				let genesis: GenesisContainer = json::from_reader(buf.as_ref())
 					.map_err(|e| format!("Error parsing embedded file: {}", e))?;
 				Ok(genesis.genesis)
 			},
-			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 {
@@ -140,24 +131,12 @@ impl<G: RuntimeGenesis, EHF: HostFunctions> GenesisSource<G, EHF> {
 	}
 }
 
-impl<G: RuntimeGenesis, E, EHF> BuildStorage for ChainSpec<G, E, EHF>
+impl<E, EHF> BuildStorage for ChainSpec<E, EHF>
 where
 	EHF: HostFunctions,
 {
 	fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
 		match self.genesis.resolve()? {
-			#[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)| {
@@ -236,7 +215,7 @@ impl From<sp_core::storage::Storage> for RawGenesis {
 	}
 }
 
-/// Inner representation of [`Genesis<G>::RuntimeGenesis`] format
+/// Inner representation of [`Genesis::RuntimeGenesis`] format
 #[derive(Serialize, Deserialize, Debug)]
 struct RuntimeGenesisInner {
 	/// Runtime wasm code, expected to be hex-encoded in JSON.
@@ -249,7 +228,7 @@ struct RuntimeGenesisInner {
 }
 
 /// Represents two possible variants of the contained JSON blob for the
-/// [`Genesis<G>::RuntimeGenesis`] format.
+/// [`Genesis::RuntimeGenesis`] format.
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 enum RuntimeGenesisConfigJson {
@@ -265,31 +244,11 @@ enum RuntimeGenesisConfigJson {
 	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 generated
-	/// 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>),
+enum Genesis {
 	/// The genesis storage as raw data. Typically raw key-value entries in state.
 	Raw(RawGenesis),
 	/// State root hash of the genesis storage.
@@ -343,7 +302,7 @@ struct ClientSpec<E> {
 pub type NoExtension = Option<()>;
 
 /// Builder for creating [`ChainSpec`] instances.
-pub struct ChainSpecBuilder<G, E = NoExtension, EHF = ()> {
+pub struct ChainSpecBuilder<E = NoExtension, EHF = ()> {
 	code: Vec<u8>,
 	extensions: E,
 	name: String,
@@ -355,10 +314,9 @@ pub struct ChainSpecBuilder<G, E = NoExtension, EHF = ()> {
 	protocol_id: Option<String>,
 	fork_id: Option<String>,
 	properties: Option<Properties>,
-	_genesis: PhantomData<G>,
 }
 
-impl<G, E, EHF> ChainSpecBuilder<G, E, EHF> {
+impl<E, EHF> ChainSpecBuilder<E, EHF> {
 	/// Creates a new builder instance with no defaults.
 	pub fn new(code: &[u8], extensions: E) -> Self {
 		Self {
@@ -373,7 +331,6 @@ impl<G, E, EHF> ChainSpecBuilder<G, E, EHF> {
 			protocol_id: None,
 			fork_id: None,
 			properties: None,
-			_genesis: Default::default(),
 		}
 	}
 
@@ -457,7 +414,7 @@ impl<G, E, EHF> ChainSpecBuilder<G, E, EHF> {
 	}
 
 	/// Builds a [`ChainSpec`] instance using the provided settings.
-	pub fn build(self) -> ChainSpec<G, E, EHF> {
+	pub fn build(self) -> ChainSpec<E, EHF> {
 		let client_spec = ClientSpec {
 			name: self.name,
 			id: self.id,
@@ -486,13 +443,13 @@ impl<G, E, EHF> ChainSpecBuilder<G, E, EHF> {
 /// The chain spec is generic over the native `RuntimeGenesisConfig` struct (`G`). It is also
 /// possible to parametrize chain spec over the extended host functions (EHF). It should be use if
 /// runtime is using the non-standard host function during genesis state creation.
-pub struct ChainSpec<G, E = NoExtension, EHF = ()> {
+pub struct ChainSpec<E = NoExtension, EHF = ()> {
 	client_spec: ClientSpec<E>,
-	genesis: GenesisSource<G, EHF>,
+	genesis: GenesisSource<EHF>,
 	_host_functions: PhantomData<EHF>,
 }
 
-impl<G, E: Clone, EHF> Clone for ChainSpec<G, E, EHF> {
+impl<E: Clone, EHF> Clone for ChainSpec<E, EHF> {
 	fn clone(&self) -> Self {
 		ChainSpec {
 			client_spec: self.client_spec.clone(),
@@ -502,7 +459,7 @@ impl<G, E: Clone, EHF> Clone for ChainSpec<G, E, EHF> {
 	}
 }
 
-impl<G, E, EHF> ChainSpec<G, E, EHF> {
+impl<E, EHF> ChainSpec<E, EHF> {
 	/// A list of bootnode addresses.
 	pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
 		&self.client_spec.boot_nodes
@@ -555,58 +512,18 @@ impl<G, E, EHF> ChainSpec<G, E, EHF> {
 		&mut self.client_spec.extensions
 	}
 
-	/// 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,
-		chain_type: ChainType,
-		constructor: F,
-		boot_nodes: Vec<MultiaddrWithPeerId>,
-		telemetry_endpoints: Option<TelemetryEndpoints>,
-		protocol_id: Option<&str>,
-		fork_id: Option<&str>,
-		properties: Option<Properties>,
-		extensions: E,
-		code: &[u8],
-	) -> Self {
-		let client_spec = ClientSpec {
-			name: name.to_owned(),
-			id: id.to_owned(),
-			chain_type,
-			boot_nodes,
-			telemetry_endpoints,
-			protocol_id: protocol_id.map(str::to_owned),
-			fork_id: fork_id.map(str::to_owned),
-			properties,
-			extensions,
-			consensus_engine: (),
-			genesis: Default::default(),
-			code_substitutes: BTreeMap::new(),
-		};
-
-		ChainSpec {
-			client_spec,
-			genesis: GenesisSource::Factory(Arc::new(constructor), code.into()),
-			_host_functions: Default::default(),
-		}
-	}
-
 	/// 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, EHF> {
+	pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder<E, EHF> {
 		ChainSpecBuilder::new(code, extensions)
 	}
 }
 
-impl<G: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned, EHF> ChainSpec<G, E, EHF> {
+impl<E: serde::de::DeserializeOwned, EHF> ChainSpec<E, EHF> {
 	/// Parse json content into a `ChainSpec`
 	pub fn from_json_bytes(json: impl Into<Cow<'static, [u8]>>) -> Result<Self, String> {
 		let json = json.into();
@@ -649,17 +566,17 @@ impl<G: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned, EHF> ChainS
 #[derive(Serialize, Deserialize)]
 // we cannot #[serde(deny_unknown_fields)]. Otherwise chain-spec-builder will fail on any
 // non-standard spec.
-struct ChainSpecJsonContainer<G, E> {
+struct ChainSpecJsonContainer<E> {
 	#[serde(flatten)]
 	client_spec: ClientSpec<E>,
-	genesis: Genesis<G>,
+	genesis: Genesis,
 }
 
-impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static, EHF> ChainSpec<G, E, EHF>
+impl<E: serde::Serialize + Clone + 'static, EHF> ChainSpec<E, EHF>
 where
 	EHF: HostFunctions,
 {
-	fn json_container(&self, raw: bool) -> Result<ChainSpecJsonContainer<G, E>, String> {
+	fn json_container(&self, raw: bool) -> Result<ChainSpecJsonContainer<E>, String> {
 		let raw_genesis = match (raw, self.genesis.resolve()?) {
 			(
 				true,
@@ -685,20 +602,7 @@ where
 				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()?;
-				RawGenesis::from(storage)
-			},
 			(true, Genesis::Raw(raw)) => raw,
-
 			(_, genesis) =>
 				return Ok(ChainSpecJsonContainer { client_spec: self.client_spec.clone(), genesis }),
 		};
@@ -716,9 +620,8 @@ where
 	}
 }
 
-impl<G, E, EHF> crate::ChainSpec for ChainSpec<G, E, EHF>
+impl<E, EHF> crate::ChainSpec for ChainSpec<E, EHF>
 where
-	G: RuntimeGenesis + 'static,
 	E: GetExtension + serde::Serialize + Clone + Send + Sync + 'static,
 	EHF: HostFunctions,
 {
@@ -831,8 +734,8 @@ fn json_contains_path(doc: &json::Value, path: &mut VecDeque<&str>) -> bool {
 
 /// 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.
+/// Function support updating the runtime code in provided JSON chain spec blob. `Genesis::Raw`
+/// and `Genesis::RuntimeGenesis` formats are supported.
 ///
 /// If update was successful `true` is returned, otherwise `false`. Chain spec JSON is modified in
 /// place.
@@ -871,19 +774,7 @@ mod tests {
 	use sp_core::storage::well_known_keys;
 	use sp_keyring::AccountKeyring;
 
-	#[derive(Debug, Serialize, Deserialize)]
-	struct Genesis(BTreeMap<String, String>);
-
-	impl BuildStorage for Genesis {
-		fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
-			storage.top.extend(
-				self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())),
-			);
-			Ok(())
-		}
-	}
-
-	type TestSpec = ChainSpec<Genesis>;
+	type TestSpec = ChainSpec;
 
 	#[test]
 	fn should_deserialize_example_chain_spec() {
@@ -919,7 +810,7 @@ mod tests {
 		}
 	}
 
-	type TestSpec2 = ChainSpec<Genesis, Extension1>;
+	type TestSpec2 = ChainSpec<Extension1>;
 
 	#[test]
 	fn should_deserialize_chain_spec_with_extensions() {
@@ -1137,10 +1028,10 @@ mod tests {
 
 	#[test]
 	fn chain_spec_as_json_fails_with_invalid_config() {
-		let expected_error_message =
-			include_str!("../res/chain_spec_as_json_fails_with_invalid_config.err");
-		let j =
-			include_str!("../../../test-utils/runtime/res/default_genesis_config_invalid_2.json");
+		let invalid_genesis_config = from_str::<Value>(include_str!(
+			"../../../test-utils/runtime/res/default_genesis_config_invalid_2.json"
+		))
+		.unwrap();
 		let output = ChainSpec::<()>::builder(
 			substrate_test_runtime::wasm_binary_unwrap().into(),
 			Default::default(),
@@ -1148,12 +1039,25 @@ mod tests {
 		.with_name("TestName")
 		.with_id("test_id")
 		.with_chain_type(ChainType::Local)
-		.with_genesis_config(from_str(j).unwrap())
+		.with_genesis_config(invalid_genesis_config.clone())
 		.build();
 
-		let result = output.as_json(true);
+		let result = output.as_json(true).unwrap_err();
+		let mut result = result.lines();
 
-		assert_eq!(result.err().unwrap(), expected_error_message);
+		let result_header = result.next().unwrap();
+		let result_body = result.collect::<Vec<&str>>().join("\n");
+		let result_body: Value = serde_json::from_str(&result_body).unwrap();
+
+		let re = regex::Regex::new(concat!(
+			r"^Invalid JSON blob: unknown field `babex`, expected one of `system`, `babe`, ",
+			r"`substrateTest`, `balances` at line \d+ column \d+ for blob:$"
+		))
+		.unwrap();
+
+		assert_eq!(json!({"a":1,"b":2}), json!({"b":2,"a":1}));
+		assert!(re.is_match(result_header));
+		assert_eq!(invalid_genesis_config, result_body);
 	}
 
 	#[test]
@@ -1278,35 +1182,4 @@ mod tests {
 			&|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,
-			|| 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" }
-		));
-	}
 }
diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs
index abe01dafd92..066a0ab9e2a 100644
--- a/substrate/client/chain-spec/src/lib.rs
+++ b/substrate/client/chain-spec/src/lib.rs
@@ -257,7 +257,7 @@
 //! 	pub known_blocks: HashMap<u64, String>,
 //! }
 //!
-//! pub type MyChainSpec<G> = GenericChainSpec<G, MyExtension>;
+//! pub type MyChainSpec = GenericChainSpec<MyExtension>;
 //! ```
 //! 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`]
@@ -286,10 +286,10 @@
 //! pub type BlockNumber = u64;
 //!
 //! /// A chain spec supporting forkable `ClientParams`.
-//! pub type MyChainSpec1<G> = GenericChainSpec<G, Forks<BlockNumber, ClientParams>>;
+//! pub type MyChainSpec1 = GenericChainSpec<Forks<BlockNumber, ClientParams>>;
 //!
 //! /// A chain spec supporting forkable `Extension`.
-//! pub type MyChainSpec2<G> = GenericChainSpec<G, Forks<BlockNumber, Extension>>;
+//! pub type MyChainSpec2 = GenericChainSpec<Forks<BlockNumber, Extension>>;
 //! ```
 //! 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
@@ -316,7 +316,7 @@
 //! 	pub pool: Forks<u64, PoolParams>,
 //! }
 //!
-//! pub type MyChainSpec<G> = GenericChainSpec<G, Extension>;
+//! pub type MyChainSpec = GenericChainSpec<Extension>;
 //! ```
 //! 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.
@@ -344,7 +344,6 @@ pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
 
 use sc_network::config::MultiaddrWithPeerId;
 use sc_telemetry::TelemetryEndpoints;
-use serde::{de::DeserializeOwned, Serialize};
 use sp_core::storage::Storage;
 use sp_runtime::BuildStorage;
 
@@ -373,10 +372,6 @@ impl Default for ChainType {
 /// Arbitrary properties defined in chain spec as a JSON object
 pub type Properties = serde_json::map::Map<String, serde_json::Value>;
 
-/// A set of traits for the runtime genesis config.
-pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
-impl<T: Serialize + DeserializeOwned + BuildStorage> RuntimeGenesis for T {}
-
 /// Common interface of a chain specification.
 pub trait ChainSpec: BuildStorage + Send + Sync {
 	/// Spec name.
diff --git a/substrate/client/cli/src/commands/insert_key.rs b/substrate/client/cli/src/commands/insert_key.rs
index 3d89610b28b..66dbec79486 100644
--- a/substrate/client/cli/src/commands/insert_key.rs
+++ b/substrate/client/cli/src/commands/insert_key.rs
@@ -126,8 +126,10 @@ mod tests {
 		}
 
 		fn load_spec(&self, _: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
+			let builder =
+				GenericChainSpec::<NoExtension, ()>::builder(Default::default(), NoExtension::None);
 			Ok(Box::new(
-				GenericChainSpec::<()>::builder(Default::default(), NoExtension::None)
+				builder
 					.with_name("test")
 					.with_id("test_id")
 					.with_chain_type(ChainType::Development)
diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs
index 3bf27680784..6d986e38d2f 100644
--- a/substrate/client/cli/src/runner.rs
+++ b/substrate/client/cli/src/runner.rs
@@ -252,12 +252,15 @@ mod tests {
 				state_pruning: None,
 				blocks_pruning: sc_client_db::BlocksPruning::KeepAll,
 				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(),
+					GenericChainSpec::<NoExtension, ()>::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,
diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs
index bc3023fc028..d7153a79ce0 100644
--- a/substrate/client/consensus/grandpa/src/communication/tests.rs
+++ b/substrate/client/consensus/grandpa/src/communication/tests.rs
@@ -706,25 +706,12 @@ fn peer_with_higher_view_leads_to_catch_up_request() {
 }
 
 fn local_chain_spec() -> Box<dyn sc_chain_spec::ChainSpec> {
-	use sc_chain_spec::{ChainSpec, GenericChainSpec};
-	use serde::{Deserialize, Serialize};
-	use sp_runtime::{BuildStorage, Storage};
-
-	#[derive(Debug, Serialize, Deserialize)]
-	struct Genesis(std::collections::BTreeMap<String, String>);
-	impl BuildStorage for Genesis {
-		fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
-			storage.top.extend(
-				self.0.iter().map(|(a, b)| (a.clone().into_bytes(), b.clone().into_bytes())),
-			);
-			Ok(())
-		}
-	}
-	let chain_spec = GenericChainSpec::<Genesis>::from_json_bytes(
-		&include_bytes!("../../../../chain-spec/res/chain_spec.json")[..],
-	)
-	.unwrap();
-	chain_spec.cloned_box()
+	let chain_spec =
+		sc_chain_spec::GenericChainSpec::<sc_chain_spec::NoExtension, ()>::from_json_bytes(
+			&include_bytes!("../../../../chain-spec/res/chain_spec.json")[..],
+		)
+		.unwrap();
+	sc_chain_spec::ChainSpec::cloned_box(&chain_spec)
 }
 
 #[test]
diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs
index d251fd2b58f..a51bb4012d5 100644
--- a/substrate/client/service/src/lib.rs
+++ b/substrate/client/service/src/lib.rs
@@ -76,7 +76,7 @@ pub use config::{
 };
 pub use sc_chain_spec::{
 	ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension,
-	Properties, RuntimeGenesis,
+	Properties,
 };
 
 pub use sc_consensus::ImportQueue;
diff --git a/substrate/client/service/test/src/lib.rs b/substrate/client/service/test/src/lib.rs
index f19b5a19739..e60bd9410c6 100644
--- a/substrate/client/service/test/src/lib.rs
+++ b/substrate/client/service/test/src/lib.rs
@@ -31,7 +31,7 @@ use sc_service::{
 	client::Client,
 	config::{BasePath, DatabaseSource, KeystoreConfig, RpcBatchRequestConfig},
 	BlocksPruning, ChainSpecExtension, Configuration, Error, GenericChainSpec, Role,
-	RuntimeGenesis, SpawnTaskHandle, TaskManager,
+	SpawnTaskHandle, TaskManager,
 };
 use sc_transaction_pool_api::TransactionPool;
 use sp_blockchain::HeaderBackend;
@@ -46,16 +46,16 @@ mod client;
 /// Maximum duration of single wait call.
 const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3);
 
-struct TestNet<G, E, F, U> {
+struct TestNet<E, F, U> {
 	runtime: Runtime,
 	authority_nodes: Vec<(usize, F, U, MultiaddrWithPeerId)>,
 	full_nodes: Vec<(usize, F, U, MultiaddrWithPeerId)>,
-	chain_spec: GenericChainSpec<G, E>,
+	chain_spec: GenericChainSpec<E>,
 	base_port: u16,
 	nodes: usize,
 }
 
-impl<G, E, F, U> Drop for TestNet<G, E, F, U> {
+impl<E, F, U> Drop for TestNet<E, F, U> {
 	fn drop(&mut self) {
 		// Drop the nodes before dropping the runtime, as the runtime otherwise waits for all
 		// futures to be ended and we run into a dead lock.
@@ -162,7 +162,7 @@ where
 	}
 }
 
-impl<G, E, F, U> TestNet<G, E, F, U>
+impl<E, F, U> TestNet<E, F, U>
 where
 	F: Clone + Send + 'static,
 	U: Clone + Send + 'static,
@@ -193,12 +193,9 @@ where
 	}
 }
 
-fn node_config<
-	G: RuntimeGenesis + 'static,
-	E: ChainSpecExtension + Clone + 'static + Send + Sync,
->(
+fn node_config<E: ChainSpecExtension + Clone + 'static + Send + Sync>(
 	index: usize,
-	spec: &GenericChainSpec<G, E>,
+	spec: &GenericChainSpec<E>,
 	role: Role,
 	tokio_handle: tokio::runtime::Handle,
 	key_seed: Option<String>,
@@ -272,19 +269,18 @@ fn node_config<
 	}
 }
 
-impl<G, E, F, U> TestNet<G, E, F, U>
+impl<E, F, U> TestNet<E, F, U>
 where
 	F: TestNetNode,
 	E: ChainSpecExtension + Clone + 'static + Send + Sync,
-	G: RuntimeGenesis + 'static,
 {
 	fn new(
 		temp: &TempDir,
-		spec: GenericChainSpec<G, E>,
+		spec: GenericChainSpec<E>,
 		full: impl Iterator<Item = impl FnOnce(Configuration) -> Result<(F, U), Error>>,
 		authorities: impl Iterator<Item = (String, impl FnOnce(Configuration) -> Result<(F, U), Error>)>,
 		base_port: u16,
-	) -> TestNet<G, E, F, U> {
+	) -> TestNet<E, F, U> {
 		sp_tracing::try_init_simple();
 		fdlimit::raise_fd_limit().unwrap();
 		let runtime = Runtime::new().expect("Error creating tokio runtime");
@@ -365,10 +361,9 @@ fn tempdir_with_prefix(prefix: &str) -> TempDir {
 		.expect("Error creating test dir")
 }
 
-pub fn connectivity<G, E, Fb, F>(spec: GenericChainSpec<G, E>, full_builder: Fb)
+pub fn connectivity<E, Fb, F>(spec: GenericChainSpec<E>, full_builder: Fb)
 where
 	E: ChainSpecExtension + Clone + 'static + Send + Sync,
-	G: RuntimeGenesis + 'static,
 	Fb: Fn(Configuration) -> Result<F, Error>,
 	F: TestNetNode,
 {
@@ -442,8 +437,8 @@ where
 	}
 }
 
-pub fn sync<G, E, Fb, F, B, ExF, U>(
-	spec: GenericChainSpec<G, E>,
+pub fn sync<E, Fb, F, B, ExF, U>(
+	spec: GenericChainSpec<E>,
 	full_builder: Fb,
 	mut make_block_and_import: B,
 	mut extrinsic_factory: ExF,
@@ -454,7 +449,6 @@ pub fn sync<G, E, Fb, F, B, ExF, U>(
 	ExF: FnMut(&F, &U) -> <F::Block as BlockT>::Extrinsic,
 	U: Clone + Send + 'static,
 	E: ChainSpecExtension + Clone + 'static + Send + Sync,
-	G: RuntimeGenesis + 'static,
 {
 	const NUM_FULL_NODES: usize = 10;
 	const NUM_BLOCKS: usize = 512;
@@ -513,15 +507,14 @@ pub fn sync<G, E, Fb, F, B, ExF, U>(
 	network.run_until_all_full(|_index, service| service.transaction_pool().ready().count() == 1);
 }
 
-pub fn consensus<G, E, Fb, F>(
-	spec: GenericChainSpec<G, E>,
+pub fn consensus<E, Fb, F>(
+	spec: GenericChainSpec<E>,
 	full_builder: Fb,
 	authorities: impl IntoIterator<Item = String>,
 ) where
 	Fb: Fn(Configuration) -> Result<F, Error>,
 	F: TestNetNode,
 	E: ChainSpecExtension + Clone + 'static + Send + Sync,
-	G: RuntimeGenesis + 'static,
 {
 	const NUM_FULL_NODES: usize = 10;
 	const NUM_BLOCKS: usize = 10; // 10 * 2 sec block production time = ~20 seconds
diff --git a/templates/minimal/node/src/chain_spec.rs b/templates/minimal/node/src/chain_spec.rs
index 6b721deb6d1..7a3475bb167 100644
--- a/templates/minimal/node/src/chain_spec.rs
+++ b/templates/minimal/node/src/chain_spec.rs
@@ -21,7 +21,7 @@ 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<()>;
+pub type ChainSpec = sc_service::GenericChainSpec;
 
 fn props() -> Properties {
 	let mut properties = Properties::new();
diff --git a/templates/parachain/node/src/chain_spec.rs b/templates/parachain/node/src/chain_spec.rs
index 51710f1199c..3fa91c02616 100644
--- a/templates/parachain/node/src/chain_spec.rs
+++ b/templates/parachain/node/src/chain_spec.rs
@@ -8,7 +8,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<(), 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;
diff --git a/templates/solochain/node/src/chain_spec.rs b/templates/solochain/node/src/chain_spec.rs
index be49f2c1fc7..651025e68de 100644
--- a/templates/solochain/node/src/chain_spec.rs
+++ b/templates/solochain/node/src/chain_spec.rs
@@ -1,5 +1,5 @@
 use sc_service::ChainType;
-use solochain_template_runtime::{AccountId, RuntimeGenesisConfig, Signature, WASM_BINARY};
+use solochain_template_runtime::{AccountId, Signature, WASM_BINARY};
 use sp_consensus_aura::sr25519::AuthorityId as AuraId;
 use sp_consensus_grandpa::AuthorityId as GrandpaId;
 use sp_core::{sr25519, Pair, Public};
@@ -9,7 +9,7 @@ use sp_runtime::traits::{IdentifyAccount, Verify};
 // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
 
 /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
-pub type ChainSpec = sc_service::GenericChainSpec<RuntimeGenesisConfig>;
+pub type ChainSpec = sc_service::GenericChainSpec;
 
 /// Generate a crypto pair from seed.
 pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
-- 
GitLab