Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
132 contributors

Users who have contributed to this file

@shawntabrizi @kianenigma @gavofyork @bkchr @thiolliere @rphmeier @andresilva @coderobe @ggwpez @ordian @s3krit @KiChjang
// Copyright 2017-2020 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 <http://www.gnu.org/licenses/>.
//! The Polkadot 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 256.
#![recursion_limit = "256"]
use pallet_transaction_payment::CurrencyAdapter;
use runtime_common::{
auctions, claims, crowdloan, impl_runtime_weights, impls::DealWithFees, paras_registrar,
prod_or_fast, slots, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate,
};
use runtime_parachains::{
configuration as parachains_configuration, disputes as parachains_disputes,
dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points,
runtime_api_impl::v2 as parachains_runtime_api_impl, scheduler as parachains_scheduler,
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump,
};
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
use beefy_primitives::crypto::AuthorityId as BeefyId;
use frame_election_provider_support::{generate_solution_type, onchain, SequentialPhragmen};
use frame_support::{
construct_runtime, parameter_types,
traits::{
ConstU32, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier,
PrivilegeCmp, WithdrawReasons,
},
weights::ConstantMultiplier,
PalletId, RuntimeDebug,
};
use frame_system::EnsureRoot;
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId};
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pallet_session::historical as session_historical;
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use primitives::{
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
CoreState, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage,
Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes,
SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
LOWEST_PUBLIC_ID,
};
use sp_core::OpaqueMetadata;
use sp_mmr_primitives as mmr;
use sp_runtime::{
create_runtime_str,
curve::PiecewiseLinear,
generic, impl_opaque_keys,
traits::{
AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT,
OpaqueKeys, SaturatedConversion, Verify,
},
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill,
};
use sp_staking::SessionIndex;
use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*};
#[cfg(any(feature = "std", test))]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use static_assertions::const_assert;
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_election_provider_multi_phase::Call as EPMCall;
#[cfg(feature = "std")]
pub use pallet_staking::StakerStatus;
use pallet_staking::UseValidatorsMap;
pub use pallet_timestamp::Call as TimestampCall;
use sp_runtime::traits::Get;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
/// Constant values used within the runtime.
use polkadot_runtime_constants::{currency::*, fee::*, time::*};
// Weights used in the runtime.
mod weights;
mod bag_thresholds;
pub mod xcm_config;
impl_runtime_weights!(polkadot_runtime_constants);
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
// Polkadot version identifier;
/// Runtime version (Polkadot).
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("polkadot"),
impl_name: create_runtime_str!("parity-polkadot"),
authoring_version: 0,
spec_version: 9370,
impl_version: 0,
#[cfg(not(feature = "disable-runtime-api"))]
apis: RUNTIME_API_VERSIONS,
#[cfg(feature = "disable-runtime-api")]
apis: sp_version::create_apis_vec![[]],
transaction_version: 20,
state_version: 0,
};
/// The BABE epoch configuration at genesis.
pub const BABE_GENESIS_EPOCH_CONFIG: babe_primitives::BabeEpochConfiguration =
babe_primitives::BabeEpochConfiguration {
c: PRIMARY_PROBABILITY,
allowed_slots: babe_primitives::AllowedSlots::PrimaryAndSecondaryVRFSlots,
};
/// Native version.
#[cfg(any(feature = "std", test))]
pub fn native_version() -> NativeVersion {
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}
type MoreThanHalfCouncil = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>,
>;
parameter_types! {
pub const Version: RuntimeVersion = VERSION;
pub const SS58Prefix: u8 = 0;
}
impl frame_system::Config for Runtime {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = BlockWeights;
type BlockLength = BlockLength;
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Index = Nonce;
type BlockNumber = BlockNumber;
type Hash = Hash;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = AccountIdLookup<AccountId, ()>;
type Header = generic::Header<BlockNumber, BlakeTwo256>;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type DbWeight = RocksDbWeight;
type Version = Version;
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = weights::frame_system::WeightInfo<Runtime>;
type SS58Prefix = SS58Prefix;
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
pub const MaxScheduledPerBlock: u32 = 50;
pub const NoPreimagePostponement: Option<u32> = Some(10);
}
type ScheduleOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 2>,
>;
/// Used the compare the privilege of an origin inside the scheduler.
pub struct OriginPrivilegeCmp;
impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option<Ordering> {
if left == right {
return Some(Ordering::Equal)
}
match (left, right) {
// Root is greater than anything.
(OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater),
// Check which one has more yes votes.
(
OriginCaller::Council(pallet_collective::RawOrigin::Members(l_yes_votes, l_count)),
OriginCaller::Council(pallet_collective::RawOrigin::Members(r_yes_votes, r_count)),
) => Some((l_yes_votes * r_count).cmp(&(r_yes_votes * l_count))),
// For every other origin we don't care, as they are not used for `ScheduleOrigin`.
_ => None,
}
}
}
impl pallet_scheduler::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type RuntimeEvent = RuntimeEvent;
type PalletsOrigin = OriginCaller;
type RuntimeCall = RuntimeCall;
type MaximumWeight = MaximumSchedulerWeight;
type ScheduleOrigin = ScheduleOrigin;
type MaxScheduledPerBlock = MaxScheduledPerBlock;
type WeightInfo = weights::pallet_scheduler::WeightInfo<Runtime>;
type OriginPrivilegeCmp = OriginPrivilegeCmp;
type Preimages = Preimage;
}
parameter_types! {
pub const PreimageMaxSize: u32 = 4096 * 1024;
pub const PreimageBaseDeposit: Balance = deposit(2, 64);
pub const PreimageByteDeposit: Balance = deposit(0, 1);
}
impl pallet_preimage::Config for Runtime {
type WeightInfo = weights::pallet_preimage::WeightInfo<Runtime>;
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type ManagerOrigin = EnsureRoot<AccountId>;
type BaseDeposit = PreimageBaseDeposit;
type ByteDeposit = PreimageByteDeposit;
}
parameter_types! {
pub EpochDuration: u64 = prod_or_fast!(
EPOCH_DURATION_IN_SLOTS as u64,
2 * MINUTES as u64,
"DOT_EPOCH_DURATION"
);
pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
pub ReportLongevity: u64 =
BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get();
}
impl pallet_babe::Config for Runtime {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
// session module is the trigger
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 = 10 * DOLLARS;
}
impl pallet_indices::Config for Runtime {
type AccountIndex = AccountIndex;
type Currency = Balances;
type Deposit = IndexDeposit;
type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::pallet_indices::WeightInfo<Runtime>;
}
parameter_types! {
pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
pub const MaxLocks: u32 = 50;
pub const MaxReserves: u32 = 50;
}
impl pallet_balances::Config for Runtime {
type Balance = Balance;
type DustRemoval = ();
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type MaxLocks = MaxLocks;
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
type WeightInfo = weights::pallet_balances::WeightInfo<Runtime>;
}
parameter_types! {
pub const TransactionByteFee: Balance = 10 * MILLICENTS;
/// This value increases the priority of `Operational` transactions by adding
/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
pub const OperationalFeeMultiplier: u8 = 5;
}
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees<Runtime>>;
type OperationalFeeMultiplier = OperationalFeeMultiplier;
type WeightToFee = WeightToFee;
type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
}
parameter_types! {
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
}
impl pallet_timestamp::Config for Runtime {
type Moment = u64;
type OnTimestampSet = Babe;
type MinimumPeriod = MinimumPeriod;
type WeightInfo = weights::pallet_timestamp::WeightInfo<Runtime>;
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Babe>;
type EventHandler = (Staking, ImOnline);
}
impl_opaque_keys! {
pub struct SessionKeys {
pub grandpa: Grandpa,
pub babe: Babe,
pub im_online: ImOnline,
pub para_validator: Initializer,
pub para_assignment: ParaSessionInfo,
pub authority_discovery: AuthorityDiscovery,
}
}
impl pallet_session::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ValidatorId = 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 = weights::pallet_session::WeightInfo<Runtime>;
}
impl pallet_session::historical::Config for Runtime {
type FullIdentification = pallet_staking::Exposure<AccountId, Balance>;
type FullIdentificationOf = pallet_staking::ExposureOf<Runtime>;
}
parameter_types! {
// phase durations. 1/4 of the last session for each.
// in testing: 1min or half of the session for each
pub SignedPhase: u32 = prod_or_fast!(
EPOCH_DURATION_IN_SLOTS / 4,
(1 * MINUTES).min(EpochDuration::get().saturated_into::<u32>() / 2),
"DOT_SIGNED_PHASE"
);
pub UnsignedPhase: u32 = prod_or_fast!(
EPOCH_DURATION_IN_SLOTS / 4,
(1 * MINUTES).min(EpochDuration::get().saturated_into::<u32>() / 2),
"DOT_UNSIGNED_PHASE"
);
// signed config
pub const SignedMaxSubmissions: u32 = 16;
pub const SignedMaxRefunds: u32 = 16 / 4;
// 40 DOTs fixed deposit..
pub const SignedDepositBase: Balance = deposit(2, 0);
// 0.01 DOT per KB of solution data.
pub const SignedDepositByte: Balance = deposit(0, 10) / 1024;
// Each good submission will get 1 DOT as reward
pub SignedRewardBase: Balance = 1 * UNITS;
pub BetterUnsignedThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
// 4 hour session, 1 hour unsigned phase, 32 offchain executions.
pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 32;
/// We take the top 22500 nominators as electing voters..
pub const MaxElectingVoters: u32 = 22_500;
/// ... and all of the validators as electable targets. Whilst this is the case, we cannot and
/// shall not increase the size of the validator intentions.
pub const MaxElectableTargets: u16 = u16::MAX;
/// Setup election pallet to support maximum winners upto 1200. This will mean Staking Pallet
/// cannot have active validators higher than this count.
pub const MaxActiveValidators: u32 = 1200;
}
generate_solution_type!(
#[compact]
pub struct NposCompactSolution16::<
VoterIndex = u32,
TargetIndex = u16,
Accuracy = sp_runtime::PerU16,
MaxVoters = MaxElectingVoters,
>(16)
);
pub struct OnChainSeqPhragmen;
impl onchain::Config for OnChainSeqPhragmen {
type System = Runtime;
type Solver = SequentialPhragmen<AccountId, runtime_common::elections::OnChainAccuracy>;
type DataProvider = Staking;
type WeightInfo = weights::frame_election_provider_support::WeightInfo<Runtime>;
type MaxWinners = MaxActiveValidators;
type VotersBound = MaxElectingVoters;
type TargetsBound = MaxElectableTargets;
}
impl pallet_election_provider_multi_phase::MinerConfig for Runtime {
type AccountId = AccountId;
type MaxLength = OffchainSolutionLengthLimit;
type MaxWeight = OffchainSolutionWeightLimit;
type Solution = NposCompactSolution16;
type MaxVotesPerVoter = <
<Self as pallet_election_provider_multi_phase::Config>::DataProvider
as
frame_election_provider_support::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 RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type EstimateCallFee = TransactionPayment;
type SignedPhase = SignedPhase;
type UnsignedPhase = UnsignedPhase;
type SignedMaxSubmissions = SignedMaxSubmissions;
type SignedMaxRefunds = SignedMaxRefunds;
type SignedRewardBase = SignedRewardBase;
type SignedDepositBase = SignedDepositBase;
type SignedDepositByte = SignedDepositByte;
type SignedDepositWeight = ();
type SignedMaxWeight =
<Self::MinerConfig as pallet_election_provider_multi_phase::MinerConfig>::MaxWeight;
type MinerConfig = Self;
type SlashHandler = (); // burn slashes
type RewardHandler = (); // nothing to do upon rewards
type BetterUnsignedThreshold = BetterUnsignedThreshold;
type BetterSignedThreshold = ();
type OffchainRepeat = OffchainRepeat;
type MinerTxPriority = NposSolutionPriority;
type DataProvider = Staking;
#[cfg(feature = "fast-runtime")]
type Fallback = onchain::OnChainExecution<OnChainSeqPhragmen>;
#[cfg(not(feature = "fast-runtime"))]
type Fallback = frame_election_provider_support::NoElection<(
AccountId,
BlockNumber,
Staking,
MaxActiveValidators,
)>;
type GovernanceFallback = onchain::OnChainExecution<OnChainSeqPhragmen>;
type Solver = SequentialPhragmen<
AccountId,
pallet_election_provider_multi_phase::SolutionAccuracyOf<Self>,
(),
>;
type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig;
type ForceOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 2, 3>,
>;
type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo<Self>;
type MaxElectingVoters = MaxElectingVoters;
type MaxElectableTargets = MaxElectableTargets;
type MaxWinners = MaxActiveValidators;
}
parameter_types! {
pub const BagThresholds: &'static [u64] = &bag_thresholds::THRESHOLDS;
}
type VoterBagsListInstance = pallet_bags_list::Instance1;
impl pallet_bags_list::Config<VoterBagsListInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type ScoreProvider = Staking;
type WeightInfo = weights::pallet_bags_list::WeightInfo<Runtime>;
type BagThresholds = BagThresholds;
type Score = sp_npos_elections::VoteWeight;
}
// TODO #6469: This shouldn't be static, but a lazily cached value, not built unless needed, and
// re-built in case input parameters have changed. The `ideal_stake` should be determined by the
// amount of parachain slots being bid on: this should be around `(75 - 25.min(slots / 4))%`.
pallet_staking_reward_curve::build! {
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
min_inflation: 0_025_000,
max_inflation: 0_100_000,
// 3:2:1 staked : parachains : float.
// while there's no parachains, then this is 75% staked : 25% float.
ideal_stake: 0_750_000,
falloff: 0_050_000,
max_piece_count: 40,
test_precision: 0_005_000,
);
}
parameter_types! {
// Six sessions in an era (24 hours).
pub const SessionsPerEra: SessionIndex = prod_or_fast!(6, 1);
// 28 eras for unbonding (28 days).
pub BondingDuration: sp_staking::EraIndex = prod_or_fast!(
28,
28,
"DOT_BONDING_DURATION"
);
pub SlashDeferDuration: sp_staking::EraIndex = prod_or_fast!(
27,
27,
"DOT_SLASH_DEFER_DURATION"
);
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
pub const MaxNominatorRewardedPerValidator: u32 = 512;
pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17);
// 16
pub const MaxNominations: u32 = <NposCompactSolution16 as frame_election_provider_support::NposSolution>::LIMIT as u32;
}
type StakingAdminOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 4>,
>;
pub struct EraPayout;
impl pallet_staking::EraPayout<Balance> for EraPayout {
fn era_payout(
total_staked: Balance,
total_issuance: Balance,
era_duration_millis: u64,
) -> (Balance, Balance) {
// all para-ids that are not active.
let auctioned_slots = Paras::parachains()
.into_iter()
// all active para-ids that do not belong to a system or common good chain is the number
// of parachains that we should take into account for inflation.
.filter(|i| *i >= LOWEST_PUBLIC_ID)
.count() as u64;
const MAX_ANNUAL_INFLATION: Perquintill = Perquintill::from_percent(10);
const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100;
runtime_common::impls::era_payout(
total_staked,
total_issuance,
MAX_ANNUAL_INFLATION,
Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR),
auctioned_slots,
)
}
}
impl pallet_staking::Config for Runtime {
type MaxNominations = MaxNominations;
type Currency = Balances;
type CurrencyBalance = Balance;
type UnixTime = Timestamp;
type CurrencyToVote = CurrencyToVote;
type RewardRemainder = Treasury;
type RuntimeEvent = RuntimeEvent;
type Slash = Treasury;
type Reward = ();
type SessionsPerEra = SessionsPerEra;
type BondingDuration = BondingDuration;
type SlashDeferDuration = SlashDeferDuration;
type AdminOrigin = StakingAdminOrigin;
type SessionInterface = Self;
type EraPayout = EraPayout;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
type NextNewSession = Session;
type ElectionProvider = ElectionProviderMultiPhase;
type GenesisElectionProvider = onchain::OnChainExecution<OnChainSeqPhragmen>;
type VoterList = VoterList;
type TargetList = UseValidatorsMap<Self>;
type MaxUnlockingChunks = frame_support::traits::ConstU32<32>;
type HistoryDepth = frame_support::traits::ConstU32<84>;
type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig;
type OnStakerSlash = NominationPools;
type WeightInfo = weights::pallet_staking::WeightInfo<Runtime>;
}
impl pallet_fast_unstake::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type BatchSize = frame_support::traits::ConstU32<16>;
type Deposit = frame_support::traits::ConstU128<{ UNITS }>;
type ControlOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 2>,
>;
type Staking = Staking;
type MaxErasToCheckPerBlock = ConstU32<1>;
#[cfg(feature = "runtime-benchmarks")]
type MaxBackersPerValidator = MaxNominatorRewardedPerValidator;
type WeightInfo = weights::pallet_fast_unstake::WeightInfo<Runtime>;
}
parameter_types! {
// Minimum 4 CENTS/byte
pub const BasicDeposit: Balance = deposit(1, 258);
pub const FieldDeposit: Balance = deposit(0, 66);
pub const SubAccountDeposit: Balance = deposit(1, 53);
pub const MaxSubAccounts: u32 = 100;
pub const MaxAdditionalFields: u32 = 100;
pub const MaxRegistrars: u32 = 20;
}
impl pallet_identity::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
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 = MoreThanHalfCouncil;
type RegistrarOrigin = MoreThanHalfCouncil;
type WeightInfo = weights::pallet_identity::WeightInfo<Runtime>;
}
parameter_types! {
pub LaunchPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1, "DOT_LAUNCH_PERIOD");
pub VotingPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1 * MINUTES, "DOT_VOTING_PERIOD");
pub FastTrackVotingPeriod: BlockNumber = prod_or_fast!(3 * HOURS, 1 * MINUTES, "DOT_FAST_TRACK_VOTING_PERIOD");
pub const MinimumDeposit: Balance = 100 * DOLLARS;
pub EnactmentPeriod: BlockNumber = prod_or_fast!(28 * DAYS, 1, "DOT_ENACTMENT_PERIOD");
pub CooloffPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1, "DOT_COOLOFF_PERIOD");
pub const InstantAllowed: bool = true;
pub const MaxVotes: u32 = 100;
pub const MaxProposals: u32 = 100;
}
impl pallet_democracy::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type EnactmentPeriod = EnactmentPeriod;
type VoteLockingPeriod = EnactmentPeriod;
type LaunchPeriod = LaunchPeriod;
type VotingPeriod = VotingPeriod;
type MinimumDeposit = MinimumDeposit;
/// A straight majority of the council can decide what their next motion is.
type ExternalOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 2>,
frame_system::EnsureRoot<AccountId>,
>;
/// A 60% super-majority can have the next scheduled referendum be a straight majority-carries vote.
type ExternalMajorityOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 5>,
frame_system::EnsureRoot<AccountId>,
>;
/// A unanimous council can have the next scheduled referendum be a straight default-carries
/// (NTB) vote.
type ExternalDefaultOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 1, 1>,
frame_system::EnsureRoot<AccountId>,
>;
/// Two thirds of the technical committee can have an `ExternalMajority/ExternalDefault` vote
/// be tabled immediately and with a shorter voting/enactment period.
type FastTrackOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, TechnicalCollective, 2, 3>,
frame_system::EnsureRoot<AccountId>,
>;
type InstantOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, TechnicalCollective, 1, 1>,
frame_system::EnsureRoot<AccountId>,
>;
type InstantAllowed = InstantAllowed;
type FastTrackVotingPeriod = FastTrackVotingPeriod;
// To cancel a proposal which has been passed, 2/3 of the council must agree to it.
type CancellationOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 2, 3>,
EnsureRoot<AccountId>,
>;
// To cancel a proposal before it has been passed, the technical committee must be unanimous or
// Root must agree.
type CancelProposalOrigin = EitherOfDiverse<
pallet_collective::EnsureProportionAtLeast<AccountId, TechnicalCollective, 1, 1>,
EnsureRoot<AccountId>,
>;
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 cooloff period.
type VetoOrigin = pallet_collective::EnsureMember<AccountId, TechnicalCollective>;
type CooloffPeriod = CooloffPeriod;
type Slash = Treasury;
type Scheduler = Scheduler;
type PalletsOrigin = OriginCaller;
type MaxVotes = MaxVotes;
type WeightInfo = weights::pallet_democracy::WeightInfo<Runtime>;
type MaxProposals = MaxProposals;
type Preimages = Preimage;
type MaxDeposits = ConstU32<100>;
type MaxBlacklisted = ConstU32<100>;
}
parameter_types! {
pub CouncilMotionDuration: BlockNumber = prod_or_fast!(7 * DAYS, 2 * MINUTES, "DOT_MOTION_DURATION");
pub const CouncilMaxProposals: u32 = 100;
pub const CouncilMaxMembers: u32 = 100;
}
pub type CouncilCollective = pallet_collective::Instance1;
impl pallet_collective::Config<CouncilCollective> for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = CouncilMotionDuration;
type MaxProposals = CouncilMaxProposals;
type MaxMembers = CouncilMaxMembers;
type DefaultVote = pallet_collective::PrimeDefaultVote;
type WeightInfo = weights::pallet_collective_council::WeightInfo<Runtime>;
}
parameter_types! {
pub const CandidacyBond: Balance = 100 * 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);
/// Weekly council elections; scaling up to monthly eventually.
pub TermDuration: BlockNumber = prod_or_fast!(7 * DAYS, 2 * MINUTES, "DOT_TERM_DURATION");
/// 13 members initially, to be increased to 23 eventually.
pub const DesiredMembers: u32 = 13;
pub const DesiredRunnersUp: u32 = 20;
pub const MaxVoters: u32 = 10 * 1000;
pub const MaxCandidates: u32 = 1000;
pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect";
}
// Make sure that there are no more than `MaxMembers` members elected via phragmen.
const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get());
impl pallet_elections_phragmen::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type PalletId = PhragmenElectionPalletId;
type Currency = Balances;
type ChangeMembers = Council;
type InitializeMembers = Council;
type CurrencyToVote = frame_support::traits::U128CurrencyToVote;
type CandidacyBond = CandidacyBond;
type VotingBondBase = VotingBondBase;
type VotingBondFactor = VotingBondFactor;
type LoserCandidate = Treasury;
type KickedMember = Treasury;
type DesiredMembers = DesiredMembers;
type DesiredRunnersUp = DesiredRunnersUp;
type TermDuration = TermDuration;
type MaxVoters = MaxVoters;
type MaxCandidates = MaxCandidates;
type WeightInfo = weights::pallet_elections_phragmen::WeightInfo<Runtime>;
}
parameter_types! {
pub const TechnicalMotionDuration: BlockNumber = 7 * DAYS;
pub const TechnicalMaxProposals: u32 = 100;
pub const TechnicalMaxMembers: u32 = 100;
}
pub type TechnicalCollective = pallet_collective::Instance2;
impl pallet_collective::Config<TechnicalCollective> for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = TechnicalMotionDuration;
type MaxProposals = TechnicalMaxProposals;
type MaxMembers = TechnicalMaxMembers;
type DefaultVote = pallet_collective::PrimeDefaultVote;
type WeightInfo = weights::pallet_collective_technical_committee::WeightInfo<Runtime>;
}
impl pallet_membership::Config<pallet_membership::Instance1> for Runtime {
type RuntimeEvent = RuntimeEvent;
type AddOrigin = MoreThanHalfCouncil;
type RemoveOrigin = MoreThanHalfCouncil;
type SwapOrigin = MoreThanHalfCouncil;
type ResetOrigin = MoreThanHalfCouncil;
type PrimeOrigin = MoreThanHalfCouncil;
type MembershipInitialized = TechnicalCommittee;
type MembershipChanged = TechnicalCommittee;
type MaxMembers = TechnicalMaxMembers;
type WeightInfo = weights::pallet_membership::WeightInfo<Runtime>;
}
parameter_types! {
pub const ProposalBond: Permill = Permill::from_percent(5);
pub const ProposalBondMinimum: Balance = 100 * DOLLARS;
pub const ProposalBondMaximum: Balance = 500 * DOLLARS;
pub const SpendPeriod: BlockNumber = 24 * DAYS;
pub const Burn: Permill = Permill::from_percent(1);
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
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 MaxApprovals: u32 = 100;
pub const MaxAuthorities: u32 = 100_000;
pub const MaxKeys: u32 = 10_000;
pub const MaxPeerInHeartbeats: u32 = 10_000;
pub const MaxPeerDataEncodingSize: u32 = 1_000;
pub const RootSpendOriginMaxAmount: Balance = Balance::MAX;
}
type ApproveOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 5>,
>;
impl pallet_treasury::Config for Runtime {
type PalletId = TreasuryPalletId;
type Currency = Balances;
type ApproveOrigin = ApproveOrigin;
type RejectOrigin = MoreThanHalfCouncil;
type RuntimeEvent = RuntimeEvent;
type OnSlash = Treasury;
type ProposalBond = ProposalBond;
type ProposalBondMinimum = ProposalBondMinimum;
type ProposalBondMaximum = ProposalBondMaximum;
type SpendPeriod = SpendPeriod;
type Burn = Burn;
type BurnDestination = ();
type SpendFunds = Bounties;
type MaxApprovals = MaxApprovals;
type WeightInfo = weights::pallet_treasury::WeightInfo<Runtime>;
type SpendOrigin = frame_system::EnsureRootWithSuccess<AccountId, RootSpendOriginMaxAmount>;
}
parameter_types! {
pub const BountyDepositBase: Balance = 1 * DOLLARS;
pub const BountyDepositPayoutDelay: BlockNumber = 8 * DAYS;
pub const BountyUpdatePeriod: BlockNumber = 90 * DAYS;
pub const MaximumReasonLength: u32 = 16384;
pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50);
pub const CuratorDepositMin: Balance = 10 * DOLLARS;
pub const CuratorDepositMax: Balance = 200 * DOLLARS;
pub const BountyValueMinimum: Balance = 10 * DOLLARS;
}
impl pallet_bounties::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type BountyDepositBase = BountyDepositBase;
type BountyDepositPayoutDelay = BountyDepositPayoutDelay;
type BountyUpdatePeriod = BountyUpdatePeriod;
type CuratorDepositMultiplier = CuratorDepositMultiplier;
type CuratorDepositMin = CuratorDepositMin;
type CuratorDepositMax = CuratorDepositMax;
type BountyValueMinimum = BountyValueMinimum;
type ChildBountyManager = ChildBounties;
type DataDepositPerByte = DataDepositPerByte;
type MaximumReasonLength = MaximumReasonLength;
type WeightInfo = weights::pallet_bounties::WeightInfo<Runtime>;
}
parameter_types! {
pub const MaxActiveChildBountyCount: u32 = 100;
pub const ChildBountyValueMinimum: Balance = BountyValueMinimum::get() / 10;
}
impl pallet_child_bounties::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type MaxActiveChildBountyCount = MaxActiveChildBountyCount;
type ChildBountyValueMinimum = ChildBountyValueMinimum;
type WeightInfo = weights::pallet_child_bounties::WeightInfo<Runtime>;
}
impl pallet_tips::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type DataDepositPerByte = DataDepositPerByte;
type MaximumReasonLength = MaximumReasonLength;
type Tippers = PhragmenElection;
type TipCountdown = TipCountdown;
type TipFindersFee = TipFindersFee;
type TipReportDepositBase = TipReportDepositBase;
type WeightInfo = weights::pallet_tips::WeightInfo<Runtime>;
}
impl pallet_offences::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type OnOffenceHandler = Staking;
}
impl pallet_authority_discovery::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
}
parameter_types! {
pub NposSolutionPriority: TransactionPriority =
Perbill::from_percent(90) * TransactionPriority::max_value();
pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
}
impl pallet_im_online::Config for Runtime {
type AuthorityId = ImOnlineId;
type RuntimeEvent = RuntimeEvent;
type ValidatorSet = Historical;
type NextSessionRotation = Babe;
type ReportUnresponsiveness = Offences;
type UnsignedPriority = ImOnlineUnsignedPriority;
type WeightInfo = weights::pallet_im_online::WeightInfo<Runtime>;
type MaxKeys = MaxKeys;
type MaxPeerInHeartbeats = MaxPeerInHeartbeats;
type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize;
}
parameter_types! {
pub MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get();
}
impl pallet_grandpa::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type KeyOwnerProof =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
GrandpaId,
)>>::IdentificationTuple;
type KeyOwnerProofSystem = Historical;
type HandleEquivocation = pallet_grandpa::EquivocationHandler<
Self::KeyOwnerIdentification,
Offences,
ReportLongevity,
>;
type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;
type MaxSetIdSessionEntries = MaxSetIdSessionEntries;
}
/// Submits a transaction with the node's public and signature type. Adheres to the signed extension
/// format of the chain.
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
where
RuntimeCall: From<LocalCall>,
{
fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
call: RuntimeCall,
public: <Signature as Verify>::Signer,
account: AccountId,
nonce: <Runtime as frame_system::Config>::Index,
) -> Option<(RuntimeCall, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
use sp_runtime::traits::StaticLookup;
// 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 tip = 0;
let extra: SignedExtra = (
frame_system::CheckNonZeroSender::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckMortality::<Runtime>::from(generic::Era::mortal(
period,
current_block,
)),
frame_system::CheckNonce::<Runtime>::from(nonce),
frame_system::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
claims::PrevalidateAttests::<Runtime>::new(),
);
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 (call, extra, _) = raw_payload.deconstruct();
let address = <Runtime as frame_system::Config>::Lookup::unlookup(account);
Some((call, (address, signature, extra)))
}
}
impl frame_system::offchain::SigningTypes for Runtime {
type Public = <Signature as Verify>::Signer;
type Signature = Signature;
}
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
where
RuntimeCall: From<C>,
{
type Extrinsic = UncheckedExtrinsic;
type OverarchingCall = RuntimeCall;
}
parameter_types! {
pub const ParathreadDeposit: Balance = 500 * DOLLARS;
pub const MaxRetries: u32 = 3;
}
parameter_types! {
pub Prefix: &'static [u8] = b"Pay DOTs to the Polkadot account:";
}
impl claims::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type VestingSchedule = Vesting;
type Prefix = Prefix;
/// At least 3/4 of the council must agree to a claim move before it can happen.
type MoveClaimOrigin =
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 3, 4>;
type WeightInfo = weights::runtime_common_claims::WeightInfo<Runtime>;
}
parameter_types! {
pub const MinVestedTransfer: Balance = 1 * DOLLARS;
pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons =
WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE);
}
impl pallet_vesting::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type BlockNumberToBalance = ConvertInto;
type MinVestedTransfer = MinVestedTransfer;
type WeightInfo = weights::pallet_vesting::WeightInfo<Runtime>;
type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons;
const MAX_VESTING_SCHEDULES: u32 = 28;
}
impl pallet_utility::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type PalletsOrigin = OriginCaller;
type WeightInfo = weights::pallet_utility::WeightInfo<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);
pub const MaxSignatories: u32 = 100;
}
impl pallet_multisig::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type Currency = Balances;
type DepositBase = DepositBase;
type DepositFactor = DepositFactor;
type MaxSignatories = MaxSignatories;
type WeightInfo = weights::pallet_multisig::WeightInfo<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 MaxProxies: u16 = 32;
pub const AnnouncementDepositBase: Balance = deposit(1, 8);
pub const AnnouncementDepositFactor: Balance = deposit(0, 66);
pub const MaxPending: u16 = 32;
}
/// 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 = 0,
NonTransfer = 1,
Governance = 2,
Staking = 3,
// Skip 4 as it is now removed (was SudoBalances)
IdentityJudgement = 5,
CancelProxy = 6,
Auction = 7,
}
#[cfg(test)]
mod proxy_type_tests {
use super::*;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug)]
pub enum OldProxyType {
Any,
NonTransfer,
Governance,
Staking,
SudoBalances,
IdentityJudgement,
}
#[test]
fn proxy_type_decodes_correctly() {
for (i, j) in vec![
(OldProxyType::Any, ProxyType::Any),
(OldProxyType::NonTransfer, ProxyType::NonTransfer),
(OldProxyType::Governance, ProxyType::Governance),
(OldProxyType::Staking, ProxyType::Staking),
(OldProxyType::IdentityJudgement, ProxyType::IdentityJudgement),
]
.into_iter()
{
assert_eq!(i.encode(), j.encode());
}
assert!(ProxyType::decode(&mut &OldProxyType::SudoBalances.encode()[..]).is_err());
}
}
impl Default for ProxyType {
fn default() -> Self {
Self::Any
}
}
impl InstanceFilter<RuntimeCall> for ProxyType {
fn filter(&self, c: &RuntimeCall) -> bool {
match self {
ProxyType::Any => true,
ProxyType::NonTransfer => matches!(
c,
RuntimeCall::System(..) |
RuntimeCall::Scheduler(..) |
RuntimeCall::Babe(..) |
RuntimeCall::Timestamp(..) |
RuntimeCall::Indices(pallet_indices::Call::claim{..}) |
RuntimeCall::Indices(pallet_indices::Call::free{..}) |
RuntimeCall::Indices(pallet_indices::Call::freeze{..}) |
// Specifically omitting Indices `transfer`, `force_transfer`
// Specifically omitting the entire Balances pallet
RuntimeCall::Staking(..) |
RuntimeCall::Session(..) |
RuntimeCall::Grandpa(..) |
RuntimeCall::ImOnline(..) |
RuntimeCall::Democracy(..) |
RuntimeCall::Council(..) |
RuntimeCall::TechnicalCommittee(..) |
RuntimeCall::PhragmenElection(..) |
RuntimeCall::TechnicalMembership(..) |
RuntimeCall::Treasury(..) |
RuntimeCall::Bounties(..) |
RuntimeCall::ChildBounties(..) |
RuntimeCall::Tips(..) |
RuntimeCall::Claims(..) |
RuntimeCall::Vesting(pallet_vesting::Call::vest{..}) |
RuntimeCall::Vesting(pallet_vesting::Call::vest_other{..}) |
// Specifically omitting Vesting `vested_transfer`, and `force_vested_transfer`
RuntimeCall::Utility(..) |
RuntimeCall::Identity(..) |
RuntimeCall::Proxy(..) |
RuntimeCall::Multisig(..) |
RuntimeCall::Registrar(paras_registrar::Call::register {..}) |
RuntimeCall::Registrar(paras_registrar::Call::deregister {..}) |
// Specifically omitting Registrar `swap`
RuntimeCall::Registrar(paras_registrar::Call::reserve {..}) |
RuntimeCall::Crowdloan(..) |
RuntimeCall::Slots(..) |
RuntimeCall::Auctions(..) | // Specifically omitting the entire XCM Pallet
RuntimeCall::VoterList(..) |
RuntimeCall::NominationPools(..) |
RuntimeCall::FastUnstake(..)
),
ProxyType::Governance =>
matches!(
c,
RuntimeCall::Democracy(..) |
RuntimeCall::Council(..) | RuntimeCall::TechnicalCommittee(..) |
RuntimeCall::PhragmenElection(..) |
RuntimeCall::Treasury(..) |
RuntimeCall::Bounties(..) |
RuntimeCall::Tips(..) | RuntimeCall::Utility(..) |
RuntimeCall::ChildBounties(..)
),
ProxyType::Staking => {
matches!(
c,
RuntimeCall::Staking(..) |
RuntimeCall::Session(..) | RuntimeCall::Utility(..) |
RuntimeCall::FastUnstake(..)
)
},
ProxyType::IdentityJudgement => matches!(
c,
RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) |
RuntimeCall::Utility(..)
),
ProxyType::CancelProxy => {
matches!(c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }))
},
ProxyType::Auction => matches!(
c,
RuntimeCall::Auctions(..) |
RuntimeCall::Crowdloan(..) |
RuntimeCall::Registrar(..) |
RuntimeCall::Slots(..)
),
}
}
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 RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type Currency = Balances;
type ProxyType = ProxyType;
type ProxyDepositBase = ProxyDepositBase;
type ProxyDepositFactor = ProxyDepositFactor;
type MaxProxies = MaxProxies;
type WeightInfo = weights::pallet_proxy::WeightInfo<Runtime>;
type MaxPending = MaxPending;
type CallHasher = BlakeTwo256;
type AnnouncementDepositBase = AnnouncementDepositBase;
type AnnouncementDepositFactor = AnnouncementDepositFactor;
}
impl parachains_origin::Config for Runtime {}
impl parachains_configuration::Config for Runtime {
type WeightInfo = weights::runtime_parachains_configuration::WeightInfo<Runtime>;
}
impl parachains_shared::Config for Runtime {}
impl parachains_session_info::Config for Runtime {
type ValidatorSet = Historical;
}
impl parachains_inclusion::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type DisputesHandler = ParasDisputes;
type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>;
}
parameter_types! {
pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
}
impl parachains_paras::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>;
type UnsignedPriority = ParasUnsignedPriority;
type NextSessionRotation = Babe;
}
parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100;
}
impl parachains_ump::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type UmpSink =
crate::parachains_ump::XcmSink<xcm_executor::XcmExecutor<xcm_config::XcmConfig>, Runtime>;
type FirstMessageFactorPercent = FirstMessageFactorPercent;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
type WeightInfo = weights::runtime_parachains_ump::WeightInfo<Self>;
}
impl parachains_dmp::Config for Runtime {}
impl parachains_hrmp::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo<Self>;
}
impl parachains_paras_inherent::Config for Runtime {
type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo<Runtime>;
}
impl parachains_scheduler::Config for Runtime {}
impl parachains_initializer::Config for Runtime {
type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
type ForceOrigin = EnsureRoot<AccountId>;
type WeightInfo = weights::runtime_parachains_initializer::WeightInfo<Runtime>;
}
impl parachains_disputes::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RewardValidators = ();
type SlashingHandler = ();
type WeightInfo = weights::runtime_parachains_disputes::WeightInfo<Runtime>;
}
parameter_types! {
// Mostly arbitrary deposit price, but should provide an adequate incentive not to spam reserve
// `ParaId`s.
pub const ParaDeposit: Balance = 100 * DOLLARS;
pub const ParaDataByteDeposit: Balance = deposit(0, 1);
}
impl paras_registrar::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type OnSwap = (Crowdloan, Slots);
type ParaDeposit = ParaDeposit;
type DataDepositPerByte = ParaDataByteDeposit;
type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo<Runtime>;
}
parameter_types! {
// 12 weeks = 3 months per lease period -> 8 lease periods ~ 2 years
pub LeasePeriod: BlockNumber = prod_or_fast!(12 * WEEKS, 12 * WEEKS, "DOT_LEASE_PERIOD");
// Polkadot Genesis was on May 26, 2020.
// Target Parachain Onboarding Date: Dec 15, 2021.
// Difference is 568 days.
// We want a lease period to start on the target onboarding date.
// 568 % (12 * 7) = 64 day offset
pub LeaseOffset: BlockNumber = prod_or_fast!(64 * DAYS, 0, "DOT_LEASE_OFFSET");
}
impl slots::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type Registrar = Registrar;
type LeasePeriod = LeasePeriod;
type LeaseOffset = LeaseOffset;
type ForceOrigin = MoreThanHalfCouncil;
type WeightInfo = weights::runtime_common_slots::WeightInfo<Runtime>;
}
parameter_types! {
pub const CrowdloanId: PalletId = PalletId(*b"py/cfund");
// Accounts for 10_000 contributions, each using 48 bytes (16 bytes for balance, and 32 bytes
// for a memo).
pub const SubmissionDeposit: Balance = deposit(1, 480_000);
// The minimum crowdloan contribution.
pub const MinContribution: Balance = 5 * DOLLARS;
pub const RemoveKeysLimit: u32 = 1000;
// Allow 32 bytes for an additional memo to a crowdloan.
pub const MaxMemoLength: u8 = 32;
}
impl crowdloan::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type PalletId = CrowdloanId;
type SubmissionDeposit = SubmissionDeposit;
type MinContribution = MinContribution;
type RemoveKeysLimit = RemoveKeysLimit;
type Registrar = Registrar;
type Auctioneer = Auctions;
type MaxMemoLength = MaxMemoLength;
type WeightInfo = weights::runtime_common_crowdloan::WeightInfo<Runtime>;
}
parameter_types! {
// The average auction is 7 days long, so this will be 70% for ending period.
// 5 Days = 72000 Blocks @ 6 sec per block
pub const EndingPeriod: BlockNumber = 5 * DAYS;
// ~ 1000 samples per day -> ~ 20 blocks per sample -> 2 minute samples
pub const SampleLength: BlockNumber = 2 * MINUTES;
}
type AuctionInitiate = EitherOfDiverse<
EnsureRoot<AccountId>,
pallet_collective::EnsureProportionAtLeast<AccountId, CouncilCollective, 2, 3>,
>;
impl auctions::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Leaser = Slots;
type Registrar = Registrar;
type EndingPeriod = EndingPeriod;
type SampleLength = SampleLength;
type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
type InitiateOrigin = AuctionInitiate;
type WeightInfo = weights::runtime_common_auctions::WeightInfo<Runtime>;
}
parameter_types! {
pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
// Allow pools that got slashed up to 90% to remain operational.
pub const MaxPointsToBalance: u8 = 10;
}
impl pallet_nomination_pools::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type RewardCounter = FixedU128;
type BalanceToU256 = runtime_common::BalanceToU256;
type U256ToBalance = runtime_common::U256ToBalance;
type Staking = Staking;
type PostUnbondingPoolsWindow = frame_support::traits::ConstU32<4>;
type MaxMetadataLen = frame_support::traits::ConstU32<256>;
// we use the same number of allowed unlocking chunks as with staking.
type MaxUnbonding = <Self as pallet_staking::Config>::MaxUnlockingChunks;
type PalletId = PoolsPalletId;
type MaxPointsToBalance = MaxPointsToBalance;
type WeightInfo = weights::pallet_nomination_pools::WeightInfo<Self>;
}
pub struct InitiateNominationPools;
impl frame_support::traits::OnRuntimeUpgrade for InitiateNominationPools {
fn on_runtime_upgrade() -> frame_support::weights::Weight {
// we use one as an indicator if this has already been set.
if pallet_nomination_pools::MaxPools::<Runtime>::get().is_none() {
// 5 DOT to join a pool.
pallet_nomination_pools::MinJoinBond::<Runtime>::put(5 * UNITS);
// 100 DOT to create a pool.
pallet_nomination_pools::MinCreateBond::<Runtime>::put(100 * UNITS);
// Initialize with limits for now.
pallet_nomination_pools::MaxPools::<Runtime>::put(0);
pallet_nomination_pools::MaxPoolMembersPerPool::<Runtime>::put(0);
pallet_nomination_pools::MaxPoolMembers::<Runtime>::put(0);
log::info!(target: "runtime::polkadot", "pools config initiated 🎉");
<Runtime as frame_system::Config>::DbWeight::get().reads_writes(1, 5)
} else {
log::info!(target: "runtime::polkadot", "pools config already initiated 😏");
<Runtime as frame_system::Config>::DbWeight::get().reads(1)
}
}
}
construct_runtime! {
pub enum Runtime where
Block = Block,
NodeBlock = primitives::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// Basic stuff; balances is uncallable initially.
System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 0,
Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event<T>} = 1,
Preimage: pallet_preimage::{Pallet, Call, Storage, Event<T>} = 10,
// Babe must be before session.
Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned} = 2,
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3,
Indices: pallet_indices::{Pallet, Call, Storage, Config<T>, Event<T>} = 4,
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 5,
TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event<T>} = 32,
// Consensus support.
// Authorship must be before session in order to note author in the correct session and era
// for im-online and staking.
Authorship: pallet_authorship::{Pallet, Storage} = 6,
Staking: pallet_staking::{Pallet, Call, Storage, Config<T>, Event<T>} = 7,
Offences: pallet_offences::{Pallet, Storage, Event} = 8,
Historical: session_historical::{Pallet} = 33,
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 9,
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned} = 11,
ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 12,
AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config} = 13,
// Governance stuff.
Democracy: pallet_democracy::{Pallet, Call, Storage, Config<T>, Event<T>} = 14,
Council: pallet_collective::<Instance1>::{Pallet, Call, Storage, Origin<T>, Event<T>, Config<T>} = 15,
TechnicalCommittee: pallet_collective::<Instance2>::{Pallet, Call, Storage, Origin<T>, Event<T>, Config<T>} = 16,
PhragmenElection: pallet_elections_phragmen::{Pallet, Call, Storage, Event<T>, Config<T>} = 17,
TechnicalMembership: pallet_membership::<Instance1>::{Pallet, Call, Storage, Event<T>, Config<T>} = 18,
Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 19,
// Claims. Usable initially.
Claims: claims::{Pallet, Call, Storage, Event<T>, Config<T>, ValidateUnsigned} = 24,
// Vesting. Usable initially, but removed once all vesting is finished.
Vesting: pallet_vesting::{Pallet, Call, Storage, Event<T>, Config<T>} = 25,
// Cunning utilities. Usable initially.
Utility: pallet_utility::{Pallet, Call, Event} = 26,
// Identity. Late addition.
Identity: pallet_identity::{Pallet, Call, Storage, Event<T>} = 28,
// Proxy module. Late addition.
Proxy: pallet_proxy::{Pallet, Call, Storage, Event<T>} = 29,
// Multisig dispatch. Late addition.
Multisig: pallet_multisig::{Pallet, Call, Storage, Event<T>} = 30,
// Bounties modules.
Bounties: pallet_bounties::{Pallet, Call, Storage, Event<T>} = 34,
ChildBounties: pallet_child_bounties = 38,
// Tips module.
Tips: pallet_tips::{Pallet, Call, Storage, Event<T>} = 35,
// Election pallet. Only works with staking, but placed here to maintain indices.
ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event<T>, ValidateUnsigned} = 36,
// Provides a semi-sorted list of nominators for staking.
VoterList: pallet_bags_list::<Instance1>::{Pallet, Call, Storage, Event<T>} = 37,
// Nomination pools: extension to staking.
NominationPools: pallet_nomination_pools::{Pallet, Call, Storage, Event<T>, Config<T>} = 39,
// Fast unstake pallet: extension to staking.
FastUnstake: pallet_fast_unstake = 40,
// Parachains pallets. Start indices at 50 to leave room.
ParachainsOrigin: parachains_origin::{Pallet, Origin} = 50,
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>} = 51,
ParasShared: parachains_shared::{Pallet, Call, Storage} = 52,
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>} = 53,
ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 54,
ParaScheduler: parachains_scheduler::{Pallet, Storage} = 55,
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56,
Initializer: parachains_initializer::{Pallet, Call, Storage} = 57,
Dmp: parachains_dmp::{Pallet, Call, Storage} = 58,
Ump: parachains_ump::{Pallet, Call, Storage, Event} = 59,
Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60,
ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61,
ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62,
// Parachain Onboarding Pallets. Start indices at 70 to leave room.
Registrar: paras_registrar::{Pallet, Call, Storage, Event<T>} = 70,
Slots: slots::{Pallet, Call, Storage, Event<T>} = 71,
Auctions: auctions::{Pallet, Call, Storage, Event<T>} = 72,
Crowdloan: crowdloan::{Pallet, Call, Storage, Event<T>} = 73,
// Pallet for sending XCM.
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99,
}
}
/// The address format for describing accounts.
pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
/// 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.
pub type SignedExtra = (
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckMortality<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
claims::PrevalidateAttests<Runtime>,
);
pub struct StakingMigrationV11OldPallet;
impl Get<&'static str> for StakingMigrationV11OldPallet {
fn get() -> &'static str {
"VoterList"
}
}
/// All migrations that will run on the next runtime upgrade.
///
/// Should be cleared after every release.
pub type Migrations = (
// "Use 2D weights in XCM v3" <https://github.com/paritytech/polkadot/pull/6134>
pallet_xcm::migration::v1::MigrateToV1<Runtime>,
parachains_ump::migration::v1::MigrateToV1<Runtime>,
// Remove stale entries in the set id -> session index storage map (after
// this release they will be properly pruned after the bonding duration has
// elapsed)
pallet_grandpa::migrations::CleanupSetIdSessionMap<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
Migrations,
>;
/// The payload being signed in transactions.
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
#[cfg(feature = "runtime-benchmarks")]
#[macro_use]
extern crate frame_benchmarking;
#[cfg(feature = "runtime-benchmarks")]
mod benches {
define_benchmarks!(
// Polkadot
// NOTE: Make sure to prefix these with `runtime_common::` so
// the that path resolves correctly in the generated file.
[runtime_common::auctions, Auctions]
[runtime_common::claims, Claims]
[runtime_common::crowdloan, Crowdloan]
[runtime_common::slots, Slots]
[runtime_common::paras_registrar, Registrar]
[runtime_parachains::configuration, Configuration]
[runtime_parachains::disputes, ParasDisputes]
[runtime_parachains::hrmp, Hrmp]
[runtime_parachains::initializer, Initializer]
[runtime_parachains::paras, Paras]
[runtime_parachains::paras_inherent, ParaInherent]
[runtime_parachains::ump, Ump]
// Substrate
[pallet_bags_list, VoterList]
[pallet_balances, Balances]
[frame_benchmarking::baseline, Baseline::<Runtime>]
[pallet_bounties, Bounties]
[pallet_child_bounties, ChildBounties]
[pallet_collective, Council]
[pallet_collective, TechnicalCommittee]
[pallet_democracy, Democracy]
[pallet_elections_phragmen, PhragmenElection]
[pallet_election_provider_multi_phase, ElectionProviderMultiPhase]
[frame_election_provider_support, ElectionProviderBench::<Runtime>]
[pallet_fast_unstake, FastUnstake]
[pallet_identity, Identity]
[pallet_im_online, ImOnline]
[pallet_indices, Indices]
[pallet_membership, TechnicalMembership]
[pallet_multisig, Multisig]
[pallet_nomination_pools, NominationPoolsBench::<Runtime>]
[pallet_offences, OffencesBench::<Runtime>]
[pallet_preimage, Preimage]
[pallet_proxy, Proxy]
[pallet_scheduler, Scheduler]
[pallet_session, SessionBench::<Runtime>]
[pallet_staking, Staking]
[frame_system, SystemBench::<Runtime>]
[pallet_timestamp, Timestamp]
[pallet_tips, Tips]
[pallet_treasury, Treasury]
[pallet_utility, Utility]
[pallet_vesting, Vesting]
// XCM
[pallet_xcm, XcmPallet]
);
}
#[cfg(not(feature = "disable-runtime-api"))]
sp_api::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 block_builder_api::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: inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
data.create_extrinsics()
}
fn check_inherents(
block: Block,
data: inherents::InherentData,
) -> inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
}
impl pallet_nomination_pools_runtime_api::NominationPoolsApi<
Block,
AccountId,
Balance,
> for Runtime {
fn pending_rewards(member: AccountId) -> Balance {
NominationPools::pending_rewards(member).unwrap_or_default()
}
}
impl tx_pool_api::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 offchain_primitives::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(header: &<Block as BlockT>::Header) {
Executive::offchain_worker(header)
}
}
impl primitives::runtime_api::ParachainHost<Block, Hash, BlockNumber> for Runtime {
fn validators() -> Vec<ValidatorId> {
parachains_runtime_api_impl::validators::<Runtime>()
}
fn validator_groups() -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>) {
parachains_runtime_api_impl::validator_groups::<Runtime>()
}
fn availability_cores() -> Vec<CoreState<Hash, BlockNumber>> {
parachains_runtime_api_impl::availability_cores::<Runtime>()
}
fn persisted_validation_data(para_id: ParaId, assumption: OccupiedCoreAssumption)
-> Option<PersistedValidationData<Hash, BlockNumber>> {
parachains_runtime_api_impl::persisted_validation_data::<Runtime>(para_id, assumption)
}
fn assumed_validation_data(
para_id: ParaId,
expected_persisted_validation_data_hash: Hash,
) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
parachains_runtime_api_impl::assumed_validation_data::<Runtime>(
para_id,
expected_persisted_validation_data_hash,
)
}
fn check_validation_outputs(
para_id: ParaId,
outputs: primitives::CandidateCommitments,
) -> bool {
parachains_runtime_api_impl::check_validation_outputs::<Runtime>(para_id, outputs)
}
fn session_index_for_child() -> SessionIndex {
parachains_runtime_api_impl::session_index_for_child::<Runtime>()
}
fn validation_code(para_id: ParaId, assumption: OccupiedCoreAssumption)
-> Option<ValidationCode> {
parachains_runtime_api_impl::validation_code::<Runtime>(para_id, assumption)
}
fn candidate_pending_availability(para_id: ParaId) -> Option<CommittedCandidateReceipt<Hash>> {
parachains_runtime_api_impl::candidate_pending_availability::<Runtime>(para_id)
}
fn candidate_events() -> Vec<CandidateEvent<Hash>> {
parachains_runtime_api_impl::candidate_events::<Runtime, _>(|ev| {
match ev {
RuntimeEvent::ParaInclusion(ev) => {
Some(ev)
}
_ => None,
}
})
}
fn session_info(index: SessionIndex) -> Option<SessionInfo> {
parachains_runtime_api_impl::session_info::<Runtime>(index)
}
fn dmq_contents(recipient: ParaId) -> Vec<InboundDownwardMessage<BlockNumber>> {
parachains_runtime_api_impl::dmq_contents::<Runtime>(recipient)
}
fn inbound_hrmp_channels_contents(
recipient: ParaId
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>> {
parachains_runtime_api_impl::inbound_hrmp_channels_contents::<Runtime>(recipient)
}
fn validation_code_by_hash(hash: ValidationCodeHash) -> Option<ValidationCode> {
parachains_runtime_api_impl::validation_code_by_hash::<Runtime>(hash)
}
fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
parachains_runtime_api_impl::on_chain_votes::<Runtime>()
}
fn submit_pvf_check_statement(
stmt: primitives::PvfCheckStatement,
signature: primitives::ValidatorSignature,
) {
parachains_runtime_api_impl::submit_pvf_check_statement::<Runtime>(stmt, signature)
}
fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
parachains_runtime_api_impl::pvfs_require_precheck::<Runtime>()
}
fn validation_code_hash(para_id: ParaId, assumption: OccupiedCoreAssumption)
-> Option<ValidationCodeHash>
{
parachains_runtime_api_impl::validation_code_hash::<Runtime>(para_id, assumption)
}
}
impl beefy_primitives::BeefyApi<Block> for Runtime {
fn validator_set() -> Option<beefy_primitives::ValidatorSet<BeefyId>> {
// dummy implementation due to lack of BEEFY pallet.
None
}
}
impl mmr::MmrApi<Block, Hash, BlockNumber> for Runtime {
fn mmr_root() -> Result<Hash, mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}
fn mmr_leaf_count() -> Result<mmr::LeafIndex, mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}
fn generate_proof(
_block_numbers: Vec<BlockNumber>,
_best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<Hash>), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}
fn verify_proof(_leaves: Vec<mmr::EncodableOpaqueLeaf>, _proof: mmr::Proof<Hash>)
-> Result<(), mmr::Error>
{
Err(mmr::Error::PalletNotIncluded)
}
fn verify_proof_stateless(
_root: Hash,
_leaves: Vec<mmr::EncodableOpaqueLeaf>,
_proof: mmr::Proof<Hash>
) -> Result<(), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
fn grandpa_authorities() -> Vec<(GrandpaId, u64)> {
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,
sp_runtime::traits::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: fg_primitives::AuthorityId,
) -> Option<fg_primitives::OpaqueKeyOwnershipProof> {
use parity_scale_codec::Encode;
Historical::prove((fg_primitives::KEY_TYPE, authority_id))
.map(|p| p.encode())
.map(fg_primitives::OpaqueKeyOwnershipProof::new)
}
}
impl babe_primitives::BabeApi<Block> for Runtime {
fn configuration() -> babe_primitives::BabeConfiguration {
let epoch_config = Babe::epoch_config().unwrap_or(BABE_GENESIS_EPOCH_CONFIG);
babe_primitives::BabeConfiguration {
slot_duration: Babe::slot_duration(),
epoch_length: EpochDuration::get(),
c: epoch_config.c,
authorities: Babe::authorities().to_vec(),
randomness: Babe::randomness(),
allowed_slots: epoch_config.allowed_slots,
}
}
fn current_epoch_start() -> babe_primitives::Slot {
Babe::current_epoch_start()
}
fn current_epoch() -> babe_primitives::Epoch {
Babe::current_epoch()
}
fn next_epoch() -> babe_primitives::Epoch {
Babe::next_epoch()
}
fn generate_key_ownership_proof(
_slot: babe_primitives::Slot,
authority_id: babe_primitives::AuthorityId,
) -> Option<babe_primitives::OpaqueKeyOwnershipProof> {
use parity_scale_codec::Encode;
Historical::prove((babe_primitives::KEY_TYPE, authority_id))
.map(|p| p.encode())
.map(babe_primitives::OpaqueKeyOwnershipProof::new)
}
fn submit_report_equivocation_unsigned_extrinsic(
equivocation_proof: babe_primitives::EquivocationProof<<Block as BlockT>::Header>,
key_owner_proof: babe_primitives::OpaqueKeyOwnershipProof,
) -> Option<()> {
let key_owner_proof = key_owner_proof.decode()?;
Babe::submit_unsigned_equivocation_report(
equivocation_proof,
key_owner_proof,
)
}
}
impl authority_discovery_primitives::AuthorityDiscoveryApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityDiscoveryId> {
parachains_runtime_api_impl::relevant_authority_ids::<Runtime>()
}
}
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>, sp_core::crypto::KeyTypeId)>> {
SessionKeys::decode_into_raw_public_keys(&encoded)
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
fn account_nonce(account: AccountId) -> Nonce {
System::account_nonce(account)
}
}
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)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
for Runtime
{
fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo<Balance> {
TransactionPayment::query_call_info(call, len)
}
fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails<Balance> {
TransactionPayment::query_call_fee_details(call, len)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
#[cfg(feature = "try-runtime")]
impl frame_try_runtime::TryRuntime<Block> for Runtime {
fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
log::info!("try-runtime::on_runtime_upgrade polkadot.");
let weight = Executive::try_runtime_upgrade(checks).unwrap();
(weight, BlockWeights::get().max_block)
}
fn execute_block(
block: Block,
state_root_check: bool,
signature_check: bool,
select: frame_try_runtime::TryStateSelect,
) -> Weight {
// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
// have a backtrace here.
Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
}
}
#[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::{Benchmarking, BenchmarkList};
use frame_support::traits::StorageInfoTrait;
use pallet_session_benchmarking::Pallet as SessionBench;
use pallet_offences_benchmarking::Pallet as OffencesBench;
use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench;
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
use frame_system_benchmarking::Pallet as SystemBench;
use frame_benchmarking::baseline::Pallet as Baseline;
let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra);
let storage_info = AllPalletsWithSystem::storage_info();
return (list, storage_info)
}
fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig
) -> Result<
Vec<frame_benchmarking::BenchmarkBatch>,
sp_runtime::RuntimeString,
> {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey};
// Trying to add benchmarks directly to some pallets caused cyclic dependency issues.
// To get around that, we separated the benchmarks into its own crate.
use pallet_session_benchmarking::Pallet as SessionBench;
use pallet_offences_benchmarking::Pallet as OffencesBench;
use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench;
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
use frame_system_benchmarking::Pallet as SystemBench;
use frame_benchmarking::baseline::Pallet as Baseline;
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 frame_benchmarking::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(),
// 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 test_fees {
use super::*;
use frame_support::{dispatch::GetDispatchInfo, weights::WeightToFee as WeightToFeeT};
use keyring::Sr25519Keyring::{Alice, Charlie};
use pallet_transaction_payment::Multiplier;
use runtime_common::MinimumMultiplier;
use separator::Separatable;
use sp_runtime::{assert_eq_error_rate, FixedPointNumber, MultiAddress, MultiSignature};
#[test]
fn payout_weight_portion() {
use pallet_staking::WeightInfo;
let payout_weight =
<Runtime as pallet_staking::Config>::WeightInfo::payout_stakers_alive_staked(
MaxNominatorRewardedPerValidator::get(),
)
.ref_time() as f64;
let block_weight = BlockWeights::get().max_block.ref_time() as f64;
println!(
"a full payout takes {:.2} of the block weight [{} / {}]",
payout_weight / block_weight,
payout_weight,
block_weight
);
assert!(payout_weight * 2f64 < block_weight);
}
#[test]
fn block_cost() {
let max_block_weight = BlockWeights::get().max_block;
let raw_fee = WeightToFee::weight_to_fee(&max_block_weight);
let fee_with_multiplier = |m: Multiplier| {
println!(
"Full Block weight == {} // multiplier: {:?} // WeightToFee(full_block) == {} plank",
max_block_weight,
m,
m.saturating_mul_int(raw_fee).separated_string(),
);
};
fee_with_multiplier(MinimumMultiplier::get());
fee_with_multiplier(Multiplier::from_rational(1, 2));
fee_with_multiplier(Multiplier::from_u32(1));
fee_with_multiplier(Multiplier::from_u32(2));
}
#[test]
fn transfer_cost_min_multiplier() {
let min_multiplier = MinimumMultiplier::get();
let call = pallet_balances::Call::<Runtime>::transfer_keep_alive {
dest: Charlie.to_account_id().into(),
value: Default::default(),
};
let info = call.get_dispatch_info();
println!("call = {:?} / info = {:?}", call, info);
// convert to runtime call.
let call = RuntimeCall::Balances(call);
let extra: SignedExtra = (
frame_system::CheckNonZeroSender::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckMortality::<Runtime>::from(generic::Era::immortal()),
frame_system::CheckNonce::<Runtime>::from(1),
frame_system::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
claims::PrevalidateAttests::<Runtime>::new(),
);
let uxt = UncheckedExtrinsic {
function: call,
signature: Some((
MultiAddress::Id(Alice.to_account_id()),
MultiSignature::Sr25519(Alice.sign(b"foo")),
extra,
)),
};
let len = uxt.encoded_size();
let mut ext = sp_io::TestExternalities::new_empty();
let mut test_with_multiplier = |m: Multiplier| {
ext.execute_with(|| {
pallet_transaction_payment::NextFeeMultiplier::<Runtime>::put(m);
let fee = TransactionPayment::query_fee_details(uxt.clone(), len as u32);
println!(
"multiplier = {:?} // fee details = {:?} // final fee = {:?}",
pallet_transaction_payment::NextFeeMultiplier::<Runtime>::get(),
fee,
fee.final_fee().separated_string(),
);
});
};
test_with_multiplier(min_multiplier);
test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1u128));
test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_0u128));
test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_00u128));
test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000u128));
test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000u128));
test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000_000u128));
}
#[test]
fn full_block_council_election_cost() {
// the number of voters needed to consume almost a full block in council election, and how
// much it is going to cost.
use pallet_elections_phragmen::WeightInfo;
// Loser candidate lose a lot of money; sybil attack by candidates is even more expensive,
// and we don't care about it here. For now, we assume no extra candidates, and only
// superfluous voters.
let candidates = DesiredMembers::get() + DesiredRunnersUp::get();
let mut voters = 1u32;
let weight_with = |v| {
<Runtime as pallet_elections_phragmen::Config>::WeightInfo::election_phragmen(
candidates,
v,
v * 16,
)
};
while weight_with(voters).all_lte(BlockWeights::get().max_block) {
voters += 1;
}
let cost = voters as Balance * (VotingBondBase::get() + 16 * VotingBondFactor::get());
let cost_dollars = cost / DOLLARS;
println!(
"can support {} voters in a single block for council elections; total bond {}",
voters, cost_dollars,
);
// The minimal number of voters we expect per block.
assert!(voters >= 1_000);
assert!(cost_dollars >= 10_000);
}
#[test]
fn nominator_limit() {
use pallet_election_provider_multi_phase::WeightInfo;
// starting point of the nominators.
let target_voters: u32 = 50_000;
// assuming we want around 5k candidates and 1k active validators. (March 31, 2021)
let all_targets: u32 = 5_000;
let desired: u32 = 1_000;
let weight_with = |active| {
<Runtime as pallet_election_provider_multi_phase::Config>::WeightInfo::submit_unsigned(
active,
all_targets,
active,
desired,
)
};
let mut active = target_voters;
while weight_with(active).all_lte(OffchainSolutionWeightLimit::get()) ||
active == target_voters
{
active += 1;
}
println!("can support {} nominators to yield a weight of {}", active, weight_with(active));
assert!(active > target_voters, "we need to reevaluate the weight of the election system");
}
#[test]
fn signed_deposit_is_sensible() {
// ensure this number does not change, or that it is checked after each change.
// a 1 MB solution should take (40 + 10) DOTs of deposit.
let deposit = SignedDepositBase::get() + (SignedDepositByte::get() * 1024 * 1024);
assert_eq_error_rate!(deposit, 50 * DOLLARS, DOLLARS);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn call_size() {
assert!(
core::mem::size_of::<RuntimeCall>() <= 230,
"size of RuntimeCall is more than 230 bytes: some calls have too big arguments, use Box to \
reduce the size of RuntimeCall.
If the limit is too strong, maybe consider increase the limit",
);
}
}
#[cfg(test)]
mod multiplier_tests {
use super::*;
use frame_support::{dispatch::DispatchInfo, traits::OnFinalize};
use runtime_common::{MinimumMultiplier, TargetBlockFullness};
use separator::Separatable;
use sp_runtime::traits::Convert;
fn run_with_system_weight<F>(w: Weight, mut assertions: F)
where
F: FnMut() -> (),
{
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.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.saturating_mul(101) / 100, || {
let next = SlowAdjustingFeeUpdate::<Runtime>::convert(minimum_multiplier);
assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier);
})
}
#[test]
fn fast_unstake_estimate() {
use pallet_fast_unstake::WeightInfo;
let block_time = BlockWeights::get().max_block.ref_time() as f32;
let on_idle = weights::pallet_fast_unstake::WeightInfo::<Runtime>::on_idle_check(
300,
<Runtime as pallet_fast_unstake::Config>::BatchSize::get(),
)
.ref_time() as f32;
println!("ratio of block weight for full batch fast-unstake {}", on_idle / block_time);
assert!(on_idle / block_time <= 0.5f32)
}
#[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 = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap();
let mut blocks = 0;
let mut fees_paid = 0;
frame_system::Pallet::<Runtime>::set_block_consumed_resources(Weight::MAX, 0);
let info = DispatchInfo { weight: Weight::MAX, ..Default::default() };
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.unwrap()
.into();
// set the minimum
t.execute_with(|| {
pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(MinimumMultiplier::get());
});
while multiplier <= Multiplier::from_u32(1) {
t.execute_with(|| {
// imagine this tx was called.
let fee = TransactionPayment::compute_fee(0, &info, 0);
fees_paid += fee;
// this will update the multiplier.
System::set_block_consumed_resources(block_weight, 0);
TransactionPayment::on_finalize(1);
let next = TransactionPayment::next_fee_multiplier();
assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier);
multiplier = next;
println!(
"block = {} / multiplier {:?} / fee = {:?} / fess so far {:?}",
blocks,
multiplier,
fee.separated_string(),
fees_paid.separated_string()
);
});
blocks += 1;
}
}
#[test]
#[ignore]
fn multiplier_cool_down_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 = Multiplier::from_u32(2);
let mut blocks = 0;
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.unwrap()
.into();
// set the minimum
t.execute_with(|| {
pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(multiplier);
});
while multiplier > Multiplier::from_u32(0) {
t.execute_with(|| {
// this will update the multiplier.
TransactionPayment::on_finalize(1);
let next = TransactionPayment::next_fee_multiplier();
assert!(next < multiplier, "{:?} !>= {:?}", next, multiplier);
multiplier = next;
println!("block = {} / multiplier {:?}", blocks, multiplier);
});
blocks += 1;
}
}
}
#[cfg(all(test, feature = "try-runtime"))]
mod remote_tests {
use super::*;
use frame_try_runtime::{runtime_decl_for_TryRuntime::TryRuntime, UpgradeCheckSelect};
use remote_externalities::{
Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, Transport,
};
use std::env::var;
#[tokio::test]
async fn run_migrations() {
if var("RUN_MIGRATION_TESTS").is_err() {
return
}
sp_tracing::try_init_simple();
let transport: Transport =
var("WS").unwrap_or("wss://rpc.polkadot.io:443".to_string()).into();
let maybe_state_snapshot: Option<SnapshotConfig> = var("SNAP").map(|s| s.into()).ok();
let mut ext = Builder::<Block>::default()
.mode(if let Some(state_snapshot) = maybe_state_snapshot {
Mode::OfflineOrElseOnline(
OfflineConfig { state_snapshot: state_snapshot.clone() },
OnlineConfig {
transport,
state_snapshot: Some(state_snapshot),
..Default::default()
},
)
} else {
Mode::Online(OnlineConfig { transport, ..Default::default() })
})
.build()
.await
.unwrap();