#![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 frame_system::{EnsureRoot, EnsureRootWithSuccess}; use runtime_common::{ impls::DealWithFees, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, impl_runtime_weights, prod_or_fast, }; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use frame_election_provider_support::{ generate_solution_type, onchain, SequentialPhragmen, bounds::ElectionBoundsBuilder, }; use frame_support::{ construct_runtime, parameter_types, genesis_builder_helper::{build_state, get_preset}, traits::{ fungible::HoldConsideration, tokens::UnityAssetBalanceConversion, ConstU128, ConstU32, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, WithdrawReasons, }, weights::ConstantMultiplier, PalletId }; #[cfg(feature = "runtime-benchmarks")] use runtime_common::benchmarking::BenchmarkTreasuryHelper; use frame_support::traits::tokens::pay::PayFromAccount; use pallet_transaction_payment::FungibleAdapter; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; use ghost_slow_clap::sr25519::AuthorityId as SlowClapId; use pallet_session::historical as session_historical; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce, Signature, ReserveIdentifier, }; use sp_core::OpaqueMetadata; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, FixedU128, curve::PiecewiseLinear, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, OpaqueKeys, SaturatedConversion, Verify, IdentityLookup, ConvertInto, ConstU16, }, transaction_validity::{ TransactionPriority, TransactionSource, TransactionValidity, }, ApplyExtrinsicResult, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, }; use sp_genesis_builder::PresetId; use sp_std::prelude::*; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; #[cfg(feature = "std")] pub use pallet_staking::StakerStatus; use pallet_staking::UseValidatorsMap; pub use pallet_timestamp::Call as TimestampCall; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; /// Constant values used within the runtime. use casper_runtime_constants::{currency::*, time::*, fee::*}; mod weights; mod bag_thresholds; mod impls; mod genesis_config_presets; pub use impls::{AllianceProposalProvider, EqualOrGreatestRootCmp}; // Governance configuration. pub mod cult; use cult::{ pallet_cult_origins, CultCollectiveInstance, CultTreasurySpender, Geniuses, Degens, Zombies, Skeletons, Ghosts, }; pub const LOG_TARGET: &str = "runtime::casper"; impl_runtime_weights!(casper_runtime_constants); // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod opaque { use super::*; pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; pub type Block = generic::Block; impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, pub babe: Babe, pub authority_discovery: AuthorityDiscovery, pub slow_clap: GhostSlowClaps, } } } /// Runtime version (Casper). #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("casper"), impl_name: create_runtime_str!("casper-svengali"), authoring_version: 0, spec_version: 1, impl_version : 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, 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, }; /// The version information used to identify this runtime when compiled natively. #[cfg(any(feature = "std", test))] pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default(), } } parameter_types! { pub const Version: RuntimeVersion = VERSION; pub const SS58Prefix: u16 = 1996; } // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; type BlockLength = BlockLength; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeTask = RuntimeTask; type Nonce = Nonce; type Hash = Hash; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = AccountIdLookup; type Block = Block; type BlockHashCount = BlockHashCount; type DbWeight = RocksDbWeight; type Version = Version; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = weights::frame_system::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; type SingleBlockMigrations = (); type MultiBlockMigrator = (); type PreInherents = (); type PostInherents = (); type PostTransactions = (); } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 50; } impl pallet_scheduler::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = MaxScheduledPerBlock; type OriginPrivilegeCmp = EqualOrGreatestRootCmp; type Preimages = Preimage; type WeightInfo = weights::pallet_scheduler::WeightInfo; } parameter_types! { pub const PreimageBaseDeposit: Balance = deposit(2, 64); pub const PreimageByteDeposit: Balance = deposit(0, 1); pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); } impl pallet_preimage::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; type Consideration = HoldConsideration< AccountId, Balances, PreimageHoldReason, LinearStoragePrice, >; type WeightInfo = weights::pallet_preimage::WeightInfo; } parameter_types! { pub const EpochDuration: u64 = prod_or_fast!( EPOCH_DURATION_IN_SLOTS as u64, 2 * MINUTES as u64 ); pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get(); } impl pallet_babe::Config for Runtime { type EpochDuration = EpochDuration; type ExpectedBlockTime = ExpectedBlockTime; // Session module trigger type EpochChangeTrigger = pallet_babe::ExternalTrigger; type DisabledValidators = Session; type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxNominators = MaxNominators; type KeyOwnerProof = >::Proof; type EquivocationReportSystem = pallet_babe::EquivocationReportSystem; } parameter_types! { pub const IndexDeposit: Balance = 10 * CSPR; } impl pallet_indices::Config for Runtime { type AccountIndex = AccountIndex; type Currency = Balances; type Deposit = IndexDeposit; type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_indices::WeightInfo; } 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 = ReserveIdentifier; type WeightInfo = weights::pallet_balances::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; } parameter_types! { pub const TransactionByteFee: Balance = 10 * STNK; pub const OperationalFeeMultiplier: u8 = 5; } impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = FungibleAdapter>; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; } parameter_types! { pub const MinimumPeriod: u64 = SLOT_DURATION / 2; } impl pallet_timestamp::Config for Runtime { type Moment = Moment; type OnTimestampSet = Babe; type MinimumPeriod = MinimumPeriod; type WeightInfo = weights::pallet_timestamp::WeightInfo; } impl pallet_authorship::Config for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; type EventHandler = Staking; } impl pallet_session::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; type NextSessionRotation = Babe; type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = opaque::SessionKeys; type WeightInfo = weights::pallet_session::WeightInfo; } impl pallet_session::historical::Config for Runtime { type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } parameter_types! { pub SignedPhase: u32 = prod_or_fast!( EPOCH_DURATION_IN_SLOTS / 4, (1 * MINUTES).min(EpochDuration::get().saturated_into::() / 2) ); pub UnsignedPhase: u32 = prod_or_fast!( EPOCH_DURATION_IN_SLOTS / 4, (1 * MINUTES).min(EpochDuration::get().saturated_into::() / 2) ); // signed config pub const SignedMaxSubmissions: u32 = 16; pub const SignedMaxRefunds: u32 = 16 / 4; pub const SignedFixedDeposit: Balance = deposit(2, 0); pub const SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); // 0.01 CSPR per KB of solution data. pub const SignedDepositByte: Balance = deposit(0, 10) / 1024; // Each good submission will get 1 CSPR as reward pub SignedRewardBase: Balance = 1 * CSPR; // 4 hour session, 1 hour unsigned phase, 32 ofchain executions. pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 32; // We take the top 22_500 nominators as electing voters. pub const MaxElectingVoters: u32 = 22_500; // ... and all of the validators as electable targets. Whilist this is the // case, we cannot and shall increase the size of the validator intentions. pub ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); // Setup election pallet to support maximum winners upto 1_200. This will // mean Staking Pallet cannot have active validators higher than this count. pub const MaxActiveValidators: u32 = 1_200; } 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; type DataProvider = Staking; type MaxWinners = MaxActiveValidators; type Bounds = ElectionBounds; type WeightInfo = weights::frame_election_provider_support::WeightInfo; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { type AccountId = AccountId; type MaxLength = OffchainSolutionLengthLimit; type MaxWeight = OffchainSolutionWeightLimit; type Solution = NposCompactSolution16; type MaxVotesPerVoter = < ::DataProvider as frame_election_provider_support::ElectionDataProvider >::MaxVotesPerVoter; type MaxWinners = MaxActiveValidators; // 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 { < ::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 = GeometricDepositBase; type SignedDepositByte = SignedDepositByte; type SignedDepositWeight = (); type SignedMaxWeight = ::MaxWeight; type MinerConfig = Self; type SlashHandler = (); type RewardHandler= (); type BetterSignedThreshold = (); type OffchainRepeat = OffchainRepeat; type MinerTxPriority = NposSolutionPriority; type DataProvider = Staking; #[cfg(any(feature = "fast-runtime", feature = "runtime-benchmarks"))] type Fallback = onchain::OnChainExecution; #[cfg(not(any(feature = "fast-runtime", feature = "runtime-benchmarks")))] type Fallback = frame_election_provider_support::NoElection<( AccountId, BlockNumber, Staking, MaxActiveValidators, )>; type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen< AccountId, pallet_election_provider_multi_phase::SolutionAccuracyOf, (), >; type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig; type ForceOrigin = EitherOf< EnsureRootWithSuccess>, Zombies, >; type MaxWinners = MaxActiveValidators; type ElectionBounds = ElectionBounds; type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; } parameter_types! { pub const BagThresholds: &'static [u64] = &bag_thresholds::THRESHOLDS; } type VoterBagsListInstance = pallet_bags_list::Instance1; impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ScoreProvider = Staking; type BagThresholds = BagThresholds; type Score = sp_npos_elections::VoteWeight; type WeightInfo = weights::pallet_bags_list::WeightInfo; } pallet_staking_reward_curve::build! { const REWARD_CURVE: PiecewiseLinear<'static> = curve!( min_inflation: 0_025_000, max_inflation: 0_100_000, ideal_stake: 0_750_000, falloff: 0_050_000, max_piece_count: 40, test_precision: 0_005_000, ); } parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = prod_or_fast!(6, 1); pub const BondingDuration: sp_staking::EraIndex = prod_or_fast!(28, 28); pub const SlashDeferDuration: sp_staking::EraIndex = prod_or_fast!(27, 27); pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxExposurePageSize: u32 = 512; pub const MaxNominators: u32 = 512; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxNominations: u32 = ::LIMIT as u32; } impl pallet_staking::Config for Runtime { type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; type CurrencyToVote = CurrencyToVote; type RewardRemainder = Treasury; type RuntimeEvent = RuntimeEvent; type Slash = Treasury; type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; type AdminOrigin = EitherOf< EnsureRootWithSuccess>, Skeletons, >; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = MaxExposurePageSize; type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; type NextNewSession = Session; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; type MaxControllersInDeprecationBatch = ConstU32<5314>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; type EventListeners = NominationPools; type WeightInfo = weights::pallet_staking::WeightInfo; } impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BatchSize = frame_support::traits::ConstU32<16>; type Deposit = ConstU128<{ STRH }>; type ControlOrigin = EitherOf< EnsureRootWithSuccess>, Zombies, >; type Staking = Staking; type MaxErasToCheckPerBlock = ConstU32<1>; type WeightInfo = weights::pallet_fast_unstake::WeightInfo; } parameter_types! { pub const BasicDeposit: Balance = deposit(1, 258); pub const ByteDeposit: Balance = deposit(0, 1); pub const SubAccountDeposit: Balance = deposit(1, 53); pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; pub const MaxRegistrars: u32 = 100; } impl pallet_identity::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; type MaxRegistrars = MaxRegistrars; type Slashed = Treasury; type ForceOrigin = Geniuses; type RegistrarOrigin = Geniuses; type UsernameAuthorityOrigin = Geniuses; type OffchainSignature = Signature; type SigningPublicKey = ::Signer; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const ProposalBondMinimum: Balance = 10 * CSPR; pub const ProposalBondMaximum: Balance = 50 * CSPR; pub const SpendPeriod: BlockNumber = 24 * DAYS; pub const Burn: Permill = Permill::from_percent(0); pub const MaxBalance: Balance = Balance::MAX; pub const PayoutPeriod: BlockNumber = 30 * DAYS; pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); pub const DataDepositPerByte: Balance = 1 * STRH; pub const MaxApprovals: u32 = 100; pub const MaxAuthorities: u32 = 100_000; } impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; #[cfg(not(feature = "runtime-benchmarks"))] type ApproveOrigin = frame_support::traits::NeverEnsureOrigin; #[cfg(feature = "runtime-benchmarks")] type ApproveOrigin = EnsureRoot; type RejectOrigin = EitherOf< EnsureRootWithSuccess>, Degens, >; type RuntimeEvent = RuntimeEvent; type OnSlash = Treasury; type ProposalBond = ProposalBond; #[cfg(not(feature = "runtime-benchmarks"))] type ProposalBondMinimum = ProposalBondMinimum; #[cfg(feature = "runtime-benchmarks")] type ProposalBondMinimum = ConstU128<{ ExistentialDeposit::get() * 100 }>; #[cfg(not(feature = "runtime-benchmarks"))] type ProposalBondMaximum = ProposalBondMaximum; #[cfg(feature = "runtime-benchmarks")] type ProposalBondMaximum = ConstU128<{ ExistentialDeposit::get() * 500 }>; type SpendPeriod = SpendPeriod; type Burn = Burn; type BurnDestination = (); type SpendFunds = Bounties; type MaxApprovals = MaxApprovals; type WeightInfo = (); type SpendOrigin = EitherOf< EnsureRootWithSuccess, CultTreasurySpender >; type AssetKind = (); type Beneficiary = AccountId; type BeneficiaryLookup = IdentityLookup; type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = PayoutPeriod; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkTreasuryHelper; } parameter_types! { pub const BountyDepositBase: Balance = 10 * CSPR; pub const BountyDepositPayoutDelay: BlockNumber = DAYS; pub const BountyUpdatePeriod: BlockNumber = 2 * WEEKS; pub const MaximumReasonLength: u32 = 16_384; pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); pub const CuratorDepositMin: Balance = 10 * CSPR; pub const CuratorDepositMax: Balance = 200 * CSPR; pub const BountyValueMinimum: Balance = 10 * CSPR; } 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 = (); } 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 = (); } impl pallet_offences::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnOffenceHandler = Staking; type IdentificationTuple = pallet_session::historical::IdentificationTuple; } impl pallet_authority_discovery::Config for Runtime { type MaxAuthorities = MaxAuthorities; } parameter_types! { pub NposSolutionPriority: TransactionPriority = Perbill::from_percent(90) * TransactionPriority::MAX; } parameter_types! { pub MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); } impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; type KeyOwnerProof = >::Proof; type EquivocationReportSystem = pallet_grandpa::EquivocationReportSystem; } /// Submits a transaction with the node's public and signature type. Adheres /// to the signed extension format of the chain. impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { fn create_transaction>( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, ) -> Option<(RuntimeCall, ::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::() // 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::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckMortality::::from( generic::Era::mortal(period, current_block), ), frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), ); let raw_payload = SignedPayload::new(call, extra) .map_err(|e| { log::warn!(target: LOG_TARGET, "🫢 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 = ::Lookup::unlookup(account); Some((call, (address, signature, extra))) } } impl frame_system::offchain::SigningTypes for Runtime { type Public = ::Signer; type Signature = Signature; } impl frame_system::offchain::SendTransactionTypes for Runtime where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; type OverarchingCall = RuntimeCall; } parameter_types! { pub const MinVestedTransfer: Balance = CSPR; 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; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; type BlockNumberProvider = System; 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; } parameter_types! { pub const DepositBase: Balance = deposit(1, 88); 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; } parameter_types! { pub const ProxyDepositBase: Balance = deposit(1, 8); 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, CancelProxy = 4, IdentityJudgement = 5, NominationPools = 6, } impl Default for ProxyType { fn default() -> Self { Self::Any } } impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, ProxyType::NonTransfer => matches!(c, RuntimeCall::Balances { .. }), ProxyType::Governance => matches!( c, RuntimeCall::Bounties { .. } | RuntimeCall::Utility { .. } | RuntimeCall::ChildBounties { .. } | RuntimeCall::CultReferenda { .. } | RuntimeCall::CultCollective { .. } | RuntimeCall::Whitelist { .. } | RuntimeCall::AllianceMotion { .. } | RuntimeCall::Alliance { .. } | RuntimeCall::Multisig { .. } ), ProxyType::Staking => matches!( c, RuntimeCall::Staking { .. } | RuntimeCall::Session { .. } | RuntimeCall::Utility { .. } | RuntimeCall::FastUnstake { .. } | RuntimeCall::VoterList { .. } | RuntimeCall::NominationPools { .. } ), ProxyType::IdentityJudgement => matches!( c, RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | RuntimeCall::Utility { .. } ), ProxyType::CancelProxy => matches!( c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), ProxyType::NominationPools => matches!( c, RuntimeCall::NominationPools { .. } | RuntimeCall::Utility { .. } ), } } 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 MaxPending = MaxPending; type CallHasher = BlakeTwo256; type AnnouncementDepositBase = AnnouncementDepositBase; type AnnouncementDepositFactor = AnnouncementDepositFactor; type WeightInfo = weights::pallet_proxy::WeightInfo; } 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 RuntimeFreezeReason = RuntimeFreezeReason; 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>; type MaxUnbonding = ::MaxUnlockingChunks; type PalletId = PoolsPalletId; type MaxPointsToBalance = MaxPointsToBalance; type AdminOrigin = EitherOf< EnsureRootWithSuccess>, Zombies, >; type WeightInfo = weights::pallet_nomination_pools::WeightInfo; } pub struct InitiateNominationPools; impl frame_support::traits::OnRuntimeUpgrade for InitiateNominationPools { fn on_runtime_upgrade() -> Weight { // we use one as an indicator if this has already been set. if pallet_nomination_pools::MaxPools::::get().is_none() { pallet_nomination_pools::MinJoinBond::::put(5 * CSPR); pallet_nomination_pools::MinCreateBond::::put(100 * CSPR); pallet_nomination_pools::MaxPools::::put(0); pallet_nomination_pools::MaxPoolMembersPerPool::::put(0); pallet_nomination_pools::MaxPoolMembers::::put(0); log::info!(target: LOG_TARGET, "🎉 pools config initiated"); ::DbWeight::get().reads_writes(1, 5) } else { log::info!(target: LOG_TARGET, "😏 pools config already initiated"); ::DbWeight::get().reads(1) } } } pub const ALLIANCE_MOTION_DURATION: BlockNumber = 5 * DAYS; parameter_types! { pub const AllianceMotionDuration: BlockNumber = ALLIANCE_MOTION_DURATION; pub MaxProposalWeight: Weight = Perbill::from_percent(50) * BlockWeights::get().max_block; } pub const ALLIANCE_MAX_PROPOSALS: u32 = 100; pub const ALLIANCE_MAX_MEMBERS: u32 = 100; type AllianceCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; type MotionDuration = AllianceMotionDuration; type MaxProposals = ConstU32; type MaxMembers = ConstU32; type DefaultVote = pallet_collective::MoreThanMajorityThenPrimeDefaultVote; type SetMembersOrigin = EnsureRoot; type MaxProposalWeight = MaxProposalWeight; type WeightInfo = weights::pallet_collective::WeightInfo; } pub const MAX_FELLOWS: u32 = ALLIANCE_MAX_MEMBERS; pub const MAX_ALLIES: u32 = 100; parameter_types! { pub const AllyDeposit: Balance = 1_000 * CSPR; pub TreasuryAccount: AccountId = Treasury::account_id(); // The number of blocks a member must wait between giving a retirement notice // and retiring. Supposed to be greater than time required to `kick_member` // with alliance motion. pub const AllianceRetriementPeriod: BlockNumber = (4 * WEEKS) + ALLIANCE_MOTION_DURATION; } pub type RootOrAllianceTwoThirdsMajority = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, >; impl pallet_alliance::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Proposal = RuntimeCall; type AdminOrigin = RootOrAllianceTwoThirdsMajority; type MembershipManager = RootOrAllianceTwoThirdsMajority; type AnnouncementOrigin = RootOrAllianceTwoThirdsMajority; type Currency = Balances; type Slashed = Treasury; type InitializeMembers = AllianceMotion; type MembershipChanged = AllianceMotion; type RetirementPeriod = AllianceRetriementPeriod; type IdentityVerifier = (); type ProposalProvider = AllianceProposalProvider; type MaxProposals = ConstU32; type MaxFellows = ConstU32; type MaxAllies = ConstU32; type MaxUnscrupulousItems = ConstU32<100>; type MaxWebsiteUrlLength = ConstU32<255>; type MaxAnnouncementsCount = ConstU32<100>; type MaxMembersCount = ConstU32; type AllyDeposit = AllyDeposit; type WeightInfo = weights::pallet_alliance::WeightInfo; } // Ghosts specific pallets impl ghost_networks::Config for Runtime { type RuntimeEvent = RuntimeEvent; type NetworkId = u64; type RegisterOrigin = EitherOf< EnsureRootWithSuccess>, Ghosts, >; type UpdateOrigin = EitherOf< EnsureRootWithSuccess>, Zombies, >; type RemoveOrigin = EitherOf< EnsureRootWithSuccess>, Skeletons, >; type WeightInfo = weights::ghost_networks::WeightInfo; } parameter_types! { pub ClaimPrefix: &'static [u8] = b"CasperAccountId:"; pub MaximumWithdrawAmount: Balance = 500 * CSPR; pub VestingBlocks: u32 = 10 * WEEKS; } impl ghost_claims::Config for Runtime { type RuntimeEvent = RuntimeEvent; type VestingSchedule = Vesting; type BlockNumberProvider = System; type MemberSwappedHandler = (); type Prefix = ClaimPrefix; type MaximumWithdrawAmount = MaximumWithdrawAmount; type VestingBlocks = VestingBlocks; type WeightInfo = weights::ghost_claims::WeightInfo; } parameter_types! { // maximum number of claps in one tx pub MaxNumberOfClaps: u32 = 5; // will be used in `Perbill::from_percent()` pub ApplauseThreshold: u32 = 70; // will be used in `Perbill::from_percent()` pub OffenceThreshold: u32 = 40; pub const SlowClapUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); } impl ghost_slow_clap::Config for Runtime { type RuntimeEvent = RuntimeEvent; type AuthorityId = SlowClapId; type NextSessionRotation = Babe; type ValidatorSet = Historical; type Currency = Balances; type NetworkDataHandler = GhostNetworks; type BlockNumberProvider = System; type ReportUnresponsiveness = Offences; type MaxAuthorities = MaxAuthorities; type MaxNumberOfClaps = MaxNumberOfClaps; type ApplauseThreshold = ApplauseThreshold; type MaxAuthorityInfoInSession = MaxAuthorities; type OffenceThreshold = OffenceThreshold; type UnsignedPriority = SlowClapUnsignedPriority; type TreasuryPalletId = TreasuryPalletId; type WeightInfo = weights::ghost_slow_clap::WeightInfo; } construct_runtime! { pub enum Runtime { // Basic stuff; balances is uncallable initially. System: frame_system = 0, Scheduler: pallet_scheduler = 1, Preimage: pallet_preimage = 10, // Babe must be before session. Babe: pallet_babe = 2, Timestamp: pallet_timestamp = 3, Indices: pallet_indices = 4, Balances: pallet_balances = 5, TransactionPayment: pallet_transaction_payment = 28, // Consensus support. // Authorship must be before session in order to note authoer in the // correct session and era for im-online and staking. Authorship: pallet_authorship = 6, Staking: pallet_staking = 7, Offences: pallet_offences = 8, Historical: session_historical = 29, Session: pallet_session = 9, Grandpa: pallet_grandpa = 11, AuthorityDiscovery: pallet_authority_discovery = 12, // Governance stuff. Treasury: pallet_treasury = 19, CultOrigins: pallet_cult_origins = 21, Whitelist: pallet_whitelist = 22, Vesting: pallet_vesting = 23, Utility: pallet_utility = 24, Identity: pallet_identity = 25, Proxy: pallet_proxy = 26, Multisig: pallet_multisig = 27, Bounties: pallet_bounties = 30, ChildBounties: pallet_child_bounties = 31, // Election pallet. Only works with staking, but places here to // maintain indicies. ElectionProviderMultiPhase: pallet_election_provider_multi_phase = 32, // Provides a semi-sorted list of nominators for staking. VoterList: pallet_bags_list:: = 33, NominationPools: pallet_nomination_pools = 34, FastUnstake: pallet_fast_unstake = 35, // Governance Alliance: pallet_alliance = 36, AllianceMotion: pallet_collective:: = 37, CultCollective: pallet_ranked_collective:: = 38, CultReferenda: pallet_referenda:: = 39, CultCore: pallet_core_fellowship:: = 40, CultSalary: pallet_salary:: = 41, // Ghosts stuff. Start indicies at 50 to leave room. GhostNetworks: ghost_networks = 50, GhostClaims: ghost_claims:: = 51, GhostSlowClaps: ghost_slow_clap = 52, } } /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. pub type Header = generic::Header; /// Block type as expected by this runtime. pub type Block = generic::Block; /// A block signed with a Justification. pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; /// The `SignedExtension` to the basic transaction logic. pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, frame_system::CheckGenesis, frame_system::CheckMortality, frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); /// All migrations that will run on the next runtime upgrade. /// Should be cleared after release. pub type Migrations = (); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, Block, frame_system::ChainContext, Runtime, AllPalletsWithSystem, Migrations, >; /// The payload being signed in transaction. pub type SignedPayload = generic::SignedPayload; #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( // Ghosts // Note: Make sure to prefix these with `runtime_common::` so // that path resolves correctly in the generated file. // Substrate [pallet_alliance, Alliance] [pallet_babe, Babe] [pallet_bags_list, VoterList] [pallet_balances, Balances] [frame_benchmarking::baseline, Baseline::] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] [pallet_collective, AllianceMotion] [pallet_core_fellowship, CultCore] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [frame_election_provider_support, ElectionProviderBench::] [pallet_fast_unstake, FastUnstake] [pallet_grandpa, Grandpa] [pallet_identity, Identity] [pallet_indices, Indices] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] [pallet_offences, OffencesBench::] [pallet_preimage, Preimage] [pallet_proxy, Proxy] [pallet_ranked_collective, CultCollective] [pallet_referenda, CultReferenda] [pallet_salary, CultSalary] [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] [pallet_whitelist, Whitelist] // Ghosts [ghost_networks, GhostNetworks] [ghost_claims, GhostClaims] [ghost_slow_clap, GhostSlowClaps] ); } sp_api::impl_runtime_apis! { impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { VERSION } fn execute_block(block: Block) { Executive::execute_block(block); } fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { Executive::initialize_block(header) } } impl sp_api::Metadata for Runtime { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } fn metadata_at_version(version: u32) -> Option { Runtime::metadata_at_version(version) } fn metadata_versions() -> sp_std::vec::Vec { Runtime::metadata_versions() } } impl block_builder_api::BlockBuilder for Runtime { fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { Executive::apply_extrinsic(extrinsic) } fn finalize_block() -> ::Header { Executive::finalize_block() } fn inherent_extrinsics(data: inherents::InherentData) -> Vec<::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::api_pending_rewards(member).unwrap_or_default() } fn points_to_balance(pool_id: pallet_nomination_pools::PoolId, points: Balance) -> Balance { NominationPools::api_points_to_balance(pool_id, points) } fn balance_to_points(pool_id: pallet_nomination_pools::PoolId, new_funds: Balance) -> Balance { NominationPools::api_balance_to_points(pool_id, new_funds) } } impl pallet_staking_runtime_api::StakingApi for Runtime { fn nominations_quota(balance: Balance) -> u32 { Staking::api_nominations_quota(balance) } fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page { Staking::api_eras_stakers_page_count(era, account) } fn pending_rewards(era: sp_staking::EraIndex, account: AccountId) -> bool { Staking::api_pending_rewards(era, account) } } impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { fn validate_transaction( source: TransactionSource, tx: ::Extrinsic, block_hash: ::Hash, ) -> TransactionValidity { Executive::validate_transaction(source, tx, block_hash) } } impl offchain_primitives::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { Executive::offchain_worker(header) } } impl fg_primitives::GrandpaApi 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< ::Hash, sp_runtime::traits::NumberFor, >, 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 { use codec::Encode; Historical::prove((fg_primitives::KEY_TYPE, authority_id)) .map(|p| p.encode()) .map(fg_primitives::OpaqueKeyOwnershipProof::new) } } impl babe_primitives::BabeApi 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 { use 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<::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 for Runtime { fn authorities() -> Vec { AuthorityDiscovery::authorities() } } impl sp_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { opaque::SessionKeys::generate(seed) } fn decode_session_keys(encoded: Vec) -> Option, sp_core::crypto::KeyTypeId)>> { opaque::SessionKeys::decode_into_raw_public_keys(&encoded) } } impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Nonce { System::account_nonce(account) } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { fn query_info(uxt: ::Extrinsic, len: u32) -> RuntimeDispatchInfo { TransactionPayment::query_info(uxt, len) } fn query_fee_details(uxt: ::Extrinsic, len: u32) -> FeeDetails { 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 for Runtime { fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo { TransactionPayment::query_call_info(call, len) } fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails { 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) } } impl sp_genesis_builder::GenesisBuilder for Runtime { fn build_state(json: Vec) -> sp_genesis_builder::Result { build_state::(json) } fn get_preset(id: &Option) -> Option> { get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { genesis_config_presets::preset_names() } } #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { log::info!(target: LOG_TARGET, "😏 try-runtime::on_runtime_upgrade casper."); 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 { log::info!( target: LOG_TARGET, "😏 try-runtime::executing block {:?} / root checks: {:?} / try-state-select: {:?}", block.header.hash(), state_root_check, select, ); Executive::try_executive_block(block, state_root_check, signature_check, select).unwrap() } } #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( Vec, Vec, ) { 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::::new(); list_benchmarks!(list, extra); let storage_info = AllPalletsWithSystem::storage_info(); (list, storage_info) } fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig, ) -> Result< Vec, sp_runtime::RuntimeString > { use frame_support::traits::WhitelistedStorageKeys; use frame_benchmarking::{Benchmarking, BenchmarkBatch}; use sp_storage::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 pallet_nomination_pools_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {} let mut whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); let treasury_key = frame_system::Account::::hashed_key_for(Treasury::account_id()); whitelist.push(treasury_key.to_vec().into()); let mut batches = Vec::::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 = ::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::::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::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckMortality::::from(generic::Era::immortal()), frame_system::CheckNonce::::from(1), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), ); 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::::put(m); let fee = TransactionPayment::query_fee_details(uxt.clone(), len as u32); println!( "multiplier = {:?} // fee details = {:?} // final fee = {:?}", pallet_transaction_payment::NextFeeMultiplier::::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 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| { ::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() { RuntimeCall::assert_size_under(256) } #[test] fn check_whitelist() { let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() .iter() .map(|e| HexDisplay::from(&e.key).to_string()) .collect(); // Block number assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")); // Total issuance assert!(whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")); // Execution phase assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")); // Event count assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")); // System events assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")); } #[test] fn check_treasury_pallet_id() { assert_eq!( ::index() as u8, casper_runtime_constants::TREASURY_PALLET_ID ); } } #[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(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.saturating_mul(101) / 100, || { let next = SlowAdjustingFeeUpdate::::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::::on_idle_check( 300, ::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::::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::() .unwrap() .into(); // set the minimum t.execute_with(|| { pallet_transaction_payment::NextFeeMultiplier::::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::() .unwrap() .into(); // set the minimum t.execute_with(|| { pallet_transaction_payment::NextFeeMultiplier::::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; } } }