#![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 authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use frame_election_provider_support::{ bounds::ElectionBoundsBuilder, generate_solution_type, onchain, SequentialPhragmen, }; use frame_support::{ construct_runtime, parameter_types, PalletId, weights::ConstantMultiplier, pallet_prelude::EnsureOrigin, genesis_builder_helper::{build_state, get_preset}, traits::{ fungible::HoldConsideration, tokens::{imbalance::ResolveTo, UnityAssetBalanceConversion}, ConstU128, ConstU32, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, }, }; #[cfg(not(feature = "runtime-benchmarks"))] use frame_support::traits::tokens::PayFromAccount; use frame_system::EnsureRoot; use runtime_common::{ impl_runtime_weights, impls::DealWithFees, prod_or_fast, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, }; #[cfg(feature = "runtime-benchmarks")] use runtime_common::benchmarking::{BenchmarkTreasuryHelper, BenchmarkTreasuryPaymaster}; use codec::{Decode, Encode, MaxEncodedLen}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; use pallet_session::historical as session_historical; use pallet_transaction_payment::FungibleAdapter; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use primitives::{ AccountId, Balance, BlockNumber, Hash, Moment, Nonce, Signature, ReserveIdentifier, }; use sp_core::OpaqueMetadata; use sp_genesis_builder::PresetId; use sp_runtime::{ create_runtime_str, curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ AccountIdLookup, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, IdentityLookup, OpaqueKeys, SaturatedConversion, Verify, AccountIdConversion, }, transaction_validity::{ TransactionPriority, TransactionSource, TransactionValidity, }, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, }; 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}; use ghost_weaver::sr25519::AuthorityId as GhostWeaverId; use ghost_exodus::sr25519::AuthorityId as GhostExodusId; #[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::*, fee::*, time::*}; mod bag_thresholds; mod genesis_config_presets; mod weights; pub mod genesis { pub use super::genesis_config_presets::*; } type NetworkId = ghost_helpers::NetworkIdU64; 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 babe: Babe, pub grandpa: Grandpa, pub authority_discovery: AuthorityDiscovery, pub weaver: GhostWeaver, pub exodus: GhostExodus, } } } /// 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: 6, impl_version: 4, apis: RUNTIME_API_VERSIONS, transaction_version: 1, state_version: 1, }; /// 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 = ConstU32<16>; type SingleBlockMigrations = (); type MultiBlockMigrator = (); type PreInherents = (); type PostInherents = (); type PostTransactions = (); } parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(20) * 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 = frame_support::traits::EqualPrivilegeOnly; 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 = EPOCH_DURATION_IN_SLOTS 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 = weights::pallet_babe::WeightInfo; type MaxAuthorities = MaxActiveValidators; type MaxNominators = MaxElectingVoters; type KeyOwnerProof = >::Proof; type EquivocationReportSystem = pallet_babe::EquivocationReportSystem; } parameter_types! { pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; pub const MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; pub const MaxFreezes: u32 = 10; } impl pallet_balances::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AccountStore = System; type DustRemoval = ResolveTo; type ExistentialDeposit = ExistentialDeposit; type ReserveIdentifier = ReserveIdentifier; type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = RuntimeFreezeReason; type MaxLocks = MaxLocks; type MaxReserves = MaxReserves; type MaxFreezes = MaxFreezes; type WeightInfo = weights::pallet_balances::WeightInfo; } 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 = EPOCH_DURATION_IN_SLOTS / 4; pub UnsignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4; // 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 0 CSPR as reward pub SignedRewardBase: Balance = 0 * STRH; // 4 hour session, 1 hour unsigned phase, 32 ofchain executions. pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 32; pub const MaxElectingVoters: u32 = 3_000; pub const MaxElectableTargets: u32 = 400; pub const MaxActiveValidators: u32 = 300; // ... 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()) .targets_count(MaxElectableTargets::get().into()) .build(); } 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 = EnsureRoot; 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_006_900, max_inflation: 0_690_000, ideal_stake: 0_690_000, falloff: 0_050_000, max_piece_count: 100, 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!(1, 1); pub const SlashDeferDuration: sp_staking::EraIndex = prod_or_fast!(0, 0); pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxExposurePageSize: u32 = 512; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxNominations: u32 = ::LIMIT as u32; pub const StakingHistoryDepth: u32 = 14; pub const MaxUnlockingChunks: u32 = 32; } 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 = EnsureRoot; type SessionInterface = Self; type EraPayout = ghost_networks::BridgedInflationCurve; 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 = MaxUnlockingChunks; type HistoryDepth = StakingHistoryDepth; type MaxControllersInDeprecationBatch = ConstU32<5314>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; type EventListeners = NominationPools; type WeightInfo = weights::pallet_staking::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 = EnsureRoot; type RegistrarOrigin = EnsureRoot; type UsernameAuthorityOrigin = EnsureRoot; 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 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 = 10; } #[cfg(not(feature = "runtime-benchmarks"))] parameter_types! { pub const ProposalBondMinimum: Balance = 100 * STRH; pub const ProposalBondMaximum: Balance = 500 * STRH; pub const SpendPeriod: BlockNumber = 6 * DAYS; } #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub const ProposalBondMinimum: Balance = ExistentialDeposit::get() * 100; pub const ProposalBondMaximum: Balance = ExistentialDeposit::get() * 500; pub const SpendPeriod: BlockNumber = 1; } pub struct RootSpendOrigin; impl EnsureOrigin for RootSpendOrigin { type Success = Balance; fn try_origin(o: RuntimeOrigin) -> Result { EnsureRoot::::try_origin(o)?; Ok(Balance::MAX) } #[cfg(feature = "runtime-benchmarks")] fn try_successful_origin() -> Result { EnsureRoot::::try_successful_origin() } } pub struct TreasuryAccount; impl frame_support::traits::Get for TreasuryAccount { fn get() -> AccountId { TreasuryPalletId::get().into_account_truncating() } } impl frame_support::pallet_prelude::TypedGet for TreasuryAccount { type Type = AccountId; fn get() -> Self::Type { TreasuryPalletId::get().into_account_truncating() } } impl pallet_treasury::Config for Runtime { type PalletId = TreasuryPalletId; type Currency = Balances; type ApproveOrigin = EnsureRoot; type RejectOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; type ProposalBond = ProposalBond; type OnSlash = (); type ProposalBondMinimum = ProposalBondMinimum; type ProposalBondMaximum = ProposalBondMaximum; type SpendPeriod = SpendPeriod; type Burn = Burn; type SpendFunds = (); type BurnDestination = (); type MaxApprovals = MaxApprovals; type SpendOrigin = RootSpendOrigin; type AssetKind = (); type Beneficiary = AccountId; type BeneficiaryLookup = IdentityLookup; #[cfg(not(feature = "runtime-benchmarks"))] type Paymaster = PayFromAccount; #[cfg(feature = "runtime-benchmarks")] type Paymaster = BenchmarkTreasuryPaymaster; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = PayoutPeriod; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = BenchmarkTreasuryHelper; type WeightInfo = weights::pallet_treasury::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 = MaxActiveValidators; } 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 = weights::pallet_grandpa::WeightInfo; type MaxAuthorities = MaxActiveValidators; type MaxNominators = MaxElectingVoters; 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; } 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 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, Transfer = 1, Staking = 2, CancelProxy = 3, IdentityJudgement = 4, NominationPools = 5, } 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::Transfer => matches!(c, RuntimeCall::Balances { .. }), ProxyType::Staking => matches!( c, RuntimeCall::Staking { .. } | RuntimeCall::Session { .. } | RuntimeCall::Utility { .. } | RuntimeCall::VoterList { .. } ), 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 { .. } ), 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::Transfer, _) => 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"); pub const MaxPointsToBalance: u8 = 10; } impl ghost_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<128>; type MaxUnbonding = ::MaxUnlockingChunks; type PalletId = PoolsPalletId; type MaxPointsToBalance = MaxPointsToBalance; type AdminOrigin = EnsureRoot; type WeightInfo = (); // TODO: weights::ghost_nomination_pools::WeightInfo; } impl ghost_networks::Config for Runtime { type RuntimeEvent = RuntimeEvent; type NetworkId = NetworkId; type Currency = Balances; type MaxNetworks = ConstU32<30>; type RegisterOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; type RemoveOrigin = EnsureRoot; type WeightInfo = (); } parameter_types! { pub MaximumWithdrawAmount: Balance = 500 * CSPR; pub VestingBlocks: u32 = 10 * WEEKS; } impl ghost_governance::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type NetworkDataHandler = GhostNetworks; type MinimumDonation = ConstU128<{ 6_900 * STRH }>; type MaxProofDepth = ConstU32<20>; type WeightInfo = (); } impl ghost_sudo::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type WeightInfo = weights::ghost_sudo::WeightInfo; } parameter_types! { pub WeaverUnsignedPriority: TransactionPriority = Perbill::from_percent(30) * TransactionPriority::MAX; pub ExodusUnsignedPriority: TransactionPriority = Perbill::from_percent(90) * TransactionPriority::MAX; pub MaxAuthoritiesChunks: u32 = 32; pub WeavingDelay: u64 = 50; pub AttestationDelay: u64 = 25; pub ExodusUnsignedLongevity: u64 = 10; pub ExodusDkgRoundPeriod: u64 = 50; pub ExodusRemovalLimit: u32 = 64; pub ExodusMaxCursorLen: u32 = 100; } impl ghost_weaver::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type AuthorityId = GhostWeaverId; type BlockNumberProvider = System; type NetworkDataHandler = GhostNetworks; type MaxAuthorities = MaxActiveValidators; type MaxAuthoritiesChunks = MaxAuthoritiesChunks; type WeavingDelay = WeavingDelay; type AttestationDelay = AttestationDelay; type UnsignedPriority = WeaverUnsignedPriority; type WeightInfo = (); } impl ghost_exodus::Config for Runtime { type RuntimeEvent = RuntimeEvent; type AuthorityId = GhostExodusId; type ValidatorSet = Historical; type Currency = Balances; type NetworkDataHandler = GhostNetworks; type BlockNumberProvider = System; type DisabledValidators = Session; type UnsignedLongevity = ExodusUnsignedLongevity; type UnsignedPriority = ExodusUnsignedPriority; type MaxAuthorities = MaxActiveValidators; type MaxAuthoritiesChunks = MaxAuthoritiesChunks; type DkgRoundPeriod = ExodusDkgRoundPeriod; type RemovalLimit = ExodusRemovalLimit; type MaxCursorLen = ExodusMaxCursorLen; type WeightInfo = (); } construct_runtime! { pub enum Runtime { // Basic stuff; balances is uncallable initially. System: frame_system = 0, Scheduler: pallet_scheduler = 2, Preimage: pallet_preimage = 10, // Babe must be before session. Babe: pallet_babe = 1, Timestamp: pallet_timestamp = 3, 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, GhostSudo: ghost_sudo = 13, // Governance stuff. Treasury: pallet_treasury = 19, Utility: pallet_utility = 24, Identity: pallet_identity = 25, Proxy: pallet_proxy = 26, // 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: ghost_nomination_pools = 34, // Ghosts stuff. Start indicies at 50 to leave room. GhostNetworks: ghost_networks = 50, GhostGovernance: ghost_governance = 51, GhostWeaver: ghost_weaver = 52, GhostExodus: ghost_exodus = 53, } } /// 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_babe, Babe] [pallet_bags_list, VoterList] [pallet_balances, Balances] [frame_benchmarking::baseline, Baseline::] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [frame_election_provider_support, ElectionProviderBench::] [pallet_grandpa, Grandpa] [pallet_identity, Identity] [pallet_offences, OffencesBench::] [pallet_preimage, Preimage] [pallet_proxy, Proxy] [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] [pallet_treasury, Treasury] [pallet_utility, Utility] // Ghosts [ghost_nomination_pools, NominationPoolsBench::] [ghost_networks, GhostNetworks] [ghost_governance, GhostGovernance] [ghost_weaver, GhostWeaver] [ghost_exodus, GhostExodus] [ghost_sudo, GhostSudo] ); } 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 ghost_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: ghost_nomination_pools::PoolId, points: Balance) -> Balance { NominationPools::api_points_to_balance(pool_id, points) } fn balance_to_points(pool_id: ghost_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 ghost_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) } #[allow(non_local_definitions)] 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 ghost_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 ghost_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( MaxExposurePageSize::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 = 3_000; // assuming we want around 3k candidates and 300 active validators. let all_targets: u32 = 400; let desired: u32 = 300; 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() { use sp_runtime::traits::Convert; let items_count: usize = 1; let bytes_count = 1024 * 1024; // 1 MB worth of bytes type SignedDepositBaseConfig = ::SignedDepositBase; let base_deposit = >::convert(items_count); let deposit = base_deposit + (SignedDepositByte::get() * bytes_count); // ensure this number does not change, or that it is checked after each change. // a 1 MB solution should take (2 + 1) CSPRs of deposit. assert_eq_error_rate!(deposit, 2 * CSPR, CSPR); } } #[cfg(test)] mod test { use super::*; #[test] fn call_size() { RuntimeCall::assert_size_under(256) } } #[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 t = frame_system::GenesisConfig::::default() .build_storage() .unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.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] #[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 t = frame_system::GenesisConfig::::default() .build_storage() .unwrap(); let mut ext = sp_io::TestExternalities::new(t); // set the minimum ext.execute_with(|| { pallet_transaction_payment::NextFeeMultiplier::::set(MinimumMultiplier::get()); }); while multiplier <= Multiplier::from_u32(1) { ext.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 t = frame_system::GenesisConfig::::default() .build_storage() .unwrap(); let mut ext = sp_io::TestExternalities::new(t); // set the minimum ext.execute_with(|| { pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); }); while multiplier > Multiplier::from_u32(0) { ext.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; } } }