Skip to content

Commit e34f1a3

Browse files
committed
add tests to check not eligible for rewards when not have min bonded and cool down starts. initialise default bonded amounts to 0 in implementation
1 parent bdbaeaf commit e34f1a3

File tree

2 files changed

+166
-87
lines changed

2 files changed

+166
-87
lines changed

pallets/mining/rewards-allowance/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,8 @@ pub mod pallet {
899899
// half of 5000 DHX daily allowance (of 2500 DHX), but in that case we split the rewards
900900
// (i.e. 25,133 DHX locked at 10:1 gives 2513 DHX reward)
901901

902-
let mut locks_first_amount_as_u128 = default_bonded_amount_u128.clone();
902+
// initialise so they have no locks and are ineligible for rewards
903+
let mut locks_first_amount_as_u128 = 0u128.clone();
903904
let locked_vec = <pallet_balances::Pallet<T>>::locks(miner.clone()).into_inner();
904905
if locked_vec.len() != 0 {
905906
// println!("locked_vec: {:?}", locked_vec);
@@ -916,8 +917,9 @@ pub mod pallet {
916917
locks_first_amount_as_u128 = x;
917918
}
918919
}
919-
log::info!("locks_first_amount_as_u128: {:?}", locks_first_amount_as_u128.clone());
920920
}
921+
log::info!("locks_first_amount_as_u128: {:?}", locks_first_amount_as_u128.clone());
922+
// println!("locks_first_amount_as_u128 {:#?}", locks_first_amount_as_u128);
921923

922924
// Example output below of vote with 9.9999 tokens on a referendum associated with a proposal
923925
// that was seconded
@@ -951,7 +953,6 @@ pub mod pallet {
951953
bonded_dhx_current_u128 = x;
952954
}
953955
}
954-
log::info!("set_bonded_dhx_of_account_for_date: {:?} {:?}", start_of_requested_date_millis.clone(), bonded_dhx_current_u128.clone());
955956

956957
let mut min_bonded_dhx_daily: BalanceOf<T> = 10u32.into();
957958
let mut min_bonded_dhx_daily_u128;
@@ -972,6 +973,8 @@ pub mod pallet {
972973
is_bonding_min_dhx = true;
973974
}
974975
log::info!("is_bonding_min_dhx: {:?} {:?}", is_bonding_min_dhx.clone(), miner.clone());
976+
// println!("is_bonding_min_dhx {:#?}", is_bonding_min_dhx);
977+
// println!("min_bonded_dhx_daily_u128 {:#?}", min_bonded_dhx_daily_u128);
975978

976979
// TODO - move this into off-chain workers function
977980
let mut min_mpower_daily_u128: u128 = 5u128;

pallets/mining/rewards-allowance/src/tests.rs

Lines changed: 160 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -53,26 +53,26 @@ fn it_sets_rewards_allowance_with_genesis_defaults_automatically_in_on_finalize_
5353
// same timestamp for all the blocks and tests below.
5454
fn it_distributes_rewards_automatically_in_on_finalize_for_default_amount() {
5555
new_test_ext().execute_with(|| {
56-
setup_bonding(NORMAL_AMOUNT, TEN_DHX);
56+
let r = setup_bonding(NORMAL_AMOUNT, TEN_DHX);
5757

5858
setup_treasury_balance();
5959

6060
setup_multiplier();
6161

62-
distribute_rewards(NORMAL_AMOUNT);
62+
distribute_rewards(NORMAL_AMOUNT, r);
6363
})
6464
}
6565

6666
#[test]
6767
fn it_distributes_rewards_automatically_in_on_finalize_for_large_amount() {
6868
new_test_ext().execute_with(|| {
69-
setup_bonding(LARGE_AMOUNT_DHX, TEN_DHX);
69+
let r = setup_bonding(LARGE_AMOUNT_DHX, TEN_DHX);
7070

7171
setup_treasury_balance();
7272

7373
setup_multiplier();
7474

75-
distribute_rewards(LARGE_AMOUNT_DHX);
75+
distribute_rewards(LARGE_AMOUNT_DHX, r);
7676
})
7777
}
7878

