Skip to content

Commit

Permalink
mock and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nanocryk committed Nov 7, 2024
1 parent a5ef43b commit 586d1a4
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 6 deletions.
19 changes: 14 additions & 5 deletions pallets/external-validators-rewards/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

pub use pallet::*;

use {
Expand All @@ -27,7 +33,10 @@ use {

#[frame_support::pallet]
pub mod pallet {
use {frame_support::pallet_prelude::*, sp_std::collections::btree_map::BTreeMap, tp_traits::EraIndexProvider};
use {
frame_support::pallet_prelude::*, sp_std::collections::btree_map::BTreeMap,
tp_traits::EraIndexProvider,
};

/// The current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
Expand All @@ -39,6 +48,7 @@ pub mod pallet {
pub trait Config: frame_system::Config {
type EraIndexProvider: EraIndexProvider;

#[pallet::constant]
type HistoryDepth: Get<EraIndex>;
}

Expand All @@ -65,14 +75,14 @@ pub mod pallet {
/// TODO: Docs
#[pallet::storage]
#[pallet::unbounded]
pub type ErasRewardPoints<T: Config> =
pub type RewardPointsForEra<T: Config> =
StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints<T::AccountId>, ValueQuery>;

impl<T: Config> Pallet<T> {
pub fn reward_by_ids(points: impl IntoIterator<Item = (T::AccountId, RewardPoints)>) {
let active_era = T::EraIndexProvider::active_era();

ErasRewardPoints::<T>::mutate(active_era.index, |era_rewards| {
RewardPointsForEra::<T>::mutate(active_era.index, |era_rewards| {
for (validator, points) in points.into_iter() {
*era_rewards.individual.entry(validator).or_default() += points;
era_rewards.total += points;
Expand All @@ -87,7 +97,7 @@ pub mod pallet {
return;
};

ErasRewardPoints::<T>::remove(era_index_to_delete);
RewardPointsForEra::<T>::remove(era_index_to_delete);
}
}
}
Expand Down Expand Up @@ -156,4 +166,3 @@ where
Self::reward_only_active(session, validators, DISPUTE_STATEMENT_POINTS);
}
}

182 changes: 182 additions & 0 deletions pallets/external-validators-rewards/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Copyright (C) Moondance Labs Ltd.
// This file is part of Tanssi.

// Tanssi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Tanssi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Tanssi. If not, see <http://www.gnu.org/licenses/>

use {
crate as pallet_external_validators_rewards,
frame_support::{
parameter_types,
traits::{ConstU32, ConstU64},
},
pallet_balances::AccountData,
sp_core::H256,
sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
},
};

type Block = frame_system::mocking::MockBlock<Test>;

// Configure a mock runtime to test the pallet.
frame_support::construct_runtime!(
pub enum Test
{
System: frame_system,
ExternalValidatorsRewards: pallet_external_validators_rewards,
// Session: pallet_session,
Balances: pallet_balances,
Timestamp: pallet_timestamp,
Mock: mock_data,
}
);

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const SS58Prefix: u8 = 42;
}

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

parameter_types! {
pub const ExistentialDeposit: u64 = 5;
pub const MaxReserves: u32 = 50;
}

impl pallet_balances::Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type Balance = u64;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type ReserveIdentifier = [u8; 8];
type RuntimeHoldReason = ();
type RuntimeFreezeReason = ();
type FreezeIdentifier = ();
type MaxLocks = ();
type MaxReserves = MaxReserves;
type MaxFreezes = ConstU32<0>;
}

impl pallet_timestamp::Config for Test {
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = ConstU64<5>;
type WeightInfo = ();
}

impl mock_data::Config for Test {}

impl pallet_external_validators_rewards::Config for Test {
type EraIndexProvider = Mock;
type HistoryDepth = ConstU32<10>;
}

// Pallet to provide some mock data, used to test
#[frame_support::pallet]
pub mod mock_data {
use {
frame_support::pallet_prelude::*,
tp_traits::{ActiveEraInfo, EraIndex, EraIndexProvider},
};

#[derive(Clone, Default, Encode, Decode, sp_core::RuntimeDebug, scale_info::TypeInfo)]
pub struct Mocks {
pub active_era: Option<ActiveEraInfo>,
}

#[pallet::config]
pub trait Config: frame_system::Config {}

#[pallet::call]
impl<T: Config> Pallet<T> {}

#[pallet::pallet]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);

#[pallet::storage]
pub(super) type Mock<T: Config> = StorageValue<_, Mocks, ValueQuery>;

impl<T: Config> Pallet<T> {
pub fn mock() -> Mocks {
Mock::<T>::get()
}
pub fn mutate<F, R>(f: F) -> R
where
F: FnOnce(&mut Mocks) -> R,
{
Mock::<T>::mutate(f)
}
}

impl<T: Config> EraIndexProvider for Pallet<T> {
fn active_era() -> ActiveEraInfo {
Self::mock()
.active_era
.expect("active_era should be set in test")
.clone()
}

fn era_to_session_start(_era_index: EraIndex) -> Option<u32> {
unimplemented!()
}
}
}

pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default()
.build_storage()
.unwrap();

let balances = vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)];
pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut t)
.unwrap();

let ext: sp_io::TestExternalities = t.into();

ext
}
84 changes: 84 additions & 0 deletions pallets/external-validators-rewards/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (C) Moondance Labs Ltd.
// This file is part of Tanssi.

