diff --git a/Cargo.lock b/Cargo.lock index 7376d035104b4..ed6a4c356d10f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2865,6 +2865,7 @@ dependencies = [ "sp-core", "sp-core-hashing-proc-macro", "sp-debug-derive", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-runtime", @@ -3916,6 +3917,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f54898088ccb91df1b492cc80029a6fdf1c48ca0db7c6822a8babad69c94658" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "jsonrpsee" version = "0.16.2" @@ -12153,6 +12165,7 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures", + "json-patch", "log", "pallet-babe", "pallet-balances", @@ -12160,8 +12173,11 @@ dependencies = [ "parity-scale-codec", "sc-block-builder", "sc-executor", + "sc-executor-common", "sc-service", "scale-info", + "serde", + "serde_json", "sp-api", "sp-application-crypto", "sp-block-builder", @@ -12171,6 +12187,7 @@ dependencies = [ "sp-consensus-grandpa", "sp-core", "sp-externalities", + "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index 4a0a14750717f..4a5030891d362 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -194,7 +194,7 @@ async fn follow_with_runtime() { [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\ [\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\ - [\"0xed99c5acb25eedf5\",3]],\"transactionVersion\":1,\"stateVersion\":1}"; + [\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":1}"; let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap(); diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 7c73c1e1cd8da..35352f6d890ed 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -518,7 +518,7 @@ async fn should_return_runtime_version() { [\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\ [\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\ [\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\ - [\"0xed99c5acb25eedf5\",3]],\"transactionVersion\":1,\"stateVersion\":1}"; + [\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":1}"; let runtime_version = api.runtime_version(None.into()).unwrap(); let serialized = serde_json::to_string(&runtime_version).unwrap(); diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index f483c632a9698..37e51c2a92e5f 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -40,11 +40,12 @@ log = { version = "0.4.17", default-features = false } sp-core-hashing-proc-macro = { version = "9.0.0", path = "../../primitives/core/hashing/proc-macro" } k256 = { version = "0.13.0", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } +sp-genesis-builder = { version = "0.1.0", default-features=false, path = "../../primitives/genesis-builder" } +serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } aquamarine = { version = "0.3.2" } [dev-dependencies] -serde_json = "1.0.85" assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } @@ -72,6 +73,7 @@ std = [ "frame-support-procedural/std", "log/std", "environmental/std", + "sp-genesis-builder/std" ] runtime-benchmarks = [ "frame-system/runtime-benchmarks", diff --git a/frame/support/src/genesis_builder_helper.rs b/frame/support/src/genesis_builder_helper.rs new file mode 100644 index 0000000000000..d4144a4d9fd19 --- /dev/null +++ b/frame/support/src/genesis_builder_helper.rs @@ -0,0 +1,41 @@ +// 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. + +//! Helper functions for implementing [`sp_genesis_builder::GenesisBuilder`] for runtimes. +//! +//! Provides common logic. For more info refer to [`sp_genesis_builder::GenesisBuilder`]. + +use frame_support::traits::BuildGenesisConfig; +use sp_genesis_builder::Result as BuildResult; +use sp_runtime::format_runtime_string; + +/// Get the default `GenesisConfig` as a JSON blob. For more info refer to +/// [`sp_genesis_builder::GenesisBuilder::create_default_config`] +pub fn create_default_config() -> sp_std::vec::Vec { + serde_json::to_string(&GC::default()) + .expect("serialization to json is expected to work. qed.") + .into_bytes() +} + +/// Build `GenesisConfig` from a JSON blob not using any defaults and store it in the storage. For +/// more info refer to [`sp_genesis_builder::GenesisBuilder::build_config`]. +pub fn build_config(json: sp_std::vec::Vec) -> BuildResult { + let gc = serde_json::from_slice::(&json) + .map_err(|e| format_runtime_string!("Invalid JSON blob: {}", e))?; + ::build(&gc); + Ok(()) +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 438d4151e3252..d2c4781be5672 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -2915,3 +2915,6 @@ pub use frame_support_procedural::register_default_impl; // Generate a macro that will enable/disable code based on `std` feature being active. sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); + +// Helper for implementing GenesisBuilder runtime API +pub mod genesis_builder_helper; diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 35c26a62be2d6..2b80d1c64bc2d 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -13,9 +13,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-application-crypto = { version = "23.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } -sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } +sp-application-crypto = { version = "23.0.0", default-features = false, path = "../../primitives/application-crypto", features = ["serde"] } +sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura", features = ["serde"] } +sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe", features = ["serde"] } +sp-genesis-builder = { version = "0.1.0-dev", default-features = false, path = "../../primitives/genesis-builder" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } @@ -29,14 +30,14 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. sp-version = { version = "22.0.0", default-features = false, path = "../../primitives/version" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../primitives/session" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } -sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime" } +sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime", features = ["serde"] } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../frame/balances" } frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../frame/executive" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" } frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" } pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../frame/timestamp" } -sp-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/grandpa" } +sp-consensus-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/grandpa", features = ["serde"] } sp-trie = { version = "22.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.27.0", default-features = false } @@ -47,14 +48,18 @@ sp-externalities = { version = "0.19.0", default-features = false, path = "../.. # 3rd party array-bytes = { version = "6.1", optional = true } log = { version = "0.4.17", default-features = false } +serde = { version = "1.0.163", features = ["alloc", "derive"], default-features = false } +serde_json = { version = "1.0.85", default-features = false, features = ["alloc"] } [dev-dependencies] futures = "0.3.21" sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" } sc-executor = { version = "0.10.0-dev", path = "../../client/executor" } +sc-executor-common = { version = "0.10.0-dev", path = "../../client/executor/common" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime-client = { version = "2.0.0", path = "./client" } sp-tracing = { version = "10.0.0", path = "../../primitives/tracing" } +json-patch = { version = "1.0.0", default-features = false } [build-dependencies] substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-builder", optional = true } @@ -63,8 +68,10 @@ substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-build default = [ "std", ] + std = [ "array-bytes", + "sp-genesis-builder/std", "sp-application-crypto/std", "sp-consensus-aura/std", "sp-consensus-babe/std", @@ -100,3 +107,6 @@ std = [ ] # Special feature to disable logging disable-logging = [ "sp-api/disable-logging" ] + +#Enabling this flag will disable GenesisBuilder API implementation in runtime. +disable-genesis-builder = [] diff --git a/test-utils/runtime/build.rs b/test-utils/runtime/build.rs index dd79ce2c5ae84..230606635f7dc 100644 --- a/test-utils/runtime/build.rs +++ b/test-utils/runtime/build.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +const BUILD_NO_GENESIS_BUILDER_SUPPORT_ENV: &str = "BUILD_NO_GENESIS_BUILDER_SUPPORT"; + fn main() { #[cfg(feature = "std")] { @@ -29,6 +31,19 @@ fn main() { .build(); } + #[cfg(feature = "std")] + if std::env::var(BUILD_NO_GENESIS_BUILDER_SUPPORT_ENV).is_ok() { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .append_to_rust_flags("-Clink-arg=-zstack-size=1048576") + .set_file_name("wasm_binary_no_genesis_builder") + .import_memory() + .enable_feature("disable-genesis-builder") + .build(); + } + println!("cargo:rerun-if-env-changed={}", BUILD_NO_GENESIS_BUILDER_SUPPORT_ENV); + #[cfg(feature = "std")] { substrate_wasm_builder::WasmBuilder::new() diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 97504c232aef5..8a4d6dbe4a71a 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -73,10 +73,10 @@ impl Default for GenesisStorageBuilder { } impl GenesisStorageBuilder { - /// Creates a storage builder for genesis config. `substrage test runtime` `GenesisConfig` is - /// initialized with provided `authorities`, `endowed_accounts` with given balance. Key-pairs - /// from `extra_storage` will be injected into built storage. `HEAP_PAGES` key and value will - /// also be placed into storage. + /// Creates a storage builder for genesis config. `substrage test runtime` + /// [`RuntimeGenesisConfig`] is initialized with provided `authorities`, `endowed_accounts` with + /// given balance. Key-value pairs from `extra_storage` will be injected into built storage. + /// `HEAP_PAGES` key and value will also be placed into storage. pub fn new( authorities: Vec, endowed_accounts: Vec, @@ -91,7 +91,7 @@ impl GenesisStorageBuilder { } } - /// Override default wasm code to be placed into GenesisConfig. + /// Override default wasm code to be placed into RuntimeGenesisConfig. pub fn with_wasm_code(mut self, wasm_code: &Option>) -> Self { self.wasm_code = wasm_code.clone(); self @@ -107,8 +107,8 @@ impl GenesisStorageBuilder { self } - /// Builds the `GenesisConfig` and returns its storage. - pub fn build(self) -> Storage { + /// A `RuntimeGenesisConfig` from internal configuration + pub fn genesis_config(&self) -> RuntimeGenesisConfig { let authorities_sr25519: Vec<_> = self .authorities .clone() @@ -116,7 +116,7 @@ impl GenesisStorageBuilder { .map(|id| sr25519::Public::from(id)) .collect(); - let genesis_config = RuntimeGenesisConfig { + RuntimeGenesisConfig { system: frame_system::GenesisConfig { code: self.wasm_code.clone().unwrap_or(wasm_binary_unwrap().to_vec()), ..Default::default() @@ -135,11 +135,15 @@ impl GenesisStorageBuilder { ..Default::default() }, balances: pallet_balances::GenesisConfig { balances: self.balances.clone() }, - }; + } + } - let mut storage = genesis_config + /// Builds the `RuntimeGenesisConfig` and returns its storage. + pub fn build(self) -> Storage { + let mut storage = self + .genesis_config() .build_storage() - .expect("Build storage from substrate-test-runtime GenesisConfig"); + .expect("Build storage from substrate-test-runtime RuntimeGenesisConfig"); if let Some(heap_pages) = self.heap_pages_override { storage.top.insert(well_known_keys::HEAP_PAGES.into(), heap_pages.encode()); diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index b17c31fb3ea04..0cc32e50956c8 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -26,6 +26,8 @@ pub mod genesismap; pub mod substrate_test_pallet; use codec::{Decode, Encode}; +#[cfg(not(feature = "disable-genesis-builder"))] +use frame_support::genesis_builder_helper::{build_config, create_default_config}; use frame_support::{ construct_runtime, dispatch::DispatchClass, @@ -42,6 +44,8 @@ use frame_system::{ }; use scale_info::TypeInfo; use sp_std::prelude::*; +#[cfg(not(feature = "std"))] +use sp_std::vec; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; use sp_core::{OpaqueMetadata, RuntimeDebug}; @@ -717,6 +721,17 @@ impl_runtime_apis! { None } } + + #[cfg(not(feature = "disable-genesis-builder"))] + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn create_default_config() -> Vec { + create_default_config::() + } + + fn build_config(config: Vec) -> sp_genesis_builder::Result { + build_config::(config) + } + } } fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { @@ -850,24 +865,23 @@ pub mod storage_key_generator { } let keys: Vec> = vec![ + vec![b"Babe", b":__STORAGE_VERSION__:"], vec![b"Babe", b"Authorities"], vec![b"Babe", b"EpochConfig"], vec![b"Babe", b"NextAuthorities"], vec![b"Babe", b"SegmentIndex"], - vec![b"Babe", b":__STORAGE_VERSION__:"], vec![b"Balances", b":__STORAGE_VERSION__:"], vec![b"Balances", b"TotalIssuance"], - vec![b"SubstrateTest", b"Authorities"], vec![b"SubstrateTest", b":__STORAGE_VERSION__:"], + vec![b"SubstrateTest", b"Authorities"], + vec![b"System", b":__STORAGE_VERSION__:"], vec![b"System", b"LastRuntimeUpgrade"], vec![b"System", b"ParentHash"], - vec![b"System", b":__STORAGE_VERSION__:"], vec![b"System", b"UpgradedToTripleRefCount"], vec![b"System", b"UpgradedToU32RefCount"], ]; let mut expected_keys = keys.iter().map(concat_hashes).collect::>(); - expected_keys.extend(literals.into_iter().map(hex)); let balances_map_keys = (0..16_usize) @@ -912,7 +926,7 @@ pub mod storage_key_generator { /// aka when overriding the heap pages to be used by the executor. pub fn get_expected_storage_hashed_keys(custom_heap_pages: bool) -> Vec<&'static str> { let mut res = vec![ - //System|:__STORAGE_VERSION__: + //SubstrateTest|:__STORAGE_VERSION__: "00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429", //SubstrateTest|Authorities "00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d", @@ -1190,4 +1204,249 @@ mod tests { ); }) } + + #[cfg(not(feature = "disable-genesis-builder"))] + mod genesis_builder_tests { + use super::*; + use crate::genesismap::GenesisStorageBuilder; + use sc_executor::{error::Result, WasmExecutor}; + use sc_executor_common::runtime_blob::RuntimeBlob; + use serde_json::json; + use sp_application_crypto::Ss58Codec; + use sp_core::traits::Externalities; + use sp_genesis_builder::Result as BuildResult; + use sp_state_machine::BasicExternalities; + use std::{fs, io::Write}; + use storage_key_generator::hex; + + pub fn executor_call( + ext: &mut dyn Externalities, + method: &str, + data: &[u8], + ) -> Result> { + let executor = WasmExecutor::::builder().build(); + executor.uncached_call( + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), + ext, + true, + method, + data, + ) + } + + #[test] + fn build_minimal_genesis_config_works() { + sp_tracing::try_init_simple(); + let default_minimal_json = r#"{"system":{"code":"0x"},"babe":{"authorities":[],"epochConfig":{"c": [ 3, 10 ],"allowed_slots":"PrimaryAndSecondaryPlainSlots"}},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + let mut t = BasicExternalities::new_empty(); + + executor_call(&mut t, "GenesisBuilder_build_config", &default_minimal_json.encode()) + .unwrap(); + + let mut keys = t.into_storages().top.keys().cloned().map(hex).collect::>(); + keys.sort(); + + let mut expected = [ + //SubstrateTest|Authorities + "00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d", + //Babe|SegmentIndex + "1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4", + //Babe|EpochConfig + "1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef", + //System|UpgradedToU32RefCount + "26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710", + //System|ParentHash + "26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", + //System::BlockHash|0 + "26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000", + //System|UpgradedToTripleRefCount + "26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439", + + // System|LastRuntimeUpgrade + "26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8", + // :code + "3a636f6465", + // :extrinsic_index + "3a65787472696e7369635f696e646578", + // Balances|TotalIssuance + "c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80", + + // added by on_genesis: + // Balances|:__STORAGE_VERSION__: + "c2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429", + //System|:__STORAGE_VERSION__: + "26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429", + //Babe|:__STORAGE_VERSION__: + "1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429", + //SubstrateTest|:__STORAGE_VERSION__: + "00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429", + ].into_iter().map(String::from).collect::>(); + expected.sort(); + + assert_eq!(keys, expected); + } + + #[test] + fn default_config_as_json_works() { + sp_tracing::try_init_simple(); + let mut t = BasicExternalities::new_empty(); + let r = executor_call(&mut t, "GenesisBuilder_create_default_config", &vec![]).unwrap(); + let r = Vec::::decode(&mut &r[..]).unwrap(); + let json = String::from_utf8(r.into()).expect("returned value is json. qed."); + + let expected = r#"{"system":{"code":"0x"},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#; + assert_eq!(expected.to_string(), json); + } + + #[test] + fn build_config_from_json_works() { + sp_tracing::try_init_simple(); + let j = include_str!("test_json/default_genesis_config.json"); + + let mut t = BasicExternalities::new_empty(); + let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); + let r = BuildResult::decode(&mut &r[..]); + assert!(r.is_ok()); + + let keys = t.into_storages().top.keys().cloned().map(hex).collect::>(); + assert_eq!(keys, storage_key_generator::get_expected_storage_hashed_keys(false)); + } + + #[test] + fn build_config_from_invalid_json_fails() { + sp_tracing::try_init_simple(); + let j = include_str!("test_json/default_genesis_config_invalid.json"); + let mut t = BasicExternalities::new_empty(); + let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); + let r = BuildResult::decode(&mut &r[..]).unwrap(); + log::info!("result: {:#?}", r); + assert_eq!(r, Err( + sp_runtime::RuntimeString::Owned( + "Invalid JSON blob: unknown field `renamed_authorities`, expected `authorities` or `epochConfig` at line 6 column 25".to_string(), + )) + ); + } + + #[test] + fn build_config_from_incomplete_json_fails() { + sp_tracing::try_init_simple(); + let j = include_str!("test_json/default_genesis_config_incomplete.json"); + + let mut t = BasicExternalities::new_empty(); + let r = executor_call(&mut t, "GenesisBuilder_build_config", &j.encode()).unwrap(); + let r = + core::result::Result::<(), sp_runtime::RuntimeString>::decode(&mut &r[..]).unwrap(); + assert_eq!( + r, + Err(sp_runtime::RuntimeString::Owned( + "Invalid JSON blob: missing field `authorities` at line 13 column 3" + .to_string() + )) + ); + } + + #[test] + fn write_default_config_to_tmp_file() { + if std::env::var("WRITE_DEFAULT_JSON_FOR_STR_GC").is_ok() { + sp_tracing::try_init_simple(); + let mut file = fs::OpenOptions::new() + .create(true) + .write(true) + .open("/tmp/default_genesis_config.json") + .unwrap(); + + let j = serde_json::to_string(&GenesisStorageBuilder::default().genesis_config()) + .unwrap() + .into_bytes(); + file.write_all(&j).unwrap(); + } + } + + #[test] + fn build_genesis_config_with_patch_json_works() { + //this tests shows how to do patching on native side + sp_tracing::try_init_simple(); + + let mut t = BasicExternalities::new_empty(); + let r = executor_call(&mut t, "GenesisBuilder_create_default_config", &vec![]).unwrap(); + let r = Vec::::decode(&mut &r[..]).unwrap(); + let mut default_config: serde_json::Value = + serde_json::from_slice(&r[..]).expect("returned value is json. qed."); + + // Patch default json with some custom values: + let patch = json!({ + "babe": { + "epochConfig": { + "c": [ + 7, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + AccountKeyring::Ferdie.public().to_ss58check(), + AccountKeyring::Alice.public().to_ss58check() + ], + } + }); + + json_patch::merge(&mut default_config, &patch); + + // Build genesis config using custom json: + let mut t = BasicExternalities::new_empty(); + executor_call( + &mut t, + "GenesisBuilder_build_config", + &default_config.to_string().encode(), + ) + .unwrap(); + + // Ensure that custom values are in the genesis storage: + let storage = t.into_storages(); + let get_from_storage = |key: &str| -> Vec { + storage.top.get(&array_bytes::hex2bytes(key).unwrap()).unwrap().clone() + }; + + //SubstrateTest|Authorities + let value: Vec = get_from_storage( + "00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d", + ); + let authority_key_vec = + Vec::::decode(&mut &value[..]).unwrap(); + assert_eq!(authority_key_vec.len(), 2); + assert_eq!(authority_key_vec[0], sp_keyring::AccountKeyring::Ferdie.public()); + assert_eq!(authority_key_vec[1], sp_keyring::AccountKeyring::Alice.public()); + + //Babe|Authorities + let value: Vec = get_from_storage( + "1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef", + ); + assert_eq!( + BabeEpochConfiguration::decode(&mut &value[..]).unwrap(), + BabeEpochConfiguration { + c: (7, 10), + allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots + } + ); + + // Ensure that some values are default ones: + // Balances|TotalIssuance + let value: Vec = get_from_storage( + "c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80", + ); + assert_eq!(u64::decode(&mut &value[..]).unwrap(), 0); + + // :code + let value: Vec = get_from_storage("3a636f6465"); + assert!(Vec::::decode(&mut &value[..]).is_err()); + + //System|ParentHash + let value: Vec = get_from_storage( + "26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", + ); + assert_eq!(H256::decode(&mut &value[..]).unwrap(), [69u8; 32].into()); + } + } } diff --git a/test-utils/runtime/src/test_json/README.md b/test-utils/runtime/src/test_json/README.md new file mode 100644 index 0000000000000..6d6ae55c34639 --- /dev/null +++ b/test-utils/runtime/src/test_json/README.md @@ -0,0 +1,24 @@ +`default_genesis_config.json` file has been generated by the following code: +``` + use crate::genesismap::GenesisStorageBuilder; + #[test] + fn write_default_config_to_tmp_file() { + let j = json::to_string(&GenesisStorageBuilder::default().genesis_config()).unwrap().into_bytes(); + let mut file = fs::OpenOptions::new() + .create(true) + .write(true) + .open("/tmp/default_genesis_config.json").unwrap(); + file.write_all(&j); + } +``` + +`:code` field has been manually truncated to reduce file size. Test is only +comparing keys, not the values. + +`default_genesis_config_invalid.json` is just a broken copy of +`default_genesis_config.json` with `authorities` field renamed to +`renamed_authorities`. + + +`default_genesis_config_invalid.json` is just an imcomplete copy of +`default_genesis_config.json` with `babe::authorities` field removed. diff --git a/test-utils/runtime/src/test_json/default_genesis_config.json b/test-utils/runtime/src/test_json/default_genesis_config.json new file mode 100644 index 0000000000000..b0218d417daa5 --- /dev/null +++ b/test-utils/runtime/src/test_json/default_genesis_config.json @@ -0,0 +1,115 @@ +{ + "system": { + "code": "0x52" + }, + "babe": { + "authorities": [ + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 1 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1 + ] + ], + "epochConfig": { + "c": [ + 3, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" + ] + }, + "balances": { + "balances": [ + [ + "5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH", + 100000000000000000 + ], + [ + "5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o", + 100000000000000000 + ], + [ + "5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9", + 100000000000000000 + ], + [ + "5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK", + 100000000000000000 + ], + [ + "5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW", + 100000000000000000 + ], + [ + "5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR", + 100000000000000000 + ], + [ + "5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY", + 100000000000000000 + ], + [ + "5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ", + 100000000000000000 + ], + [ + "5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX", + 100000000000000000 + ], + [ + "5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q", + 100000000000000000 + ], + [ + "5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz", + 100000000000000000 + ], + [ + "5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf", + 100000000000000000 + ], + [ + "5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz", + 100000000000000000 + ], + [ + "5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC", + 100000000000000000 + ], + [ + "5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51", + 100000000000000000 + ], + [ + "5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e", + 100000000000000000 + ], + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 100000000000000000 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 100000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 100000000000000000 + ] + ] + } +} diff --git a/test-utils/runtime/src/test_json/default_genesis_config_incomplete.json b/test-utils/runtime/src/test_json/default_genesis_config_incomplete.json new file mode 100644 index 0000000000000..e25730ee11cf0 --- /dev/null +++ b/test-utils/runtime/src/test_json/default_genesis_config_incomplete.json @@ -0,0 +1,101 @@ +{ + "system": { + "code": "0x52" + }, + "babe": { + "epochConfig": { + "c": [ + 3, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" + ] + }, + "balances": { + "balances": [ + [ + "5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH", + 100000000000000000 + ], + [ + "5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o", + 100000000000000000 + ], + [ + "5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9", + 100000000000000000 + ], + [ + "5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK", + 100000000000000000 + ], + [ + "5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW", + 100000000000000000 + ], + [ + "5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR", + 100000000000000000 + ], + [ + "5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY", + 100000000000000000 + ], + [ + "5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ", + 100000000000000000 + ], + [ + "5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX", + 100000000000000000 + ], + [ + "5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q", + 100000000000000000 + ], + [ + "5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz", + 100000000000000000 + ], + [ + "5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf", + 100000000000000000 + ], + [ + "5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz", + 100000000000000000 + ], + [ + "5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC", + 100000000000000000 + ], + [ + "5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51", + 100000000000000000 + ], + [ + "5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e", + 100000000000000000 + ], + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 100000000000000000 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 100000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 100000000000000000 + ] + ] + } +} diff --git a/test-utils/runtime/src/test_json/default_genesis_config_invalid.json b/test-utils/runtime/src/test_json/default_genesis_config_invalid.json new file mode 100644 index 0000000000000..00550efaeec9f --- /dev/null +++ b/test-utils/runtime/src/test_json/default_genesis_config_invalid.json @@ -0,0 +1,115 @@ +{ + "system": { + "code": "0x52" + }, + "babe": { + "renamed_authorities": [ + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 1 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1 + ] + ], + "epochConfig": { + "c": [ + 3, + 10 + ], + "allowed_slots": "PrimaryAndSecondaryPlainSlots" + } + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" + ] + }, + "balances": { + "balances": [ + [ + "5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH", + 100000000000000000 + ], + [ + "5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o", + 100000000000000000 + ], + [ + "5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9", + 100000000000000000 + ], + [ + "5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK", + 100000000000000000 + ], + [ + "5DiDShBWa1fQx6gLzpf3SFBhMinCoyvHM1BWjPNsmXS8hkrW", + 100000000000000000 + ], + [ + "5EFb84yH9tpcFuiKUcsmdoF7xeeY3ajG1ZLQimxQoFt9HMKR", + 100000000000000000 + ], + [ + "5DZLHESsfGrJ5YzT3HuRPXsSNb589xQ4Unubh1mYLodzKdVY", + 100000000000000000 + ], + [ + "5GHJzqvG6tXnngCpG7B12qjUvbo5e4e9z8Xjidk3CQZHxTPZ", + 100000000000000000 + ], + [ + "5CUnSsgAyLND3bxxnfNhgWXSe9Wn676JzLpGLgyJv858qhoX", + 100000000000000000 + ], + [ + "5CVKn7HAZW1Ky4r7Vkgsr7VEW88C2sHgUNDiwHY9Ct2hjU8q", + 100000000000000000 + ], + [ + "5H673aukQ4PeDe1U2nuv1bi32xDEziimh3PZz7hDdYUB7TNz", + 100000000000000000 + ], + [ + "5HTe9L15LJryjUAt1jZXZCBPnzbbGnpvFwbjE3NwCWaAqovf", + 100000000000000000 + ], + [ + "5D7LFzGpMwHPyDBavkRbWSKWTtJhCaPPZ379wWLT23bJwXJz", + 100000000000000000 + ], + [ + "5CLepMARnEgtVR1EkUuJVUvKh97gzergpSxUU3yKGx1v6EwC", + 100000000000000000 + ], + [ + "5Chb2UhfvZpmjjEziHbFbotM4quX32ZscRV6QJBt1rUKzz51", + 100000000000000000 + ], + [ + "5HmRp3i3ZZk7xsAvbi8hyXVP6whSMnBJGebVC4FsiZVhx52e", + 100000000000000000 + ], + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 100000000000000000 + ], + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 100000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 100000000000000000 + ] + ] + } +}