From 67405850a9d1118548417cdb1cdafb4ec4541c91 Mon Sep 17 00:00:00 2001 From: DarkingLee Date: Tue, 5 Sep 2023 16:54:28 +0800 Subject: [PATCH] test: add frame-executive-ext test --- Cargo.lock | 265 +++- crates/auto-config/src/lib.rs | 4 +- crates/core-primitives/Cargo.toml | 23 + crates/core-primitives/src/lib.rs | 3 + crates/core-primitives/src/testing.rs | 419 ++++++ crates/frame-executive-ext/Cargo.toml | 34 +- crates/frame-executive-ext/src/lib.rs | 1967 +++++++++++++------------ node/src/chain_spec.rs | 2 +- 8 files changed, 1700 insertions(+), 1017 deletions(-) create mode 100644 crates/core-primitives/src/testing.rs diff --git a/Cargo.lock b/Cargo.lock index 5b164e9..7ab7374 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,6 +284,12 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" +[[package]] +name = "array-bytes" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" + [[package]] name = "arrayref" version = "0.3.7" @@ -548,6 +554,15 @@ dependencies = [ "serde", ] +[[package]] +name = "binary-merkle-tree" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "hash-db 0.16.0", + "log", +] + [[package]] name = "bincode" version = "1.3.3" @@ -992,6 +1007,15 @@ dependencies = [ "inout", ] +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" +dependencies = [ + "cfg-if", +] + [[package]] name = "clang-sys" version = "1.6.1" @@ -2338,7 +2362,7 @@ version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "Inflector", - "array-bytes", + "array-bytes 4.2.0", "chrono", "clap 4.4.1", "comfy-table", @@ -2407,39 +2431,27 @@ dependencies = [ "sp-std 5.0.0", ] -[[package]] -name = "frame-executive" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" -dependencies = [ - "frame-support 4.0.0-dev", - "frame-system 4.0.0-dev", - "parity-scale-codec", - "scale-info", - "sp-core 7.0.0", - "sp-io 7.0.0", - "sp-runtime 7.0.0", - "sp-std 5.0.0", - "sp-tracing 6.0.0", -] - [[package]] name = "frame-executive-ext" version = "4.0.0-dev" dependencies = [ - "frame-executive", + "array-bytes 6.1.0", "frame-support 4.0.0-dev", "frame-system 4.0.0-dev", "frame-system-ext", "frame-try-runtime", "melo-core-primitives", + "pallet-balances", + "pallet-transaction-payment", "parity-scale-codec", "scale-info", "sp-core 7.0.0", + "sp-inherents 4.0.0-dev", "sp-io 7.0.0", "sp-runtime 7.0.0", "sp-std 5.0.0", "sp-tracing 6.0.0", + "sp-version 5.0.0", ] [[package]] @@ -4589,14 +4601,21 @@ dependencies = [ "melo-das-primitives", "melo-erasure-coding", "parity-scale-codec", + "rand 0.8.5", "rayon", "scale-info", "serde", + "serde_json", "sp-api 4.0.0-dev", + "sp-application-crypto 7.0.0", "sp-core 7.0.0", "sp-io 7.0.0", "sp-runtime 7.0.0", + "sp-state-machine 0.13.0", "sp-std 5.0.0", + "sp-tracing 6.0.0", + "substrate-test-runtime-client", + "zstd 0.12.4", ] [[package]] @@ -5501,6 +5520,49 @@ dependencies = [ "sp-std 5.0.0", ] +[[package]] +name = "pallet-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "frame-support 4.0.0-dev", + "frame-system 4.0.0-dev", + "pallet-authorship", + "pallet-session 4.0.0-dev", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-beefy", + "sp-runtime 7.0.0", + "sp-session 4.0.0-dev", + "sp-staking 4.0.0-dev", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-beefy-mmr" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "array-bytes 4.2.0", + "binary-merkle-tree", + "frame-support 4.0.0-dev", + "frame-system 4.0.0-dev", + "log", + "pallet-beefy", + "pallet-mmr", + "pallet-session 4.0.0-dev", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 4.0.0-dev", + "sp-consensus-beefy", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-runtime 7.0.0", + "sp-std 5.0.0", +] + [[package]] name = "pallet-bounties" version = "4.0.0-dev" @@ -5670,6 +5732,23 @@ dependencies = [ "sp-std 5.0.0", ] +[[package]] +name = "pallet-mmr" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "frame-benchmarking 4.0.0-dev", + "frame-support 4.0.0-dev", + "frame-system 4.0.0-dev", + "parity-scale-codec", + "scale-info", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-mmr-primitives", + "sp-runtime 7.0.0", + "sp-std 5.0.0", +] + [[package]] name = "pallet-nomination-pools" version = "1.0.0" @@ -7374,7 +7453,7 @@ name = "sc-cli" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "chrono", "clap 4.4.1", "fdlimit", @@ -7563,7 +7642,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ahash 0.8.3", - "array-bytes", + "array-bytes 4.2.0", "async-trait", "dyn-clone", "finality-grandpa", @@ -7729,7 +7808,7 @@ name = "sc-keystore" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", "parking_lot 0.12.1", "serde_json", @@ -7744,7 +7823,7 @@ name = "sc-network" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-channel", "async-trait", "asynchronous-codec", @@ -7809,7 +7888,7 @@ name = "sc-network-common" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", "bitflags 1.3.2", "bytes", @@ -7856,7 +7935,7 @@ name = "sc-network-light" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "futures", "libp2p", "log", @@ -7878,7 +7957,7 @@ name = "sc-network-sync" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", "fork-tree", "futures", @@ -7912,7 +7991,7 @@ name = "sc-network-transactions" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "futures", "libp2p", "log", @@ -7932,7 +8011,7 @@ name = "sc-offchain" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "bytes", "fnv", "futures", @@ -8049,7 +8128,7 @@ name = "sc-rpc-spec-v2" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "futures", "futures-util", "hex", @@ -9029,6 +9108,25 @@ dependencies = [ "sp-timestamp 4.0.0-dev", ] +[[package]] +name = "sp-consensus-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "lazy_static", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 4.0.0-dev", + "sp-application-crypto 7.0.0", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-mmr-primitives", + "sp-runtime 7.0.0", + "sp-std 5.0.0", + "strum", +] + [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" @@ -9064,7 +9162,7 @@ name = "sp-core" version = "7.0.0" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "bitflags 1.3.2", "blake2", "bounded-collections", @@ -9109,7 +9207,7 @@ version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64002b155ecf2e000b65b777d392b9a79b2865823b17e4511cb131b45ba537cb" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "base58", "bitflags 1.3.2", "blake2", @@ -9400,6 +9498,24 @@ dependencies = [ "sp-std 5.0.0", ] +[[package]] +name = "sp-mmr-primitives" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "ckb-merkle-mountain-range", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api 4.0.0-dev", + "sp-core 7.0.0", + "sp-debug-derive 5.0.0", + "sp-runtime 7.0.0", + "sp-std 5.0.0", + "thiserror", +] + [[package]] name = "sp-npos-elections" version = "4.0.0-dev" @@ -10171,6 +10287,95 @@ dependencies = [ "sp-runtime 7.0.0", ] +[[package]] +name = "substrate-test-client" +version = "2.0.1" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "array-bytes 4.2.0", + "async-trait", + "futures", + "parity-scale-codec", + "sc-client-api", + "sc-client-db", + "sc-consensus", + "sc-executor", + "sc-offchain", + "sc-service", + "serde", + "serde_json", + "sp-blockchain", + "sp-consensus", + "sp-core 7.0.0", + "sp-keyring", + "sp-keystore 0.13.0", + "sp-runtime 7.0.0", + "sp-state-machine 0.13.0", +] + +[[package]] +name = "substrate-test-runtime" +version = "2.0.0" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "cfg-if", + "frame-support 4.0.0-dev", + "frame-system 4.0.0-dev", + "frame-system-rpc-runtime-api", + "log", + "memory-db 0.32.0", + "pallet-babe", + "pallet-beefy-mmr", + "pallet-timestamp 4.0.0-dev", + "parity-scale-codec", + "sc-service", + "scale-info", + "serde", + "sp-api 4.0.0-dev", + "sp-application-crypto 7.0.0", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-consensus-grandpa", + "sp-core 7.0.0", + "sp-externalities 0.13.0", + "sp-inherents 4.0.0-dev", + "sp-io 7.0.0", + "sp-keyring", + "sp-offchain", + "sp-runtime 7.0.0", + "sp-runtime-interface 7.0.0", + "sp-session 4.0.0-dev", + "sp-state-machine 0.13.0", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-trie 7.0.0", + "sp-version 5.0.0", + "substrate-wasm-builder", + "trie-db 0.27.1", +] + +[[package]] +name = "substrate-test-runtime-client" +version = "2.0.0" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "futures", + "parity-scale-codec", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-consensus", + "sp-api 4.0.0-dev", + "sp-blockchain", + "sp-consensus", + "sp-core 7.0.0", + "sp-runtime 7.0.0", + "substrate-test-client", + "substrate-test-runtime", +] + [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" diff --git a/crates/auto-config/src/lib.rs b/crates/auto-config/src/lib.rs index 666b2e9..fd42120 100644 --- a/crates/auto-config/src/lib.rs +++ b/crates/auto-config/src/lib.rs @@ -18,7 +18,7 @@ //! //! ## Example Usage //! -//! ```rust +//! ```ignore //! use melo_auto_config::auto_config; //! //! #[auto_config] @@ -33,7 +33,7 @@ //! - `skip_weight`: Skips the generation of `WeightInfo` type //! - `include_currency`: Includes the generation of `Currency` type //! -//! ```rust +//! ```ignore //! #[auto_config(skip_event, include_currency)] //! impl pallet_balances::Config for Runtime { //! // ... diff --git a/crates/core-primitives/Cargo.toml b/crates/core-primitives/Cargo.toml index d272d97..b67ea3f 100644 --- a/crates/core-primitives/Cargo.toml +++ b/crates/core-primitives/Cargo.toml @@ -25,11 +25,24 @@ sp-runtime = { version = "7.0.0", default-features = false, git = "https://githu sp-io = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } sp-api = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +# For testing +rand = { version = "0.8.5", optional = true } +sp-application-crypto = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } + +[dev-dependencies] +rand = "0.8.5" +serde_json = "1.0.85" +zstd = { version = "0.12.3", default-features = false } +sp-state-machine = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +sp-tracing = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } + [features] default = ["std"] std = [ "codec/std", "log/std", + "rand", "scale-info/std", "serde", "sp-core/std", @@ -39,7 +52,17 @@ std = [ "sp-std/std", "sp-api/std", "melo-das-primitives/serde", + "sp-state-machine/std", + "sp-tracing/std", + "sp-application-crypto/std", ] parallel = [ "melo-das-primitives/parallel", +] +# Serde support without relying on std features. +serde = [ + "dep:serde", + "scale-info/serde", + "sp-core/serde", + "sp-application-crypto/serde", ] \ No newline at end of file diff --git a/crates/core-primitives/src/lib.rs b/crates/core-primitives/src/lib.rs index 1060a4f..c402ab7 100644 --- a/crates/core-primitives/src/lib.rs +++ b/crates/core-primitives/src/lib.rs @@ -32,3 +32,6 @@ pub use sidercar::*; pub mod localstorage; pub mod traits; + +#[cfg(feature = "std")] +pub mod testing; diff --git a/crates/core-primitives/src/testing.rs b/crates/core-primitives/src/testing.rs new file mode 100644 index 0000000..9eb1adf --- /dev/null +++ b/crates/core-primitives/src/testing.rs @@ -0,0 +1,419 @@ +// 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. + +//! Testing utilities. +use crate::traits::ExtendedHeader; +use crate::traits::HeaderCommitList; +use crate::Header as HeaderT; +use melo_das_primitives::KZGCommitment; + +use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; +use sp_core::{ + crypto::{key_types, ByteArray, CryptoType, Dummy}, + U256, +}; +pub use sp_core::{sr25519, H256}; +use sp_runtime::{ + codec::{Codec, Decode, Encode, MaxEncodedLen}, + generic, + scale_info::TypeInfo, + traits::{ + self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys, + PostDispatchInfoOf, SignedExtension, ValidateUnsigned, + }, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, + ApplyExtrinsicResultWithInfo, KeyTypeId, +}; +use std::{ + cell::RefCell, + fmt::{self, Debug}, + ops::Deref, +}; + +pub struct CommitListTest(); + +impl HeaderCommitList for CommitListTest { + fn last() -> Vec { + vec![] + } +} + +/// A dummy type which can be used instead of regular cryptographic primitives. +/// +/// 1. Wraps a `u64` `AccountId` and is able to `IdentifyAccount`. +/// 2. Can be converted to any `Public` key. +/// 3. Implements `RuntimeAppPublic` so it can be used instead of regular application-specific +/// crypto. +#[derive( + Default, + PartialEq, + Eq, + Clone, + Encode, + Decode, + Debug, + Hash, + Serialize, + Deserialize, + PartialOrd, + Ord, + MaxEncodedLen, + TypeInfo, +)] +pub struct UintAuthorityId(pub u64); + +impl From for UintAuthorityId { + fn from(id: u64) -> Self { + UintAuthorityId(id) + } +} + +impl From for u64 { + fn from(id: UintAuthorityId) -> u64 { + id.0 + } +} + +impl UintAuthorityId { + /// Convert this authority ID into a public key. + pub fn to_public_key(&self) -> T { + let bytes: [u8; 32] = U256::from(self.0).into(); + T::from_slice(&bytes).unwrap() + } +} + +impl CryptoType for UintAuthorityId { + type Pair = Dummy; +} + +impl AsRef<[u8]> for UintAuthorityId { + fn as_ref(&self) -> &[u8] { + // Unsafe, i know, but it's test code and it's just there because it's really convenient to + // keep `UintAuthorityId` as a u64 under the hood. + unsafe { + std::slice::from_raw_parts( + &self.0 as *const u64 as *const _, + std::mem::size_of::(), + ) + } + } +} + +thread_local! { + /// A list of all UintAuthorityId keys returned to the runtime. + static ALL_KEYS: RefCell> = RefCell::new(vec![]); +} + +impl UintAuthorityId { + /// Set the list of keys returned by the runtime call for all keys of that type. + pub fn set_all_keys>(keys: impl IntoIterator) { + ALL_KEYS.with(|l| *l.borrow_mut() = keys.into_iter().map(Into::into).collect()) + } +} + +impl sp_application_crypto::RuntimeAppPublic for UintAuthorityId { + const ID: KeyTypeId = key_types::DUMMY; + + type Signature = TestSignature; + + fn all() -> Vec { + ALL_KEYS.with(|l| l.borrow().clone()) + } + + fn generate_pair(_: Option>) -> Self { + use rand::RngCore; + UintAuthorityId(rand::thread_rng().next_u64()) + } + + fn sign>(&self, msg: &M) -> Option { + Some(TestSignature(self.0, msg.as_ref().to_vec())) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + traits::Verify::verify(signature, msg.as_ref(), &self.0) + } + + fn to_raw_vec(&self) -> Vec { + AsRef::<[u8]>::as_ref(self).to_vec() + } +} + +impl OpaqueKeys for UintAuthorityId { + type KeyTypeIdProviders = (); + + fn key_ids() -> &'static [KeyTypeId] { + &[key_types::DUMMY] + } + + fn get_raw(&self, _: KeyTypeId) -> &[u8] { + self.as_ref() + } + + fn get(&self, _: KeyTypeId) -> Option { + self.using_encoded(|mut x| T::decode(&mut x)).ok() + } +} + +impl traits::IdentifyAccount for UintAuthorityId { + type AccountId = u64; + + fn into_account(self) -> Self::AccountId { + self.0 + } +} + +/// A dummy signature type, to match `UintAuthorityId`. +#[derive(Eq, PartialEq, Clone, Debug, Hash, Serialize, Deserialize, Encode, Decode, TypeInfo)] +pub struct TestSignature(pub u64, pub Vec); + +impl traits::Verify for TestSignature { + type Signer = UintAuthorityId; + + fn verify>(&self, mut msg: L, signer: &u64) -> bool { + signer == &self.0 && msg.get() == &self.1[..] + } +} + +/// Digest item +pub type DigestItem = generic::DigestItem; + +/// Header Digest +pub type Digest = generic::Digest; + +/// Block Header +pub type Header = HeaderT; + +impl Header { + /// A new header with the given number and default hash for all other fields. + pub fn new_from_number(number: ::Number) -> Self { + Self { + number, + extrinsics_root: Default::default(), + state_root: Default::default(), + parent_hash: Default::default(), + digest: Default::default(), + extension: Default::default(), + } + } +} + +/// An opaque extrinsic wrapper type. +#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] +pub struct ExtrinsicWrapper(Xt); + +impl traits::Extrinsic for ExtrinsicWrapper { + type Call = (); + type SignaturePayload = (); + + fn is_signed(&self) -> Option { + None + } +} + +impl serde::Serialize for ExtrinsicWrapper { + fn serialize(&self, seq: S) -> Result + where + S: ::serde::Serializer, + { + self.using_encoded(|bytes| seq.serialize_bytes(bytes)) + } +} + +impl From for ExtrinsicWrapper { + fn from(xt: Xt) -> Self { + ExtrinsicWrapper(xt) + } +} + +impl Deref for ExtrinsicWrapper { + type Target = Xt; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// Testing block +#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode)] +pub struct Block { + /// Block header + pub header: Header, + /// List of extrinsics + pub extrinsics: Vec, +} + +impl< + Xt: 'static + Codec + Sized + Send + Sync + Serialize + Clone + Eq + Debug + traits::Extrinsic, + > traits::Block for Block +{ + type Extrinsic = Xt; + type Header = Header; + type Hash =
::Hash; + + fn header(&self) -> &Self::Header { + &self.header + } + fn extrinsics(&self) -> &[Self::Extrinsic] { + &self.extrinsics[..] + } + fn deconstruct(self) -> (Self::Header, Vec) { + (self.header, self.extrinsics) + } + fn new(header: Self::Header, extrinsics: Vec) -> Self { + Block { header, extrinsics } + } + fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec { + (header, extrinsics).encode() + } +} + +impl<'a, Xt> Deserialize<'a> for Block +where + Block: Decode, +{ + fn deserialize>(de: D) -> Result { + let r = >::deserialize(de)?; + Decode::decode(&mut &r[..]) + .map_err(|e| DeError::custom(format!("Invalid value passed into decode: {}", e))) + } +} + +/// Test transaction, tuple of (sender, call, signed_extra) +/// with index only used if sender is some. +/// +/// If sender is some then the transaction is signed otherwise it is unsigned. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] +pub struct TestXt { + /// Signature of the extrinsic. + pub signature: Option<(u64, Extra)>, + /// Call of the extrinsic. + pub call: Call, +} + +impl TestXt { + /// Create a new `TextXt`. + pub fn new(call: Call, signature: Option<(u64, Extra)>) -> Self { + Self { call, signature } + } +} + +impl Serialize for TestXt +where + TestXt: Encode, +{ + fn serialize(&self, seq: S) -> Result + where + S: Serializer, + { + self.using_encoded(|bytes| seq.serialize_bytes(bytes)) + } +} + +impl Debug for TestXt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TestXt({:?}, ...)", self.signature.as_ref().map(|x| &x.0)) + } +} + +impl Checkable for TestXt { + type Checked = Self; + fn check(self, _: &Context) -> Result { + Ok(self) + } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + _: &Context, + ) -> Result { + unreachable!() + } +} + +impl traits::Extrinsic for TestXt { + type Call = Call; + type SignaturePayload = (u64, Extra); + + fn is_signed(&self) -> Option { + Some(self.signature.is_some()) + } + + fn new(c: Call, sig: Option) -> Option { + Some(TestXt { signature: sig, call: c }) + } +} + +impl traits::ExtrinsicMetadata for TestXt +where + Call: Codec + Sync + Send, + Extra: SignedExtension, +{ + type SignedExtensions = Extra; + const VERSION: u8 = 0u8; +} + +impl Applyable for TestXt +where + Call: 'static + + Sized + + Send + + Sync + + Clone + + Eq + + Codec + + Debug + + Dispatchable, + Extra: SignedExtension, + Origin: From>, +{ + type Call = Call; + + /// Checks to see if this is a valid *transaction*. It returns information on it if so. + fn validate>( + &self, + source: TransactionSource, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + if let Some((ref id, ref extra)) = self.signature { + Extra::validate(extra, id, &self.call, info, len) + } else { + let valid = Extra::validate_unsigned(&self.call, info, len)?; + let unsigned_validation = U::validate_unsigned(source, &self.call)?; + Ok(valid.combine_with(unsigned_validation)) + } + } + + /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, + /// index and sender. + fn apply>( + self, + info: &DispatchInfoOf, + len: usize, + ) -> ApplyExtrinsicResultWithInfo> { + let maybe_who = if let Some((who, extra)) = self.signature { + Extra::pre_dispatch(extra, &who, &self.call, info, len)?; + Some(who) + } else { + Extra::pre_dispatch_unsigned(&self.call, info, len)?; + U::pre_dispatch(&self.call)?; + None + }; + + Ok(self.call.dispatch(maybe_who.into())) + } +} diff --git a/crates/frame-executive-ext/Cargo.toml b/crates/frame-executive-ext/Cargo.toml index 114b8fb..ef54897 100644 --- a/crates/frame-executive-ext/Cargo.toml +++ b/crates/frame-executive-ext/Cargo.toml @@ -16,12 +16,8 @@ targets = ["x86_64-unknown-linux-gnu"] frame-system-ext = { version = "4.0.0-dev", default-features = false, path = "../frame-system-ext"} melo-core-primitives = { version = "0.1.0", default-features = false, path = "../core-primitives"} -frame-executive = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42"} sp-std = { version = "5.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } - -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ - "derive", -] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive",] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42"} frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42"} @@ -32,11 +28,33 @@ sp-runtime = { version = "7.0.0", default-features = false, git = "https://githu sp-tracing = { version = "6.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42"} [dev-dependencies] +array-bytes = "6.1" +pallet-balances = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +sp-inherents = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } +sp-version = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } [features] default = ["std"] +with-tracing = ["sp-tracing/with-tracing"] std = [ - -] -try-runtime = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-tracing/std", + "pallet-balances/std", + "pallet-transaction-payment/std", + "sp-inherents/std", + "sp-version/std", + "frame-try-runtime?/std", + # For frame-system-ext + "frame-system-ext/std", + "melo-core-primitives/std", + ] +try-runtime = ["frame-support/try-runtime", "frame-try-runtime/try-runtime", "sp-runtime/try-runtime"] diff --git a/crates/frame-executive-ext/src/lib.rs b/crates/frame-executive-ext/src/lib.rs index 7ce96b0..b266af0 100644 --- a/crates/frame-executive-ext/src/lib.rs +++ b/crates/frame-executive-ext/src/lib.rs @@ -53,7 +53,7 @@ //! //! ``` //! # use sp_runtime::generic; -//! # use frame_executive as executive; +//! # use frame_executive_ext as executive; //! # pub struct UncheckedExtrinsic {}; //! # pub struct Header {}; //! # type Context = frame_system::ChainContext; @@ -84,7 +84,7 @@ //! //! ``` //! # use sp_runtime::generic; -//! # use frame_executive as executive; +//! # use frame_executive_ext as executive; //! # pub struct UncheckedExtrinsic {}; //! # pub struct Header {}; //! # type Context = frame_system::ChainContext; @@ -284,7 +284,7 @@ where e, err, ); - break + break; } } @@ -458,9 +458,9 @@ where // Check that `parent_hash` is correct. let n = *header.number(); assert!( - n > System::BlockNumber::zero() && - >::block_hash(n - System::BlockNumber::one()) == - *header.parent_hash(), + n > System::BlockNumber::zero() + && >::block_hash(n - System::BlockNumber::one()) + == *header.parent_hash(), "Parent hash should be valid.", ); @@ -568,7 +568,7 @@ where // The entire block should be discarded if an inherent fails to apply. Otherwise // it may open an attack vector. if r.is_err() && dispatch_info.class == DispatchClass::Mandatory { - return Err(InvalidTransaction::BadMandatory.into()) + return Err(InvalidTransaction::BadMandatory.into()); } >::note_applied_extrinsic(&r, dispatch_info); @@ -638,7 +638,7 @@ where }; if dispatch_info.class == DispatchClass::Mandatory { - return Err(InvalidTransaction::MandatoryValidation.into()) + return Err(InvalidTransaction::MandatoryValidation.into()); } within_span! { @@ -668,971 +668,986 @@ where } } -// #[cfg(test)] -// mod tests { -// use super::*; - -// use sp_core::H256; -// use sp_runtime::{ -// generic::{DigestItem, Era}, -// testing::{Block, Digest, Header}, -// traits::{BlakeTwo256, Block as BlockT, Header as HeaderT, IdentityLookup}, -// transaction_validity::{ -// InvalidTransaction, TransactionValidityError, UnknownTransaction, ValidTransaction, -// }, -// DispatchError, -// }; - -// use frame_support::{ -// assert_err, parameter_types, -// traits::{fungible, ConstU32, ConstU64, ConstU8, Currency}, -// weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, -// }; -// use frame_system::{ChainContext, LastRuntimeUpgradeInfo}; -// use pallet_balances::Call as BalancesCall; -// use pallet_transaction_payment::CurrencyAdapter; - -// const TEST_KEY: &[u8] = b":test:key:"; - -// #[frame_support::pallet(dev_mode)] -// mod custom { -// use frame_support::pallet_prelude::*; -// use frame_system::pallet_prelude::*; - -// #[pallet::pallet] -// pub struct Pallet(_); - -// #[pallet::config] -// pub trait Config: frame_system::Config {} - -// #[pallet::hooks] -// impl Hooks> for Pallet { -// // module hooks. -// // one with block number arg and one without -// fn on_initialize(n: T::BlockNumber) -> Weight { -// println!("on_initialize({})", n); -// Weight::from_parts(175, 0) -// } - -// fn on_idle(n: T::BlockNumber, remaining_weight: Weight) -> Weight { -// println!("on_idle{}, {})", n, remaining_weight); -// Weight::from_parts(175, 0) -// } - -// fn on_finalize(n: T::BlockNumber) { -// println!("on_finalize({})", n); -// } - -// fn on_runtime_upgrade() -> Weight { -// sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); -// Weight::from_parts(200, 0) -// } - -// fn offchain_worker(n: T::BlockNumber) { -// assert_eq!(T::BlockNumber::from(1u32), n); -// } -// } - -// #[pallet::call] -// impl Pallet { -// #[pallet::call_index(0)] -// #[pallet::weight(100)] -// pub fn some_function(origin: OriginFor) -> DispatchResult { -// // NOTE: does not make any different. -// frame_system::ensure_signed(origin)?; -// Ok(()) -// } - -// #[pallet::call_index(1)] -// #[pallet::weight((200, DispatchClass::Operational))] -// pub fn some_root_operation(origin: OriginFor) -> DispatchResult { -// frame_system::ensure_root(origin)?; -// Ok(()) -// } - -// #[pallet::call_index(2)] -// #[pallet::weight(0)] -// pub fn some_unsigned_message(origin: OriginFor) -> DispatchResult { -// frame_system::ensure_none(origin)?; -// Ok(()) -// } - -// #[pallet::call_index(3)] -// #[pallet::weight(0)] -// pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { -// frame_system::ensure_root(origin)?; -// Ok(()) -// } - -// #[pallet::call_index(4)] -// #[pallet::weight(0)] -// pub fn unallowed_unsigned(origin: OriginFor) -> DispatchResult { -// frame_system::ensure_root(origin)?; -// Ok(()) -// } - -// #[pallet::call_index(5)] -// #[pallet::weight((0, DispatchClass::Mandatory))] -// pub fn inherent_call(origin: OriginFor) -> DispatchResult { -// frame_system::ensure_none(origin)?; -// Ok(()) -// } - -// #[pallet::call_index(6)] -// #[pallet::weight(0)] -// pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { -// let root = sp_io::storage::root(sp_runtime::StateVersion::V1); -// sp_io::storage::set("storage_root".as_bytes(), &root); -// Ok(()) -// } -// } - -// #[pallet::inherent] -// impl ProvideInherent for Pallet { -// type Call = Call; - -// type Error = sp_inherents::MakeFatalError<()>; - -// const INHERENT_IDENTIFIER: [u8; 8] = *b"test1234"; - -// fn create_inherent(_data: &InherentData) -> Option { -// None -// } - -// fn is_inherent(call: &Self::Call) -> bool { -// *call == Call::::inherent_call {} -// } -// } - -// #[pallet::validate_unsigned] -// impl ValidateUnsigned for Pallet { -// type Call = Call; - -// // Inherent call is accepted for being dispatched -// fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { -// match call { -// Call::allowed_unsigned { .. } => Ok(()), -// Call::inherent_call { .. } => Ok(()), -// _ => Err(UnknownTransaction::NoUnsignedValidator.into()), -// } -// } - -// // Inherent call is not validated as unsigned -// fn validate_unsigned( -// _source: TransactionSource, -// call: &Self::Call, -// ) -> TransactionValidity { -// match call { -// Call::allowed_unsigned { .. } => Ok(Default::default()), -// _ => UnknownTransaction::NoUnsignedValidator.into(), -// } -// } -// } -// } - -// frame_support::construct_runtime!( -// pub struct Runtime where -// Block = TestBlock, -// NodeBlock = TestBlock, -// UncheckedExtrinsic = TestUncheckedExtrinsic -// { -// System: frame_system::{Pallet, Call, Config, Storage, Event}, -// Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, -// TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, -// Custom: custom::{Pallet, Call, ValidateUnsigned, Inherent}, -// } -// ); - -// parameter_types! { -// pub BlockWeights: frame_system::limits::BlockWeights = -// frame_system::limits::BlockWeights::builder() -// .base_block(Weight::from_parts(10, 0)) -// .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_parts(5, 0)) -// .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_parts(1024, u64::MAX).into()) -// .build_or_panic(); -// pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { -// read: 10, -// write: 100, -// }; -// } -// impl frame_system::Config for Runtime { -// type BaseCallFilter = frame_support::traits::Everything; -// type BlockWeights = BlockWeights; -// type BlockLength = (); -// type DbWeight = (); -// type RuntimeOrigin = RuntimeOrigin; -// type Index = u64; -// type RuntimeCall = RuntimeCall; -// type BlockNumber = u64; -// type Hash = sp_core::H256; -// type Hashing = BlakeTwo256; -// type AccountId = u64; -// type Lookup = IdentityLookup; -// type Header = Header; -// type RuntimeEvent = RuntimeEvent; -// type BlockHashCount = ConstU64<250>; -// type Version = RuntimeVersion; -// type PalletInfo = PalletInfo; -// type AccountData = pallet_balances::AccountData; -// type OnNewAccount = (); -// type OnKilledAccount = (); -// type SystemWeightInfo = (); -// type SS58Prefix = (); -// type OnSetCode = (); -// type MaxConsumers = ConstU32<16>; -// } - -// type Balance = u64; -// impl pallet_balances::Config for Runtime { -// type Balance = Balance; -// type RuntimeEvent = RuntimeEvent; -// type DustRemoval = (); -// type ExistentialDeposit = ConstU64<1>; -// type AccountStore = System; -// type MaxLocks = (); -// type MaxReserves = (); -// type ReserveIdentifier = [u8; 8]; -// type WeightInfo = (); -// type FreezeIdentifier = (); -// type MaxFreezes = ConstU32<1>; -// type HoldIdentifier = (); -// type MaxHolds = ConstU32<1>; -// } - -// parameter_types! { -// pub const TransactionByteFee: Balance = 0; -// } -// impl pallet_transaction_payment::Config for Runtime { -// type RuntimeEvent = RuntimeEvent; -// type OnChargeTransaction = CurrencyAdapter; -// type OperationalFeeMultiplier = ConstU8<5>; -// type WeightToFee = IdentityFee; -// type LengthToFee = ConstantMultiplier; -// type FeeMultiplierUpdate = (); -// } -// impl custom::Config for Runtime {} - -// pub struct RuntimeVersion; -// impl frame_support::traits::Get for RuntimeVersion { -// fn get() -> sp_version::RuntimeVersion { -// RuntimeVersionTestValues::get().clone() -// } -// } - -// parameter_types! { -// pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = -// Default::default(); -// } - -// type SignedExtra = ( -// frame_system::CheckEra, -// frame_system::CheckNonce, -// frame_system::CheckWeight, -// pallet_transaction_payment::ChargeTransactionPayment, -// ); -// type TestXt = sp_runtime::testing::TestXt; -// type TestBlock = Block; -// type TestUncheckedExtrinsic = TestXt; - -// // Will contain `true` when the custom runtime logic was called. -// const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; - -// struct CustomOnRuntimeUpgrade; -// impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { -// fn on_runtime_upgrade() -> Weight { -// sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); -// sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); -// System::deposit_event(frame_system::Event::CodeUpdated); -// Weight::from_parts(100, 0) -// } -// } - -// type Executive = super::Executive< -// Runtime, -// Block, -// ChainContext, -// Runtime, -// AllPalletsWithSystem, -// CustomOnRuntimeUpgrade, -// >; - -// fn extra(nonce: u64, fee: Balance) -> SignedExtra { -// ( -// frame_system::CheckEra::from(Era::Immortal), -// frame_system::CheckNonce::from(nonce), -// frame_system::CheckWeight::new(), -// pallet_transaction_payment::ChargeTransactionPayment::from(fee), -// ) -// } - -// fn sign_extra(who: u64, nonce: u64, fee: Balance) -> Option<(u64, SignedExtra)> { -// Some((who, extra(nonce, fee))) -// } - -// fn call_transfer(dest: u64, value: u64) -> RuntimeCall { -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) -// } - -// #[test] -// fn balance_transfer_dispatch_works() { -// let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); -// pallet_balances::GenesisConfig:: { balances: vec![(1, 211)] } -// .assimilate_storage(&mut t) -// .unwrap(); -// let xt = TestXt::new(call_transfer(2, 69), sign_extra(1, 0, 0)); -// let weight = xt.get_dispatch_info().weight + -// ::BlockWeights::get() -// .get(DispatchClass::Normal) -// .base_extrinsic; -// let fee: Balance = -// ::WeightToFee::weight_to_fee(&weight); -// let mut t = sp_io::TestExternalities::new(t); -// t.execute_with(|| { -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); -// let r = Executive::apply_extrinsic(xt); -// assert!(r.is_ok()); -// assert_eq!(>::total_balance(&1), 142 - fee); -// assert_eq!(>::total_balance(&2), 69); -// }); -// } - -// fn new_test_ext(balance_factor: Balance) -> sp_io::TestExternalities { -// let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); -// pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } -// .assimilate_storage(&mut t) -// .unwrap(); -// t.into() -// } - -// fn new_test_ext_v0(balance_factor: Balance) -> sp_io::TestExternalities { -// let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); -// pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } -// .assimilate_storage(&mut t) -// .unwrap(); -// (t, sp_runtime::StateVersion::V0).into() -// } - -// #[test] -// fn block_import_works() { -// block_import_works_inner( -// new_test_ext_v0(1), -// array_bytes::hex_n_into_unchecked( -// "65e953676859e7a33245908af7ad3637d6861eb90416d433d485e95e2dd174a1", -// ), -// ); -// block_import_works_inner( -// new_test_ext(1), -// array_bytes::hex_n_into_unchecked( -// "5a19b3d6fdb7241836349fdcbe2d9df4d4f945b949d979e31ad50bff1cbcd1c2", -// ), -// ); -// } -// fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { -// ext.execute_with(|| { -// Executive::execute_block(Block { -// header: Header { -// parent_hash: [69u8; 32].into(), -// number: 1, -// state_root, -// extrinsics_root: array_bytes::hex_n_into_unchecked( -// "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", -// ), -// digest: Digest { logs: vec![] }, -// }, -// extrinsics: vec![], -// }); -// }); -// } - -// #[test] -// #[should_panic] -// fn block_import_of_bad_state_root_fails() { -// new_test_ext(1).execute_with(|| { -// Executive::execute_block(Block { -// header: Header { -// parent_hash: [69u8; 32].into(), -// number: 1, -// state_root: [0u8; 32].into(), -// extrinsics_root: array_bytes::hex_n_into_unchecked( -// "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", -// ), -// digest: Digest { logs: vec![] }, -// }, -// extrinsics: vec![], -// }); -// }); -// } - -// #[test] -// #[should_panic] -// fn block_import_of_bad_extrinsic_root_fails() { -// new_test_ext(1).execute_with(|| { -// Executive::execute_block(Block { -// header: Header { -// parent_hash: [69u8; 32].into(), -// number: 1, -// state_root: array_bytes::hex_n_into_unchecked( -// "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", -// ), -// extrinsics_root: [0u8; 32].into(), -// digest: Digest { logs: vec![] }, -// }, -// extrinsics: vec![], -// }); -// }); -// } - -// #[test] -// fn bad_extrinsic_not_inserted() { -// let mut t = new_test_ext(1); -// // bad nonce check! -// let xt = TestXt::new(call_transfer(33, 69), sign_extra(1, 30, 0)); -// t.execute_with(|| { -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); -// assert_err!( -// Executive::apply_extrinsic(xt), -// TransactionValidityError::Invalid(InvalidTransaction::Future) -// ); -// assert_eq!(>::extrinsic_index(), Some(0)); -// }); -// } - -// #[test] -// fn block_weight_limit_enforced() { -// let mut t = new_test_ext(10000); -// // given: TestXt uses the encoded len as fixed Len: -// let xt = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), -// sign_extra(1, 0, 0), -// ); -// let encoded = xt.encode(); -// let encoded_len = encoded.len() as u64; -// // on_initialize weight + base block execution weight -// let block_weights = ::BlockWeights::get(); -// let base_block_weight = Weight::from_parts(175, 0) + block_weights.base_block; -// let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight; -// let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5); -// t.execute_with(|| { -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); -// // Base block execution weight + `on_initialize` weight from the custom module. -// assert_eq!(>::block_weight().total(), base_block_weight); - -// for nonce in 0..=num_to_exhaust_block { -// let xt = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { -// dest: 33, -// value: 0, -// }), -// sign_extra(1, nonce.into(), 0), -// ); -// let res = Executive::apply_extrinsic(xt); -// if nonce != num_to_exhaust_block { -// assert!(res.is_ok()); -// assert_eq!( -// >::block_weight().total(), -// //--------------------- on_initialize + block_execution + extrinsic_base weight -// Weight::from_parts((encoded_len + 5) * (nonce + 1), 0) + base_block_weight, -// ); -// assert_eq!( -// >::extrinsic_index(), -// Some(nonce as u32 + 1) -// ); -// } else { -// assert_eq!(res, Err(InvalidTransaction::ExhaustsResources.into())); -// } -// } -// }); -// } - -// #[test] -// fn block_weight_and_size_is_stored_per_tx() { -// let xt = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), -// sign_extra(1, 0, 0), -// ); -// let x1 = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), -// sign_extra(1, 1, 0), -// ); -// let x2 = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), -// sign_extra(1, 2, 0), -// ); -// let len = xt.clone().encode().len() as u32; -// let mut t = new_test_ext(1); -// t.execute_with(|| { -// // Block execution weight + on_initialize weight from custom module -// let base_block_weight = Weight::from_parts(175, 0) + -// ::BlockWeights::get().base_block; - -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// assert_eq!(>::block_weight().total(), base_block_weight); -// assert_eq!(>::all_extrinsics_len(), 0); - -// assert!(Executive::apply_extrinsic(xt.clone()).unwrap().is_ok()); -// assert!(Executive::apply_extrinsic(x1.clone()).unwrap().is_ok()); -// assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); - -// // default weight for `TestXt` == encoded length. -// let extrinsic_weight = Weight::from_parts(len as u64, 0) + -// ::BlockWeights::get() -// .get(DispatchClass::Normal) -// .base_extrinsic; -// assert_eq!( -// >::block_weight().total(), -// base_block_weight + 3u64 * extrinsic_weight, -// ); -// assert_eq!(>::all_extrinsics_len(), 3 * len); - -// let _ = >::finalize(); -// // All extrinsics length cleaned on `System::finalize` -// assert_eq!(>::all_extrinsics_len(), 0); - -// // New Block -// Executive::initialize_block(&Header::new( -// 2, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// // Block weight cleaned up on `System::initialize` -// assert_eq!(>::block_weight().total(), base_block_weight); -// }); -// } - -// #[test] -// fn validate_unsigned() { -// let valid = TestXt::new(RuntimeCall::Custom(custom::Call::allowed_unsigned {}), None); -// let invalid = TestXt::new(RuntimeCall::Custom(custom::Call::unallowed_unsigned {}), None); -// let mut t = new_test_ext(1); - -// t.execute_with(|| { -// assert_eq!( -// Executive::validate_transaction( -// TransactionSource::InBlock, -// valid.clone(), -// Default::default(), -// ), -// Ok(ValidTransaction::default()), -// ); -// assert_eq!( -// Executive::validate_transaction( -// TransactionSource::InBlock, -// invalid.clone(), -// Default::default(), -// ), -// Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)), -// ); -// assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin))); -// assert_eq!( -// Executive::apply_extrinsic(invalid), -// Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)) -// ); -// }); -// } - -// #[test] -// fn can_not_pay_for_tx_fee_on_full_lock() { -// let mut t = new_test_ext(1); -// t.execute_with(|| { -// as fungible::MutateFreeze>::set_freeze( -// &(), -// &1, -// 110, -// ) -// .unwrap(); -// let xt = TestXt::new( -// RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), -// sign_extra(1, 0, 0), -// ); -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// assert_eq!(Executive::apply_extrinsic(xt), Err(InvalidTransaction::Payment.into()),); -// assert_eq!(>::total_balance(&1), 111); -// }); -// } - -// #[test] -// fn block_hooks_weight_is_stored() { -// new_test_ext(1).execute_with(|| { -// Executive::initialize_block(&Header::new_from_number(1)); -// Executive::finalize_block(); -// // NOTE: might need updates over time if new weights are introduced. -// // For now it only accounts for the base block execution weight and -// // the `on_initialize` weight defined in the custom test module. -// assert_eq!( -// >::block_weight().total(), -// Weight::from_parts(175 + 175 + 10, 0) -// ); -// }) -// } - -// #[test] -// fn runtime_upgraded_should_work() { -// new_test_ext(1).execute_with(|| { -// RuntimeVersionTestValues::mutate(|v| *v = Default::default()); -// // It should be added at genesis -// assert!(frame_system::LastRuntimeUpgrade::::exists()); -// assert!(!Executive::runtime_upgraded()); - -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } -// }); -// assert!(Executive::runtime_upgraded()); -// assert_eq!( -// Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "".into() }), -// frame_system::LastRuntimeUpgrade::::get(), -// ); - -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { -// spec_version: 1, -// spec_name: "test".into(), -// ..Default::default() -// } -// }); -// assert!(Executive::runtime_upgraded()); -// assert_eq!( -// Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }), -// frame_system::LastRuntimeUpgrade::::get(), -// ); - -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { -// spec_version: 1, -// spec_name: "test".into(), -// impl_version: 2, -// ..Default::default() -// } -// }); -// assert!(!Executive::runtime_upgraded()); - -// frame_system::LastRuntimeUpgrade::::take(); -// assert!(Executive::runtime_upgraded()); -// assert_eq!( -// Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }), -// frame_system::LastRuntimeUpgrade::::get(), -// ); -// }) -// } - -// #[test] -// fn last_runtime_upgrade_was_upgraded_works() { -// let test_data = vec![ -// (0, "", 1, "", true), -// (1, "", 1, "", false), -// (1, "", 1, "test", true), -// (1, "", 0, "", false), -// (1, "", 0, "test", true), -// ]; - -// for (spec_version, spec_name, c_spec_version, c_spec_name, result) in test_data { -// let current = sp_version::RuntimeVersion { -// spec_version: c_spec_version, -// spec_name: c_spec_name.into(), -// ..Default::default() -// }; - -// let last = LastRuntimeUpgradeInfo { -// spec_version: spec_version.into(), -// spec_name: spec_name.into(), -// }; - -// assert_eq!(result, last.was_upgraded(¤t)); -// } -// } - -// #[test] -// fn custom_runtime_upgrade_is_called_before_modules() { -// new_test_ext(1).execute_with(|| { -// // Make sure `on_runtime_upgrade` is called. -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } -// }); - -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); -// assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); -// }); -// } - -// #[test] -// fn event_from_runtime_upgrade_is_included() { -// new_test_ext(1).execute_with(|| { -// // Make sure `on_runtime_upgrade` is called. -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } -// }); - -// // set block number to non zero so events are not excluded -// System::set_block_number(1); - -// Executive::initialize_block(&Header::new( -// 2, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// System::assert_last_event(frame_system::Event::::CodeUpdated.into()); -// }); -// } - -// /// Regression test that ensures that the custom on runtime upgrade is called when executive is -// /// used through the `ExecuteBlock` trait. -// #[test] -// fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { -// let xt = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), -// sign_extra(1, 0, 0), -// ); - -// let header = new_test_ext(1).execute_with(|| { -// // Make sure `on_runtime_upgrade` is called. -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } -// }); - -// // Let's build some fake block. -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); - -// Executive::finalize_block() -// }); - -// // Reset to get the correct new genesis below. -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } -// }); - -// new_test_ext(1).execute_with(|| { -// // Make sure `on_runtime_upgrade` is called. -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } -// }); - -// >>::execute_block(Block::new(header, vec![xt])); - -// assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); -// assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); -// }); -// } - -// #[test] -// fn all_weights_are_recorded_correctly() { -// new_test_ext(1).execute_with(|| { -// // Make sure `on_runtime_upgrade` is called for maximum complexity -// RuntimeVersionTestValues::mutate(|v| { -// *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } -// }); - -// let block_number = 1; - -// Executive::initialize_block(&Header::new( -// block_number, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// // All weights that show up in the `initialize_block_impl` -// let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade(); -// let runtime_upgrade_weight = -// ::on_runtime_upgrade(); -// let on_initialize_weight = -// >::on_initialize(block_number); -// let base_block_weight = -// ::BlockWeights::get().base_block; - -// // Weights are recorded correctly -// assert_eq!( -// frame_system::Pallet::::block_weight().total(), -// custom_runtime_upgrade_weight + -// runtime_upgrade_weight + -// on_initialize_weight + base_block_weight, -// ); -// }); -// } - -// #[test] -// fn offchain_worker_works_as_expected() { -// new_test_ext(1).execute_with(|| { -// let parent_hash = sp_core::H256::from([69u8; 32]); -// let mut digest = Digest::default(); -// digest.push(DigestItem::Seal([1, 2, 3, 4], vec![5, 6, 7, 8])); - -// let header = -// Header::new(1, H256::default(), H256::default(), parent_hash, digest.clone()); - -// Executive::offchain_worker(&header); - -// assert_eq!(digest, System::digest()); -// assert_eq!(parent_hash, System::block_hash(0)); -// assert_eq!(header.hash(), System::block_hash(1)); -// }); -// } - -// #[test] -// fn calculating_storage_root_twice_works() { -// let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); -// let xt = TestXt::new(call, sign_extra(1, 0, 0)); - -// let header = new_test_ext(1).execute_with(|| { -// // Let's build some fake block. -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); - -// Executive::finalize_block() -// }); - -// new_test_ext(1).execute_with(|| { -// Executive::execute_block(Block::new(header, vec![xt])); -// }); -// } - -// #[test] -// #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] -// fn invalid_inherent_position_fail() { -// let xt1 = TestXt::new( -// RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), -// sign_extra(1, 0, 0), -// ); -// let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); - -// let header = new_test_ext(1).execute_with(|| { -// // Let's build some fake block. -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); -// Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); - -// Executive::finalize_block() -// }); - -// new_test_ext(1).execute_with(|| { -// Executive::execute_block(Block::new(header, vec![xt1, xt2])); -// }); -// } - -// #[test] -// fn valid_inherents_position_works() { -// let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); -// let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); - -// let header = new_test_ext(1).execute_with(|| { -// // Let's build some fake block. -// Executive::initialize_block(&Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// )); - -// Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); -// Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); - -// Executive::finalize_block() -// }); - -// new_test_ext(1).execute_with(|| { -// Executive::execute_block(Block::new(header, vec![xt1, xt2])); -// }); -// } - -// #[test] -// #[should_panic(expected = "A call was labelled as mandatory, but resulted in an Error.")] -// fn invalid_inherents_fail_block_execution() { -// let xt1 = -// TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), sign_extra(1, 0, 0)); - -// new_test_ext(1).execute_with(|| { -// Executive::execute_block(Block::new( -// Header::new( -// 1, -// H256::default(), -// H256::default(), -// [69u8; 32].into(), -// Digest::default(), -// ), -// vec![xt1], -// )); -// }); -// } - -// // Inherents are created by the runtime and don't need to be validated. -// #[test] -// fn inherents_fail_validate_block() { -// let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); - -// new_test_ext(1).execute_with(|| { -// assert_eq!( -// Executive::validate_transaction(TransactionSource::External, xt1, H256::random()) -// .unwrap_err(), -// InvalidTransaction::MandatoryValidation.into() -// ); -// }) -// } -// } +#[cfg(test)] +mod tests { + use super::*; + + use sp_core::H256; + use sp_runtime::{ + generic::{DigestItem, Era}, + traits::{BlakeTwo256, Block as BlockT, Header as HeaderT, IdentityLookup}, + transaction_validity::{ + InvalidTransaction, TransactionValidityError, UnknownTransaction, ValidTransaction, + }, + DispatchError, + }; + + use frame_support::{ + assert_err, parameter_types, + traits::{fungible, ConstU32, ConstU64, ConstU8, Currency}, + weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee}, + }; + use frame_system::{ChainContext, LastRuntimeUpgradeInfo}; + use pallet_balances::Call as BalancesCall; + use pallet_transaction_payment::CurrencyAdapter; + + use melo_core_primitives::{ + testing::{Block, Digest, CommitListTest}, + Header as ExtendedHeader, + }; + + const TEST_KEY: &[u8] = b":test:key:"; + + #[frame_support::pallet(dev_mode)] + mod custom { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::hooks] + impl Hooks> for Pallet { + // module hooks. + // one with block number arg and one without + fn on_initialize(n: T::BlockNumber) -> Weight { + println!("on_initialize({})", n); + Weight::from_parts(175, 0) + } + + fn on_idle(n: T::BlockNumber, remaining_weight: Weight) -> Weight { + println!("on_idle{}, {})", n, remaining_weight); + Weight::from_parts(175, 0) + } + + fn on_finalize(n: T::BlockNumber) { + println!("on_finalize({})", n); + } + + fn on_runtime_upgrade() -> Weight { + sp_io::storage::set(super::TEST_KEY, "module".as_bytes()); + Weight::from_parts(200, 0) + } + + fn offchain_worker(n: T::BlockNumber) { + assert_eq!(T::BlockNumber::from(1u32), n); + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(100)] + pub fn some_function(origin: OriginFor) -> DispatchResult { + // NOTE: does not make any different. + frame_system::ensure_signed(origin)?; + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight((200, DispatchClass::Operational))] + pub fn some_root_operation(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(0)] + pub fn some_unsigned_message(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + Ok(()) + } + + #[pallet::call_index(3)] + #[pallet::weight(0)] + pub fn allowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + #[pallet::call_index(4)] + #[pallet::weight(0)] + pub fn unallowed_unsigned(origin: OriginFor) -> DispatchResult { + frame_system::ensure_root(origin)?; + Ok(()) + } + + #[pallet::call_index(5)] + #[pallet::weight((0, DispatchClass::Mandatory))] + pub fn inherent_call(origin: OriginFor) -> DispatchResult { + frame_system::ensure_none(origin)?; + Ok(()) + } + + #[pallet::call_index(6)] + #[pallet::weight(0)] + pub fn calculate_storage_root(_origin: OriginFor) -> DispatchResult { + let root = sp_io::storage::root(sp_runtime::StateVersion::V1); + sp_io::storage::set("storage_root".as_bytes(), &root); + Ok(()) + } + } + + #[pallet::inherent] + impl ProvideInherent for Pallet { + type Call = Call; + + type Error = sp_inherents::MakeFatalError<()>; + + const INHERENT_IDENTIFIER: [u8; 8] = *b"test1234"; + + fn create_inherent(_data: &InherentData) -> Option { + None + } + + fn is_inherent(call: &Self::Call) -> bool { + *call == Call::::inherent_call {} + } + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + // Inherent call is accepted for being dispatched + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + match call { + Call::allowed_unsigned { .. } => Ok(()), + Call::inherent_call { .. } => Ok(()), + _ => Err(UnknownTransaction::NoUnsignedValidator.into()), + } + } + + // Inherent call is not validated as unsigned + fn validate_unsigned( + _source: TransactionSource, + call: &Self::Call, + ) -> TransactionValidity { + match call { + Call::allowed_unsigned { .. } => Ok(Default::default()), + _ => UnknownTransaction::NoUnsignedValidator.into(), + } + } + } + } + + pub type Header = ExtendedHeader; + + frame_support::construct_runtime!( + pub struct Runtime where + Block = TestBlock, + NodeBlock = TestBlock, + UncheckedExtrinsic = TestUncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + Custom: custom::{Pallet, Call, ValidateUnsigned, Inherent}, + } + ); + + parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::builder() + .base_block(Weight::from_parts(10, 0)) + .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_parts(5, 0)) + .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_parts(1024, u64::MAX).into()) + .build_or_panic(); + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 10, + write: 100, + }; + } + impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = u64; + type Hash = sp_core::H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = RuntimeVersion; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; + } + + type Balance = u64; + impl pallet_balances::Config for Runtime { + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<1>; + type HoldIdentifier = (); + type MaxHolds = ConstU32<1>; + } + + impl frame_system_ext::Config for Runtime { + type CommitList = CommitListTest; + type ExtendedHeader = Header; + } + + parameter_types! { + pub const TransactionByteFee: Balance = 0; + } + impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = (); + } + impl custom::Config for Runtime {} + + pub struct RuntimeVersion; + impl frame_support::traits::Get for RuntimeVersion { + fn get() -> sp_version::RuntimeVersion { + RuntimeVersionTestValues::get().clone() + } + } + + parameter_types! { + pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = + Default::default(); + } + + type SignedExtra = ( + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + ); + type TestXt = sp_runtime::testing::TestXt; + type TestBlock = Block; + type TestUncheckedExtrinsic = TestXt; + + // Will contain `true` when the custom runtime logic was called. + const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; + + struct CustomOnRuntimeUpgrade; + impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { + fn on_runtime_upgrade() -> Weight { + sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes()); + sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode()); + System::deposit_event(frame_system::Event::CodeUpdated); + Weight::from_parts(100, 0) + } + } + + type Executive = super::Executive< + Runtime, + Block, + ChainContext, + Runtime, + AllPalletsWithSystem, + CustomOnRuntimeUpgrade, + >; + + fn extra(nonce: u64, fee: Balance) -> SignedExtra { + ( + frame_system::CheckEra::from(Era::Immortal), + frame_system::CheckNonce::from(nonce), + frame_system::CheckWeight::new(), + pallet_transaction_payment::ChargeTransactionPayment::from(fee), + ) + } + + fn sign_extra(who: u64, nonce: u64, fee: Balance) -> Option<(u64, SignedExtra)> { + Some((who, extra(nonce, fee))) + } + + fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }) + } + + #[test] + fn balance_transfer_dispatch_works() { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 211)] } + .assimilate_storage(&mut t) + .unwrap(); + let xt = TestXt::new(call_transfer(2, 69), sign_extra(1, 0, 0)); + let weight = xt.get_dispatch_info().weight + + ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let fee: Balance = + ::WeightToFee::weight_to_fee(&weight); + let mut t = sp_io::TestExternalities::new(t); + t.execute_with(|| { + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + let r = Executive::apply_extrinsic(xt); + assert!(r.is_ok()); + assert_eq!(>::total_balance(&1), 142 - fee); + assert_eq!(>::total_balance(&2), 69); + }); + } + + fn new_test_ext(balance_factor: Balance) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } + .assimilate_storage(&mut t) + .unwrap(); + t.into() + } + + fn new_test_ext_v0(balance_factor: Balance) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(1, 111 * balance_factor)] } + .assimilate_storage(&mut t) + .unwrap(); + (t, sp_runtime::StateVersion::V0).into() + } + + #[test] + fn block_import_works() { + block_import_works_inner( + new_test_ext_v0(1), + array_bytes::hex_n_into_unchecked( + "65e953676859e7a33245908af7ad3637d6861eb90416d433d485e95e2dd174a1", + ), + ); + block_import_works_inner( + new_test_ext(1), + array_bytes::hex_n_into_unchecked( + "5a19b3d6fdb7241836349fdcbe2d9df4d4f945b949d979e31ad50bff1cbcd1c2", + ), + ); + } + fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { + ext.execute_with(|| { + Executive::execute_block(Block { + header: Header { + parent_hash: [69u8; 32].into(), + number: 1, + state_root, + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), + digest: Digest { logs: vec![] }, + extension: Default::default(), + }, + extrinsics: vec![], + }); + }); + } + + #[test] + #[should_panic] + fn block_import_of_bad_state_root_fails() { + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block { + header: Header { + parent_hash: [69u8; 32].into(), + number: 1, + state_root: [0u8; 32].into(), + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), + digest: Digest { logs: vec![] }, + extension: Default::default(), + }, + extrinsics: vec![], + }); + }); + } + + #[test] + #[should_panic] + fn block_import_of_bad_extrinsic_root_fails() { + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block { + header: Header { + parent_hash: [69u8; 32].into(), + number: 1, + state_root: array_bytes::hex_n_into_unchecked( + "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", + ), + extrinsics_root: [0u8; 32].into(), + digest: Digest { logs: vec![] }, + extension: Default::default(), + }, + extrinsics: vec![], + }); + }); + } + + #[test] + fn bad_extrinsic_not_inserted() { + let mut t = new_test_ext(1); + // bad nonce check! + let xt = TestXt::new(call_transfer(33, 69), sign_extra(1, 30, 0)); + t.execute_with(|| { + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + assert_err!( + Executive::apply_extrinsic(xt), + TransactionValidityError::Invalid(InvalidTransaction::Future) + ); + assert_eq!(>::extrinsic_index(), Some(0)); + }); + } + + #[test] + fn block_weight_limit_enforced() { + let mut t = new_test_ext(10000); + // given: TestXt uses the encoded len as fixed Len: + let xt = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 0, 0), + ); + let encoded = xt.encode(); + let encoded_len = encoded.len() as u64; + // on_initialize weight + base block execution weight + let block_weights = ::BlockWeights::get(); + let base_block_weight = Weight::from_parts(175, 0) + block_weights.base_block; + let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight; + let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5); + t.execute_with(|| { + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + // Base block execution weight + `on_initialize` weight from the custom module. + assert_eq!(>::block_weight().total(), base_block_weight); + + for nonce in 0..=num_to_exhaust_block { + let xt = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: 33, + value: 0, + }), + sign_extra(1, nonce.into(), 0), + ); + let res = Executive::apply_extrinsic(xt); + if nonce != num_to_exhaust_block { + assert!(res.is_ok()); + assert_eq!( + >::block_weight().total(), + //--------------------- on_initialize + block_execution + extrinsic_base weight + Weight::from_parts((encoded_len + 5) * (nonce + 1), 0) + base_block_weight, + ); + assert_eq!( + >::extrinsic_index(), + Some(nonce as u32 + 1) + ); + } else { + assert_eq!(res, Err(InvalidTransaction::ExhaustsResources.into())); + } + } + }); + } + + #[test] + fn block_weight_and_size_is_stored_per_tx() { + let xt = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 0, 0), + ); + let x1 = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 1, 0), + ); + let x2 = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 2, 0), + ); + let len = xt.clone().encode().len() as u32; + let mut t = new_test_ext(1); + t.execute_with(|| { + // Block execution weight + on_initialize weight from custom module + let base_block_weight = Weight::from_parts(175, 0) + + ::BlockWeights::get().base_block; + + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + assert_eq!(>::block_weight().total(), base_block_weight); + assert_eq!(>::all_extrinsics_len(), 0); + + assert!(Executive::apply_extrinsic(xt.clone()).unwrap().is_ok()); + assert!(Executive::apply_extrinsic(x1.clone()).unwrap().is_ok()); + assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); + + // default weight for `TestXt` == encoded length. + let extrinsic_weight = Weight::from_parts(len as u64, 0) + + ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + assert_eq!( + >::block_weight().total(), + base_block_weight + 3u64 * extrinsic_weight, + ); + assert_eq!(>::all_extrinsics_len(), 3 * len); + + let _ = >::finalize(); + // All extrinsics length cleaned on `System::finalize` + assert_eq!(>::all_extrinsics_len(), 0); + + // New Block + Executive::initialize_block(&Header::new( + 2, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + // Block weight cleaned up on `System::initialize` + assert_eq!(>::block_weight().total(), base_block_weight); + }); + } + + #[test] + fn validate_unsigned() { + let valid = TestXt::new(RuntimeCall::Custom(custom::Call::allowed_unsigned {}), None); + let invalid = TestXt::new(RuntimeCall::Custom(custom::Call::unallowed_unsigned {}), None); + let mut t = new_test_ext(1); + + t.execute_with(|| { + assert_eq!( + Executive::validate_transaction( + TransactionSource::InBlock, + valid.clone(), + Default::default(), + ), + Ok(ValidTransaction::default()), + ); + assert_eq!( + Executive::validate_transaction( + TransactionSource::InBlock, + invalid.clone(), + Default::default(), + ), + Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)), + ); + assert_eq!(Executive::apply_extrinsic(valid), Ok(Err(DispatchError::BadOrigin))); + assert_eq!( + Executive::apply_extrinsic(invalid), + Err(TransactionValidityError::Unknown(UnknownTransaction::NoUnsignedValidator)) + ); + }); + } + + #[test] + fn can_not_pay_for_tx_fee_on_full_lock() { + let mut t = new_test_ext(1); + t.execute_with(|| { + as fungible::MutateFreeze>::set_freeze( + &(), + &1, + 110, + ) + .unwrap(); + let xt = TestXt::new( + RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), + sign_extra(1, 0, 0), + ); + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + assert_eq!(Executive::apply_extrinsic(xt), Err(InvalidTransaction::Payment.into()),); + assert_eq!(>::total_balance(&1), 111); + }); + } + + #[test] + fn block_hooks_weight_is_stored() { + new_test_ext(1).execute_with(|| { + Executive::initialize_block(&Header::new_from_number(1)); + Executive::finalize_block(); + // NOTE: might need updates over time if new weights are introduced. + // For now it only accounts for the base block execution weight and + // the `on_initialize` weight defined in the custom test module. + assert_eq!( + >::block_weight().total(), + Weight::from_parts(175 + 175 + 10, 0) + ); + }) + } + + #[test] + fn runtime_upgraded_should_work() { + new_test_ext(1).execute_with(|| { + RuntimeVersionTestValues::mutate(|v| *v = Default::default()); + // It should be added at genesis + assert!(frame_system::LastRuntimeUpgrade::::exists()); + assert!(!Executive::runtime_upgraded()); + + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + assert!(Executive::runtime_upgraded()); + assert_eq!( + Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "".into() }), + frame_system::LastRuntimeUpgrade::::get(), + ); + + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { + spec_version: 1, + spec_name: "test".into(), + ..Default::default() + } + }); + assert!(Executive::runtime_upgraded()); + assert_eq!( + Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }), + frame_system::LastRuntimeUpgrade::::get(), + ); + + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { + spec_version: 1, + spec_name: "test".into(), + impl_version: 2, + ..Default::default() + } + }); + assert!(!Executive::runtime_upgraded()); + + frame_system::LastRuntimeUpgrade::::take(); + assert!(Executive::runtime_upgraded()); + assert_eq!( + Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }), + frame_system::LastRuntimeUpgrade::::get(), + ); + }) + } + + #[test] + fn last_runtime_upgrade_was_upgraded_works() { + let test_data = vec![ + (0, "", 1, "", true), + (1, "", 1, "", false), + (1, "", 1, "test", true), + (1, "", 0, "", false), + (1, "", 0, "test", true), + ]; + + for (spec_version, spec_name, c_spec_version, c_spec_name, result) in test_data { + let current = sp_version::RuntimeVersion { + spec_version: c_spec_version, + spec_name: c_spec_name.into(), + ..Default::default() + }; + + let last = LastRuntimeUpgradeInfo { + spec_version: spec_version.into(), + spec_name: spec_name.into(), + }; + + assert_eq!(result, last.was_upgraded(¤t)); + } + } + + #[test] + fn custom_runtime_upgrade_is_called_before_modules() { + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); + assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); + }); + } + + #[test] + fn event_from_runtime_upgrade_is_included() { + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + // set block number to non zero so events are not excluded + System::set_block_number(1); + + Executive::initialize_block(&Header::new( + 2, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + System::assert_last_event(frame_system::Event::::CodeUpdated.into()); + }); + } + + /// Regression test that ensures that the custom on runtime upgrade is called when executive is + /// used through the `ExecuteBlock` trait. + #[test] + fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { + let xt = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 0, 0), + ); + + let header = new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + // Let's build some fake block. + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + // Reset to get the correct new genesis below. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } + }); + + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called. + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + >>::execute_block(Block::new(header, vec![xt])); + + assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); + assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); + }); + } + + #[test] + fn all_weights_are_recorded_correctly() { + new_test_ext(1).execute_with(|| { + // Make sure `on_runtime_upgrade` is called for maximum complexity + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + }); + + let block_number = 1; + + Executive::initialize_block(&Header::new( + block_number, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + // All weights that show up in the `initialize_block_impl` + let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade(); + let runtime_upgrade_weight = + ::on_runtime_upgrade(); + let on_initialize_weight = + >::on_initialize(block_number); + let base_block_weight = + ::BlockWeights::get().base_block; + + // Weights are recorded correctly + assert_eq!( + frame_system::Pallet::::block_weight().total(), + custom_runtime_upgrade_weight + + runtime_upgrade_weight + + on_initialize_weight + + base_block_weight, + ); + }); + } + + #[test] + fn offchain_worker_works_as_expected() { + new_test_ext(1).execute_with(|| { + let parent_hash = sp_core::H256::from([69u8; 32]); + let mut digest = Digest::default(); + digest.push(DigestItem::Seal([1, 2, 3, 4], vec![5, 6, 7, 8])); + + let header = + Header::new(1, H256::default(), H256::default(), parent_hash, digest.clone()); + + Executive::offchain_worker(&header); + + assert_eq!(digest, System::digest()); + assert_eq!(parent_hash, System::block_hash(0)); + assert_eq!(header.hash(), System::block_hash(1)); + }); + } + + #[test] + fn calculating_storage_root_twice_works() { + let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); + let xt = TestXt::new(call, sign_extra(1, 0, 0)); + + let header = new_test_ext(1).execute_with(|| { + // Let's build some fake block. + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new(header, vec![xt])); + }); + } + + #[test] + #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] + fn invalid_inherent_position_fail() { + let xt1 = TestXt::new( + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), + sign_extra(1, 0, 0), + ); + let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); + + let header = new_test_ext(1).execute_with(|| { + // Let's build some fake block. + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new(header, vec![xt1, xt2])); + }); + } + + #[test] + fn valid_inherents_position_works() { + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); + let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + + let header = new_test_ext(1).execute_with(|| { + // Let's build some fake block. + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + + Executive::apply_extrinsic(xt1.clone()).unwrap().unwrap(); + Executive::apply_extrinsic(xt2.clone()).unwrap().unwrap(); + + Executive::finalize_block() + }); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new(header, vec![xt1, xt2])); + }); + } + + #[test] + #[should_panic(expected = "A call was labelled as mandatory, but resulted in an Error.")] + fn invalid_inherents_fail_block_execution() { + let xt1 = + TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), sign_extra(1, 0, 0)); + + new_test_ext(1).execute_with(|| { + Executive::execute_block(Block::new( + Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + ), + vec![xt1], + )); + }); + } + + // Inherents are created by the runtime and don't need to be validated. + #[test] + fn inherents_fail_validate_block() { + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); + + new_test_ext(1).execute_with(|| { + assert_eq!( + Executive::validate_transaction(TransactionSource::External, xt1, H256::random()) + .unwrap_err(), + InvalidTransaction::MandatoryValidation.into() + ); + }) + } +} diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index 4448aa1..bff4b49 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -238,7 +238,7 @@ fn testnet_genesis( epoch_config: Some(melodot_runtime::GENESIS_EPOCH_CONFIG), }, nomination_pools: NominationPoolsConfig { - min_create_bond: 10 * DOLLARS, + min_create_bond: 100_000 * DOLLARS, #[allow(clippy::identity_op)] min_join_bond: DOLLARS, ..Default::default()