// Tanssi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Tanssi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Tanssi. If not, see <http://www.gnu.org/licenses/>

use {
crate::{self as pallet_external_validators_rewards, mock::*},
sp_std::collections::btree_map::BTreeMap,
tp_traits::{ActiveEraInfo, OnEraStart},
};

#[test]
fn basic_setup_works() {
new_test_ext().execute_with(|| {
// Mock::mutate(|mock| mock.active_era = Some(ActiveEraInfo { index: 0, start: None}));
let storage_eras =
pallet_external_validators_rewards::RewardPointsForEra::<Test>::iter().count();
assert_eq!(storage_eras, 0);
});
}

#[test]
fn can_reward_validators() {
new_test_ext().execute_with(|| {
Mock::mutate(|mock| {
mock.active_era = Some(ActiveEraInfo {
index: 1,
start: None,
})
});
ExternalValidatorsRewards::reward_by_ids([(1, 10), (3, 30), (5, 50)]);
ExternalValidatorsRewards::reward_by_ids([(1, 10), (3, 10), (5, 10)]);

let storage_eras =
pallet_external_validators_rewards::RewardPointsForEra::<Test>::iter().count();
assert_eq!(storage_eras, 1);

let era_points = pallet_external_validators_rewards::RewardPointsForEra::<Test>::get(1);
let mut expected_map = BTreeMap::new();
expected_map.insert(1, 20);
expected_map.insert(3, 40);
expected_map.insert(5, 60);
assert_eq!(era_points.individual, expected_map);
assert_eq!(era_points.total, 20 + 40 + 60);
})
}

#[test]
fn history_limit() {
new_test_ext().execute_with(|| {
Mock::mutate(|mock| {
mock.active_era = Some(ActiveEraInfo {
index: 1,
start: None,
})
});
ExternalValidatorsRewards::reward_by_ids([(1, 10), (3, 30), (5, 50)]);

let storage_eras =
pallet_external_validators_rewards::RewardPointsForEra::<Test>::iter().count();
assert_eq!(storage_eras, 1);

ExternalValidatorsRewards::on_era_start(10, 0);
let storage_eras =
pallet_external_validators_rewards::RewardPointsForEra::<Test>::iter().count();
assert_eq!(storage_eras, 1, "shouldn't erase data yet");

ExternalValidatorsRewards::on_era_start(11, 0);
let storage_eras =
pallet_external_validators_rewards::RewardPointsForEra::<Test>::iter().count();
assert_eq!(storage_eras, 0, "data should be erased now");
})
}
2 changes: 1 addition & 1 deletion primitives/traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ impl<AccountId> MaybeSelfChainBlockAuthor<AccountId> for () {
}

/// Information regarding the active era (era in used in session).
#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct ActiveEraInfo {
/// Index of era.
pub index: EraIndex,
Expand Down

0 comments on commit 586d1a4

Please sign in to comment.