@@ -282,7 +282,7 @@ fn it_allows_us_to_retrieve_genesis_value_for_min_mpower_daily() {
282282
});
283283
}
284284

285-
fn distribute_rewards(amount_bonded_each_miner: u128) {
285+
fn distribute_rewards(amount_bonded_each_miner: u128, referendum_index: u32) {
286286
assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(1)));
287287
assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(2)));
288288
assert_ok!(MiningRewardsAllowanceTestModule::set_registered_dhx_miner(Origin::signed(3)));
@@ -300,6 +300,93 @@ fn distribute_rewards(amount_bonded_each_miner: u128) {
300300
assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days(), Some(1));
301301
assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_daily(), Some(FIVE_THOUSAND_DHX));
302302

303+
check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner.clone());
304+
305+
// check that rewards multiplier increases by multiplier every period days and that days total and remaining are reset
306+
check_rewards_double_each_multiplier_period();
307+
308+
// check that after the multiplier doubles, they are no longer eligible to receive the rewards
309+
// if they have the same amount bonded (since they’d then need twice the amount bonded as ratio changes from 10:1 to 20:1),
310+
// even if they have sufficient mpower
311+
check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner.clone(), referendum_index.clone());
312+
}
313+
314+
fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) -> u32 {
315+
assert_ok!(MiningRewardsAllowanceTestModule::set_min_bonded_dhx_daily(
316+
Origin::signed(1),
317+
min_bonding_dhx_daily.clone(),
318+
));
319+
assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(min_bonding_dhx_daily.clone()));
320+
321+
// create a test that instead of using a hard-coded value for `locks_first_amount_as_u128`
322+
// that is in the implementation, it instead sets the locked value of each of them using frame_balances
323+
// for the 3x miners, since we can then store that with `set_bonded_dhx_of_account_for_date` and
324+
// then use that easier for the tests too for trying different values that they have bonded.
325+
//
326+
// in this test we'll test that it distributes rewards when each of their account balances are very large
327+
// (i.e. a third of the total supply) ONE_THIRD_OF_TOTAL_SUPPLY_DHX
328+
329+
assert_ok!(Balances::set_balance(Origin::root(), 1, amount_bonded_each_miner, 0));
330+
assert_ok!(Balances::set_balance(Origin::root(), 2, amount_bonded_each_miner, 0));
331+
assert_ok!(Balances::set_balance(Origin::root(), 3, amount_bonded_each_miner, 0));
332+
333+
assert_eq!(Balances::free_balance(&1), amount_bonded_each_miner);
334+
assert_eq!(Balances::free_balance(&2), amount_bonded_each_miner);
335+
assert_eq!(Balances::free_balance(&3), amount_bonded_each_miner);
336+
337+
assert_eq!(Balances::reserved_balance(&1), 0);
338+
339+
let pre_image_hash = BlakeTwo256::hash(b"test");
340+
// params: end block, proposal hash, threshold, delay
341+
let r = Democracy::inject_referendum(1, pre_image_hash.clone(), VoteThreshold::SuperMajorityApprove, 2);
342+
// lock the whole balance of account 1, 2, and 3 in voting
343+
let v1a1 = AccountVote::Standard { vote: AYE, balance: Balances::free_balance(1) };
344+
let v1a2 = AccountVote::Standard { vote: AYE, balance: Balances::free_balance(2) };
345+
let v1a3 = AccountVote::Standard { vote: AYE, balance: Balances::free_balance(3) };
346+
// vote on referenda using time-lock voting with a conviction to scale the vote power
347+
// note: second parameter is the referendum index being voted on
348+
assert_ok!(Democracy::vote(Origin::signed(1), r, v1a1));
349+
assert_ok!(Democracy::vote(Origin::signed(2), r, v1a2));
350+
assert_ok!(Democracy::vote(Origin::signed(3), r, v1a3));
351+
352+
// // assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 });
353+
assert_eq!(Balances::locks(1)[0],
354+
BalanceLock {
355+
id: [100, 101, 109, 111, 99, 114, 97, 99],
356+
amount: amount_bonded_each_miner,
357+
reasons: Reasons::Misc
358+
}
359+
);
360+
361+
return r;
362+
}
363+
364+
fn setup_multiplier() {
365+
assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_operation(
366+
Origin::signed(0),
367+
1u8,
368+
));
369+
370+
// in the tests we want the period between each 10:1, 20:1 cycle to be just 2 days instead of 90 days
371+
// since we don't want to wait so long to check that it changes each cycle in the tests
372+
assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_default_period_days(
373+
Origin::signed(0),
374+
2u32,
375+
));
376+
377+
assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_next_period_days(
378+
Origin::signed(0),
379+
2u32,
380+
));
381+
}
382+
383+
fn setup_treasury_balance() {
384+
// set the balance of the treasury so it distributes rewards
385+
Balances::set_balance(Origin::root(), Treasury::account_id(), INIT_DAO_BALANCE_DHX, 0);
386+
assert_eq!(Balances::usable_balance(&Treasury::account_id()), INIT_DAO_BALANCE_DHX);
387+
}
388+
389+
fn check_eligible_for_rewards_after_cooling_off_period_if_suffient_bonded(amount_bonded_each_miner: u128) {
303390
// since the timestamp is 0 (corresponds to 1970-01-01) at block number #1, we early exit from on_initialize in
304391
// that block in the implementation and do not set any storage values associated with the date until block #2.
305392
// in the tests we could set the timestamp before we run on_initialize(1), but that wouldn't reflect reality.
@@ -339,6 +426,8 @@ fn distribute_rewards(amount_bonded_each_miner: u128) {
339426
// 29th August 2021 @ 12am is 1630195200000 (start of day)
340427
Timestamp::set_timestamp(1630195200000u64);
341428
MiningRewardsAllowanceTestModule::on_initialize(4);
429+
// a day before we start the new multiplier period and change from 10:1 to 20:1 since no more days remaining
430+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_multiplier_current_period_days_remaining(), Some((1630022400000, 1630195200000, 2u32, 0u32)));
342431

343432
assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, 1)), Some(amount_bonded_each_miner));
344433
assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630195200000, 2)), Some(amount_bonded_each_miner));
@@ -397,85 +486,6 @@ fn distribute_rewards(amount_bonded_each_miner: u128) {
397486
// Update: difficult to add a test to check they are reset before next day, just check it works using the logs.
398487
// assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630281600000), Some(0u128));
399488
// assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630281600000, 1)), Some(0u128));
400-
401-
check_rewards_double_each_multiplier_period();
402-
}
403-
404-
fn setup_bonding(amount_bonded_each_miner: u128, min_bonding_dhx_daily: u128) {
405-
assert_ok!(MiningRewardsAllowanceTestModule::set_min_bonded_dhx_daily(
406-
Origin::signed(1),
407-
min_bonding_dhx_daily.clone(),
408-
));
409-
assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(min_bonding_dhx_daily.clone()));
410-
411-
// create a test that instead of using a hard-coded value for `locks_first_amount_as_u128`
412-
// that is in the implementation, it instead sets the locked value of each of them using frame_balances
413-
// for the 3x miners, since we can then store that with `set_bonded_dhx_of_account_for_date` and
414-
// then use that easier for the tests too for trying different values that they have bonded.
415-
//
416-
// in this test we'll test that it distributes rewards when each of their account balances are very large
417-
// (i.e. a third of the total supply) ONE_THIRD_OF_TOTAL_SUPPLY_DHX
418-
419-
assert_ok!(Balances::set_balance(Origin::root(), 1, amount_bonded_each_miner, 0));
420-
assert_ok!(Balances::set_balance(Origin::root(), 2, amount_bonded_each_miner, 0));
421-
assert_ok!(Balances::set_balance(Origin::root(), 3, amount_bonded_each_miner, 0));
422-
423-
assert_eq!(Balances::free_balance(&1), amount_bonded_each_miner);
424-
assert_eq!(Balances::free_balance(&2), amount_bonded_each_miner);
425-
assert_eq!(Balances::free_balance(&3), amount_bonded_each_miner);
426-
427-
assert_eq!(Balances::reserved_balance(&1), 0);
428-
429-
let pre_image_hash = BlakeTwo256::hash(b"test");
430-
let r = Democracy::inject_referendum(1, pre_image_hash.clone(), VoteThreshold::SuperMajorityApprove, 2);
431-
// lock the whole balance of account 1, 2, and 3 in voting
432-
let v1a1 = AccountVote::Standard { vote: AYE, balance: Balances::free_balance(1) };
433-
let v1a2 = AccountVote::Standard { vote: AYE, balance: Balances::free_balance(2) };
434-
let v1a3 = AccountVote::Standard { vote: AYE, balance: Balances::free_balance(3) };
435-
// vote on referenda using time-lock voting with a conviction to scale the vote power
436-
// note: second parameter is the referendum index being voted on
437-
assert_ok!(Democracy::vote(Origin::signed(1), r, v1a1));
438-
assert_ok!(Democracy::vote(Origin::signed(2), r, v1a2));
439-
assert_ok!(Democracy::vote(Origin::signed(3), r, v1a3));
440-
// let v2 = AccountVote::Split { aye: 1, nay: 2 };
441-
// assert_ok!(Democracy::vote(Origin::signed(1), r, v2));
442-
443-
// TODO - use this later to simulate that unbonding works
444-
// // assert_ok!(Democracy::remove_vote(Origin::signed(1), r));
445-
// // assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 });
446-
// // assert_ok!(Democracy::unlock(Origin::signed(1), 5));
447-
assert_eq!(Balances::locks(1)[0],
448-
BalanceLock {
449-
id: [100, 101, 109, 111, 99, 114, 97, 99],
450-
amount: amount_bonded_each_miner,
451-
reasons: Reasons::Misc
452-
}
453-
);
454-
}
455-
456-
fn setup_multiplier() {
457-
assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_operation(
458-
Origin::signed(0),
459-
1u8,
460-
));
461-
462-
// in the tests we want the period between each 10:1, 20:1 cycle to be just 2 days instead of 90 days
463-
// since we don't want to wait so long to check that it changes each cycle in the tests
464-
assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_default_period_days(
465-
Origin::signed(0),
466-
2u32,
467-
));
468-
469-
assert_ok!(MiningRewardsAllowanceTestModule::set_rewards_multiplier_next_period_days(
470-
Origin::signed(0),
471-
2u32,
472-
));
473-
}
474-
475-
fn setup_treasury_balance() {
476-
// set the balance of the treasury so it distributes rewards
477-
Balances::set_balance(Origin::root(), Treasury::account_id(), INIT_DAO_BALANCE_DHX, 0);
478-
assert_eq!(Balances::usable_balance(&Treasury::account_id()), INIT_DAO_BALANCE_DHX);
479489
}
480490

