美文网首页
Basic Pallet集成

Basic Pallet集成

作者: 元苍子 | 来源:发表于2022-06-14 09:02 被阅读0次

    目标

    • 1、如何包含实现事件和运行时,调用自定义内部pallet?
    • 2、如何将从Crates.io中的pallet添加到到运行时?

    导入pallet

    1、创建名为pallet——something的本地pallet,并通过向/runtime/src/lib.rs添加以下内容来导入此pallet:

    // Import your pallet.
    pub use pallet_something;
    

    2、配置pallet的runtime实现。假设本地托盘仅具有暴露给运行时的Event和类型。Call将以下内容添加到/runtime/src/lib.rs:

    // Configure your pallet.
    impl pallet_something::Config for Runtime {
        type Event = Event;
        type Call = Call;
    }
    

    3、声明pallet并使其公开。包括运行时宏的Pallet和Storage类型。在construct_runtime!中,添加以下内容:

    construct_runtime!(
        pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
        {
            /* --snip-- */
            Something: pallet_something::{Pallet, Call, Storage, Event<T>},
            /* --snip-- */
        }
    );
    

    注意:要添加外部pallet,可以使用与本地pallet类似的方法,但必须包括托盘公开的所有类型。还必须包括相关的参数类型和常量。

    更新/runtime/Cargo.toml

    本地pallet

    在/runtime/Cargo.toml中,将您的托盘作为本地依赖项包含在std并添加runtime-benchmarks. 例如

    # --snip--
    pallet-something = { default-features = false,   path = '../pallets/something'
    version = '3.0.0'
    # --snip--
    [features]
    default = ['std']
    runtime-benchmarks = [
      # --snip--
      'pallet-something/runtime-benchmarks',
    ]
    std = [
      'pallet-something/std',
      # --snip--
    ]
    

    外部pallet

    以下是一个示例,说明如果pallet托管在 crates.parity.io:

    pallet-external = {default-features = false, git = "https://github.com/paritytech/substrate.git", version = "4.0.0-dev"}
    
    # --snip--
    runtime-benchmarks = [
      /* --snip */
      'pallet-external/runtime-benchmarks',
    ]
    std = [
      'pallet-external/std',
      # --snip--
    ]
    

    示例-timestamp pallet

    // This file is part of Substrate.
    
    // Copyright (C) 2018-2022 Parity Technologies (UK) Ltd.
    // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
    
    // This program is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, either version 3 of the License, or
    // (at your option) any later version.
    
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    // GNU General Public License for more details.
    
    // You should have received a copy of the GNU General Public License
    // along with this program. If not, see <https://www.gnu.org/licenses/>.
    
    //! The Substrate runtime. This can be compiled with `#[no_std]`, ready for Wasm.
    
    #![cfg_attr(not(feature = "std"), no_std)]
    // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512.
    #![recursion_limit = "512"]
    
    use codec::{Decode, Encode, MaxEncodedLen};
    use frame_election_provider_support::{
        onchain, ElectionDataProvider, ExtendedBalance, SequentialPhragmen, VoteWeight,
    };
    use frame_support::{
        construct_runtime,
        pallet_prelude::Get,
        parameter_types,
        traits::{
            AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse,
            EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem,
            LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote,
        },
        weights::{
            constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
            ConstantMultiplier, DispatchClass, IdentityFee, Weight,
        },
        PalletId, RuntimeDebug,
    };
    use frame_system::{
        limits::{BlockLength, BlockWeights},
        EnsureRoot, EnsureRootWithSuccess, EnsureSigned,
    };
    pub use node_primitives::{AccountId, Signature};
    use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment};
    use pallet_contracts::weights::WeightInfo;
    use pallet_election_provider_multi_phase::SolutionAccuracyOf;
    use pallet_grandpa::{
        fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
    };
    use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
    use pallet_session::historical::{self as pallet_session_historical};
    pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
    use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
    use sp_api::impl_runtime_apis;
    use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
    use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
    use sp_inherents::{CheckInherentsResult, InherentData};
    use sp_runtime::{
        create_runtime_str,
        curve::PiecewiseLinear,
        generic, impl_opaque_keys,
        traits::{
            self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys,
            SaturatedConversion, StaticLookup,
        },
        transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
        ApplyExtrinsicResult, FixedPointNumber, Perbill, Percent, Permill, Perquintill,
    };
    use sp_std::prelude::*;
    #[cfg(any(feature = "std", test))]
    use sp_version::NativeVersion;
    use sp_version::RuntimeVersion;
    use static_assertions::const_assert;
    
    #[cfg(any(feature = "std", test))]
    pub use frame_system::Call as SystemCall;
    #[cfg(any(feature = "std", test))]
    pub use pallet_balances::Call as BalancesCall;
    #[cfg(any(feature = "std", test))]
    pub use pallet_staking::StakerStatus;
    #[cfg(any(feature = "std", test))]
    pub use pallet_sudo::Call as SudoCall;
    #[cfg(any(feature = "std", test))]
    pub use sp_runtime::BuildStorage;
    
    /// Implementations of some helper traits passed into runtime modules as associated types.
    pub mod impls;
    #[cfg(not(feature = "runtime-benchmarks"))]
    use impls::AllianceIdentityVerifier;
    use impls::{AllianceProposalProvider, Author, CreditToBlockAuthor};
    
    /// Constant values used within the runtime.
    pub mod constants;
    use constants::{currency::*, time::*};
    use sp_runtime::generic::Era;
    
    /// Generated voter bag information.
    mod voter_bags;
    
    // Make the WASM binary available.
    #[cfg(feature = "std")]
    include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
    
    /// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
    #[cfg(feature = "std")]
    pub fn wasm_binary_unwrap() -> &'static [u8] {
        WASM_BINARY.expect(
            "Development wasm binary is not available. This means the client is built with \
             `SKIP_WASM_BUILD` flag and it is only usable for production chains. Please rebuild with \
             the flag disabled.",
        )
    }
    
    /// Runtime version.
    #[sp_version::runtime_version]
    pub const VERSION: RuntimeVersion = RuntimeVersion {
        spec_name: create_runtime_str!("node"),
        impl_name: create_runtime_str!("substrate-node"),
        authoring_version: 10,
        // Per convention: if the runtime behavior changes, increment spec_version
        // and set impl_version to 0. If only runtime
        // implementation changes and behavior does not, then leave spec_version as
        // is and increment impl_version.
        spec_version: 268,
        impl_version: 0,
        apis: RUNTIME_API_VERSIONS,
        transaction_version: 2,
        state_version: 1,
    };
    
    /// The BABE epoch configuration at genesis.
    pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
        sp_consensus_babe::BabeEpochConfiguration {
            c: PRIMARY_PROBABILITY,
            allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
        };
    
    /// Native version.
    #[cfg(any(feature = "std", test))]
    pub fn native_version() -> NativeVersion {
        NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
    }
    
    type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
    
    pub struct DealWithFees;
    impl OnUnbalanced<NegativeImbalance> for DealWithFees {
        fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
            if let Some(fees) = fees_then_tips.next() {
                // for fees, 80% to treasury, 20% to author
                let mut split = fees.ration(80, 20);
                if let Some(tips) = fees_then_tips.next() {
                    // for tips, if any, 80% to treasury, 20% to author (though this can be anything)
                    tips.ration_merge_into(80, 20, &mut split);
                }
                Treasury::on_unbalanced(split.0);
                Author::on_unbalanced(split.1);
            }
        }
    }
    
    /// We assume that ~10% of the block weight is consumed by `on_initialize` handlers.
    /// This is used to limit the maximal weight of a single extrinsic.
    const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
    /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
    /// by  Operational  extrinsics.
    const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
    /// We allow for 2 seconds of compute with a 6 second average block time.
    const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND;
    
    parameter_types! {
        pub const BlockHashCount: BlockNumber = 2400;
        pub const Version: RuntimeVersion = VERSION;
        pub RuntimeBlockLength: BlockLength =
            BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
        pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
            .base_block(BlockExecutionWeight::get())
            .for_class(DispatchClass::all(), |weights| {
                weights.base_extrinsic = ExtrinsicBaseWeight::get();
            })
            .for_class(DispatchClass::Normal, |weights| {
                weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
            })
            .for_class(DispatchClass::Operational, |weights| {
                weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
                // Operational transactions have some extra reserved space, so that they
                // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
                weights.reserved = Some(
                    MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
                );
            })
            .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
            .build_or_panic();
    }
    
    const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct());
    
    impl frame_system::Config for Runtime {
        type BaseCallFilter = Everything;
        type BlockWeights = RuntimeBlockWeights;
        type BlockLength = RuntimeBlockLength;
        type DbWeight = RocksDbWeight;
        type Origin = Origin;
        type Call = Call;
        type Index = Index;
        type BlockNumber = BlockNumber;
        type Hash = Hash;
        type Hashing = BlakeTwo256;
        type AccountId = AccountId;
        type Lookup = Indices;
        type Header = generic::Header<BlockNumber, BlakeTwo256>;
        type Event = Event;
        type BlockHashCount = BlockHashCount;
        type Version = Version;
        type PalletInfo = PalletInfo;
        type AccountData = pallet_balances::AccountData<Balance>;
        type OnNewAccount = ();
        type OnKilledAccount = ();
        type SystemWeightInfo = frame_system::weights::SubstrateWeight<Runtime>;
        type SS58Prefix = ConstU16<42>;
        type OnSetCode = ();
        type MaxConsumers = ConstU32<16>;
    }
    
    impl pallet_randomness_collective_flip::Config for Runtime {}
    
    impl pallet_utility::Config for Runtime {
        type Event = Event;
        type Call = Call;
        type PalletsOrigin = OriginCaller;
        type WeightInfo = pallet_utility::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
        pub const DepositBase: Balance = deposit(1, 88);
        // Additional storage item size of 32 bytes.
        pub const DepositFactor: Balance = deposit(0, 32);
    }
    
    impl pallet_multisig::Config for Runtime {
        type Event = Event;
        type Call = Call;
        type Currency = Balances;
        type DepositBase = DepositBase;
        type DepositFactor = DepositFactor;
        type MaxSignatories = ConstU16<100>;
        type WeightInfo = pallet_multisig::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        // One storage item; key size 32, value size 8; .
        pub const ProxyDepositBase: Balance = deposit(1, 8);
        // Additional storage item size of 33 bytes.
        pub const ProxyDepositFactor: Balance = deposit(0, 33);
        pub const AnnouncementDepositBase: Balance = deposit(1, 8);
        pub const AnnouncementDepositFactor: Balance = deposit(0, 66);
    }
    
    /// The type used to represent the kinds of proxying allowed.
    #[derive(
        Copy,
        Clone,
        Eq,
        PartialEq,
        Ord,
        PartialOrd,
        Encode,
        Decode,
        RuntimeDebug,
        MaxEncodedLen,
        scale_info::TypeInfo,
    )]
    pub enum ProxyType {
        Any,
        NonTransfer,
        Governance,
        Staking,
    }
    impl Default for ProxyType {
        fn default() -> Self {
            Self::Any
        }
    }
    impl InstanceFilter<Call> for ProxyType {
        fn filter(&self, c: &Call) -> bool {
            match self {
                ProxyType::Any => true,
                ProxyType::NonTransfer => !matches!(
                    c,
                    Call::Balances(..) |
                        Call::Assets(..) | Call::Uniques(..) |
                        Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) |
                        Call::Indices(pallet_indices::Call::transfer { .. })
                ),
                ProxyType::Governance => matches!(
                    c,
                    Call::Democracy(..) |
                        Call::Council(..) | Call::Society(..) |
                        Call::TechnicalCommittee(..) |
                        Call::Elections(..) | Call::Treasury(..)
                ),
                ProxyType::Staking => matches!(c, Call::Staking(..)),
            }
        }
        fn is_superset(&self, o: &Self) -> bool {
            match (self, o) {
                (x, y) if x == y => true,
                (ProxyType::Any, _) => true,
                (_, ProxyType::Any) => false,
                (ProxyType::NonTransfer, _) => true,
                _ => false,
            }
        }
    }
    
    impl pallet_proxy::Config for Runtime {
        type Event = Event;
        type Call = Call;
        type Currency = Balances;
        type ProxyType = ProxyType;
        type ProxyDepositBase = ProxyDepositBase;
        type ProxyDepositFactor = ProxyDepositFactor;
        type MaxProxies = ConstU32<32>;
        type WeightInfo = pallet_proxy::weights::SubstrateWeight<Runtime>;
        type MaxPending = ConstU32<32>;
        type CallHasher = BlakeTwo256;
        type AnnouncementDepositBase = AnnouncementDepositBase;
        type AnnouncementDepositFactor = AnnouncementDepositFactor;
    }
    
    parameter_types! {
        pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
            RuntimeBlockWeights::get().max_block;
        // Retry a scheduled item every 10 blocks (1 minute) until the preimage exists.
        pub const NoPreimagePostponement: Option<u32> = Some(10);
    }
    
    impl pallet_scheduler::Config for Runtime {
        type Event = Event;
        type Origin = Origin;
        type PalletsOrigin = OriginCaller;
        type Call = Call;
        type MaximumWeight = MaximumSchedulerWeight;
        type ScheduleOrigin = EnsureRoot<AccountId>;
        type MaxScheduledPerBlock = ConstU32<50>;
        type WeightInfo = pallet_scheduler::weights::SubstrateWeight<Runtime>;
        type OriginPrivilegeCmp = EqualPrivilegeOnly;
        type PreimageProvider = Preimage;
        type NoPreimagePostponement = NoPreimagePostponement;
    }
    
    parameter_types! {
        pub const PreimageMaxSize: u32 = 4096 * 1024;
        pub const PreimageBaseDeposit: Balance = 1 * DOLLARS;
        // One cent: $10,000 / MB
        pub const PreimageByteDeposit: Balance = 1 * CENTS;
    }
    
    impl pallet_preimage::Config for Runtime {
        type WeightInfo = pallet_preimage::weights::SubstrateWeight<Runtime>;
        type Event = Event;
        type Currency = Balances;
        type ManagerOrigin = EnsureRoot<AccountId>;
        type MaxSize = PreimageMaxSize;
        type BaseDeposit = PreimageBaseDeposit;
        type ByteDeposit = PreimageByteDeposit;
    }
    
    parameter_types! {
        // NOTE: Currently it is not possible to change the epoch duration after the chain has started.
        //       Attempting to do so will brick block production.
        pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS;
        pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
        pub const ReportLongevity: u64 =
            BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get();
    }
    
    impl pallet_babe::Config for Runtime {
        type EpochDuration = EpochDuration;
        type ExpectedBlockTime = ExpectedBlockTime;
        type EpochChangeTrigger = pallet_babe::ExternalTrigger;
        type DisabledValidators = Session;
    
        type KeyOwnerProofSystem = Historical;
    
        type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
            KeyTypeId,
            pallet_babe::AuthorityId,
        )>>::Proof;
    
        type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
            KeyTypeId,
            pallet_babe::AuthorityId,
        )>>::IdentificationTuple;
    
        type HandleEquivocation =
            pallet_babe::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;
    
        type WeightInfo = ();
        type MaxAuthorities = MaxAuthorities;
    }
    
    parameter_types! {
        pub const IndexDeposit: Balance = 1 * DOLLARS;
    }
    
    impl pallet_indices::Config for Runtime {
        type AccountIndex = AccountIndex;
        type Currency = Balances;
        type Deposit = IndexDeposit;
        type Event = Event;
        type WeightInfo = pallet_indices::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const ExistentialDeposit: Balance = 1 * DOLLARS;
        // For weight estimation, we assume that the most locks on an individual account will be 50.
        // This number may need to be adjusted in the future if this assumption no longer holds true.
        pub const MaxLocks: u32 = 50;
        pub const MaxReserves: u32 = 50;
    }
    
    impl pallet_balances::Config for Runtime {
        type MaxLocks = MaxLocks;
        type MaxReserves = MaxReserves;
        type ReserveIdentifier = [u8; 8];
        type Balance = Balance;
        type DustRemoval = ();
        type Event = Event;
        type ExistentialDeposit = ExistentialDeposit;
        type AccountStore = frame_system::Pallet<Runtime>;
        type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const TransactionByteFee: Balance = 10 * MILLICENTS;
        pub const OperationalFeeMultiplier: u8 = 5;
        pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
        pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 100_000);
        pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000_000u128);
    }
    
    impl pallet_transaction_payment::Config for Runtime {
        type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees>;
        type OperationalFeeMultiplier = OperationalFeeMultiplier;
        type WeightToFee = IdentityFee<Balance>;
        type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
        type FeeMultiplierUpdate =
            TargetedFeeAdjustment<Self, TargetBlockFullness, AdjustmentVariable, MinimumMultiplier>;
    }
    
    impl pallet_asset_tx_payment::Config for Runtime {
        type Fungibles = Assets;
        type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter<
            pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
            CreditToBlockAuthor,
        >;
    }
    
    parameter_types! {
        pub const MinimumPeriod: Moment = SLOT_DURATION / 2;
    }
    
    impl pallet_timestamp::Config for Runtime {
        type Moment = Moment;
        type OnTimestampSet = Babe;
        type MinimumPeriod = MinimumPeriod;
        type WeightInfo = pallet_timestamp::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const UncleGenerations: BlockNumber = 5;
    }
    
    impl pallet_authorship::Config for Runtime {
        type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Babe>;
        type UncleGenerations = UncleGenerations;
        type FilterUncle = ();
        type EventHandler = (Staking, ImOnline);
    }
    
    impl_opaque_keys! {
        pub struct SessionKeys {
            pub grandpa: Grandpa,
            pub babe: Babe,
            pub im_online: ImOnline,
            pub authority_discovery: AuthorityDiscovery,
        }
    }
    
    impl pallet_session::Config for Runtime {
        type Event = Event;
        type ValidatorId = <Self as frame_system::Config>::AccountId;
        type ValidatorIdOf = pallet_staking::StashOf<Self>;
        type ShouldEndSession = Babe;
        type NextSessionRotation = Babe;
        type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
        type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
        type Keys = SessionKeys;
        type WeightInfo = pallet_session::weights::SubstrateWeight<Runtime>;
    }
    
    impl pallet_session::historical::Config for Runtime {
        type FullIdentification = pallet_staking::Exposure<AccountId, Balance>;
        type FullIdentificationOf = pallet_staking::ExposureOf<Runtime>;
    }
    
    pallet_staking_reward_curve::build! {
        const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
            min_inflation: 0_025_000,
            max_inflation: 0_100_000,
            ideal_stake: 0_500_000,
            falloff: 0_050_000,
            max_piece_count: 40,
            test_precision: 0_005_000,
        );
    }
    
    parameter_types! {
        pub const SessionsPerEra: sp_staking::SessionIndex = 6;
        pub const BondingDuration: sp_staking::EraIndex = 24 * 28;
        pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration.
        pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
        pub const MaxNominatorRewardedPerValidator: u32 = 256;
        pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17);
        pub OffchainRepeat: BlockNumber = 5;
    }
    
    pub struct StakingBenchmarkingConfig;
    impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig {
        type MaxNominators = ConstU32<1000>;
        type MaxValidators = ConstU32<1000>;
    }
    
    impl pallet_staking::Config for Runtime {
        type MaxNominations = MaxNominations;
        type Currency = Balances;
        type CurrencyBalance = Balance;
        type UnixTime = Timestamp;
        type CurrencyToVote = U128CurrencyToVote;
        type RewardRemainder = Treasury;
        type Event = Event;
        type Slash = Treasury; // send the slashed funds to the treasury.
        type Reward = (); // rewards are minted from the void
        type SessionsPerEra = SessionsPerEra;
        type BondingDuration = BondingDuration;
        type SlashDeferDuration = SlashDeferDuration;
        /// A super-majority of the council can cancel the slash.
        type SlashCancelOrigin = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 4>,
        >;
        type SessionInterface = Self;
        type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
        type NextNewSession = Session;
        type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
        type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
        type ElectionProvider = ElectionProviderMultiPhase;
        type GenesisElectionProvider = onchain::UnboundedExecution<OnChainSeqPhragmen>;
        type VoterList = BagsList;
        type MaxUnlockingChunks = ConstU32<32>;
        type OnStakerSlash = NominationPools;
        type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
        type BenchmarkingConfig = StakingBenchmarkingConfig;
    }
    
    parameter_types! {
        // phase durations. 1/4 of the last session for each.
        pub const SignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4;
        pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4;
    
        // signed config
        pub const SignedRewardBase: Balance = 1 * DOLLARS;
        pub const SignedDepositBase: Balance = 1 * DOLLARS;
        pub const SignedDepositByte: Balance = 1 * CENTS;
    
        pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(1u32, 10_000);
    
        // miner configs
        pub const MultiPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64;
        pub MinerMaxWeight: Weight = RuntimeBlockWeights::get()
            .get(DispatchClass::Normal)
            .max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed")
            .saturating_sub(BlockExecutionWeight::get());
        // Solution can occupy 90% of normal block size
        pub MinerMaxLength: u32 = Perbill::from_rational(9u32, 10) *
            *RuntimeBlockLength::get()
            .max
            .get(DispatchClass::Normal);
    }
    
    frame_election_provider_support::generate_solution_type!(
        #[compact]
        pub struct NposSolution16::<
            VoterIndex = u32,
            TargetIndex = u16,
            Accuracy = sp_runtime::PerU16,
            MaxVoters = MaxElectingVoters,
        >(16)
    );
    
    parameter_types! {
        pub MaxNominations: u32 = <NposSolution16 as frame_election_provider_support::NposSolution>::LIMIT as u32;
        pub MaxElectingVoters: u32 = 10_000;
    }
    
    /// The numbers configured here could always be more than the the maximum limits of staking pallet
    /// to ensure election snapshot will not run out of memory. For now, we set them to smaller values
    /// since the staking is bounded and the weight pipeline takes hours for this single pallet.
    pub struct ElectionProviderBenchmarkConfig;
    impl pallet_election_provider_multi_phase::BenchmarkingConfig for ElectionProviderBenchmarkConfig {
        const VOTERS: [u32; 2] = [1000, 2000];
        const TARGETS: [u32; 2] = [500, 1000];
        const ACTIVE_VOTERS: [u32; 2] = [500, 800];
        const DESIRED_TARGETS: [u32; 2] = [200, 400];
        const SNAPSHOT_MAXIMUM_VOTERS: u32 = 1000;
        const MINER_MAXIMUM_VOTERS: u32 = 1000;
        const MAXIMUM_TARGETS: u32 = 300;
    }
    
    /// Maximum number of iterations for balancing that will be executed in the embedded OCW
    /// miner of election provider multi phase.
    pub const MINER_MAX_ITERATIONS: u32 = 10;
    
    /// A source of random balance for NposSolver, which is meant to be run by the OCW election miner.
    pub struct OffchainRandomBalancing;
    impl Get<Option<(usize, ExtendedBalance)>> for OffchainRandomBalancing {
        fn get() -> Option<(usize, ExtendedBalance)> {
            use sp_runtime::traits::TrailingZeroInput;
            let iters = match MINER_MAX_ITERATIONS {
                0 => 0,
                max => {
                    let seed = sp_io::offchain::random_seed();
                    let random = <u32>::decode(&mut TrailingZeroInput::new(&seed))
                        .expect("input is padded with zeroes; qed") %
                        max.saturating_add(1);
                    random as usize
                },
            };
    
            Some((iters, 0))
        }
    }
    
    pub struct OnChainSeqPhragmen;
    impl onchain::Config for OnChainSeqPhragmen {
        type System = Runtime;
        type Solver = SequentialPhragmen<
            AccountId,
            pallet_election_provider_multi_phase::SolutionAccuracyOf<Runtime>,
        >;
        type DataProvider = <Runtime as pallet_election_provider_multi_phase::Config>::DataProvider;
        type WeightInfo = frame_election_provider_support::weights::SubstrateWeight<Runtime>;
    }
    
    impl onchain::BoundedConfig for OnChainSeqPhragmen {
        type VotersBound = MaxElectingVoters;
        type TargetsBound = ConstU32<2_000>;
    }
    
    impl pallet_election_provider_multi_phase::MinerConfig for Runtime {
        type AccountId = AccountId;
        type MaxLength = MinerMaxLength;
        type MaxWeight = MinerMaxWeight;
        type Solution = NposSolution16;
        type MaxVotesPerVoter =
        <<Self as pallet_election_provider_multi_phase::Config>::DataProvider as ElectionDataProvider>::MaxVotesPerVoter;
    
        // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their
        // weight estimate function is wired to this call's weight.
        fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight {
            <
                <Self as pallet_election_provider_multi_phase::Config>::WeightInfo
                as
                pallet_election_provider_multi_phase::WeightInfo
            >::submit_unsigned(v, t, a, d)
        }
    }
    
    impl pallet_election_provider_multi_phase::Config for Runtime {
        type Event = Event;
        type Currency = Balances;
        type EstimateCallFee = TransactionPayment;
        type SignedPhase = SignedPhase;
        type UnsignedPhase = UnsignedPhase;
        type BetterUnsignedThreshold = BetterUnsignedThreshold;
        type BetterSignedThreshold = ();
        type OffchainRepeat = OffchainRepeat;
        type MinerTxPriority = MultiPhaseUnsignedPriority;
        type MinerConfig = Self;
        type SignedMaxSubmissions = ConstU32<10>;
        type SignedRewardBase = SignedRewardBase;
        type SignedDepositBase = SignedDepositBase;
        type SignedDepositByte = SignedDepositByte;
        type SignedMaxRefunds = ConstU32<3>;
        type SignedDepositWeight = ();
        type SignedMaxWeight = MinerMaxWeight;
        type SlashHandler = (); // burn slashes
        type RewardHandler = (); // nothing to do upon rewards
        type DataProvider = Staking;
        type Fallback = onchain::BoundedExecution<OnChainSeqPhragmen>;
        type GovernanceFallback = onchain::BoundedExecution<OnChainSeqPhragmen>;
        type Solver = SequentialPhragmen<AccountId, SolutionAccuracyOf<Self>, OffchainRandomBalancing>;
        type ForceOrigin = EnsureRootOrHalfCouncil;
        type MaxElectableTargets = ConstU16<{ u16::MAX }>;
        type MaxElectingVoters = MaxElectingVoters;
        type BenchmarkingConfig = ElectionProviderBenchmarkConfig;
        type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight<Self>;
    }
    
    parameter_types! {
        pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS;
    }
    
    impl pallet_bags_list::Config for Runtime {
        type Event = Event;
        type ScoreProvider = Staking;
        type WeightInfo = pallet_bags_list::weights::SubstrateWeight<Runtime>;
        type BagThresholds = BagThresholds;
        type Score = VoteWeight;
    }
    
    parameter_types! {
        pub const PostUnbondPoolsWindow: u32 = 4;
        pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls");
        pub const MinPointsToBalance: u32 = 10;
    }
    
    use sp_runtime::traits::Convert;
    pub struct BalanceToU256;
    impl Convert<Balance, sp_core::U256> for BalanceToU256 {
        fn convert(balance: Balance) -> sp_core::U256 {
            sp_core::U256::from(balance)
        }
    }
    pub struct U256ToBalance;
    impl Convert<sp_core::U256, Balance> for U256ToBalance {
        fn convert(n: sp_core::U256) -> Balance {
            n.try_into().unwrap_or(Balance::max_value())
        }
    }
    
    impl pallet_nomination_pools::Config for Runtime {
        type WeightInfo = ();
        type Event = Event;
        type Currency = Balances;
        type BalanceToU256 = BalanceToU256;
        type U256ToBalance = U256ToBalance;
        type StakingInterface = pallet_staking::Pallet<Self>;
        type PostUnbondingPoolsWindow = PostUnbondPoolsWindow;
        type MaxMetadataLen = ConstU32<256>;
        type MaxUnbonding = ConstU32<8>;
        type PalletId = NominationPoolsPalletId;
        type MinPointsToBalance = MinPointsToBalance;
    }
    
    parameter_types! {
        pub const VoteLockingPeriod: BlockNumber = 30 * DAYS;
    }
    
    impl pallet_conviction_voting::Config for Runtime {
        type WeightInfo = pallet_conviction_voting::weights::SubstrateWeight<Self>;
        type Event = Event;
        type Currency = Balances;
        type VoteLockingPeriod = VoteLockingPeriod;
        type MaxVotes = ConstU32<512>;
        type MaxTurnout = frame_support::traits::TotalIssuanceOf<Balances, Self::AccountId>;
        type Polls = Referenda;
    }
    
    parameter_types! {
        pub const AlarmInterval: BlockNumber = 1;
        pub const SubmissionDeposit: Balance = 100 * DOLLARS;
        pub const UndecidingTimeout: BlockNumber = 28 * DAYS;
    }
    
    pub struct TracksInfo;
    impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo {
        type Id = u16;
        type Origin = <Origin as frame_support::traits::OriginTrait>::PalletsOrigin;
        fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] {
            static DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 1] = [(
                0u16,
                pallet_referenda::TrackInfo {
                    name: "root",
                    max_deciding: 1,
                    decision_deposit: 10,
                    prepare_period: 4,
                    decision_period: 4,
                    confirm_period: 2,
                    min_enactment_period: 4,
                    min_approval: pallet_referenda::Curve::LinearDecreasing {
                        length: Perbill::from_percent(100),
                        floor: Perbill::from_percent(50),
                        ceil: Perbill::from_percent(100),
                    },
                    min_support: pallet_referenda::Curve::LinearDecreasing {
                        length: Perbill::from_percent(100),
                        floor: Perbill::from_percent(0),
                        ceil: Perbill::from_percent(100),
                    },
                },
            )];
            &DATA[..]
        }
        fn track_for(id: &Self::Origin) -> Result<Self::Id, ()> {
            if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) {
                match system_origin {
                    frame_system::RawOrigin::Root => Ok(0),
                    _ => Err(()),
                }
            } else {
                Err(())
            }
        }
    }
    
    impl pallet_referenda::Config for Runtime {
        type WeightInfo = pallet_referenda::weights::SubstrateWeight<Self>;
        type Call = Call;
        type Event = Event;
        type Scheduler = Scheduler;
        type Currency = pallet_balances::Pallet<Self>;
        type SubmitOrigin = EnsureSigned<AccountId>;
        type CancelOrigin = EnsureRoot<AccountId>;
        type KillOrigin = EnsureRoot<AccountId>;
        type Slash = ();
        type Votes = pallet_conviction_voting::VotesOf<Runtime>;
        type Tally = pallet_conviction_voting::TallyOf<Runtime>;
        type SubmissionDeposit = SubmissionDeposit;
        type MaxQueued = ConstU32<100>;
        type UndecidingTimeout = UndecidingTimeout;
        type AlarmInterval = AlarmInterval;
        type Tracks = TracksInfo;
    }
    
    impl pallet_referenda::Config<pallet_referenda::Instance2> for Runtime {
        type WeightInfo = pallet_referenda::weights::SubstrateWeight<Self>;
        type Call = Call;
        type Event = Event;
        type Scheduler = Scheduler;
        type Currency = pallet_balances::Pallet<Self>;
        type SubmitOrigin = EnsureSigned<AccountId>;
        type CancelOrigin = EnsureRoot<AccountId>;
        type KillOrigin = EnsureRoot<AccountId>;
        type Slash = ();
        type Votes = pallet_ranked_collective::Votes;
        type Tally = pallet_ranked_collective::TallyOf<Runtime>;
        type SubmissionDeposit = SubmissionDeposit;
        type MaxQueued = ConstU32<100>;
        type UndecidingTimeout = UndecidingTimeout;
        type AlarmInterval = AlarmInterval;
        type Tracks = TracksInfo;
    }
    
    impl pallet_ranked_collective::Config for Runtime {
        type WeightInfo = pallet_ranked_collective::weights::SubstrateWeight<Self>;
        type Event = Event;
        type PromoteOrigin = EnsureRootWithSuccess<AccountId, ConstU16<65535>>;
        type DemoteOrigin = EnsureRootWithSuccess<AccountId, ConstU16<65535>>;
        type Polls = RankedPolls;
        type MinRankOfClass = traits::Identity;
        type VoteWeight = pallet_ranked_collective::Geometric;
    }
    
    impl pallet_remark::Config for Runtime {
        type WeightInfo = pallet_remark::weights::SubstrateWeight<Self>;
        type Event = Event;
    }
    
    parameter_types! {
        pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
        pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
        pub const FastTrackVotingPeriod: BlockNumber = 3 * 24 * 60 * MINUTES;
        pub const MinimumDeposit: Balance = 100 * DOLLARS;
        pub const EnactmentPeriod: BlockNumber = 30 * 24 * 60 * MINUTES;
        pub const CooloffPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
        pub const MaxProposals: u32 = 100;
    }
    
    impl pallet_democracy::Config for Runtime {
        type Proposal = Call;
        type Event = Event;
        type Currency = Balances;
        type EnactmentPeriod = EnactmentPeriod;
        type LaunchPeriod = LaunchPeriod;
        type VotingPeriod = VotingPeriod;
        type VoteLockingPeriod = EnactmentPeriod; // Same as EnactmentPeriod
        type MinimumDeposit = MinimumDeposit;
        /// A straight majority of the council can decide what their next motion is.
        type ExternalOrigin =
            pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 2>;
        /// A super-majority can have the next scheduled referendum be a straight majority-carries vote.
        type ExternalMajorityOrigin =
            pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 4>;
        /// A unanimous council can have the next scheduled referendum be a straight default-carries
        /// (NTB) vote.
        type ExternalDefaultOrigin =
            pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 1>;
        /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote
        /// be tabled immediately and with a shorter voting/enactment period.
        type FastTrackOrigin =
            pallet_collective::EnsureProportionAtLeast<AccountId, TechnicalCollective, 2, 3>;
        type InstantOrigin =
            pallet_collective::EnsureProportionAtLeast<AccountId, TechnicalCollective, 1, 1>;
        type InstantAllowed = frame_support::traits::ConstBool<true>;
        type FastTrackVotingPeriod = FastTrackVotingPeriod;
        // To cancel a proposal which has been passed, 2/3 of the council must agree to it.
        type CancellationOrigin =
            pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 2, 3>;
        // To cancel a proposal before it has been passed, the technical committee must be unanimous or
        // Root must agree.
        type CancelProposalOrigin = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionAtLeast<AccountId, TechnicalCollective, 1, 1>,
        >;
        type BlacklistOrigin = EnsureRoot<AccountId>;
        // Any single technical committee member may veto a coming council proposal, however they can
        // only do it once and it lasts only for the cool-off period.
        type VetoOrigin = pallet_collective::EnsureMember<AccountId, TechnicalCollective>;
        type CooloffPeriod = CooloffPeriod;
        type PreimageByteDeposit = PreimageByteDeposit;
        type OperationalPreimageOrigin = pallet_collective::EnsureMember<AccountId, CouncilCollective>;
        type Slash = Treasury;
        type Scheduler = Scheduler;
        type PalletsOrigin = OriginCaller;
        type MaxVotes = ConstU32<100>;
        type WeightInfo = pallet_democracy::weights::SubstrateWeight<Runtime>;
        type MaxProposals = MaxProposals;
    }
    
    parameter_types! {
        pub const CouncilMotionDuration: BlockNumber = 5 * DAYS;
        pub const CouncilMaxProposals: u32 = 100;
        pub const CouncilMaxMembers: u32 = 100;
    }
    
    type CouncilCollective = pallet_collective::Instance1;
    impl pallet_collective::Config<CouncilCollective> for Runtime {
        type Origin = Origin;
        type Proposal = Call;
        type Event = Event;
        type MotionDuration = CouncilMotionDuration;
        type MaxProposals = CouncilMaxProposals;
        type MaxMembers = CouncilMaxMembers;
        type DefaultVote = pallet_collective::PrimeDefaultVote;
        type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const CandidacyBond: Balance = 10 * DOLLARS;
        // 1 storage item created, key size is 32 bytes, value size is 16+16.
        pub const VotingBondBase: Balance = deposit(1, 64);
        // additional data per vote is 32 bytes (account id).
        pub const VotingBondFactor: Balance = deposit(0, 32);
        pub const TermDuration: BlockNumber = 7 * DAYS;
        pub const DesiredMembers: u32 = 13;
        pub const DesiredRunnersUp: u32 = 7;
        pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect";
    }
    
    // Make sure that there are no more than `MaxMembers` members elected via elections-phragmen.
    const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get());
    
    impl pallet_elections_phragmen::Config for Runtime {
        type Event = Event;
        type PalletId = ElectionsPhragmenPalletId;
        type Currency = Balances;
        type ChangeMembers = Council;
        // NOTE: this implies that council's genesis members cannot be set directly and must come from
        // this module.
        type InitializeMembers = Council;
        type CurrencyToVote = U128CurrencyToVote;
        type CandidacyBond = CandidacyBond;
        type VotingBondBase = VotingBondBase;
        type VotingBondFactor = VotingBondFactor;
        type LoserCandidate = ();
        type KickedMember = ();
        type DesiredMembers = DesiredMembers;
        type DesiredRunnersUp = DesiredRunnersUp;
        type TermDuration = TermDuration;
        type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const TechnicalMotionDuration: BlockNumber = 5 * DAYS;
        pub const TechnicalMaxProposals: u32 = 100;
        pub const TechnicalMaxMembers: u32 = 100;
    }
    
    type TechnicalCollective = pallet_collective::Instance2;
    impl pallet_collective::Config<TechnicalCollective> for Runtime {
        type Origin = Origin;
        type Proposal = Call;
        type Event = Event;
        type MotionDuration = TechnicalMotionDuration;
        type MaxProposals = TechnicalMaxProposals;
        type MaxMembers = TechnicalMaxMembers;
        type DefaultVote = pallet_collective::PrimeDefaultVote;
        type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
    }
    
    type EnsureRootOrHalfCouncil = EitherOfDiverse<
        EnsureRoot<AccountId>,
        pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>,
    >;
    impl pallet_membership::Config<pallet_membership::Instance1> for Runtime {
        type Event = Event;
        type AddOrigin = EnsureRootOrHalfCouncil;
        type RemoveOrigin = EnsureRootOrHalfCouncil;
        type SwapOrigin = EnsureRootOrHalfCouncil;
        type ResetOrigin = EnsureRootOrHalfCouncil;
        type PrimeOrigin = EnsureRootOrHalfCouncil;
        type MembershipInitialized = TechnicalCommittee;
        type MembershipChanged = TechnicalCommittee;
        type MaxMembers = TechnicalMaxMembers;
        type WeightInfo = pallet_membership::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const ProposalBond: Permill = Permill::from_percent(5);
        pub const ProposalBondMinimum: Balance = 1 * DOLLARS;
        pub const SpendPeriod: BlockNumber = 1 * DAYS;
        pub const Burn: Permill = Permill::from_percent(50);
        pub const TipCountdown: BlockNumber = 1 * DAYS;
        pub const TipFindersFee: Percent = Percent::from_percent(20);
        pub const TipReportDepositBase: Balance = 1 * DOLLARS;
        pub const DataDepositPerByte: Balance = 1 * CENTS;
        pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
        pub const MaximumReasonLength: u32 = 300;
        pub const MaxApprovals: u32 = 100;
    }
    
    impl pallet_treasury::Config for Runtime {
        type PalletId = TreasuryPalletId;
        type Currency = Balances;
        type ApproveOrigin = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 5>,
        >;
        type RejectOrigin = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>,
        >;
        type Event = Event;
        type OnSlash = ();
        type ProposalBond = ProposalBond;
        type ProposalBondMinimum = ProposalBondMinimum;
        type ProposalBondMaximum = ();
        type SpendPeriod = SpendPeriod;
        type Burn = Burn;
        type BurnDestination = ();
        type SpendFunds = Bounties;
        type WeightInfo = pallet_treasury::weights::SubstrateWeight<Runtime>;
        type MaxApprovals = MaxApprovals;
        type SpendOrigin = frame_support::traits::NeverEnsureOrigin<u128>;
    }
    
    parameter_types! {
        pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
        pub const BountyValueMinimum: Balance = 5 * DOLLARS;
        pub const BountyDepositBase: Balance = 1 * DOLLARS;
        pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50);
        pub const CuratorDepositMin: Balance = 1 * DOLLARS;
        pub const CuratorDepositMax: Balance = 100 * DOLLARS;
        pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
        pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
    }
    
    impl pallet_bounties::Config for Runtime {
        type Event = Event;
        type BountyDepositBase = BountyDepositBase;
        type BountyDepositPayoutDelay = BountyDepositPayoutDelay;
        type BountyUpdatePeriod = BountyUpdatePeriod;
        type CuratorDepositMultiplier = CuratorDepositMultiplier;
        type CuratorDepositMin = CuratorDepositMin;
        type CuratorDepositMax = CuratorDepositMax;
        type BountyValueMinimum = BountyValueMinimum;
        type DataDepositPerByte = DataDepositPerByte;
        type MaximumReasonLength = MaximumReasonLength;
        type WeightInfo = pallet_bounties::weights::SubstrateWeight<Runtime>;
        type ChildBountyManager = ChildBounties;
    }
    
    parameter_types! {
        pub const ChildBountyValueMinimum: Balance = 1 * DOLLARS;
    }
    
    impl pallet_child_bounties::Config for Runtime {
        type Event = Event;
        type MaxActiveChildBountyCount = ConstU32<5>;
        type ChildBountyValueMinimum = ChildBountyValueMinimum;
        type WeightInfo = pallet_child_bounties::weights::SubstrateWeight<Runtime>;
    }
    
    impl pallet_tips::Config for Runtime {
        type Event = Event;
        type DataDepositPerByte = DataDepositPerByte;
        type MaximumReasonLength = MaximumReasonLength;
        type Tippers = Elections;
        type TipCountdown = TipCountdown;
        type TipFindersFee = TipFindersFee;
        type TipReportDepositBase = TipReportDepositBase;
        type WeightInfo = pallet_tips::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const DepositPerItem: Balance = deposit(1, 0);
        pub const DepositPerByte: Balance = deposit(0, 1);
        pub const MaxValueSize: u32 = 16 * 1024;
        // The lazy deletion runs inside on_initialize.
        pub DeletionWeightLimit: Weight = RuntimeBlockWeights::get()
            .per_class
            .get(DispatchClass::Normal)
            .max_total
            .unwrap_or(RuntimeBlockWeights::get().max_block);
        // The weight needed for decoding the queue should be less or equal than a fifth
        // of the overall weight dedicated to the lazy deletion.
        pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
                <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
                <Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
            )) / 5) as u32;
        pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
    }
    
    impl pallet_contracts::Config for Runtime {
        type Time = Timestamp;
        type Randomness = RandomnessCollectiveFlip;
        type Currency = Balances;
        type Event = Event;
        type Call = Call;
        /// The safest default is to allow no calls at all.
        ///
        /// Runtimes should whitelist dispatchables that are allowed to be called from contracts
        /// and make sure they are stable. Dispatchables exposed to contracts are not allowed to
        /// change because that would break already deployed contracts. The `Call` structure itself
        /// is not allowed to change the indices of existing pallets, too.
        type CallFilter = Nothing;
        type DepositPerItem = DepositPerItem;
        type DepositPerByte = DepositPerByte;
        type CallStack = [pallet_contracts::Frame<Self>; 31];
        type WeightPrice = pallet_transaction_payment::Pallet<Self>;
        type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
        type ChainExtension = ();
        type DeletionQueueDepth = DeletionQueueDepth;
        type DeletionWeightLimit = DeletionWeightLimit;
        type Schedule = Schedule;
        type AddressGenerator = pallet_contracts::DefaultAddressGenerator;
        type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight<RuntimeBlockWeights>;
        type MaxCodeLen = ConstU32<{ 128 * 1024 }>;
        type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>;
    }
    
    impl pallet_sudo::Config for Runtime {
        type Event = Event;
        type Call = Call;
    }
    
    parameter_types! {
        pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
        /// We prioritize im-online heartbeats over election solution submission.
        pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2;
        pub const MaxAuthorities: u32 = 100;
        pub const MaxKeys: u32 = 10_000;
        pub const MaxPeerInHeartbeats: u32 = 10_000;
        pub const MaxPeerDataEncodingSize: u32 = 1_000;
    }
    
    impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
    where
        Call: From<LocalCall>,
    {
        fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
            call: Call,
            public: <Signature as traits::Verify>::Signer,
            account: AccountId,
            nonce: Index,
        ) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
            let tip = 0;
            // take the biggest period possible.
            let period =
                BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
            let current_block = System::block_number()
                .saturated_into::<u64>()
                // The `System::block_number` is initialized with `n+1`,
                // so the actual block number is `n`.
                .saturating_sub(1);
            let era = Era::mortal(period, current_block);
            let extra = (
                frame_system::CheckNonZeroSender::<Runtime>::new(),
                frame_system::CheckSpecVersion::<Runtime>::new(),
                frame_system::CheckTxVersion::<Runtime>::new(),
                frame_system::CheckGenesis::<Runtime>::new(),
                frame_system::CheckEra::<Runtime>::from(era),
                frame_system::CheckNonce::<Runtime>::from(nonce),
                frame_system::CheckWeight::<Runtime>::new(),
                pallet_asset_tx_payment::ChargeAssetTxPayment::<Runtime>::from(tip, None),
            );
            let raw_payload = SignedPayload::new(call, extra)
                .map_err(|e| {
                    log::warn!("Unable to create signed payload: {:?}", e);
                })
                .ok()?;
            let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
            let address = Indices::unlookup(account);
            let (call, extra, _) = raw_payload.deconstruct();
            Some((call, (address, signature, extra)))
        }
    }
    
    impl frame_system::offchain::SigningTypes for Runtime {
        type Public = <Signature as traits::Verify>::Signer;
        type Signature = Signature;
    }
    
    impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
    where
        Call: From<C>,
    {
        type Extrinsic = UncheckedExtrinsic;
        type OverarchingCall = Call;
    }
    
    impl pallet_im_online::Config for Runtime {
        type AuthorityId = ImOnlineId;
        type Event = Event;
        type NextSessionRotation = Babe;
        type ValidatorSet = Historical;
        type ReportUnresponsiveness = Offences;
        type UnsignedPriority = ImOnlineUnsignedPriority;
        type WeightInfo = pallet_im_online::weights::SubstrateWeight<Runtime>;
        type MaxKeys = MaxKeys;
        type MaxPeerInHeartbeats = MaxPeerInHeartbeats;
        type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize;
    }
    
    impl pallet_offences::Config for Runtime {
        type Event = Event;
        type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
        type OnOffenceHandler = Staking;
    }
    
    impl pallet_authority_discovery::Config for Runtime {
        type MaxAuthorities = MaxAuthorities;
    }
    
    impl pallet_grandpa::Config for Runtime {
        type Event = Event;
        type Call = Call;
    
        type KeyOwnerProofSystem = Historical;
    
        type KeyOwnerProof =
            <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
    
        type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
            KeyTypeId,
            GrandpaId,
        )>>::IdentificationTuple;
    
        type HandleEquivocation = pallet_grandpa::EquivocationHandler<
            Self::KeyOwnerIdentification,
            Offences,
            ReportLongevity,
        >;
    
        type WeightInfo = ();
        type MaxAuthorities = MaxAuthorities;
    }
    
    parameter_types! {
        pub const BasicDeposit: Balance = 10 * DOLLARS;       // 258 bytes on-chain
        pub const FieldDeposit: Balance = 250 * CENTS;        // 66 bytes on-chain
        pub const SubAccountDeposit: Balance = 2 * DOLLARS;   // 53 bytes on-chain
        pub const MaxSubAccounts: u32 = 100;
        pub const MaxAdditionalFields: u32 = 100;
        pub const MaxRegistrars: u32 = 20;
    }
    
    impl pallet_identity::Config for Runtime {
        type Event = Event;
        type Currency = Balances;
        type BasicDeposit = BasicDeposit;
        type FieldDeposit = FieldDeposit;
        type SubAccountDeposit = SubAccountDeposit;
        type MaxSubAccounts = MaxSubAccounts;
        type MaxAdditionalFields = MaxAdditionalFields;
        type MaxRegistrars = MaxRegistrars;
        type Slashed = Treasury;
        type ForceOrigin = EnsureRootOrHalfCouncil;
        type RegistrarOrigin = EnsureRootOrHalfCouncil;
        type WeightInfo = pallet_identity::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const ConfigDepositBase: Balance = 5 * DOLLARS;
        pub const FriendDepositFactor: Balance = 50 * CENTS;
        pub const MaxFriends: u16 = 9;
        pub const RecoveryDeposit: Balance = 5 * DOLLARS;
    }
    
    impl pallet_recovery::Config for Runtime {
        type Event = Event;
        type WeightInfo = pallet_recovery::weights::SubstrateWeight<Runtime>;
        type Call = Call;
        type Currency = Balances;
        type ConfigDepositBase = ConfigDepositBase;
        type FriendDepositFactor = FriendDepositFactor;
        type MaxFriends = MaxFriends;
        type RecoveryDeposit = RecoveryDeposit;
    }
    
    parameter_types! {
        pub const CandidateDeposit: Balance = 10 * DOLLARS;
        pub const WrongSideDeduction: Balance = 2 * DOLLARS;
        pub const MaxStrikes: u32 = 10;
        pub const RotationPeriod: BlockNumber = 80 * HOURS;
        pub const PeriodSpend: Balance = 500 * DOLLARS;
        pub const MaxLockDuration: BlockNumber = 36 * 30 * DAYS;
        pub const ChallengePeriod: BlockNumber = 7 * DAYS;
        pub const MaxCandidateIntake: u32 = 10;
        pub const SocietyPalletId: PalletId = PalletId(*b"py/socie");
    }
    
    impl pallet_society::Config for Runtime {
        type Event = Event;
        type PalletId = SocietyPalletId;
        type Currency = Balances;
        type Randomness = RandomnessCollectiveFlip;
        type CandidateDeposit = CandidateDeposit;
        type WrongSideDeduction = WrongSideDeduction;
        type MaxStrikes = MaxStrikes;
        type PeriodSpend = PeriodSpend;
        type MembershipChanged = ();
        type RotationPeriod = RotationPeriod;
        type MaxLockDuration = MaxLockDuration;
        type FounderSetOrigin =
            pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>;
        type SuspensionJudgementOrigin = pallet_society::EnsureFounder<Runtime>;
        type MaxCandidateIntake = MaxCandidateIntake;
        type ChallengePeriod = ChallengePeriod;
    }
    
    parameter_types! {
        pub const MinVestedTransfer: Balance = 100 * DOLLARS;
    }
    
    impl pallet_vesting::Config for Runtime {
        type Event = Event;
        type Currency = Balances;
        type BlockNumberToBalance = ConvertInto;
        type MinVestedTransfer = MinVestedTransfer;
        type WeightInfo = pallet_vesting::weights::SubstrateWeight<Runtime>;
        // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the
        // highest number of schedules that encodes less than 2^10.
        const MAX_VESTING_SCHEDULES: u32 = 28;
    }
    
    impl pallet_mmr::Config for Runtime {
        const INDEXING_PREFIX: &'static [u8] = b"mmr";
        type Hashing = <Runtime as frame_system::Config>::Hashing;
        type Hash = <Runtime as frame_system::Config>::Hash;
        type LeafData = pallet_mmr::ParentNumberAndHash<Self>;
        type OnNewRoot = ();
        type WeightInfo = ();
    }
    
    parameter_types! {
        pub const LotteryPalletId: PalletId = PalletId(*b"py/lotto");
        pub const MaxCalls: u32 = 10;
        pub const MaxGenerateRandom: u32 = 10;
    }
    
    impl pallet_lottery::Config for Runtime {
        type PalletId = LotteryPalletId;
        type Call = Call;
        type Currency = Balances;
        type Randomness = RandomnessCollectiveFlip;
        type Event = Event;
        type ManagerOrigin = EnsureRoot<AccountId>;
        type MaxCalls = MaxCalls;
        type ValidateCall = Lottery;
        type MaxGenerateRandom = MaxGenerateRandom;
        type WeightInfo = pallet_lottery::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const AssetDeposit: Balance = 100 * DOLLARS;
        pub const ApprovalDeposit: Balance = 1 * DOLLARS;
        pub const StringLimit: u32 = 50;
        pub const MetadataDepositBase: Balance = 10 * DOLLARS;
        pub const MetadataDepositPerByte: Balance = 1 * DOLLARS;
    }
    
    impl pallet_assets::Config for Runtime {
        type Event = Event;
        type Balance = u128;
        type AssetId = u32;
        type Currency = Balances;
        type ForceOrigin = EnsureRoot<AccountId>;
        type AssetDeposit = AssetDeposit;
        type AssetAccountDeposit = ConstU128<DOLLARS>;
        type MetadataDepositBase = MetadataDepositBase;
        type MetadataDepositPerByte = MetadataDepositPerByte;
        type ApprovalDeposit = ApprovalDeposit;
        type StringLimit = StringLimit;
        type Freezer = ();
        type Extra = ();
        type WeightInfo = pallet_assets::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub IgnoredIssuance: Balance = Treasury::pot();
        pub const QueueCount: u32 = 300;
        pub const MaxQueueLen: u32 = 1000;
        pub const FifoQueueLen: u32 = 500;
        pub const Period: BlockNumber = 30 * DAYS;
        pub const MinFreeze: Balance = 100 * DOLLARS;
        pub const IntakePeriod: BlockNumber = 10;
        pub const MaxIntakeBids: u32 = 10;
    }
    
    impl pallet_gilt::Config for Runtime {
        type Event = Event;
        type Currency = Balances;
        type CurrencyBalance = Balance;
        type AdminOrigin = frame_system::EnsureRoot<AccountId>;
        type Deficit = ();
        type Surplus = ();
        type IgnoredIssuance = IgnoredIssuance;
        type QueueCount = QueueCount;
        type MaxQueueLen = MaxQueueLen;
        type FifoQueueLen = FifoQueueLen;
        type Period = Period;
        type MinFreeze = MinFreeze;
        type IntakePeriod = IntakePeriod;
        type MaxIntakeBids = MaxIntakeBids;
        type WeightInfo = pallet_gilt::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const CollectionDeposit: Balance = 100 * DOLLARS;
        pub const ItemDeposit: Balance = 1 * DOLLARS;
        pub const KeyLimit: u32 = 32;
        pub const ValueLimit: u32 = 256;
    }
    
    impl pallet_uniques::Config for Runtime {
        type Event = Event;
        type CollectionId = u32;
        type ItemId = u32;
        type Currency = Balances;
        type ForceOrigin = frame_system::EnsureRoot<AccountId>;
        type CollectionDeposit = CollectionDeposit;
        type ItemDeposit = ItemDeposit;
        type MetadataDepositBase = MetadataDepositBase;
        type AttributeDepositBase = MetadataDepositBase;
        type DepositPerByte = MetadataDepositPerByte;
        type StringLimit = StringLimit;
        type KeyLimit = KeyLimit;
        type ValueLimit = ValueLimit;
        type WeightInfo = pallet_uniques::weights::SubstrateWeight<Runtime>;
        #[cfg(feature = "runtime-benchmarks")]
        type Helper = ();
        type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
        type Locker = ();
    }
    
    impl pallet_transaction_storage::Config for Runtime {
        type Event = Event;
        type Currency = Balances;
        type Call = Call;
        type FeeDestination = ();
        type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight<Runtime>;
    }
    
    impl pallet_whitelist::Config for Runtime {
        type Event = Event;
        type Call = Call;
        type WhitelistOrigin = EnsureRoot<AccountId>;
        type DispatchWhitelistedOrigin = EnsureRoot<AccountId>;
        type PreimageProvider = Preimage;
        type WeightInfo = pallet_whitelist::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS;
        pub const MigrationSignedDepositBase: Balance = 20 * DOLLARS;
        pub const MigrationMaxKeyLen: u32 = 512;
    }
    
    impl pallet_state_trie_migration::Config for Runtime {
        type Event = Event;
        type ControlOrigin = EnsureRoot<AccountId>;
        type Currency = Balances;
        type MaxKeyLen = MigrationMaxKeyLen;
        type SignedDepositPerItem = MigrationSignedDepositPerItem;
        type SignedDepositBase = MigrationSignedDepositBase;
        // Warning: this is not advised, as it might allow the chain to be temporarily DOS-ed.
        // Preferably, if the chain's governance/maintenance team is planning on using a specific
        // account for the migration, put it here to make sure only that account can trigger the signed
        // migrations.
        type SignedFilter = EnsureSigned<Self::AccountId>;
        type WeightInfo = ();
    }
    
    parameter_types! {
        pub const AllianceMotionDuration: BlockNumber = 5 * DAYS;
        pub const AllianceMaxProposals: u32 = 100;
        pub const AllianceMaxMembers: u32 = 100;
    }
    
    type AllianceCollective = pallet_collective::Instance3;
    impl pallet_collective::Config<AllianceCollective> for Runtime {
        type Origin = Origin;
        type Proposal = Call;
        type Event = Event;
        type MotionDuration = AllianceMotionDuration;
        type MaxProposals = AllianceMaxProposals;
        type MaxMembers = AllianceMaxMembers;
        type DefaultVote = pallet_collective::PrimeDefaultVote;
        type WeightInfo = pallet_collective::weights::SubstrateWeight<Runtime>;
    }
    
    parameter_types! {
        pub const MaxFounders: u32 = 10;
        pub const MaxFellows: u32 = AllianceMaxMembers::get() - MaxFounders::get();
        pub const MaxAllies: u32 = 100;
        pub const AllyDeposit: Balance = 10 * DOLLARS;
    }
    
    impl pallet_alliance::Config for Runtime {
        type Event = Event;
        type Proposal = Call;
        type AdminOrigin = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionMoreThan<AccountId, AllianceCollective, 2, 3>,
        >;
        type MembershipManager = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionMoreThan<AccountId, AllianceCollective, 2, 3>,
        >;
        type AnnouncementOrigin = EitherOfDiverse<
            EnsureRoot<AccountId>,
            pallet_collective::EnsureProportionMoreThan<AccountId, AllianceCollective, 2, 3>,
        >;
        type Currency = Balances;
        type Slashed = Treasury;
        type InitializeMembers = AllianceMotion;
        type MembershipChanged = AllianceMotion;
        #[cfg(not(feature = "runtime-benchmarks"))]
        type IdentityVerifier = AllianceIdentityVerifier;
        #[cfg(feature = "runtime-benchmarks")]
        type IdentityVerifier = ();
        type ProposalProvider = AllianceProposalProvider;
        type MaxProposals = AllianceMaxProposals;
        type MaxFounders = MaxFounders;
        type MaxFellows = MaxFellows;
        type MaxAllies = MaxAllies;
        type MaxUnscrupulousItems = ConstU32<100>;
        type MaxWebsiteUrlLength = ConstU32<255>;
        type MaxAnnouncementsCount = ConstU32<100>;
        type MaxMembersCount = AllianceMaxMembers;
        type AllyDeposit = AllyDeposit;
        type WeightInfo = pallet_alliance::weights::SubstrateWeight<Runtime>;
    }
    
    construct_runtime!(
        pub enum Runtime where
            Block = Block,
            NodeBlock = node_primitives::Block,
            UncheckedExtrinsic = UncheckedExtrinsic
        {
            System: frame_system,
            Utility: pallet_utility,
            Babe: pallet_babe,
            Timestamp: pallet_timestamp,
            // Authorship must be before session in order to note author in the correct session and era
            // for im-online and staking.
            Authorship: pallet_authorship,
            Indices: pallet_indices,
            Balances: pallet_balances,
            TransactionPayment: pallet_transaction_payment,
            AssetTxPayment: pallet_asset_tx_payment,
            ElectionProviderMultiPhase: pallet_election_provider_multi_phase,
            Staking: pallet_staking,
            Session: pallet_session,
            Democracy: pallet_democracy,
            Council: pallet_collective::<Instance1>,
            TechnicalCommittee: pallet_collective::<Instance2>,
            Elections: pallet_elections_phragmen,
            TechnicalMembership: pallet_membership::<Instance1>,
            Grandpa: pallet_grandpa,
            Treasury: pallet_treasury,
            Contracts: pallet_contracts,
            Sudo: pallet_sudo,
            ImOnline: pallet_im_online,
            AuthorityDiscovery: pallet_authority_discovery,
            Offences: pallet_offences,
            Historical: pallet_session_historical::{Pallet},
            RandomnessCollectiveFlip: pallet_randomness_collective_flip,
            Identity: pallet_identity,
            Society: pallet_society,
            Recovery: pallet_recovery,
            Vesting: pallet_vesting,
            Scheduler: pallet_scheduler,
            Preimage: pallet_preimage,
            Proxy: pallet_proxy,
            Multisig: pallet_multisig,
            Bounties: pallet_bounties,
            Tips: pallet_tips,
            Assets: pallet_assets,
            Mmr: pallet_mmr,
            Lottery: pallet_lottery,
            Gilt: pallet_gilt,
            Uniques: pallet_uniques,
            TransactionStorage: pallet_transaction_storage,
            BagsList: pallet_bags_list,
            StateTrieMigration: pallet_state_trie_migration,
            ChildBounties: pallet_child_bounties,
            Referenda: pallet_referenda,
            Remark: pallet_remark,
            ConvictionVoting: pallet_conviction_voting,
            Whitelist: pallet_whitelist,
            AllianceMotion: pallet_collective::<Instance3>,
            Alliance: pallet_alliance,
            NominationPools: pallet_nomination_pools,
            RankedPolls: pallet_referenda::<Instance2>,
            RankedCollective: pallet_ranked_collective,
        }
    );
    
    /// The address format for describing accounts.
    pub type Address = sp_runtime::MultiAddress<AccountId, AccountIndex>;
    /// Block header type as expected by this runtime.
    pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
    /// Block type as expected by this runtime.
    pub type Block = generic::Block<Header, UncheckedExtrinsic>;
    /// A Block signed with a Justification
    pub type SignedBlock = generic::SignedBlock<Block>;
    /// BlockId type as expected by this runtime.
    pub type BlockId = generic::BlockId<Block>;
    /// The SignedExtension to the basic transaction logic.
    ///
    /// When you change this, you **MUST** modify [`sign`] in `bin/node/testing/src/keyring.rs`!
    ///
    /// [`sign`]: <../../testing/src/keyring.rs.html>
    pub type SignedExtra = (
        frame_system::CheckNonZeroSender<Runtime>,
        frame_system::CheckSpecVersion<Runtime>,
        frame_system::CheckTxVersion<Runtime>,
        frame_system::CheckGenesis<Runtime>,
        frame_system::CheckEra<Runtime>,
        frame_system::CheckNonce<Runtime>,
        frame_system::CheckWeight<Runtime>,
        pallet_asset_tx_payment::ChargeAssetTxPayment<Runtime>,
    );
    /// Unchecked extrinsic type as expected by this runtime.
    pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
    /// The payload being signed in transactions.
    pub type SignedPayload = generic::SignedPayload<Call, SignedExtra>;
    /// Extrinsic type that has already been checked.
    pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
    /// Executive: handles dispatch to the various modules.
    pub type Executive = frame_executive::Executive<
        Runtime,
        Block,
        frame_system::ChainContext<Runtime>,
        Runtime,
        AllPalletsWithSystem,
        (),
    >;
    
    /// MMR helper types.
    mod mmr {
        use super::Runtime;
        pub use pallet_mmr::primitives::*;
    
        pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
        pub type Hash = <Runtime as pallet_mmr::Config>::Hash;
        pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
    }
    
    #[cfg(feature = "runtime-benchmarks")]
    #[macro_use]
    extern crate frame_benchmarking;
    
    #[cfg(feature = "runtime-benchmarks")]
    mod benches {
        define_benchmarks!(
            [frame_benchmarking, BaselineBench::<Runtime>]
            [pallet_assets, Assets]
            [pallet_babe, Babe]
            [pallet_bags_list, BagsList]
            [pallet_balances, Balances]
            [pallet_bounties, Bounties]
            [pallet_child_bounties, ChildBounties]
            [pallet_collective, Council]
            [pallet_conviction_voting, ConvictionVoting]
            [pallet_contracts, Contracts]
            [pallet_democracy, Democracy]
            [pallet_election_provider_multi_phase, ElectionProviderMultiPhase]
            [pallet_election_provider_support_benchmarking, EPSBench::<Runtime>]
            [pallet_elections_phragmen, Elections]
            [pallet_gilt, Gilt]
            [pallet_grandpa, Grandpa]
            [pallet_identity, Identity]
            [pallet_im_online, ImOnline]
            [pallet_indices, Indices]
            [pallet_lottery, Lottery]
            [pallet_membership, TechnicalMembership]
            [pallet_mmr, Mmr]
            [pallet_multisig, Multisig]
            [pallet_nomination_pools, NominationPoolsBench::<Runtime>]
            [pallet_offences, OffencesBench::<Runtime>]
            [pallet_preimage, Preimage]
            [pallet_proxy, Proxy]
            [pallet_ranked_collective, RankedCollective]
            [pallet_referenda, Referenda]
            [pallet_recovery, Recovery]
            [pallet_remark, Remark]
            [pallet_scheduler, Scheduler]
            [pallet_session, SessionBench::<Runtime>]
            [pallet_staking, Staking]
            [pallet_state_trie_migration, StateTrieMigration]
            [frame_system, SystemBench::<Runtime>]
            [pallet_timestamp, Timestamp]
            [pallet_tips, Tips]
            [pallet_transaction_storage, TransactionStorage]
            [pallet_treasury, Treasury]
            [pallet_uniques, Uniques]
            [pallet_utility, Utility]
            [pallet_vesting, Vesting]
            [pallet_whitelist, Whitelist]
        );
    }
    
    impl_runtime_apis! {
        impl sp_api::Core<Block> for Runtime {
            fn version() -> RuntimeVersion {
                VERSION
            }
    
            fn execute_block(block: Block) {
                Executive::execute_block(block);
            }
    
            fn initialize_block(header: &<Block as BlockT>::Header) {
                Executive::initialize_block(header)
            }
        }
    
        impl sp_api::Metadata<Block> for Runtime {
            fn metadata() -> OpaqueMetadata {
                OpaqueMetadata::new(Runtime::metadata().into())
            }
        }
    
        impl sp_block_builder::BlockBuilder<Block> for Runtime {
            fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
                Executive::apply_extrinsic(extrinsic)
            }
    
            fn finalize_block() -> <Block as BlockT>::Header {
                Executive::finalize_block()
            }
    
            fn inherent_extrinsics(data: InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
                data.create_extrinsics()
            }
    
            fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult {
                data.check_extrinsics(&block)
            }
        }
    
        impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
            fn validate_transaction(
                source: TransactionSource,
                tx: <Block as BlockT>::Extrinsic,
                block_hash: <Block as BlockT>::Hash,
            ) -> TransactionValidity {
                Executive::validate_transaction(source, tx, block_hash)
            }
        }
    
        impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
            fn offchain_worker(header: &<Block as BlockT>::Header) {
                Executive::offchain_worker(header)
            }
        }
    
        impl fg_primitives::GrandpaApi<Block> for Runtime {
            fn grandpa_authorities() -> GrandpaAuthorityList {
                Grandpa::grandpa_authorities()
            }
    
            fn current_set_id() -> fg_primitives::SetId {
                Grandpa::current_set_id()
            }
    
            fn submit_report_equivocation_unsigned_extrinsic(
                equivocation_proof: fg_primitives::EquivocationProof<
                    <Block as BlockT>::Hash,
                    NumberFor<Block>,
                >,
                key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof,
            ) -> Option<()> {
                let key_owner_proof = key_owner_proof.decode()?;
    
                Grandpa::submit_unsigned_equivocation_report(
                    equivocation_proof,
                    key_owner_proof,
                )
            }
    
            fn generate_key_ownership_proof(
                _set_id: fg_primitives::SetId,
                authority_id: GrandpaId,
            ) -> Option<fg_primitives::OpaqueKeyOwnershipProof> {
                use codec::Encode;
    
                Historical::prove((fg_primitives::KEY_TYPE, authority_id))
                    .map(|p| p.encode())
                    .map(fg_primitives::OpaqueKeyOwnershipProof::new)
            }
        }
    
        impl sp_consensus_babe::BabeApi<Block> for Runtime {
            fn configuration() -> sp_consensus_babe::BabeGenesisConfiguration {
                // The choice of `c` parameter (where `1 - c` represents the
                // probability of a slot being empty), is done in accordance to the
                // slot duration and expected target block time, for safely
                // resisting network delays of maximum two seconds.
                // <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
                sp_consensus_babe::BabeGenesisConfiguration {
                    slot_duration: Babe::slot_duration(),
                    epoch_length: EpochDuration::get(),
                    c: BABE_GENESIS_EPOCH_CONFIG.c,
                    genesis_authorities: Babe::authorities().to_vec(),
                    randomness: Babe::randomness(),
                    allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots,
                }
            }
    
            fn current_epoch_start() -> sp_consensus_babe::Slot {
                Babe::current_epoch_start()
            }
    
            fn current_epoch() -> sp_consensus_babe::Epoch {
                Babe::current_epoch()
            }
    
            fn next_epoch() -> sp_consensus_babe::Epoch {
                Babe::next_epoch()
            }
    
            fn generate_key_ownership_proof(
                _slot: sp_consensus_babe::Slot,
                authority_id: sp_consensus_babe::AuthorityId,
            ) -> Option<sp_consensus_babe::OpaqueKeyOwnershipProof> {
                use codec::Encode;
    
                Historical::prove((sp_consensus_babe::KEY_TYPE, authority_id))
                    .map(|p| p.encode())
                    .map(sp_consensus_babe::OpaqueKeyOwnershipProof::new)
            }
    
            fn submit_report_equivocation_unsigned_extrinsic(
                equivocation_proof: sp_consensus_babe::EquivocationProof<<Block as BlockT>::Header>,
                key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof,
            ) -> Option<()> {
                let key_owner_proof = key_owner_proof.decode()?;
    
                Babe::submit_unsigned_equivocation_report(
                    equivocation_proof,
                    key_owner_proof,
                )
            }
        }
    
        impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
            fn authorities() -> Vec<AuthorityDiscoveryId> {
                AuthorityDiscovery::authorities()
            }
        }
    
        impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
            fn account_nonce(account: AccountId) -> Index {
                System::account_nonce(account)
            }
        }
    
        impl pallet_contracts_rpc_runtime_api::ContractsApi<
            Block, AccountId, Balance, BlockNumber, Hash,
        >
            for Runtime
        {
            fn call(
                origin: AccountId,
                dest: AccountId,
                value: Balance,
                gas_limit: u64,
                storage_deposit_limit: Option<Balance>,
                input_data: Vec<u8>,
            ) -> pallet_contracts_primitives::ContractExecResult<Balance> {
                Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true)
            }
    
            fn instantiate(
                origin: AccountId,
                value: Balance,
                gas_limit: u64,
                storage_deposit_limit: Option<Balance>,
                code: pallet_contracts_primitives::Code<Hash>,
                data: Vec<u8>,
                salt: Vec<u8>,
            ) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, Balance>
            {
                Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true)
            }
    
            fn upload_code(
                origin: AccountId,
                code: Vec<u8>,
                storage_deposit_limit: Option<Balance>,
            ) -> pallet_contracts_primitives::CodeUploadResult<Hash, Balance>
            {
                Contracts::bare_upload_code(origin, code, storage_deposit_limit)
            }
    
            fn get_storage(
                address: AccountId,
                key: [u8; 32],
            ) -> pallet_contracts_primitives::GetStorageResult {
                Contracts::get_storage(address, key)
            }
        }
    
        impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
            Block,
            Balance,
        > for Runtime {
            fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {
                TransactionPayment::query_info(uxt, len)
            }
            fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> FeeDetails<Balance> {
                TransactionPayment::query_fee_details(uxt, len)
            }
        }
    
        impl pallet_mmr::primitives::MmrApi<
            Block,
            mmr::Hash,
        > for Runtime {
            fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex)
                -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof<mmr::Hash>), mmr::Error>
            {
                Mmr::generate_batch_proof(vec![leaf_index]).and_then(|(leaves, proof)|
                    Ok((
                        mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]),
                        mmr::BatchProof::into_single_leaf_proof(proof)?
                    ))
                )
            }
    
            fn verify_proof(leaf: mmr::EncodableOpaqueLeaf, proof: mmr::Proof<mmr::Hash>)
                -> Result<(), mmr::Error>
            {
                let leaf: mmr::Leaf = leaf
                    .into_opaque_leaf()
                    .try_decode()
                    .ok_or(mmr::Error::Verify)?;
                Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof))
            }
    
            fn verify_proof_stateless(
                root: mmr::Hash,
                leaf: mmr::EncodableOpaqueLeaf,
                proof: mmr::Proof<mmr::Hash>
            ) -> Result<(), mmr::Error> {
                let node = mmr::DataOrHash::Data(leaf.into_opaque_leaf());
                pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, vec![node], mmr::Proof::into_batch_proof(proof))
            }
    
            fn mmr_root() -> Result<mmr::Hash, mmr::Error> {
                Ok(Mmr::mmr_root())
            }
    
            fn generate_batch_proof(leaf_indices: Vec<pallet_mmr::primitives::LeafIndex>)
                -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::BatchProof<mmr::Hash>), mmr::Error>
            {
                Mmr::generate_batch_proof(leaf_indices)
                    .map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof))
            }
    
            fn verify_batch_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::BatchProof<mmr::Hash>)
                -> Result<(), mmr::Error>
            {
                let leaves = leaves.into_iter().map(|leaf|
                    leaf.into_opaque_leaf()
                    .try_decode()
                    .ok_or(mmr::Error::Verify)).collect::<Result<Vec<mmr::Leaf>, mmr::Error>>()?;
                Mmr::verify_leaves(leaves, proof)
            }
    
            fn verify_batch_proof_stateless(
                root: mmr::Hash,
                leaves: Vec<mmr::EncodableOpaqueLeaf>,
                proof: mmr::BatchProof<mmr::Hash>
            ) -> Result<(), mmr::Error> {
                let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
                pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
            }
        }
    
        impl sp_session::SessionKeys<Block> for Runtime {
            fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
                SessionKeys::generate(seed)
            }
    
            fn decode_session_keys(
                encoded: Vec<u8>,
            ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
                SessionKeys::decode_into_raw_public_keys(&encoded)
            }
        }
    
        #[cfg(feature = "try-runtime")]
        impl frame_try_runtime::TryRuntime<Block> for Runtime {
            fn on_runtime_upgrade() -> (Weight, Weight) {
                // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
                // have a backtrace here. If any of the pre/post migration checks fail, we shall stop
                // right here and right now.
                let weight = Executive::try_runtime_upgrade().unwrap();
                (weight, RuntimeBlockWeights::get().max_block)
            }
    
            fn execute_block_no_check(block: Block) -> Weight {
                Executive::execute_block_no_check(block)
            }
        }
    
        #[cfg(feature = "runtime-benchmarks")]
        impl frame_benchmarking::Benchmark<Block> for Runtime {
            fn benchmark_metadata(extra: bool) -> (
                Vec<frame_benchmarking::BenchmarkList>,
                Vec<frame_support::traits::StorageInfo>,
            ) {
                use frame_benchmarking::{baseline, Benchmarking, BenchmarkList};
                use frame_support::traits::StorageInfoTrait;
    
                // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency
                // issues. To get around that, we separated the Session benchmarks into its own crate,
                // which is why we need these two lines below.
                use pallet_session_benchmarking::Pallet as SessionBench;
                use pallet_offences_benchmarking::Pallet as OffencesBench;
                use pallet_election_provider_support_benchmarking::Pallet as EPSBench;
                use frame_system_benchmarking::Pallet as SystemBench;
                use baseline::Pallet as BaselineBench;
                use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
    
                let mut list = Vec::<BenchmarkList>::new();
                list_benchmarks!(list, extra);
    
                let storage_info = AllPalletsWithSystem::storage_info();
    
                (list, storage_info)
            }
    
            fn dispatch_benchmark(
                config: frame_benchmarking::BenchmarkConfig
            ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
                use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch,  TrackedStorageKey};
    
                // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency
                // issues. To get around that, we separated the Session benchmarks into its own crate,
                // which is why we need these two lines below.
                use pallet_session_benchmarking::Pallet as SessionBench;
                use pallet_offences_benchmarking::Pallet as OffencesBench;
                use pallet_election_provider_support_benchmarking::Pallet as EPSBench;
                use frame_system_benchmarking::Pallet as SystemBench;
                use baseline::Pallet as BaselineBench;
                use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
    
                impl pallet_session_benchmarking::Config for Runtime {}
                impl pallet_offences_benchmarking::Config for Runtime {}
                impl pallet_election_provider_support_benchmarking::Config for Runtime {}
                impl frame_system_benchmarking::Config for Runtime {}
                impl baseline::Config for Runtime {}
                impl pallet_nomination_pools_benchmarking::Config for Runtime {}
    
                let whitelist: Vec<TrackedStorageKey> = vec![
                    // Block Number
                    hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
                    // Total Issuance
                    hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
                    // Execution Phase
                    hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
                    // Event Count
                    hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
                    // System Events
                    hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
                    // System BlockWeight
                    hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96").to_vec().into(),
                    // Treasury Account
                    hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec().into(),
                ];
    
                let mut batches = Vec::<BenchmarkBatch>::new();
                let params = (&config, &whitelist);
                add_benchmarks!(params, batches);
                Ok(batches)
            }
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
        use frame_election_provider_support::NposSolution;
        use frame_system::offchain::CreateSignedTransaction;
        use sp_runtime::UpperOf;
    
        #[test]
        fn validate_transaction_submitter_bounds() {
            fn is_submit_signed_transaction<T>()
            where
                T: CreateSignedTransaction<Call>,
            {
            }
    
            is_submit_signed_transaction::<Runtime>();
        }
    
        #[test]
        fn perbill_as_onchain_accuracy() {
            type OnChainAccuracy =
                <<Runtime as pallet_election_provider_multi_phase::MinerConfig>::Solution as NposSolution>::Accuracy;
            let maximum_chain_accuracy: Vec<UpperOf<OnChainAccuracy>> = (0..MaxNominations::get())
                .map(|_| <UpperOf<OnChainAccuracy>>::from(OnChainAccuracy::one().deconstruct()))
                .collect();
            let _: UpperOf<OnChainAccuracy> =
                maximum_chain_accuracy.iter().fold(0, |acc, x| acc.checked_add(*x).unwrap());
        }
    
        #[test]
        fn call_size() {
            let size = core::mem::size_of::<Call>();
            assert!(
                size <= 208,
                "size of Call {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the
                size of Call.
                If the limit is too strong, maybe consider increase the limit to 300.",
                size,
            );
        }
    }
    

    相关文章

      网友评论

          本文标题:Basic Pallet集成

          本文链接:https://www.haomeiwen.com/subject/yxzamrtx.html