Skip to content

Commit

Permalink
Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinonard committed Oct 12, 2023
1 parent e598d1b commit fff0656
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 16 deletions.
12 changes: 9 additions & 3 deletions pallets/dapp-staking-v3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ pub mod pallet {
/// Since each entry is a 'span', covering up to `T::EraRewardSpanLength` entries, only certain era value keys can exist in storage.
/// For the sake of simplicity, valid `era` keys are calculated as:
///
/// era_key = era - (era % T::EraRewardSpanLength)
/// era_key = era - (era % T::EraRewardSpanLength)
///
/// This means that e.g. in case `EraRewardSpanLength = 8`, only era values 0, 8, 16, 24, etc. can exist in storage.
/// Eras 1-7 will be stored in the same entry as era 0, eras 9-15 will be stored in the same entry as era 8, etc.
Expand Down Expand Up @@ -1008,7 +1008,6 @@ pub mod pallet {
let era_rewards = EraRewards::<T>::get(Self::era_reward_span_index(first_claim_era))
.ok_or(Error::<T>::InternalClaimStakerError)?;

// TODO: need to know when period ended, storage item is needed for this.
// last_period_era or current_era - 1
let last_period_era = if staked_period == protocol_state.period_number() {
protocol_state.era.saturating_sub(1)
Expand All @@ -1019,6 +1018,9 @@ pub mod pallet {
};
let last_claim_era = era_rewards.last_era().min(last_period_era);

let is_full_period_claimed =
staked_period < protocol_state.period_number() && last_period_era == last_claim_era;

// Get chunks for reward claiming
let chunks_for_claim = ledger
.staked
Expand All @@ -1045,7 +1047,11 @@ pub mod pallet {
acc.saturating_add(*reward)
});

T::Currency::deposit_into_existing(&account, reward_sum);
// TODO; update & write ledger
if is_full_period_claimed {}

T::Currency::deposit_into_existing(&account, reward_sum)
.map_err(|_| Error::<T>::InternalClaimStakerError)?;
rewards.into_iter().for_each(|(era, reward)| {
Self::deposit_event(Event::<T>::Reward {
account: account.clone(),
Expand Down
1 change: 1 addition & 0 deletions pallets/dapp-staking-v3/src/test/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ impl pallet_dapp_staking::Config for Test {
type StandardErasPerVotingPeriod = ConstU32<8>;
type StandardErasPerBuildAndEarnPeriod = ConstU32<16>;
type EraRewardSpanLength = ConstU32<8>;
type RewardRetentionInPeriods = ConstU32<2>;
type MaxNumberOfContracts = ConstU16<10>;
type MaxUnlockingChunks = ConstU32<5>;
type MaxStakingChunks = ConstU32<8>;
Expand Down
111 changes: 110 additions & 1 deletion pallets/dapp-staking-v3/src/test/tests_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct DummyEraAmount {
era: u32,
}
impl AmountEraPair for DummyEraAmount {
fn new(amount: Balance, era: u32) -> Self {
Self { amount, era }
}
fn get_amount(&self) -> Balance {
self.amount
}
Expand Down Expand Up @@ -305,6 +308,7 @@ fn sparse_bounded_amount_era_vec_subtract_amount_advanced_non_consecutive_works(
#[test]
fn sparse_bounded_amount_era_vec_full_subtract_with_single_future_era() {
get_u32_type!(MaxLen, 5);

let mut vec = SparseBoundedAmountEraVec::<DummyEraAmount, MaxLen>::new();

// A scenario where some amount is added, for the first time, for era X.
Expand All @@ -320,6 +324,111 @@ fn sparse_bounded_amount_era_vec_full_subtract_with_single_future_era() {
);
}

#[test]
fn sparse_bounded_amount_era_vec_split_left_works() {
get_u32_type!(MaxLen, 4);

fn new_era_vec(vec: Vec<u32>) -> SparseBoundedAmountEraVec<DummyEraAmount, MaxLen> {
let vec: Vec<DummyEraAmount> = vec
.into_iter()
.map(|idx| DummyEraAmount::new(idx as Balance, idx))
.collect();
SparseBoundedAmountEraVec(BoundedVec::try_from(vec).unwrap())
}

// 1st scenario: [1,2,6,7] -- split(4) --> [1,2],[5,6,7]
let mut vec = new_era_vec(vec![1, 2, 6, 7]);
let result = vec.left_split(4).expect("Split should succeed.");
assert_eq!(result.0.len(), 2);
assert_eq!(result.0[0], DummyEraAmount::new(1, 1));
assert_eq!(result.0[1], DummyEraAmount::new(2, 2));

assert_eq!(vec.0.len(), 3);
assert_eq!(
vec.0[0],
DummyEraAmount::new(2, 5),
"Amount must come from last entry in the split."
);
assert_eq!(vec.0[1], DummyEraAmount::new(6, 6));
assert_eq!(vec.0[2], DummyEraAmount::new(7, 7));

// 2nd scenario: [1,2] -- split(4) --> [1,2],[5]
let mut vec = new_era_vec(vec![1, 2]);
let result = vec.left_split(4).expect("Split should succeed.");
assert_eq!(result.0.len(), 2);
assert_eq!(result.0[0], DummyEraAmount::new(1, 1));
assert_eq!(result.0[1], DummyEraAmount::new(2, 2));

assert_eq!(vec.0.len(), 1);
assert_eq!(
vec.0[0],
DummyEraAmount::new(2, 5),
"Amount must come from last entry in the split."
);

// 3rd scenario: [1,2,4,5] -- split(4) --> [1,2,4],[5]
let mut vec = new_era_vec(vec![1, 2, 4, 5]);
let result = vec.left_split(4).expect("Split should succeed.");
assert_eq!(result.0.len(), 3);
assert_eq!(result.0[0], DummyEraAmount::new(1, 1));
assert_eq!(result.0[1], DummyEraAmount::new(2, 2));
assert_eq!(result.0[2], DummyEraAmount::new(4, 4));

assert_eq!(vec.0.len(), 1);
assert_eq!(vec.0[0], DummyEraAmount::new(5, 5));

// 4th scenario: [1,2,4,6] -- split(4) --> [1,2,4],[5,6]
let mut vec = new_era_vec(vec![1, 2, 4, 6]);
let result = vec.left_split(4).expect("Split should succeed.");
assert_eq!(result.0.len(), 3);
assert_eq!(result.0[0], DummyEraAmount::new(1, 1));
assert_eq!(result.0[1], DummyEraAmount::new(2, 2));
assert_eq!(result.0[2], DummyEraAmount::new(4, 4));

assert_eq!(vec.0.len(), 2);
assert_eq!(
vec.0[0],
DummyEraAmount::new(4, 5),
"Amount must come from last entry in the split."
);
assert_eq!(vec.0[1], DummyEraAmount::new(6, 6));
}

#[test]
fn sparse_bounded_amount_era_vec_split_left_fails_with_invalid_era() {
get_u32_type!(MaxLen, 4);
let mut vec = SparseBoundedAmountEraVec::<DummyEraAmount, MaxLen>::new();
assert!(vec.add_amount(5, 5).is_ok());

assert_eq!(vec.left_split(4), Err(AccountLedgerError::SplitEraInvalid));
}

#[test]
fn sparse_bounded_amount_era_vec_get_works() {
get_u32_type!(MaxLen, 4);
let vec: Vec<DummyEraAmount> = vec![2, 3, 5]
.into_iter()
.map(|idx| DummyEraAmount::new(idx as Balance, idx))
.collect();
let vec =
SparseBoundedAmountEraVec::<DummyEraAmount, MaxLen>(BoundedVec::try_from(vec).unwrap());

assert_eq!(vec.get(1), None, "Era is not covered by the vector.");
assert_eq!(vec.get(2), Some(DummyEraAmount::new(2, 2)));
assert_eq!(vec.get(3), Some(DummyEraAmount::new(3, 3)));
assert_eq!(
vec.get(4),
Some(DummyEraAmount::new(3, 4)),
"Era is covered by the 3rd era."
);
assert_eq!(vec.get(5), Some(DummyEraAmount::new(5, 5)));
assert_eq!(
vec.get(6),
Some(DummyEraAmount::new(5, 6)),
"Era is covered by the 5th era."
);
}

#[test]
fn period_type_sanity_check() {
assert_eq!(PeriodType::Voting.next(), PeriodType::BuildAndEarn);
Expand Down Expand Up @@ -1821,7 +1930,7 @@ fn era_reward_span_fails_when_expected() {
// Attempting to push incorrect era results in an error
for wrong_era in &[era_1 - 1, era_1, era_1 + 2] {
assert_eq!(
era_reward_span.push(era_1 - 1, era_reward),
era_reward_span.push(*wrong_era, era_reward),
Err(EraRewardSpanError::InvalidEra)
);
}
Expand Down
21 changes: 9 additions & 12 deletions pallets/dapp-staking-v3/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@ where
Ok(())
}

// TODO: unit test
/// Splits the vector into two parts, using the provided `era` as the splitting point.
///
/// All entries which satisfy the condition `entry.era <= era` are removed from the vector.
Expand All @@ -240,16 +239,16 @@ where
/// The `era` argument **must** be contained within the vector's scope.
///
/// E.g.:
/// a) [1,2,6,7] -- split(4) --> [1,2,4],[5,6,7]
/// b) [1,2] -- split(4) --> [1,2,4],[5]
/// a) [1,2,6,7] -- split(4) --> [1,2],[5,6,7]
/// b) [1,2] -- split(4) --> [1,2],[5]
/// c) [1,2,4,5] -- split(4) --> [1,2,4],[5]
/// d) [1,2,4,6] -- split(4) --> [1,2,4],[5,6]
pub fn left_split(&mut self, era: EraNumber) -> Result<Self, AccountLedgerError> {
// TODO: this implementation can once again be optimized, sacrificing the code readability a bit.
// But I don't think it's worth doing, since we're aiming for the safe side here.

// Split the inner vector into two parts
let (mut left, mut right): (Vec<P>, Vec<P>) = self
let (left, mut right): (Vec<P>, Vec<P>) = self
.0
.clone()
.into_iter()
Expand All @@ -260,13 +259,6 @@ where
}

if let Some(&last_l_chunk) = left.last() {
// In case 'left' part is missing an entry covering the specified era, add it.
if last_l_chunk.get_era() < era {
let mut new_chunk = last_l_chunk;
new_chunk.set_era(era);
left.push(new_chunk);
}

// In case 'right' part is missing an entry covering the specified era, add it.
match right.first() {
Some(first_r_chunk) if first_r_chunk.get_era() > era.saturating_add(1) => {
Expand All @@ -291,7 +283,6 @@ where
))
}

// TODO: unit tests
/// Returns the most appropriate chunk for the specified era, if it exists.
pub fn get(&self, era: EraNumber) -> Option<P> {
match self.0.binary_search_by(|chunk| chunk.get_era().cmp(&era)) {
Expand Down Expand Up @@ -795,6 +786,12 @@ where
pub fn oldest_stake_era(&self) -> Option<EraNumber> {
self.staked.0.first().map(|chunk| chunk.era)
}

/// Notify ledger that all `stake` rewards have been claimed for the staked era.
pub fn all_stake_rewards_claimed(&mut self) {
self.staked = SparseBoundedAmountEraVec(BoundedVec::<StakeChunk, StakedLen>::default());
self.staked_period = None;
}
}

// TODO: it would be nice to implement add/subtract logic on this struct and use it everywhere
Expand Down

0 comments on commit fff0656

Please sign in to comment.