#![cfg(test)] use frame_support::{ derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use frame_system::EnsureRoot; use pallet_session::historical as pallet_session_historical; use sp_runtime::{ curve::PiecewiseLinear, testing::{TestXt, UintAuthorityId}, traits::{AtLeast32BitUnsigned, ConvertInto}, Permill, }; use sp_staking::{ offence::{OffenceError, ReportOffence}, SessionIndex, }; use sp_runtime::BuildStorage; use crate::{self as slow_clap, AuthIndex}; use crate::{Config, EraIndex, ExposureListener}; type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Runtime { System: frame_system, Session: pallet_session, Historical: pallet_session_historical, Balances: pallet_balances, Networks: ghost_networks, SlowClap: slow_clap, } ); parameter_types! { pub static FixedValidators: Vec = vec![0, 1, 2, 3]; } pub struct TestSessionManager; impl pallet_session::SessionManager for TestSessionManager { fn new_session(_new_index: SessionIndex) -> Option> { Some(FixedValidators::get()) } fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} } impl pallet_session::historical::SessionManager for TestSessionManager { fn new_session(_new_index: SessionIndex) -> Option> { Some(FixedValidators::get().iter().map(|l| (*l, *l)).collect()) } fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} } type IdentificationTuple = (u64, u64); type Offence = crate::SlowClapOffence; parameter_types! { pub static Offences: Vec<(Vec, Offence)> = vec![]; } pub struct OffenceHandler; impl ReportOffence for OffenceHandler { fn report_offence(reporters: Vec, offence: Offence) -> Result<(), OffenceError> { Offences::mutate(|l| l.push((reporters, offence))); Ok(()) } fn is_known_offence(_offenders: &[IdentificationTuple], _time_slot: &SessionIndex) -> bool { false } } pub fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::::default() .build_storage() .unwrap(); let mut result = sp_io::TestExternalities::new(t); result.execute_with(|| { for i in 0..=3 { System::inc_providers(&i); assert_eq!( Session::set_keys(RuntimeOrigin::signed(i), i.into(), vec![],), Ok(()) ); } }); result } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type AccountData = pallet_balances::AccountData; } parameter_types! { pub const Period: u64 = 1; pub const Offset: u64 = 0; } impl pallet_session::Config for Runtime { type ShouldEndSession = pallet_session::PeriodicSessions; type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = (SlowClap,); type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type Keys = UintAuthorityId; type RuntimeEvent = RuntimeEvent; type NextSessionRotation = pallet_session::PeriodicSessions; type WeightInfo = (); } impl pallet_session::historical::Config for Runtime { type FullIdentification = u64; type FullIdentificationOf = ConvertInto; } parameter_types! { pub static MockCurrentSessionProgress: Option> = None; } parameter_types! { pub static MockAverageSessionLength: Option = None; } impl ghost_networks::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type NetworkId = u32; type RegisterOrigin = EnsureRoot; type UpdateOrigin = EnsureRoot; type RemoveOrigin = EnsureRoot; type WeightInfo = (); } pallet_staking_reward_curve::build! { const REWARD_CURVE: PiecewiseLinear<'static> = curve!( min_inflation: 0_006_000, max_inflation: 1_000_000, ideal_stake: 0_690_000, falloff: 0_050_000, max_piece_count: 100, test_precision: 0_005_000, ); } parameter_types! { pub static ExistentialDeposit: u64 = 2; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const HistoryDepth: u32 = 10; } #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type ExistentialDeposit = ExistentialDeposit; type MaxReserves = ConstU32<2>; type AccountStore = System; type WeightInfo = (); } type Balance = u64; pub struct TestExposureListener; impl ExposureListener for TestExposureListener where Balance: AtLeast32BitUnsigned + From, { fn get_current_era() -> EraIndex { 1 } fn get_total_exposure(_era: EraIndex) -> Balance { 1_000_000_000u64.into() } fn get_validator_exposure(index: AuthIndex) -> Balance { match index { 0 => 250_000_000u64, 1 => 200_000_000u64, 2 => 250_000_000u64, 3 => 300_000_000u64, _ => 0, } .into() } } impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type AuthorityId = UintAuthorityId; type ValidatorSet = Historical; type Currency = Balances; type NetworkDataHandler = Networks; type BlockNumberProvider = System; type ReportUnresponsiveness = OffenceHandler; type DisabledValidators = Session; type ExposureListener = TestExposureListener; type MaxAuthorities = ConstU32<5>; type ApplauseThreshold = ConstU32<500_000_000>; type UnsignedPriority = ConstU64<{ 1 << 20 }>; type HistoryDepth = HistoryDepth; type MinAuthoritiesNumber = ConstU32<1>; type WeightInfo = (); } pub type Extrinsic = TestXt; impl frame_system::offchain::SendTransactionTypes for Runtime where RuntimeCall: From, { type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } pub fn advance_session() { let now = System::block_number().max(1); System::set_block_number(now + 1); Session::rotate_session(); let session_index = Session::current_index(); assert_eq!(session_index, (now / Period::get()) as u32); }