mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 19:01:08 +00:00
test-runtime: GenesisBuilder runtime API impl + tests (#14310)
* test-runtime: GenesisBuilder runtime API impl + tests This PR provides implementation of `GenesisBuilder` API for `substrate-test-runtime`, can be considered as reference imiplementation for other runtimes. The `GenesisBuilder` implementation is gated by `gensis-config` feature. Tested scenarios: - default `GenesisConfig` to JSON blob, - deserialization of `GenesisConfig` from custom JSON, and storing its keys into the Storage (genesis storage creation). - creation of genesis storage using partial JSON definition, - checking if invalid/renamed JSON files causes the runtime to panic, * missing file added * client: GenesisBuilder helper added * feature renamed: genesis-config -> genesis-builder * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml * redundant function removed * genesis builder helper: introduced RuntimeGenesisBuild * test-runtime: get rid of unused T * redundant bound removed * helper: use GenesisBuild again * tests adjusted for on_genesis * test-runtime: support for BuildGenesisConfig * helper: BuildGenesisConfig support * Update client/genesis-builder/src/lib.rs Co-authored-by: Davide Galassi <davxy@datawok.net> * Update test-utils/runtime/src/test_json/readme.md Co-authored-by: Davide Galassi <davxy@datawok.net> * Update test-utils/runtime/src/test_json/readme.md Co-authored-by: Davide Galassi <davxy@datawok.net> * Update test-utils/runtime/src/genesismap.rs Co-authored-by: Davide Galassi <davxy@datawok.net> * jsons are now human-friendly * fix * improvements * jsons fixed * helper: no_defaults added * test-runtime: no_defaults added * test-runtime: patching fn removed * helper: patching fn removed * helper: moved to frame_support * test-runtime: fixes * Cargo.lock updated * fmt + naming * test-runtime: WasmExecutor used * helper / test-runtime: struct removed * test-runtime: merge fixes * Cargo.lock + test-utils/runtime/Cargo.toml updated * doc fixed * client/rpc: test fixed (new rt api) * client/rpc-spec-v2: test fix * doc fix * test-runtime: disable-genesis-builder feature * fix * fix * ".git/.scripts/commands/fmt/fmt.sh" * test-runtime: rerun added to build script --------- Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: parity-processbot <>
This commit is contained in:
committed by
GitHub
parent
7fdcb83117
commit
53cbda1de6
Generated
+17
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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<GC: BuildGenesisConfig>() -> sp_std::vec::Vec<u8> {
|
||||
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<GC: BuildGenesisConfig>(json: sp_std::vec::Vec<u8>) -> BuildResult {
|
||||
let gc = serde_json::from_slice::<GC>(&json)
|
||||
.map_err(|e| format_runtime_string!("Invalid JSON blob: {}", e))?;
|
||||
<GC as BuildGenesisConfig>::build(&gc);
|
||||
Ok(())
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<AccountId>,
|
||||
endowed_accounts: Vec<AccountId>,
|
||||
@@ -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<Vec<u8>>) -> 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());
|
||||
|
||||
@@ -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<Block> for Runtime {
|
||||
fn create_default_config() -> Vec<u8> {
|
||||
create_default_config::<RuntimeGenesisConfig>()
|
||||
}
|
||||
|
||||
fn build_config(config: Vec<u8>) -> sp_genesis_builder::Result {
|
||||
build_config::<RuntimeGenesisConfig>(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) {
|
||||
@@ -850,24 +865,23 @@ pub mod storage_key_generator {
|
||||
}
|
||||
|
||||
let keys: Vec<Vec<&[u8]>> = 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::<Vec<String>>();
|
||||
|
||||
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<Vec<u8>> {
|
||||
let executor = WasmExecutor::<sp_io::SubstrateHostFunctions>::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::<Vec<String>>();
|
||||
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::<Vec<_>>();
|
||||
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::<u8>::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::<Vec<String>>();
|
||||
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::<u8>::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<u8> {
|
||||
storage.top.get(&array_bytes::hex2bytes(key).unwrap()).unwrap().clone()
|
||||
};
|
||||
|
||||
//SubstrateTest|Authorities
|
||||
let value: Vec<u8> = get_from_storage(
|
||||
"00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d",
|
||||
);
|
||||
let authority_key_vec =
|
||||
Vec::<sp_core::sr25519::Public>::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<u8> = 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<u8> = get_from_storage(
|
||||
"c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80",
|
||||
);
|
||||
assert_eq!(u64::decode(&mut &value[..]).unwrap(), 0);
|
||||
|
||||
// :code
|
||||
let value: Vec<u8> = get_from_storage("3a636f6465");
|
||||
assert!(Vec::<u8>::decode(&mut &value[..]).is_err());
|
||||
|
||||
//System|ParentHash
|
||||
let value: Vec<u8> = get_from_storage(
|
||||
"26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc",
|
||||
);
|
||||
assert_eq!(H256::decode(&mut &value[..]).unwrap(), [69u8; 32].into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user