// Copyright 2019-2021 Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot 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. // Polkadot 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 Polkadot. If not, see . //! Common runtime code for Polkadot and Kusama. #![cfg_attr(not(feature = "std"), no_std)] pub mod assigned_slots; pub mod auctions; pub mod claims; pub mod crowdloan; pub mod elections; pub mod impls; pub mod paras_registrar; pub mod paras_sudo_wrapper; pub mod purchase; pub mod slot_range; pub mod slots; pub mod traits; pub mod xcm_sender; #[cfg(test)] mod integration_tests; #[cfg(test)] mod mock; pub use frame_support::weights::constants::{ BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, }; use frame_support::{ parameter_types, traits::{ConstU32, Currency, OneSessionHandler}, weights::{constants::WEIGHT_PER_SECOND, DispatchClass, Weight}, }; use frame_system::limits; use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; use primitives::v2::{AssignmentId, BlockNumber, ValidatorId}; use sp_runtime::{FixedPointNumber, Perbill, Perquintill}; use static_assertions::const_assert; pub use elections::{OffchainSolutionLengthLimit, OffchainSolutionWeightLimit}; pub use pallet_balances::Call as BalancesCall; #[cfg(feature = "std")] pub use pallet_staking::StakerStatus; pub use pallet_timestamp::Call as TimestampCall; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; /// Implementations of some helper traits passed into runtime modules as associated types. pub use impls::ToAuthor; pub type NegativeImbalance = as Currency< ::AccountId, >>::NegativeImbalance; /// We assume that an on-initialize consumes 1% of the weight on average, hence a single extrinsic /// will not be allowed to consume more than `AvailableBlockRatio - 1%`. pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(1); /// 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. pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; const_assert!(NORMAL_DISPATCH_RATIO.deconstruct() >= AVERAGE_ON_INITIALIZE_RATIO.deconstruct()); // Common constants used in all runtimes. parameter_types! { pub const BlockHashCount: BlockNumber = 2400; /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure /// that combined with `AdjustmentVariable`, we can recover from the minimum. /// See `multiplier_can_grow_from_zero`. pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); /// Maximum length of block. Up to 5MB. pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); /// Block weights base values and limits. pub BlockWeights: limits::BlockWeights = limits::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 an 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(); } /// Parameterized slow adjusting fee updated based on /// https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#-2.-slow-adjusting-mechanism pub type SlowAdjustingFeeUpdate = TargetedFeeAdjustment; /// The type used for currency conversion. /// /// This must only be used as long as the balance type is `u128`. pub type CurrencyToVote = frame_support::traits::U128CurrencyToVote; static_assertions::assert_eq_size!(primitives::v2::Balance, u128); /// A placeholder since there is currently no provided session key handler for parachain validator /// keys. pub struct ParachainSessionKeyPlaceholder(sp_std::marker::PhantomData); impl sp_runtime::BoundToRuntimeAppPublic for ParachainSessionKeyPlaceholder { type Public = ValidatorId; } impl OneSessionHandler for ParachainSessionKeyPlaceholder { type Key = ValidatorId; fn on_genesis_session<'a, I: 'a>(_validators: I) where I: Iterator, T::AccountId: 'a, { } fn on_new_session<'a, I: 'a>(_changed: bool, _v: I, _q: I) where I: Iterator, T::AccountId: 'a, { } fn on_disabled(_: u32) {} } /// A placeholder since there is currently no provided session key handler for parachain validator /// keys. pub struct AssignmentSessionKeyPlaceholder(sp_std::marker::PhantomData); impl sp_runtime::BoundToRuntimeAppPublic for AssignmentSessionKeyPlaceholder { type Public = AssignmentId; } impl OneSessionHandler for AssignmentSessionKeyPlaceholder { type Key = AssignmentId; fn on_genesis_session<'a, I: 'a>(_validators: I) where I: Iterator, T::AccountId: 'a, { } fn on_new_session<'a, I: 'a>(_changed: bool, _v: I, _q: I) where I: Iterator, T::AccountId: 'a, { } fn on_disabled(_: u32) {} } /// A reasonable benchmarking config for staking pallet. pub struct StakingBenchmarkingConfig; impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { type MaxValidators = ConstU32<1000>; type MaxNominators = ConstU32<1000>; } /// Macro to set a value (e.g. when using the `parameter_types` macro) to either a production value /// or to an environment variable or testing value (in case the `fast-runtime` feature is selected). /// Note that the environment variable is evaluated _at compile time_. /// /// Usage: /// ```Rust /// parameter_types! { /// // Note that the env variable version parameter cannot be const. /// pub LaunchPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1, "KSM_LAUNCH_PERIOD"); /// pub const VotingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1 * MINUTES); /// } #[macro_export] macro_rules! prod_or_fast { ($prod:expr, $test:expr) => { if cfg!(feature = "fast-runtime") { $test } else { $prod } }; ($prod:expr, $test:expr, $env:expr) => { if cfg!(feature = "fast-runtime") { core::option_env!($env).map(|s| s.parse().ok()).flatten().unwrap_or($test) } else { $prod } }; } #[cfg(test)] mod multiplier_tests { use super::*; use frame_support::{parameter_types, weights::Weight}; use sp_core::H256; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, Convert, IdentityLookup, One}, Perbill, }; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event} } ); parameter_types! { pub const BlockHashCount: u64 = 250; pub const AvailableBlockRatio: Perbill = Perbill::one(); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength::max(2 * 1024); pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); type Origin = Origin; type Index = u64; type BlockNumber = u64; type Call = Call; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; type Event = Event; type BlockHashCount = BlockHashCount; type Version = (); type PalletInfo = PalletInfo; type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; } fn run_with_system_weight(w: Weight, mut assertions: F) where F: FnMut() -> (), { let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() .build_storage::() .unwrap() .into(); t.execute_with(|| { System::set_block_consumed_resources(w, 0); assertions() }); } #[test] fn multiplier_can_grow_from_zero() { let minimum_multiplier = MinimumMultiplier::get(); let target = TargetBlockFullness::get() * BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); // if the min is too small, then this will not change, and we are doomed forever. // the weight is 1/100th bigger than target. run_with_system_weight(target * 101 / 100, || { let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier); }) } #[test] #[ignore] fn multiplier_growth_simulator() { // assume the multiplier is initially set to its minimum. We update it with values twice the //target (target is 25%, thus 50%) and we see at which point it reaches 1. let mut multiplier = MinimumMultiplier::get(); let block_weight = TargetBlockFullness::get() * BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() * 2; let mut blocks = 0; while multiplier <= Multiplier::one() { run_with_system_weight(block_weight, || { let next = SlowAdjustingFeeUpdate::::convert(multiplier); // ensure that it is growing as well. assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier); multiplier = next; }); blocks += 1; println!("block = {} multiplier {:?}", blocks, multiplier); } } }