Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add validator sets pallet tests #614

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 21 additions & 2 deletions substrate/validator-sets/pallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ validator-sets-primitives = { package = "serai-validator-sets-primitives", path
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }

[dev-dependencies]
pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-features = false }

sp-consensus-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }

ciphersuite = { path = "../../../crypto/ciphersuite", features = ["ristretto"] }
frost = { package = "modular-frost", path = "../../../crypto/frost", features = ["tests"] }
schnorrkel = { path = "../../../crypto/schnorrkel", package = "frost-schnorrkel" }

zeroize = "^1.5"
rand_core = "0.6"

[features]
std = [
"scale/std",
Expand All @@ -56,12 +68,15 @@ std = [
"sp-runtime/std",
"sp-session/std",
"sp-staking/std",

"sp-consensus-babe/std",

"frame-system/std",
"frame-support/std",

"pallet-babe/std",
"pallet-grandpa/std",
"pallet-timestamp/std",

"serai-primitives/std",
"validator-sets-primitives/std",
Expand All @@ -70,8 +85,12 @@ std = [
"dex-pallet/std",
]

# TODO
try-runtime = []
try-runtime = [
"frame-system/try-runtime",
"frame-support/try-runtime",

"sp-runtime/try-runtime",
]

runtime-benchmarks = [
"frame-system/runtime-benchmarks",
Expand Down
19 changes: 17 additions & 2 deletions substrate/validator-sets/pallet/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

use core::marker::PhantomData;

use scale::{Encode, Decode};
Expand Down Expand Up @@ -303,6 +309,7 @@ pub mod pallet {

/// Pending deallocations, keyed by the Session they become unlocked on.
#[pallet::storage]
#[pallet::getter(fn pending_deallocations)]
type PendingDeallocations<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
Expand Down Expand Up @@ -393,6 +400,7 @@ pub mod pallet {
let allocation_per_key_share = Self::allocation_per_key_share(network).unwrap().0;

let mut participants = vec![];
let mut total_allocated_stake = 0;
{
let mut iter = SortedAllocationsIter::<T>::new(network);
let mut key_shares = 0;
Expand All @@ -403,6 +411,7 @@ pub mod pallet {
(amount.0 / allocation_per_key_share).min(u64::from(MAX_KEY_SHARES_PER_SET));
participants.push((key, these_key_shares));

total_allocated_stake += amount.0;
key_shares += these_key_shares;
}
amortize_excess_key_shares(&mut participants);
Expand All @@ -415,6 +424,12 @@ pub mod pallet {
let set = ValidatorSet { network, session };
Pallet::<T>::deposit_event(Event::NewSet { set });

// other networks set their Session(0) TAS once they set their keys but serai network
// doesn't have that so we set it here.
if network == NetworkId::Serai && session == Session(0) {
TotalAllocatedStake::<T>::set(network, Some(Amount(total_allocated_stake)));
}

Participants::<T>::set(network, Some(participants.try_into().unwrap()));
SessionBeginBlock::<T>::set(
network,
Expand Down Expand Up @@ -622,7 +637,7 @@ pub mod pallet {
// If we're not removing the entire allocation, yet the allocation is no longer at or above
// the threshold for a key share, error
let allocation_per_key_share = Self::allocation_per_key_share(network).unwrap().0;
if (new_allocation != 0) && (new_allocation < allocation_per_key_share) {
if (new_allocation > 0) && (new_allocation < allocation_per_key_share) {
Err(Error::<T>::DeallocationWouldRemoveParticipant)?;
}

Expand Down Expand Up @@ -783,7 +798,7 @@ pub mod pallet {
PendingDeallocations::<T>::take((network, key), session)
}

fn rotate_session() {
pub(crate) fn rotate_session() {
// next serai validators that is in the queue.
let now_validators = Participants::<T>::get(NetworkId::Serai)
.expect("no Serai participants upon rotate_session");
Expand Down
210 changes: 210 additions & 0 deletions substrate/validator-sets/pallet/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
//! Test environment for ValidatorSets pallet.

use super::*;

use std::collections::HashMap;

use frame_support::{
construct_runtime,
traits::{ConstU16, ConstU32, ConstU64},
};

use sp_core::{
H256, Pair as PairTrait,
sr25519::{Public, Pair},
};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};

use serai_primitives::*;
use validator_sets::{primitives::MAX_KEY_SHARES_PER_SET, MembershipProof};

pub use crate as validator_sets;
pub use coins_pallet as coins;
pub use dex_pallet as dex;
pub use pallet_babe as babe;
pub use pallet_grandpa as grandpa;
pub use pallet_timestamp as timestamp;

type Block = frame_system::mocking::MockBlock<Test>;
// Maximum number of authorities per session.
pub type MaxAuthorities = ConstU32<{ MAX_KEY_SHARES_PER_SET }>;

pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
sp_consensus_babe::BabeEpochConfiguration {
c: PRIMARY_PROBABILITY,
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
};

pub const MEDIAN_PRICE_WINDOW_LENGTH: u16 = 10;

construct_runtime!(
pub enum Test
{
System: frame_system,
Timestamp: timestamp,
Coins: coins,
LiquidityTokens: coins::<Instance1>::{Pallet, Call, Storage, Event<T>},
ValidatorSets: validator_sets,
Dex: dex,
Babe: babe,
Grandpa: grandpa,
}
);

impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = Public;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = ConstU64<250>;
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}

impl timestamp::Config for Test {
type Moment = u64;
type OnTimestampSet = Babe;
type MinimumPeriod = ConstU64<{ (TARGET_BLOCK_TIME * 1000) / 2 }>;
type WeightInfo = ();
}

impl babe::Config for Test {
type EpochDuration = ConstU64<{ FAST_EPOCH_DURATION }>;

type ExpectedBlockTime = ConstU64<{ TARGET_BLOCK_TIME * 1000 }>;
type EpochChangeTrigger = babe::ExternalTrigger;
type DisabledValidators = ValidatorSets;

type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;

type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem = ();
}

impl grandpa::Config for Test {
type RuntimeEvent = RuntimeEvent;

type WeightInfo = ();
type MaxAuthorities = MaxAuthorities;

type MaxSetIdSessionEntries = ConstU64<0>;
type KeyOwnerProof = MembershipProof<Self>;
type EquivocationReportSystem = ();
}

impl coins::Config for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = ValidatorSets;
}

impl coins::Config<coins::Instance1> for Test {
type RuntimeEvent = RuntimeEvent;
type AllowMint = ();
}

impl dex::Config for Test {
type RuntimeEvent = RuntimeEvent;

type LPFee = ConstU32<3>; // 0.3%
type MintMinLiquidity = ConstU64<10000>;

type MaxSwapPathLength = ConstU32<3>; // coin1 -> SRI -> coin2

type MedianPriceWindowLength = ConstU16<{ MEDIAN_PRICE_WINDOW_LENGTH }>;

type WeightInfo = dex::weights::SubstrateWeight<Test>;
}

impl Config for Test {
type RuntimeEvent = RuntimeEvent;
type ShouldEndSession = Babe;
}

// For a const we can't define
pub fn genesis_participants() -> Vec<Pair> {
vec![
insecure_pair_from_name("Alice"),
insecure_pair_from_name("Bob"),
insecure_pair_from_name("Charlie"),
insecure_pair_from_name("Dave"),
]
}

// Amounts for single key share per network
pub fn key_shares() -> HashMap<NetworkId, Amount> {
HashMap::from([
(NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))),
(NetworkId::External(ExternalNetworkId::Bitcoin), Amount(1_000_000 * 10_u64.pow(8))),
(NetworkId::External(ExternalNetworkId::Ethereum), Amount(1_000_000 * 10_u64.pow(8))),
(NetworkId::External(ExternalNetworkId::Monero), Amount(100_000 * 10_u64.pow(8))),
])
}

pub(crate) fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
let networks: Vec<(NetworkId, Amount)> = key_shares().into_iter().collect::<Vec<_>>();

coins::GenesisConfig::<Test> {
accounts: genesis_participants()
.clone()
.into_iter()
.map(|a| (a.public(), Balance { coin: Coin::Serai, amount: Amount(1 << 60) }))
.collect(),
_ignore: Default::default(),
}
.assimilate_storage(&mut t)
.unwrap();

validator_sets::GenesisConfig::<Test> {
networks,
participants: genesis_participants().into_iter().map(|p| p.public()).collect(),
}
.assimilate_storage(&mut t)
.unwrap();

babe::GenesisConfig::<Test> {
authorities: genesis_participants()
.into_iter()
.map(|validator| (validator.public().into(), 1))
.collect(),
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
_config: PhantomData,
}
.assimilate_storage(&mut t)
.unwrap();

grandpa::GenesisConfig::<Test> {
authorities: genesis_participants()
.into_iter()
.map(|validator| (validator.public().into(), 1))
.collect(),
_config: PhantomData,
}
.assimilate_storage(&mut t)
.unwrap();

let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| System::set_block_number(0));
ext
}
Loading
Loading