feat: Rebrand Polkadot/Substrate references to PezkuwiChain

This commit systematically rebrands various references from Parity Technologies'
Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk.

Key changes include:
- Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks.
- Modified internal documentation and code comments to reflect PezkuwiChain naming and structure.
- Replaced direct references to  with  or specific paths within the  for XCM, Pezkuwi, and other modules.
- Cleaned up deprecated  issue and PR references in various  and  files, particularly in  and  modules.
- Adjusted image and logo URLs in documentation to point to PezkuwiChain assets.
- Removed or rephrased comments related to external Polkadot/Substrate PRs and issues.

This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
2025-12-14 00:04:10 +03:00
parent 286de54384
commit 1c0e57d984
9084 changed files with 997839 additions and 997557 deletions
+61
View File
@@ -0,0 +1,61 @@
[package]
name = "pezsc-chain-spec"
version = "28.0.0"
authors.workspace = true
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage.workspace = true
repository.workspace = true
description = "Bizinikiwi chain configurations."
readme = "README.md"
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
array-bytes = { workspace = true, default-features = true }
clap = { features = ["derive"], optional = true, workspace = true }
codec = { features = ["derive"], workspace = true }
docify = { workspace = true }
memmap2 = { workspace = true }
pezsc-chain-spec-derive = { workspace = true, default-features = true }
pezsc-client-api = { workspace = true, default-features = true }
pezsc-executor = { workspace = true, default-features = true }
pezsc-network = { workspace = true, default-features = true }
pezsc-telemetry = { workspace = true, default-features = true }
serde = { features = ["derive"], workspace = true, default-features = true }
serde_json = { workspace = true, default-features = true }
pezsp-blockchain = { workspace = true, default-features = true }
pezsp-core = { workspace = true, default-features = true }
pezsp-crypto-hashing = { workspace = true, default-features = true }
pezsp-genesis-builder = { workspace = true, default-features = true }
pezsp-io = { workspace = true }
pezsp-runtime = { workspace = true, default-features = true }
pezsp-state-machine = { workspace = true, default-features = true }
pezsp-tracing = { workspace = true, default-features = true }
[dev-dependencies]
pretty_assertions = { workspace = true }
regex = { workspace = true }
pezsp-application-crypto = { features = ["serde"], workspace = true }
pezsp-consensus-babe = { features = ["serde"], workspace = true }
pezsp-keyring = { workspace = true, default-features = true }
bizinikiwi-test-runtime = { workspace = true }
[features]
runtime-benchmarks = [
"pezsc-client-api/runtime-benchmarks",
"pezsc-executor/runtime-benchmarks",
"pezsc-network/runtime-benchmarks",
"pezsp-blockchain/runtime-benchmarks",
"pezsp-consensus-babe/runtime-benchmarks",
"pezsp-genesis-builder/runtime-benchmarks",
"pezsp-io/runtime-benchmarks",
"pezsp-keyring/runtime-benchmarks",
"pezsp-runtime/runtime-benchmarks",
"pezsp-state-machine/runtime-benchmarks",
"bizinikiwi-test-runtime/runtime-benchmarks",
]
+6
View File
@@ -0,0 +1,6 @@
Bizinikiwi chain configurations.
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,24 @@
[package]
name = "pezsc-chain-spec-derive"
version = "11.0.0"
authors.workspace = true
edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage.workspace = true
repository.workspace = true
description = "Macros to derive chain spec extension traits implementation."
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[lib]
proc-macro = true
[dependencies]
proc-macro-crate = { workspace = true }
proc-macro2 = { workspace = true }
quote = { workspace = true }
syn = { workspace = true }
@@ -0,0 +1,225 @@
// This file is part of Bizinikiwi.
// 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/>.
use proc_macro2::{Span, TokenStream};
use proc_macro_crate::{crate_name, FoundCrate};
use quote::quote;
use syn::{DeriveInput, Error, Ident, Path};
const CRATE_NAME: &str = "sc-chain-spec";
const ATTRIBUTE_NAME: &str = "forks";
/// Implements `Extension's` `Group` accessor.
///
/// The struct that derives this implementation will be usable within the `ChainSpec` file.
/// The derive implements a by-type accessor method.
pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
derive(ast, |crate_name, name, generics: &syn::Generics, field_names, field_types, fields| {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let forks = fields
.named
.iter()
.find_map(|f| {
if f.attrs.iter().any(|attr| attr.path().is_ident(ATTRIBUTE_NAME)) {
let typ = &f.ty;
Some(quote! { #typ })
} else {
None
}
})
.unwrap_or_else(|| quote! { #crate_name::NoExtension });
quote! {
impl #impl_generics #crate_name::Extension for #name #ty_generics #where_clause {
type Forks = #forks;
fn get<T: 'static>(&self) -> Option<&T> {
use std::any::{Any, TypeId};
match TypeId::of::<T>() {
#( x if x == TypeId::of::<#field_types>() => <dyn Any>::downcast_ref(&self.#field_names) ),*,
_ => None,
}
}
fn get_any(&self, t: std::any::TypeId) -> &dyn std::any::Any {
use std::any::{Any, TypeId};
match t {
#( x if x == TypeId::of::<#field_types>() => &self.#field_names ),*,
_ => self,
}
}
fn get_any_mut(&mut self, t: std::any::TypeId) -> &mut dyn std::any::Any {
use std::any::{Any, TypeId};
match t {
#( x if x == TypeId::of::<#field_types>() => &mut self.#field_names ),*,
_ => self,
}
}
}
}
})
}
/// Implements required traits and creates `Fork` structs for `ChainSpec` custom parameter group.
pub fn group_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
derive(ast, |crate_name, name, generics: &syn::Generics, field_names, field_types, _fields| {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let fork_name = Ident::new(&format!("{}Fork", name), Span::call_site());
let fork_fields = generate_fork_fields(crate_name, &field_names, &field_types);
let to_fork = generate_base_to_fork(&fork_name, &field_names);
let combine_with = generate_combine_with(&field_names);
let to_base = generate_fork_to_base(name, &field_names);
let serde_crate_name = match proc_macro_crate::crate_name("serde") {
Ok(FoundCrate::Itself) => Ident::new("serde", Span::call_site()),
Ok(FoundCrate::Name(name)) => Ident::new(&name, Span::call_site()),
Err(e) => {
let err =
Error::new(Span::call_site(), &format!("Could not find `serde` crate: {}", e))
.to_compile_error();
return quote!( #err );
},
};
quote! {
#[derive(
Debug,
Clone,
PartialEq,
#serde_crate_name::Serialize,
#serde_crate_name::Deserialize,
ChainSpecExtension,
)]
pub struct #fork_name #ty_generics #where_clause {
#fork_fields
}
impl #impl_generics #crate_name::Group for #name #ty_generics #where_clause {
type Fork = #fork_name #ty_generics;
fn to_fork(self) -> Self::Fork {
use #crate_name::Group;
#to_fork
}
}
impl #impl_generics #crate_name::Fork for #fork_name #ty_generics #where_clause {
type Base = #name #ty_generics;
fn combine_with(&mut self, other: Self) {
use #crate_name::Fork;
#combine_with
}
fn to_base(self) -> Option<Self::Base> {
use #crate_name::Fork;
#to_base
}
}
}
})
}
pub fn derive(
ast: &DeriveInput,
derive: impl Fn(
&Path,
&Ident,
&syn::Generics,
Vec<&Ident>,
Vec<&syn::Type>,
&syn::FieldsNamed,
) -> TokenStream,
) -> proc_macro::TokenStream {
let err = || {
let err = Error::new(
Span::call_site(),
"ChainSpecGroup is only available for structs with named fields.",
)
.to_compile_error();
quote!( #err ).into()
};
let data = match &ast.data {
syn::Data::Struct(ref data) => data,
_ => return err(),
};
let fields = match &data.fields {
syn::Fields::Named(ref named) => named,
_ => return err(),
};
let name = &ast.ident;
let crate_path = match crate_name(CRATE_NAME) {
Ok(FoundCrate::Itself) => CRATE_NAME.replace("-", "_"),
Ok(FoundCrate::Name(chain_spec_name)) => chain_spec_name,
Err(e) => match crate_name("pezkuwi-sdk") {
Ok(FoundCrate::Name(sdk)) => format!("{sdk}::{CRATE_NAME}").replace("-", "_"),
_ => {
return Error::new(Span::call_site(), &e).to_compile_error().into();
},
},
};
let crate_path =
syn::parse_str::<Path>(&crate_path).expect("crate_name returns valid path; qed");
let field_names = fields.named.iter().flat_map(|x| x.ident.as_ref()).collect::<Vec<_>>();
let field_types = fields.named.iter().map(|x| &x.ty).collect::<Vec<_>>();
derive(&crate_path, name, &ast.generics, field_names, field_types, fields).into()
}
fn generate_fork_fields(crate_path: &Path, names: &[&Ident], types: &[&syn::Type]) -> TokenStream {
let crate_path = std::iter::repeat(crate_path);
quote! {
#( pub #names: Option<<#types as #crate_path::Group>::Fork>, )*
}
}
fn generate_base_to_fork(fork_name: &Ident, names: &[&Ident]) -> TokenStream {
let names2 = names.to_vec();
quote! {
#fork_name {
#( #names: Some(self.#names2.to_fork()), )*
}
}
}
fn generate_combine_with(names: &[&Ident]) -> TokenStream {
let names2 = names.to_vec();
quote! {
#( self.#names.combine_with(other.#names2); )*
}
}
fn generate_fork_to_base(fork: &Ident, names: &[&Ident]) -> TokenStream {
let names2 = names.to_vec();
quote! {
Some(#fork {
#( #names: self.#names2?.to_base()?, )*
})
}
}
@@ -0,0 +1,39 @@
// This file is part of Bizinikiwi.
// 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/>.
//! Macros to derive chain spec extension traits implementation.
mod impls;
use proc_macro::TokenStream;
#[proc_macro_derive(ChainSpecGroup)]
pub fn group_derive(input: TokenStream) -> TokenStream {
match syn::parse(input) {
Ok(ast) => impls::group_derive(&ast),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro_derive(ChainSpecExtension, attributes(forks))]
pub fn extensions_derive(input: TokenStream) -> TokenStream {
match syn::parse(input) {
Ok(ast) => impls::extension_derive(&ast),
Err(e) => e.to_compile_error().into(),
}
}
@@ -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
]
]
},
"bizinikiwiTest": {
"authorities": [
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y"
]
},
"system": {}
},
"code": "0x0"
}
}
}
@@ -0,0 +1,54 @@
{
"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",
"0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000"
},
"childrenDefault": {}
}
}
}
@@ -0,0 +1,35 @@
{
"name": "TestName",
"id": "test_id",
"chainType": "Local",
"bootNodes": [],
"telemetryEndpoints": null,
"protocolId": null,
"properties": null,
"codeSubstitutes": {},
"genesis": {
"runtimeGenesis": {
"patch": {
"balances": {
"balances": [
[
"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
1000000000000000
],
[
"5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",
1000000000000000
]
]
},
"bizinikiwiTest": {
"authorities": [
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"
]
}
},
"code": "0x0"
}
}
}
@@ -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
]
}
},
"bizinikiwiTest": {
"authorities": [
"5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL",
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
]
}
},
"code": "0x0"
}
}
}
@@ -0,0 +1,33 @@
{
"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",
"0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000"
},
"childrenDefault": {}
}
}
}
@@ -0,0 +1,30 @@
{
"name": "Flaming Fir",
"id": "flaming-fir",
"properties": {
"tokenDecimals": 15,
"tokenSymbol": "FIR"
},
"bootNodes": [
"/ip4/35.246.224.91/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV",
"/ip4/35.246.224.91/tcp/30334/ws/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV",
"/ip4/35.246.210.11/tcp/30333/p2p/QmWv9Ww7znzgLFyCzf21SR6tUKXrmHCZH9KhebeH4gyE9f",
"/ip4/35.246.210.11/tcp/30334/ws/p2p/QmWv9Ww7znzgLFyCzf21SR6tUKXrmHCZH9KhebeH4gyE9f",
"/ip4/35.198.110.45/tcp/30333/p2p/QmTtcYKJho9vFmqtMA548QBSmLbmwAkBSiEKK3kWKfb6bJ",
"/ip4/35.198.110.45/tcp/30334/ws/p2p/QmTtcYKJho9vFmqtMA548QBSmLbmwAkBSiEKK3kWKfb6bJ",
"/ip4/35.198.114.154/tcp/30333/p2p/QmQJmDorK9c8KjMF5PdWiH2WGUXyzJtgTeJ55S5gggdju6",
"/ip4/35.198.114.154/tcp/30334/ws/p2p/QmQJmDorK9c8KjMF5PdWiH2WGUXyzJtgTeJ55S5gggdju6"
],
"telemetryEndpoints": [
["wss://telemetry.pezkuwichain.io/submit/", 0]
],
"protocolId": "fir",
"genesis": {
"raw": [
{
"0xb2029f8665aac509629f2d28cea790a3": "0x10f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c26633919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f437800299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d655633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde787932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d129becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe96993326e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f91066e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"
},
{}
]
}
}
@@ -0,0 +1,31 @@
{
"name": "Flaming Fir",
"id": "flaming-fir",
"properties": {
"tokenDecimals": 15,
"tokenSymbol": "FIR"
},
"bootNodes": [
"/ip4/35.246.224.91/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV",
"/ip4/35.246.224.91/tcp/30334/ws/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV",
"/ip4/35.246.210.11/tcp/30333/p2p/QmWv9Ww7znzgLFyCzf21SR6tUKXrmHCZH9KhebeH4gyE9f",
"/ip4/35.246.210.11/tcp/30334/ws/p2p/QmWv9Ww7znzgLFyCzf21SR6tUKXrmHCZH9KhebeH4gyE9f",
"/ip4/35.198.110.45/tcp/30333/p2p/QmTtcYKJho9vFmqtMA548QBSmLbmwAkBSiEKK3kWKfb6bJ",
"/ip4/35.198.110.45/tcp/30334/ws/p2p/QmTtcYKJho9vFmqtMA548QBSmLbmwAkBSiEKK3kWKfb6bJ",
"/ip4/35.198.114.154/tcp/30333/p2p/QmQJmDorK9c8KjMF5PdWiH2WGUXyzJtgTeJ55S5gggdju6",
"/ip4/35.198.114.154/tcp/30334/ws/p2p/QmQJmDorK9c8KjMF5PdWiH2WGUXyzJtgTeJ55S5gggdju6"
],
"telemetryEndpoints": [
["wss://telemetry.pezkuwichain.io/submit/", 0]
],
"protocolId": "fir",
"myProperty": "Test Extension",
"genesis": {
"raw": [
{
"0xb2029f8665aac509629f2d28cea790a3": "0x10f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c26633919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f437800299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d655633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde787932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d129becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe96993326e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f91066e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"
},
{}
]
}
}
@@ -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"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,433 @@
// This file is part of Bizinikiwi.
// 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/>.
//! Chain Spec extensions helpers.
use std::{
any::{Any, TypeId},
fmt::Debug,
};
use std::collections::BTreeMap;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
/// A `ChainSpec` extension.
///
/// This trait is implemented automatically by `ChainSpecGroup` macro.
pub trait Group: Clone + Sized {
/// An associated type containing fork definition.
type Fork: Fork<Base = Self>;
/// Convert to fork type.
fn to_fork(self) -> Self::Fork;
}
/// A `ChainSpec` extension fork definition.
///
/// Basically should look the same as `Group`, but
/// all parameters are optional. This allows changing
/// only one parameter as part of the fork.
/// The forks can be combined (summed up) to specify
/// a complete set of parameters
pub trait Fork: Serialize + DeserializeOwned + Clone + Sized {
/// A base `Group` type.
type Base: Group<Fork = Self>;
/// Combine with another struct.
///
/// All parameters set in `other` should override the
/// ones in the current struct.
fn combine_with(&mut self, other: Self);
/// Attempt to convert to the base type if all parameters are set.
fn to_base(self) -> Option<Self::Base>;
}
macro_rules! impl_trivial {
() => {};
($A : ty) => {
impl_trivial!($A ,);
};
($A : ty , $( $B : ty ),*) => {
impl_trivial!($( $B ),*);
impl Group for $A {
type Fork = $A;
fn to_fork(self) -> Self::Fork {
self
}
}
impl Fork for $A {
type Base = $A;
fn combine_with(&mut self, other: Self) {
*self = other;
}
fn to_base(self) -> Option<Self::Base> {
Some(self)
}
}
}
}
impl_trivial!((), u8, u16, u32, u64, usize, String, Vec<u8>);
impl<T: Group> Group for Option<T> {
type Fork = Option<T::Fork>;
fn to_fork(self) -> Self::Fork {
self.map(|a| a.to_fork())
}
}
impl<T: Fork> Fork for Option<T> {
type Base = Option<T::Base>;
fn combine_with(&mut self, other: Self) {
*self = match (self.take(), other) {
(Some(mut a), Some(b)) => {
a.combine_with(b);
Some(a)
},
(a, b) => a.or(b),
};
}
fn to_base(self) -> Option<Self::Base> {
self.map(|x| x.to_base())
}
}
/// A collection of `ChainSpec` extensions.
///
/// This type can be passed around and allows the core
/// modules to request a strongly-typed, but optional configuration.
pub trait Extension: Serialize + DeserializeOwned + Clone {
type Forks: IsForks;
/// Get an extension of specific type.
fn get<T: 'static>(&self) -> Option<&T>;
/// Get an extension of specific type as reference to `Any`.
fn get_any(&self, t: TypeId) -> &dyn Any;
/// Get an extension of specific type as mutable reference to `Any`.
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any;
/// Get forkable extensions of specific type.
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
where
BlockNumber: Ord + Clone + 'static,
T: Group + 'static,
<Self::Forks as IsForks>::Extension: Extension,
<<Self::Forks as IsForks>::Extension as Group>::Fork: Extension,
{
self.get::<Forks<BlockNumber, <Self::Forks as IsForks>::Extension>>()?
.for_type()
}
}
impl Extension for crate::NoExtension {
type Forks = Self;
fn get<T: 'static>(&self) -> Option<&T> {
None
}
fn get_any(&self, _t: TypeId) -> &dyn Any {
self
}
fn get_any_mut(&mut self, _: TypeId) -> &mut dyn Any {
self
}
}
pub trait IsForks {
type BlockNumber: Ord + 'static;
type Extension: Group + 'static;
}
impl IsForks for Option<()> {
type BlockNumber = u64;
type Extension = Self;
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Forks<BlockNumber: Ord, T: Group> {
forks: BTreeMap<BlockNumber, T::Fork>,
#[serde(flatten)]
base: T,
}
impl<B: Ord, T: Group + Default> Default for Forks<B, T> {
fn default() -> Self {
Self { base: Default::default(), forks: Default::default() }
}
}
impl<B: Ord, T: Group> Forks<B, T>
where
T::Fork: Debug,
{
/// Create new fork definition given the base and the forks.
pub fn new(base: T, forks: BTreeMap<B, T::Fork>) -> Self {
Self { base, forks }
}
/// Return a set of parameters for `Group` including all forks up to `block` (inclusive).
pub fn at_block(&self, block: B) -> T {
let mut start = self.base.clone().to_fork();
for (_, fork) in self.forks.range(..=block) {
start.combine_with(fork.clone());
}
start
.to_base()
.expect("We start from the `base` object, so it's always fully initialized; qed")
}
}
impl<B, T> IsForks for Forks<B, T>
where
B: Ord + 'static,
T: Group + 'static,
{
type BlockNumber = B;
type Extension = T;
}
impl<B: Ord + Clone, T: Group + Extension> Forks<B, T>
where
T::Fork: Extension,
{
/// Get forks definition for a subset of this extension.
///
/// Returns the `Forks` struct, but limited to a particular type
/// within the extension.
pub fn for_type<X>(&self) -> Option<Forks<B, X>>
where
X: Group + 'static,
{
let base = self.base.get::<X>()?.clone();
let forks = self
.forks
.iter()
.filter_map(|(k, v)| Some((k.clone(), v.get::<Option<X::Fork>>()?.clone()?)))
.collect();
Some(Forks { base, forks })
}
}
impl<B, E> Extension for Forks<B, E>
where
B: Serialize + DeserializeOwned + Ord + Clone + 'static,
E: Extension + Group + 'static,
{
type Forks = Self;
fn get<T: 'static>(&self) -> Option<&T> {
if TypeId::of::<T>() == TypeId::of::<E>() {
<dyn Any>::downcast_ref(&self.base)
} else {
self.base.get()
}
}
fn get_any(&self, t: TypeId) -> &dyn Any {
if t == TypeId::of::<E>() {
&self.base
} else {
self.base.get_any(t)
}
}
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any {
if t == TypeId::of::<E>() {
&mut self.base
} else {
self.base.get_any_mut(t)
}
}
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
where
BlockNumber: Ord + Clone + 'static,
T: Group + 'static,
<Self::Forks as IsForks>::Extension: Extension,
<<Self::Forks as IsForks>::Extension as Group>::Fork: Extension,
{
if TypeId::of::<BlockNumber>() == TypeId::of::<B>() {
<dyn Any>::downcast_ref(&self.for_type::<T>()?).cloned()
} else {
self.get::<Forks<BlockNumber, <Self::Forks as IsForks>::Extension>>()?
.for_type()
}
}
}
/// A subset of the `Extension` trait that only allows for querying extensions.
pub trait GetExtension {
/// Get an extension of specific type.
fn get_any(&self, t: TypeId) -> &dyn Any;
/// Get an extension of specific type with mutable access.
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any;
}
impl<E: Extension> GetExtension for E {
fn get_any(&self, t: TypeId) -> &dyn Any {
Extension::get_any(self, t)
}
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any {
Extension::get_any_mut(self, t)
}
}
/// Helper function that queries an extension by type from `GetExtension` trait object.
pub fn get_extension<T: 'static>(e: &dyn GetExtension) -> Option<&T> {
<dyn Any>::downcast_ref(GetExtension::get_any(e, TypeId::of::<T>()))
}
/// Helper function that queries an extension by type from `GetExtension` trait object.
pub fn get_extension_mut<T: 'static>(e: &mut dyn GetExtension) -> Option<&mut T> {
<dyn Any>::downcast_mut(GetExtension::get_any_mut(e, TypeId::of::<T>()))
}
#[cfg(test)]
mod tests {
use super::*;
use pezsc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
// Make the proc macro work for tests and doc tests.
use crate as pezsc_chain_spec;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup)]
#[serde(deny_unknown_fields)]
pub struct Extension1 {
pub test: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup)]
#[serde(deny_unknown_fields)]
pub struct Extension2 {
pub test: u8,
}
#[derive(
Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension,
)]
#[serde(deny_unknown_fields)]
pub struct Extensions {
pub ext1: Extension1,
pub ext2: Extension2,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecExtension)]
#[serde(deny_unknown_fields)]
pub struct Ext2 {
#[serde(flatten)]
ext1: Extension1,
#[forks]
forkable: Forks<u64, Extensions>,
}
#[test]
fn forks_should_work_correctly() {
use super::Extension as _;
// We first need to deserialize into a `Value` because of the following bug:
// https://github.com/serde-rs/json/issues/505
let ext_val: serde_json::Value = serde_json::from_str(
r#"
{
"test": 11,
"forkable": {
"ext1": {
"test": 15
},
"ext2": {
"test": 123
},
"forks": {
"1": {
"ext1": { "test": 5 }
},
"2": {
"ext2": { "test": 5 }
},
"5": {
"ext2": { "test": 1 }
}
}
}
}
"#,
)
.unwrap();
let ext: Ext2 = serde_json::from_value(ext_val).unwrap();
assert_eq!(ext.get::<Extension1>(), Some(&Extension1 { test: 11 }));
// get forks definition
let forks = ext.get::<Forks<u64, Extensions>>().unwrap();
assert_eq!(
forks.at_block(0),
Extensions { ext1: Extension1 { test: 15 }, ext2: Extension2 { test: 123 } }
);
assert_eq!(
forks.at_block(1),
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 123 } }
);
assert_eq!(
forks.at_block(2),
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
);
assert_eq!(
forks.at_block(4),
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 5 } }
);
assert_eq!(
forks.at_block(5),
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
);
assert_eq!(
forks.at_block(10),
Extensions { ext1: Extension1 { test: 5 }, ext2: Extension2 { test: 1 } }
);
assert!(forks.at_block(10).get::<Extension2>().is_some());
// filter forks for `Extension2`
let ext2 = forks.for_type::<Extension2>().unwrap();
assert_eq!(ext2.at_block(0), Extension2 { test: 123 });
assert_eq!(ext2.at_block(2), Extension2 { test: 5 });
assert_eq!(ext2.at_block(10), Extension2 { test: 1 });
// make sure that it can return forks correctly
let ext2_2 = forks.forks::<u64, Extension2>().unwrap();
assert_eq!(ext2, ext2_2);
// also ext should be able to return forks correctly:
let ext2_3 = ext.forks::<u64, Extension2>().unwrap();
assert_eq!(ext2_2, ext2_3);
}
}
@@ -0,0 +1,148 @@
// This file is part of Bizinikiwi.
// 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/>.
//! Tool for creating the genesis block.
use std::{marker::PhantomData, sync::Arc};
use codec::Encode;
use pezsc_client_api::{backend::Backend, BlockImportOperation};
use pezsc_executor::RuntimeVersionOf;
use pezsp_core::storage::{well_known_keys, StateVersion, Storage};
use pezsp_runtime::{
traits::{Block as BlockT, Hash as HashT, HashingFor, Header as HeaderT, Zero},
BuildStorage,
};
/// Return the state version given the genesis storage and executor.
pub fn resolve_state_version_from_wasm<E, H>(
storage: &Storage,
executor: &E,
) -> pezsp_blockchain::Result<StateVersion>
where
E: RuntimeVersionOf,
H: HashT,
{
if let Some(wasm) = storage.top.get(well_known_keys::CODE) {
let mut ext = pezsp_state_machine::BasicExternalities::new_empty(); // just to read runtime version.
let code_fetcher = pezsp_core::traits::WrappedRuntimeCode(wasm.as_slice().into());
let runtime_code = pezsp_core::traits::RuntimeCode {
code_fetcher: &code_fetcher,
heap_pages: None,
hash: <H as HashT>::hash(wasm).encode(),
};
let runtime_version = RuntimeVersionOf::runtime_version(executor, &mut ext, &runtime_code)
.map_err(|e| pezsp_blockchain::Error::VersionInvalid(e.to_string()))?;
Ok(runtime_version.state_version())
} else {
Err(pezsp_blockchain::Error::VersionInvalid(
"Runtime missing from initial storage, could not read state version.".to_string(),
))
}
}
/// Create a genesis block, given the initial storage.
pub fn construct_genesis_block<Block: BlockT>(
state_root: Block::Hash,
state_version: StateVersion,
) -> Block {
let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
Vec::new(),
state_version,
);
Block::new(
<<Block as BlockT>::Header as HeaderT>::new(
Zero::zero(),
extrinsics_root,
state_root,
Default::default(),
Default::default(),
),
Default::default(),
)
}
/// Trait for building the genesis block.
pub trait BuildGenesisBlock<Block: BlockT> {
/// The import operation used to import the genesis block into the backend.
type BlockImportOperation;
/// Returns the built genesis block along with the block import operation
/// after setting the genesis storage.
fn build_genesis_block(self) -> pezsp_blockchain::Result<(Block, Self::BlockImportOperation)>;
}
/// Default genesis block builder in Bizinikiwi.
pub struct GenesisBlockBuilder<Block: BlockT, B, E> {
genesis_storage: Storage,
commit_genesis_state: bool,
backend: Arc<B>,
executor: E,
_phantom: PhantomData<Block>,
}
impl<Block: BlockT, B: Backend<Block>, E: RuntimeVersionOf> GenesisBlockBuilder<Block, B, E> {
/// Constructs a new instance of [`GenesisBlockBuilder`].
pub fn new(
build_genesis_storage: &dyn BuildStorage,
commit_genesis_state: bool,
backend: Arc<B>,
executor: E,
) -> pezsp_blockchain::Result<Self> {
let genesis_storage =
build_genesis_storage.build_storage().map_err(pezsp_blockchain::Error::Storage)?;
Self::new_with_storage(genesis_storage, commit_genesis_state, backend, executor)
}
/// Constructs a new instance of [`GenesisBlockBuilder`] using provided storage.
pub fn new_with_storage(
genesis_storage: Storage,
commit_genesis_state: bool,
backend: Arc<B>,
executor: E,
) -> pezsp_blockchain::Result<Self> {
Ok(Self {
genesis_storage,
commit_genesis_state,
backend,
executor,
_phantom: PhantomData::<Block>,
})
}
}
impl<Block: BlockT, B: Backend<Block>, E: RuntimeVersionOf> BuildGenesisBlock<Block>
for GenesisBlockBuilder<Block, B, E>
{
type BlockImportOperation = <B as Backend<Block>>::BlockImportOperation;
fn build_genesis_block(self) -> pezsp_blockchain::Result<(Block, Self::BlockImportOperation)> {
let Self { genesis_storage, commit_genesis_state, backend, executor, _phantom } = self;
let genesis_state_version =
resolve_state_version_from_wasm::<_, HashingFor<Block>>(&genesis_storage, &executor)?;
let mut op = backend.begin_operation()?;
let state_root =
op.set_genesis_state(genesis_storage, commit_genesis_state, genesis_state_version)?;
let genesis_block = construct_genesis_block::<Block>(state_root, genesis_state_version);
Ok((genesis_block, op))
}
}
@@ -0,0 +1,253 @@
// This file is part of Bizinikiwi.
// 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};
pub use pezsc_executor::pezsp_wasm_interface::HostFunctions;
use pezsc_executor::{error::Result, WasmExecutor};
use serde_json::{from_slice, Value};
use pezsp_core::{
storage::Storage,
traits::{CallContext, CodeExecutor, Externalities, FetchRuntimeCode, RuntimeCode},
};
use pezsp_genesis_builder::{PresetId, Result as BuildResult};
pub use pezsp_genesis_builder::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET};
use pezsp_state_machine::BasicExternalities;
use std::borrow::Cow;
/// A utility that facilitates calling the GenesisBuilder API from the runtime wasm code blob.
///
/// `EHF` type allows to specify the extended host function required for building runtime's genesis
/// config. The type will be combined with default `pezsp_io::BizinikiwiHostFunctions`.
pub struct GenesisConfigBuilderRuntimeCaller<'a, EHF = ()>
where
EHF: HostFunctions,
{
code: Cow<'a, [u8]>,
code_hash: Vec<u8>,
executor: WasmExecutor<(pezsp_io::BizinikiwiHostFunctions, EHF)>,
}
impl<'a, EHF> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a, EHF>
where
EHF: HostFunctions,
{
fn fetch_runtime_code(&self) -> Option<Cow<'_, [u8]>> {
Some(self.code.as_ref().into())
}
}
impl<'a, EHF> GenesisConfigBuilderRuntimeCaller<'a, EHF>
where
EHF: HostFunctions,
{
/// 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: pezsp_crypto_hashing::blake2_256(code).to_vec(),
executor: WasmExecutor::<(pezsp_io::BizinikiwiHostFunctions, EHF)>::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,
CallContext::Offchain,
)
.0
}
/// Returns a json representation of the default `RuntimeGenesisConfig` provided by the
/// `runtime`.
///
/// Calls [`GenesisBuilder::get_preset`](pezsp_genesis_builder::GenesisBuilder::get_preset) in the
/// `runtime` with `None` argument.
pub fn get_default_config(&self) -> core::result::Result<Value, String> {
self.get_named_preset(None)
}
/// Returns a JSON blob representation of the builtin `GenesisConfig` identified by `id`.
///
/// Calls [`GenesisBuilder::get_preset`](pezsp_genesis_builder::GenesisBuilder::get_preset)
/// provided by the `runtime`.
pub fn get_named_preset(&self, id: Option<&String>) -> core::result::Result<Value, String> {
let mut t = BasicExternalities::new_empty();
let call_result = self
.call(&mut t, "GenesisBuilder_get_preset", &id.encode())
.map_err(|e| format!("wasm call error {e}"))?;
let named_preset = Option::<Vec<u8>>::decode(&mut &call_result[..])
.map_err(|e| format!("scale codec error: {e}"))?;
if let Some(named_preset) = named_preset {
Ok(from_slice(&named_preset[..]).expect("returned value is json. qed."))
} else {
Err(format!("The preset with name {id:?} is not available."))
}
}
/// Calls [`pezsp_genesis_builder::GenesisBuilder::build_state`] provided by runtime.
pub fn get_storage_for_config(&self, config: Value) -> core::result::Result<Storage, String> {
let mut ext = BasicExternalities::new_empty();
let json_pretty_str = serde_json::to_string_pretty(&config)
.map_err(|e| format!("json to string failed: {e}"))?;
let call_result = self
.call(&mut ext, "GenesisBuilder_build_state", &json_pretty_str.encode())
.map_err(|e| format!("wasm call error {e}"))?;
BuildResult::decode(&mut &call_result[..])
.map_err(|e| format!("scale codec error: {e}"))?
.map_err(|e| format!("{e} for blob:\n{}", json_pretty_str))?;
Ok(ext.into_storages())
}
/// Creates the genesis state by patching the default `RuntimeGenesisConfig`.
///
/// This function generates the `RuntimeGenesisConfig` for the runtime by applying a provided
/// JSON patch. The patch modifies the default `RuntimeGenesisConfig` allowing customization of
/// the specific keys. The resulting `RuntimeGenesisConfig` 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 `RuntimeGenesisConfig` according to the following
/// rules:
/// 1. Existing keys in the default configuration will be overridden by the corresponding values
/// in the patch (also applies to `null` values).
/// 2. If a key exists in the patch but not in the default configuration, it will be added to
/// the resulting `RuntimeGenesisConfig`.
///
/// Please note that the patch may contain full `RuntimeGenesisConfig`.
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)
}
pub fn get_storage_for_named_preset(
&self,
name: Option<&String>,
) -> core::result::Result<Storage, String> {
self.get_storage_for_patch(self.get_named_preset(name)?)
}
pub fn preset_names(&self) -> core::result::Result<Vec<PresetId>, String> {
let mut t = BasicExternalities::new_empty();
let call_result = self
.call(&mut t, "GenesisBuilder_preset_names", &vec![])
.map_err(|e| format!("wasm call error {e}"))?;
let preset_names = Vec::<PresetId>::decode(&mut &call_result[..])
.map_err(|e| format!("scale codec error: {e}"))?;
Ok(preset_names)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{from_str, json};
pub use pezsp_consensus_babe::{AllowedSlots, BabeEpochConfiguration};
pub use pezsp_genesis_builder::PresetId;
#[test]
fn list_presets_works() {
pezsp_tracing::try_init_simple();
let presets =
<GenesisConfigBuilderRuntimeCaller>::new(bizinikiwi_test_runtime::wasm_binary_unwrap())
.preset_names()
.unwrap();
assert_eq!(presets, vec![PresetId::from("foobar"), PresetId::from("staging"),]);
}
#[test]
fn get_default_config_works() {
let config =
<GenesisConfigBuilderRuntimeCaller>::new(bizinikiwi_test_runtime::wasm_binary_unwrap())
.get_default_config()
.unwrap();
let expected = r#"{"babe": {"authorities": [], "epochConfig": {"allowed_slots": "PrimaryAndSecondaryVRFSlots", "c": [1, 4]}}, "balances": {"balances": [], "devAccounts": null}, "bizinikiwiTest": {"authorities": []}, "system": {}}"#;
assert_eq!(from_str::<Value>(expected).unwrap(), config);
}
#[test]
fn get_named_preset_works() {
pezsp_tracing::try_init_simple();
let config =
<GenesisConfigBuilderRuntimeCaller>::new(bizinikiwi_test_runtime::wasm_binary_unwrap())
.get_named_preset(Some(&"foobar".to_string()))
.unwrap();
let expected = r#"{"foo":"bar"}"#;
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(bizinikiwi_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,198 @@
// This file is part of Bizinikiwi.
// 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` (also if
/// value in `b` is `null`).
/// If a key exists only in `b` and not in `a`, it will be added to `a`.
/// No keys will be removed from `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 {
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_does_not_remove_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_1": null,
"enum_variant_2": 32
}
})
);
}
}
+433
View File
@@ -0,0 +1,433 @@
// This file is part of Bizinikiwi.
// 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/>.
//! This crate includes structs and utilities for defining configuration files (known as chain
//! specification) for both runtime and node.
//!
//! # Intro: Chain Specification
//!
//! 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 pezsc_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.
//!
//! # `chain-spec` formats
//!
//! In essence, the most important formats of genesis initial state in chain specification files
//! are:
//!
//! <table>
//! <thead>
//! <tr>
//! <th>Format</th>
//! <th>Description</th>
//! </tr>
//! </thead>
//! <tbody>
//! <tr>
//! <td>
//! <code>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="../pezframe_support_procedural/macro.construct_runtime.html"
//! ><code>pezkuwi_sdk_frame::runtime::prelude::construct_runtime</code></a> macro (<a
//! href="../bizinikiwi_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>: `full = default + patch`. Please note that `default`
//! `RuntimeGenesisConfig` may not be functional.
//! 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>
//!
//! The main purpose of the `RuntimeGenesisConfig` patch is to:
//! - minimize the maintenance effort when RuntimeGenesisConfig is changed in the future (e.g. new
//! pallets added to the runtime or pallet's genesis config changed),
//! - increase the readability - it only contains the relevant fields,
//! - allow to apply numerous changes in distinct domains (e.g. for zombienet).
//!
//! 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
//! [`pezsp_genesis_builder::GenesisBuilder::build_state`] function. During this operation, the
//! runtime converts the JSON representation of the genesis config into [`pezsp_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 [`pezsp_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
//! [`pezsc_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/bizinikiwi_test_runtime_from_patch.json")]
//! ```
//! ```ignore
#![doc = include_str!("../res/bizinikiwi_test_runtime_from_patch_raw.json")]
//! ```
//! The following example shows the plain full config version of chain spec:
//! ```ignore
#![doc = include_str!("../res/bizinikiwi_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 Bizinikiwi 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 pezsc_chain_spec::{GenericChainSpec, ChainSpecExtension};
//!
//! #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ChainSpecExtension)]
//! pub struct MyExtension {
//! pub known_blocks: HashMap<u64, String>,
//! }
//!
//! 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`]
//! structure to add such parameters to your chain spec. This will allow overriding a single
//! parameter starting at a specific block number.
//! ```rust
//! use pezsc_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 = GenericChainSpec<Forks<BlockNumber, ClientParams>>;
//!
//! /// A chain spec supporting forkable `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
//! achieved by declaring an extension that contains [`Forks`] within it.
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use pezsc_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 = 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.
mod chain_spec;
mod extension;
mod genesis_block;
mod genesis_config_builder;
pub mod json_patch;
pub use self::{
chain_spec::{
set_code_substitute_in_json_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_block::{
construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock,
GenesisBlockBuilder,
},
genesis_config_builder::{
GenesisConfigBuilderRuntimeCaller, DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET,
},
json_patch::merge as json_merge,
};
pub use pezsc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
use pezsc_network::config::MultiaddrWithPeerId;
use pezsc_telemetry::TelemetryEndpoints;
use pezsp_core::storage::Storage;
use pezsp_runtime::BuildStorage;
/// The type of chain.
///
/// This can be used by tools to determine the type of chain for displaying
/// additional information or enabling additional features.
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
pub enum ChainType {
/// A development chain that runs mainly on one node.
Development,
/// A local chain that runs locally on multiple nodes for testing purposes.
Local,
/// A live chain.
Live,
/// Some custom chain type.
#[cfg_attr(feature = "clap", clap(skip))]
Custom(String),
}
impl Default for ChainType {
fn default() -> Self {
Self::Live
}
}
/// Arbitrary properties defined in chain spec as a JSON object
pub type Properties = serde_json::map::Map<String, serde_json::Value>;
/// Common interface of a chain specification.
pub trait ChainSpec: BuildStorage + Send + Sync {
/// Spec name.
fn name(&self) -> &str;
/// Spec id.
fn id(&self) -> &str;
/// Type of the chain.
fn chain_type(&self) -> ChainType;
/// A list of bootnode addresses.
fn boot_nodes(&self) -> &[MultiaddrWithPeerId];
/// Telemetry endpoints (if any)
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints>;
/// Network protocol id.
fn protocol_id(&self) -> Option<&str>;
/// Optional network fork identifier. `None` by default.
fn fork_id(&self) -> Option<&str>;
/// Additional loosely-typed properties of the chain.
///
/// Returns an empty JSON object if 'properties' not defined in config
fn properties(&self) -> Properties;
/// Returns a reference to the defined chain spec extensions.
fn extensions(&self) -> &dyn GetExtension;
/// Returns a mutable reference to the defined chain spec extensions.
fn extensions_mut(&mut self) -> &mut dyn GetExtension;
/// Add a bootnode to the list.
fn add_boot_node(&mut self, addr: MultiaddrWithPeerId);
/// Return spec as JSON.
fn as_json(&self, raw: bool) -> Result<String, String>;
/// Return StorageBuilder for this spec.
fn as_storage_builder(&self) -> &dyn BuildStorage;
/// Returns a cloned `Box<dyn ChainSpec>`.
fn cloned_box(&self) -> Box<dyn ChainSpec>;
/// Set the storage that should be used by this chain spec.
///
/// This will be used as storage at genesis.
fn set_storage(&mut self, storage: Storage);
/// Returns code substitutes that should be used for the on chain wasm.
fn code_substitutes(&self) -> std::collections::BTreeMap<String, Vec<u8>>;
}
impl std::fmt::Debug for dyn ChainSpec {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "ChainSpec(name = {:?}, id = {:?})", self.name(), self.id())
}
}