feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit e4778b4576
6838 changed files with 1847450 additions and 0 deletions
@@ -0,0 +1,64 @@
[package]
name = "chain-spec-guide-runtime"
description = "A minimal runtime for chain spec guide"
version = "0.0.0"
license = "MIT-0"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[dependencies]
codec = { workspace = true }
docify = { workspace = true }
frame-support = { workspace = true }
scale-info = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
# this is a frame-based runtime, thus importing `frame` with runtime feature enabled.
frame = { features = ["experimental", "runtime"], workspace = true }
# genesis builder that allows us to interact with runtime genesis config
sp-application-crypto = { features = ["serde"], workspace = true }
sp-core = { workspace = true }
sp-genesis-builder = { workspace = true }
sp-keyring = { workspace = true }
sp-runtime = { features = ["serde"], workspace = true }
[dev-dependencies]
cmd_lib = { workspace = true }
sc-chain-spec = { workspace = true, default-features = true }
[build-dependencies]
substrate-wasm-builder = { optional = true, workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"frame-support/std",
"frame/std",
"sp-application-crypto/std",
"sp-core/std",
"sp-genesis-builder/std",
"sp-keyring/std",
"sp-runtime/std",
"serde/std",
"serde_json/std",
"substrate-wasm-builder",
]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame/runtime-benchmarks",
"sc-chain-spec/runtime-benchmarks",
"sp-genesis-builder/runtime-benchmarks",
"sp-keyring/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"substrate-wasm-builder?/runtime-benchmarks",
]
@@ -0,0 +1,23 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
fn main() {
#[cfg(feature = "std")]
{
substrate_wasm_builder::WasmBuilder::build_using_defaults();
}
}
@@ -0,0 +1,29 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]
//! A minimal runtime that shows runtime genesis state.
extern crate alloc;
pub mod pallets;
pub mod presets;
pub mod runtime;
#[cfg(feature = "std")]
pub use runtime::{WASM_BINARY, WASM_BINARY_BLOATY};
@@ -0,0 +1,138 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Pallets for the chain-spec demo runtime.
use alloc::vec::Vec;
use frame::prelude::*;
#[docify::export]
#[frame::pallet(dev_mode)]
pub mod pallet_bar {
use super::*;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::storage]
pub(super) type InitialAccount<T: Config> = StorageValue<Value = T::AccountId>;
/// Simple `GenesisConfig`.
#[pallet::genesis_config]
#[derive(DefaultNoBound)]
#[docify::export(pallet_bar_GenesisConfig)]
pub struct GenesisConfig<T: Config> {
pub initial_account: Option<T::AccountId>,
}
#[pallet::genesis_build]
#[docify::export(pallet_bar_build)]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
/// The storage building function that presents a direct mapping of the initial config
/// values to the storage items.
fn build(&self) {
InitialAccount::<T>::set(self.initial_account.clone());
}
}
}
/// The sample structure used in `GenesisConfig`.
///
/// This structure does not deny unknown fields. This may lead to some problems.
#[derive(Default, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FooStruct {
pub field_a: u8,
pub field_b: u8,
}
/// The sample structure used in `GenesisConfig`.
///
/// This structure does not deny unknown fields. This may lead to some problems.
#[derive(Default, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct SomeFooData1 {
pub a: u8,
pub b: u8,
}
/// Another sample structure used in `GenesisConfig`.
///
/// The user defined serialization is used.
#[derive(Default, serde::Serialize, serde::Deserialize)]
#[docify::export]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct SomeFooData2 {
#[serde(default, with = "sp_core::bytes")]
pub values: Vec<u8>,
}
/// Sample enum used in `GenesisConfig`.
#[derive(Default, serde::Serialize, serde::Deserialize)]
pub enum FooEnum {
#[default]
Data0,
Data1(SomeFooData1),
Data2(SomeFooData2),
}
#[docify::export]
#[frame::pallet(dev_mode)]
pub mod pallet_foo {
use super::*;
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::storage]
pub type ProcessedEnumValue<T> = StorageValue<Value = u64>;
#[pallet::storage]
pub type SomeInteger<T> = StorageValue<Value = u32>;
/// The more sophisticated structure for conveying initial state.
#[docify::export(pallet_foo_GenesisConfig)]
#[pallet::genesis_config]
#[derive(DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
pub some_integer: u32,
pub some_enum: FooEnum,
pub some_struct: FooStruct,
#[serde(skip)]
pub _phantom: PhantomData<T>,
}
#[pallet::genesis_build]
#[docify::export(pallet_foo_build)]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
/// The build method that indirectly maps an initial config values into the storage items.
fn build(&self) {
let processed_value: u64 = match &self.some_enum {
FooEnum::Data0 => 0,
FooEnum::Data1(v) => (v.a + v.b).into(),
FooEnum::Data2(v) => v.values.iter().map(|v| *v as u64).sum(),
};
ProcessedEnumValue::<T>::set(Some(processed_value));
SomeInteger::<T>::set(Some(self.some_integer));
}
}
}
@@ -0,0 +1,164 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Presets for the chain-spec demo runtime.
use crate::{
pallets::{FooEnum, SomeFooData1, SomeFooData2},
runtime::{BarConfig, FooConfig, RuntimeGenesisConfig},
};
use alloc::vec;
use frame_support::build_struct_json_patch;
use serde_json::{json, to_string, Value};
use sp_application_crypto::Ss58Codec;
use sp_keyring::Sr25519Keyring;
/// A demo preset with strings only.
pub const PRESET_1: &str = "preset_1";
/// A demo preset with real types.
pub const PRESET_2: &str = "preset_2";
/// Another demo preset with real types and manually created json object.
pub const PRESET_3: &str = "preset_3";
/// A single value patch preset.
pub const PRESET_4: &str = "preset_4";
/// A single value patch preset.
pub const PRESET_INVALID: &str = "preset_invalid";
#[docify::export]
/// Function provides a preset demonstrating how use string representation of preset's internal
/// values.
fn preset_1() -> Value {
json!({
"bar": {
"initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
},
"foo": {
"someEnum": {
"Data2": {
"values": "0x0c0f"
}
},
"someStruct" : {
"fieldA": 10,
"fieldB": 20
},
"someInteger": 100
},
})
}
#[docify::export]
/// Function provides a preset demonstrating how to create a preset using
/// [`build_struct_json_patch`] macro.
fn preset_2() -> Value {
build_struct_json_patch!(RuntimeGenesisConfig {
foo: FooConfig {
some_integer: 200,
some_enum: FooEnum::Data2(SomeFooData2 { values: vec![0x0c, 0x10] })
},
bar: BarConfig { initial_account: Some(Sr25519Keyring::Ferdie.public().into()) },
})
}
#[docify::export]
/// Function provides a preset demonstrating how use the actual types to manually create a JSON
/// representing the preset.
fn preset_3() -> Value {
json!({
"bar": {
"initialAccount": Sr25519Keyring::Alice.public().to_ss58check(),
},
"foo": {
"someEnum": FooEnum::Data1(
SomeFooData1 {
a: 12,
b: 16
}
),
"someInteger": 300
},
})
}
#[docify::export]
/// Function provides a minimal preset demonstrating how to patch single key in
/// `RuntimeGenesisConfig` using [`build_struct_json_patch`] macro.
pub fn preset_4() -> Value {
build_struct_json_patch!(RuntimeGenesisConfig {
foo: FooConfig { some_enum: FooEnum::Data2(SomeFooData2 { values: vec![0x0c, 0x10] }) },
})
}
#[docify::export]
/// Function provides an invalid preset demonstrating how important is use of
/// `deny_unknown_fields` in data structures used in `GenesisConfig`.
fn preset_invalid() -> Value {
json!({
"foo": {
"someStruct": {
"fieldC": 5
},
},
})
}
/// Provides a JSON representation of preset identified by given `id`.
///
/// If no preset with given `id` exits `None` is returned.
#[docify::export]
pub fn get_builtin_preset(id: &sp_genesis_builder::PresetId) -> Option<alloc::vec::Vec<u8>> {
let preset = match id.as_ref() {
PRESET_1 => preset_1(),
PRESET_2 => preset_2(),
PRESET_3 => preset_3(),
PRESET_4 => preset_4(),
PRESET_INVALID => preset_invalid(),
_ => return None,
};
Some(
to_string(&preset)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
#[test]
#[docify::export]
fn check_presets() {
let builder = sc_chain_spec::GenesisConfigBuilderRuntimeCaller::<()>::new(
crate::WASM_BINARY.expect("wasm binary shall exists"),
);
assert!(builder.get_storage_for_named_preset(Some(&PRESET_1.to_string())).is_ok());
assert!(builder.get_storage_for_named_preset(Some(&PRESET_2.to_string())).is_ok());
assert!(builder.get_storage_for_named_preset(Some(&PRESET_3.to_string())).is_ok());
assert!(builder.get_storage_for_named_preset(Some(&PRESET_4.to_string())).is_ok());
}
#[test]
#[docify::export]
fn invalid_preset_works() {
let builder = sc_chain_spec::GenesisConfigBuilderRuntimeCaller::<()>::new(
crate::WASM_BINARY.expect("wasm binary shall exists"),
);
// Even though a preset contains invalid_key, conversion to raw storage does not fail. This is
// because the [`FooStruct`] structure is not annotated with `deny_unknown_fields` [`serde`]
// attribute.
// This may lead to hard to debug problems, that's why using ['deny_unknown_fields'] is
// recommended.
assert!(builder.get_storage_for_named_preset(Some(&PRESET_INVALID.to_string())).is_ok());
}
@@ -0,0 +1,127 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A minimal runtime that shows runtime genesis state.
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use crate::{
pallets::{pallet_bar, pallet_foo},
presets::*,
};
use alloc::{vec, vec::Vec};
use frame::{
deps::frame_support::{
genesis_builder_helper::{build_state, get_preset},
runtime,
},
prelude::*,
runtime::{apis, prelude::*},
};
use sp_genesis_builder::PresetId;
/// The runtime version.
#[runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"),
impl_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"),
authoring_version: 1,
spec_version: 0,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
system_version: 1,
};
/// The signed extensions that are added to the runtime.
type SignedExtra = ();
// Composes the runtime by adding all the used pallets and deriving necessary types.
#[runtime]
mod runtime {
/// The main runtime type.
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Runtime;
/// Mandatory system pallet that should always be included in a FRAME runtime.
#[runtime::pallet_index(0)]
pub type System = frame_system;
/// Sample pallet 1
#[runtime::pallet_index(1)]
pub type Bar = pallet_bar;
/// Sample pallet 2
#[runtime::pallet_index(2)]
pub type Foo = pallet_foo;
}
parameter_types! {
pub const Version: RuntimeVersion = VERSION;
}
/// Implements the types required for the system pallet.
#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
impl frame_system::Config for Runtime {
type Block = Block;
type Version = Version;
}
impl pallet_bar::Config for Runtime {}
impl pallet_foo::Config for Runtime {}
type Block = frame::runtime::types_common::BlockOf<Runtime, SignedExtra>;
type Header = HeaderFor<Runtime>;
#[docify::export(runtime_impl)]
impl_runtime_apis! {
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
build_state::<RuntimeGenesisConfig>(config)
}
fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
get_preset::<RuntimeGenesisConfig>(id, get_builtin_preset)
}
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
vec![
PresetId::from(PRESET_1),
PresetId::from(PRESET_2),
PresetId::from(PRESET_3),
PresetId::from(PRESET_4),
PresetId::from(PRESET_INVALID)
]
}
}
impl apis::Core<Block> for Runtime {
fn version() -> RuntimeVersion { VERSION }
fn execute_block(_: <Block as frame::traits::Block>::LazyBlock) { }
fn initialize_block(_: &Header) -> ExtrinsicInclusionMode { ExtrinsicInclusionMode::default() }
}
}
@@ -0,0 +1,203 @@
use cmd_lib::*;
use serde_json::{json, Value};
use std::str;
fn wasm_file_path() -> &'static str {
chain_spec_guide_runtime::runtime::WASM_BINARY_PATH
.expect("chain_spec_guide_runtime wasm should exist. qed")
}
const CHAIN_SPEC_BUILDER_PATH: &str = "../../../../../target/release/chain-spec-builder";
macro_rules! bash(
( chain-spec-builder $($a:tt)* ) => {{
let path = get_chain_spec_builder_path();
spawn_with_output!(
$path $($a)*
)
.expect("a process running. qed")
.wait_with_output()
.expect("to get output. qed.")
}}
);
fn get_chain_spec_builder_path() -> &'static str {
run_cmd!(
cargo build --release -p staging-chain-spec-builder --bin chain-spec-builder
)
.expect("Failed to execute command");
CHAIN_SPEC_BUILDER_PATH
}
#[docify::export_content]
fn cmd_list_presets(runtime_path: &str) -> String {
bash!(
chain-spec-builder list-presets -r $runtime_path
)
}
#[test]
fn list_presets() {
let output: serde_json::Value =
serde_json::from_slice(cmd_list_presets(wasm_file_path()).as_bytes()).unwrap();
assert_eq!(
output,
json!({
"presets":[
"preset_1",
"preset_2",
"preset_3",
"preset_4",
"preset_invalid"
]
}),
"Output did not match expected"
);
}
#[docify::export_content]
fn cmd_get_preset(runtime_path: &str) -> String {
bash!(
chain-spec-builder display-preset -r $runtime_path -p preset_2
)
}
#[test]
fn get_preset() {
let output: serde_json::Value =
serde_json::from_slice(cmd_get_preset(wasm_file_path()).as_bytes()).unwrap();
assert_eq!(
output,
json!({
"bar": {
"initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
},
"foo": {
"someEnum": {
"Data2": {
"values": "0x0c10"
}
},
"someInteger": 200
},
}),
"Output did not match expected"
);
}
#[docify::export_content]
fn cmd_generate_chain_spec(runtime_path: &str) -> String {
bash!(
chain-spec-builder -c /dev/stdout create -r $runtime_path named-preset preset_2
)
}
#[test]
fn generate_chain_spec() {
let mut output: serde_json::Value =
serde_json::from_slice(cmd_generate_chain_spec(wasm_file_path()).as_bytes()).unwrap();
if let Some(code) = output["genesis"]["runtimeGenesis"].as_object_mut().unwrap().get_mut("code")
{
*code = Value::String("0x123".to_string());
}
assert_eq!(
output,
json!({
"name": "Custom",
"id": "custom",
"chainType": "Live",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" },
"codeSubstitutes": {},
"genesis": {
"runtimeGenesis": {
"code": "0x123",
"patch": {
"bar": {
"initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
},
"foo": {
"someEnum": {
"Data2": {
"values": "0x0c10"
}
},
"someInteger": 200
}
}
}
}
}),
"Output did not match expected"
);
}
#[docify::export_content]
fn cmd_generate_para_chain_spec(runtime_path: &str) -> String {
bash!(
chain-spec-builder -c /dev/stdout create -c pezkuwi -p 1000 -r $runtime_path named-preset preset_2
)
}
#[test]
fn generate_para_chain_spec() {
let mut output: serde_json::Value =
serde_json::from_slice(cmd_generate_para_chain_spec(wasm_file_path()).as_bytes()).unwrap();
if let Some(code) = output["genesis"]["runtimeGenesis"].as_object_mut().unwrap().get_mut("code")
{
*code = Value::String("0x123".to_string());
}
assert_eq!(
output,
json!({
"name": "Custom",
"id": "custom",
"chainType": "Live",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"relay_chain": "pezkuwi",
"para_id": 1000,
"properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" },
"codeSubstitutes": {},
"genesis": {
"runtimeGenesis": {
"code": "0x123",
"patch": {
"bar": {
"initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
},
"foo": {
"someEnum": {
"Data2": {
"values": "0x0c10"
}
},
"someInteger": 200
}
}
}
}}),
"Output did not match expected"
);
}
#[test]
#[docify::export_content]
fn preset_4_json() {
assert_eq!(
chain_spec_guide_runtime::presets::preset_4(),
json!({
"foo": {
"someEnum": {
"Data2": {
"values": "0x0c10"
}
},
},
})
);
}