481491
fn check_rewards_double_each_multiplier_period() {
@@ -506,3 +516,69 @@ fn check_rewards_double_each_multiplier_period() {
506516
// check that the min_bonded_dhx_daily doubled after 3 months (we're only doing it after 2 days in the tests though) from 20 DHX to 30 DHX
507517
assert_eq!(MiningRewardsAllowanceTestModule::min_bonded_dhx_daily(), Some(THIRTY_DHX));
508518
}
519+
520+
fn check_ineligible_for_rewards_and_cooling_down_period_starts_if_insufficient_bonded(amount_bonded_each_miner: u128, referendum_index: u32) {
521+
// 3rd Sept 2021 @ ~7am is 1630652400000
522+
// 3rd Sept 2021 @ 12am is 1630627200000 (start of day)
523+
Timestamp::set_timestamp(1630652400000u64);
524+
MiningRewardsAllowanceTestModule::on_initialize(8);
525+
526+
// the below works to unbond each of the accounts
527+
528+
// check that the referendum that we created earlier still exists
529+
assert_eq!(Democracy::referendum_count(), 1, "referenda not created");
530+
531+
// remove the votes and then unlock for each account
532+
// note: `remove_vote` must be done before `unlock`
533+
assert_ok!(Democracy::remove_vote(Origin::signed(1), referendum_index));
534+
assert_ok!(Democracy::remove_vote(Origin::signed(2), referendum_index));
535+
assert_ok!(Democracy::remove_vote(Origin::signed(3), referendum_index));
536+
// we removed their votes
537+
assert_eq!(Democracy::referendum_status(referendum_index).unwrap().tally, Tally { ayes: 0, nays: 0, turnout: 0 });
538+
assert_ok!(Democracy::unlock(Origin::signed(1), 1));
539+
assert_ok!(Democracy::unlock(Origin::signed(2), 2));
540+
assert_ok!(Democracy::unlock(Origin::signed(3), 3));
541+
542+
// check that all accounts are unlocked
543+
assert_eq!(Balances::locks(1), vec![]);
544+
assert_eq!(Balances::locks(2), vec![]);
545+
assert_eq!(Balances::locks(3), vec![]);
546+
547+
// now wait for the next day when we iterate through the miner accounts and they should have no locks
548+
// 4th Sept 2021 @ ~7am is 1630738800000
549+
// 4th Sept 2021 @ 12am is 1630713600000 (start of day)
550+
Timestamp::set_timestamp(1630738800000u64);
551+
MiningRewardsAllowanceTestModule::on_initialize(9);
552+
553+
// IMPORTANT NOTE: The min. DHX bonded has increased from 10 (10:1) to 20 (20:1) in order to be eligible
554+
// for rewards, however none of the miner's increased their bonded DHX amount proportionally to still remain
555+
// eligible for rewards, so since having insufficient bonded DHX is the same as unbonding, we expect the
556+
// cooling off period days remaining to change so they are now going through the unbonding cool down period,
557+
// (which we also count using `cooling_off_period_days_remaining`)
558+
// where they aren't eligble for rewards until they bond the new min. DHX so cooling off period starts and
559+
// then they'd be eligible for rewards after waiting that period, but also note that if they don't bond the new min.
560+
// DHX and wait until the end of the cool down period then they'll be able to withdraw the amount they had bonded.
561+
//
562+
// but in the tests the initial bonded amounts were much more than the min. DHX bonded, so even after it increases
563+
// from 10 (10:1) to 20 (20:1) they are still eligible for rewards.
564+
// so in the tests we've just decided to remove their vote and `unlock` their bonded DHX so they don't have a lock
565+
// and so don't satisfy the min. DHX bonded
566+
567+
// params: start of date, days remaining, bonding status
568+
// note: since they don't have the min. DHX bonded their bonding status changes to `2`, which is unbonding
569+
assert_eq!(MiningRewardsAllowanceTestModule::cooling_off_period_days_remaining(1), Some((1630713600000, 1, 2)));
570+
571+
assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, 1)), Some(0u128));
572+
assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, 2)), Some(0u128));
573+
assert_eq!(MiningRewardsAllowanceTestModule::bonded_dhx_of_account_for_date((1630713600000, 3)), Some(0u128));
574+
575+
// check they are not eligible for rewards due to insufficient bonded amount
576+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_aggregated_dhx_for_all_miners_for_date(1630713600000), None);
577+
578+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, 1)), None);
579+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, 2)), None);
580+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_accumulated_dhx_for_miner_for_date((1630713600000, 3)), None);
581+
582+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining(1630713600000), Some(FIVE_THOUSAND_DHX));
583+
assert_eq!(MiningRewardsAllowanceTestModule::rewards_allowance_dhx_for_date_remaining_distributed(1630713600000), Some(false));
584+
}

0 commit comments

Comments
 (0)