Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
d723499
wip: poc
wischli Jul 20, 2022
82da1d9
refactor: extrinsics and inherents
wischli Jul 28, 2022
03cd34d
refactor: remove storage redundancy
wischli Jul 29, 2022
766c777
tests: fix existing ones for staking
wischli Jul 29, 2022
791ef9c
tests: 80%
wischli Aug 1, 2022
38e92dd
feat: rm delegate_another_candidate and more
wischli Aug 1, 2022
d8bb955
docs: remove deprecated weight
wischli Aug 1, 2022
24dc4bf
Apply suggestions from code review
wischli Aug 2, 2022
7789cda
tests: 100%
wischli Aug 2, 2022
870b534
fix: benchmarks
wischli Aug 3, 2022
8926e4c
feat: remove multiple delegations (#391)
wischli Aug 8, 2022
3dd9c6d
Merge remote-tracking branch 'origin/wf/1930-staking-refactor' into w…
wischli Aug 8, 2022
05f520e
Merge branch 'develop' into wf/1930-staking-refactor
wischli Aug 8, 2022
f8c1419
Apply suggestions from code review
wischli Aug 9, 2022
ad13650
fix: suggestions from @ntn-x2 review
wischli Aug 9, 2022
adbcd46
fmt
wischli Aug 9, 2022
ddebe3a
fix: typos
wischli Aug 9, 2022
28e47ef
Merge remote-tracking branch 'origin/develop' into wf/1930-staking-re…
wischli Aug 10, 2022
7b9fda3
fix: docker file
wischli Aug 11, 2022
3e21d0c
Merge remote-tracking branch 'origin/develop' into wf/1930-staking-re…
wischli Sep 7, 2022
e70c044
feat: add staking rewards runtime api
wischli Sep 8, 2022
b1de42a
docs: add new extrinsics to staking header
wischli Sep 8, 2022
6f73296
feat: add staking rates api
wischli Sep 8, 2022
20fd523
tests: add api
wischli Sep 8, 2022
0f8160b
fix: unify staking runtime api
wischli Sep 9, 2022
420170d
refactor: stricter claiming
wischli Sep 15, 2022
25f1878
Merge remote-tracking branch 'origin/develop' into wf/1930-staking-re…
wischli Sep 15, 2022
a3b2631
fix: easy suggestions from code review
wischli Sep 16, 2022
15424e0
refactor: separate runtime api from custom rpc
wischli Sep 16, 2022
e703493
tests: comp api claim with claiming
wischli Sep 19, 2022
a00364b
refactor: move runtime api calls to mod
wischli Sep 19, 2022
02eb407
stlye: fmt
wischli Sep 19, 2022
379c736
refactor: split api into separate crates
wischli Sep 19, 2022
dfbd9e3
Merge remote-tracking branch 'origin/develop' into wf/1930-staking-re…
wischli Oct 27, 2022
bc0890f
Merge remote-tracking branch 'origin/develop' into wf/1930-staking-re…
wischli Oct 28, 2022
c5548db
Merge remote-tracking branch 'origin/wf/1930-staking-refactor' into w…
wischli Oct 28, 2022
a9f58bc
refactor: simplify staking api name
wischli Oct 28, 2022
01d09bb
refactor: normalize public creds runtime api
wischli Oct 28, 2022
4f30a8a
refactor: machete cleanup
wischli Oct 28, 2022
36e4abd
tests: add safety check to API rewards
wischli Oct 31, 2022
56a5539
style: fmt
wischli Oct 31, 2022
98eab08
Merge branch 'develop' into wf/1930-staking-refactor
wischli Oct 31, 2022
30044dd
feat: write delegator state migration
wischli Sep 16, 2022
55620d2
refactor: remove unneeded no_std flags
wischli Oct 31, 2022
30be731
refactor: Delegator interface functions
wischli Nov 1, 2022
55c6ac3
refactor: rm Option for Delegator.owner
wischli Nov 1, 2022
cd9684e
style: apply turbofish to staking
wischli Nov 1, 2022
f459050
fix: replace RewardCount with two counters
wischli Nov 2, 2022
39e3716
refactor: rm col input for del stake adjustment
wischli Nov 2, 2022
bf304e5
Merge remote-tracking branch 'origin/wf/1930-staking-refactor' into w…
wischli Nov 2, 2022
f87f01e
style: fmt
wischli Nov 3, 2022
f6f73aa
Merge remote-tracking branch 'origin/develop' into wf-1930-staking-re…
wischli Nov 3, 2022
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
Prev Previous commit
Next Next commit
tests: 100%
  • Loading branch information
wischli committed Aug 2, 2022
commit 7789cdab043f7b191c467f02edd6fb9c9e1cca40
29 changes: 6 additions & 23 deletions pallets/parachain-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1489,8 +1489,8 @@ pub mod pallet {
/// their chances to be included in the set of candidates in the next
/// rounds.
///
/// Automatically increments the accumulated rewards of the origin of the
/// current delegation.
/// Automatically increments the accumulated rewards of the origin of
/// the current delegation.
///
/// Emits `DelegatorLeft`.
#[pallet::weight(<T as pallet::Config>::WeightInfo::leave_delegators(
Expand Down Expand Up @@ -1707,7 +1707,7 @@ pub mod pallet {
/// for anyone.
///
/// Emits `Rewarded`.
// TODO: Benchmark, unit tests
// TODO: Benchmark
#[pallet::weight(0)]
pub fn claim_rewards_for(origin: OriginFor<T>, target: <T::Lookup as StaticLookup>::Source) -> DispatchResult {
ensure_signed(origin)?;
Expand All @@ -1732,7 +1732,7 @@ pub mod pallet {
/// network.
///
/// The dispatch origin must be a collator.
// TODO: Benchmark, unit tests
// TODO: Benchmark
#[pallet::weight(0)]
pub fn increment_collator_rewards(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
let collator = ensure_signed(origin)?;
Expand All @@ -1753,19 +1753,16 @@ pub mod pallet {
/// delegations.
///
/// The dispatch origin must be a delegator.
// TODO: Benchmark, unit tests
// TODO: Benchmark
#[pallet::weight(0)]
pub fn increment_delegator_rewards(origin: OriginFor<T>) -> DispatchResult {
let delegator = ensure_signed(origin)?;
let delegation = DelegatorState::<T>::get(&delegator).ok_or(Error::<T>::DelegatorNotFound)?;
// should never throw
let collator = delegation.owner.ok_or(Error::<T>::DelegationNotFound)?;

// early exit
let reward_count = RewardCount::<T>::take(&delegator);
ensure!(!reward_count.is_zero(), Error::<T>::RewardsNotFound);

Self::do_inc_delegator_reward(&delegator, delegation.amount, &collator);
ensure!(!Rewards::<T>::get(&delegator).is_zero(), Error::<T>::RewardsNotFound);

Ok(())
}
Expand Down Expand Up @@ -2457,8 +2454,6 @@ pub mod pallet {
Rewards::<T>::mutate(acc, |reward| {
*reward = reward.saturating_add(Self::calc_block_rewards_delegator(stake, diff.into()));
});
// TODO: Investigate whether we want to set this to some input variable to
// improve `add_collator_reward`
RewardCount::<T>::insert(acc, col_reward_count);

// 4 reads from reward calc
Expand All @@ -2467,18 +2462,6 @@ pub mod pallet {
T::DbWeight::get().reads(2)
}
}

// [Post-launch TODO] Think about Collator stake or total stake?
// /// Attempts to add a collator candidate to the set of collator
// /// candidates which already reached its maximum size. On success,
// /// another collator with the minimum total stake is removed from the
// /// set. On failure, an error is returned. removing an already existing
// fn check_collator_candidate_inclusion(
// stake: Stake<T::AccountId, BalanceOf<T>>,
// mut candidates: OrderedSet<Stake<T::AccountId, BalanceOf<T>>,
// T::MaxTopCandidates>, ) -> Result<(), DispatchError> {
// todo!()
// }
}

impl<T> pallet_authorship::EventHandler<T::AccountId, T::BlockNumber> for Pallet<T>
Expand Down
285 changes: 215 additions & 70 deletions pallets/parachain-staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3887,6 +3887,7 @@ fn rewards_candidate_stake_less() {
});
});
}

#[test]
fn rewards_candidate_leave_network() {
ExtBuilder::default()
Expand All @@ -3908,7 +3909,7 @@ fn rewards_candidate_leave_network() {
roll_to(
10,
vec![
// we're in block 1 already, so cannot note_author in roll_to
// we're already in block 1, so cant note_author for block 1
None,
Some(1),
Some(2),
Expand Down Expand Up @@ -3940,6 +3941,37 @@ fn rewards_candidate_leave_network() {
});
}

#[test]
fn rewards_force_remove_candidate() {
ExtBuilder::default()
.with_balances(vec![
(1, DECIMALS),
(2, DECIMALS),
(3, DECIMALS),
(4, DECIMALS),
(5, DECIMALS),
])
.with_collators(vec![(1, DECIMALS), (4, DECIMALS), (5, DECIMALS)])
.with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)])
.build()
.execute_with(|| {
// init does not increment rewards
StakePallet::note_author(1);
StakePallet::note_author(2);

// removing triggers reward increment for collator 1 and delegators 4, 5
assert_ok!(StakePallet::force_remove_candidate(Origin::root(), 1));
(1..=3).for_each(|id| {
assert!(!StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
assert!(StakePallet::reward_count(id).is_zero(), "acc_id {:?}", id);
});
(4..=5).for_each(|id| {
assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
assert!(StakePallet::reward_count(id).is_zero(), "acc_id {:?}", id);
});
});
}

#[test]
fn reward_count_join_delegators() {
ExtBuilder::default()
Expand Down Expand Up @@ -4053,72 +4085,185 @@ fn rewards_delegator_replaced() {
});
}

// FIXME: Re-enable
// #[test]
// fn rewards_delegator_revokes_single_delegation() {
// ExtBuilder::default()
// .with_balances(vec![(1, DECIMALS), (2, 2 * DECIMALS)])
// .with_collators(vec![(1, DECIMALS)])
// .with_delegators(vec![(2, 1, DECIMALS)])
// .build()
// .execute_with(|| {
// // note once to set counter to 1
// StakePallet::note_author(1);
// assert_eq!(StakePallet::reward_count(1), 1);
// assert!(StakePallet::reward_count(2).is_zero());
// assert!(StakePallet::reward_count(3).is_zero());
// (1..=3).for_each(|id| {
// assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
// });

// // stake more to trigger reward incrementing just for 3
// assert_ok!(StakePallet::delegator_stake_more(Origin::signed(2), 1,
// DECIMALS)); // 1 should still have counter 1 but no rewards
// assert_eq!(StakePallet::reward_count(1), 1);
// assert!(StakePallet::rewards(1).is_zero());
// // 2 should still have neither rewards nor counter
// assert!(StakePallet::reward_count(2).is_zero());
// assert!(StakePallet::rewards(2).is_zero());
// // 3 should have rewards and the same counter as 1
// assert_eq!(StakePallet::reward_count(3), 1);
// assert!(!StakePallet::rewards(3).is_zero());
// });
// }

// #[test]
// fn rewards_delegator_leaves() {
// ExtBuilder::default()
// .with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, 2 * DECIMALS)])
// .with_collators(vec![(1, DECIMALS), (2, DECIMALS)])
// .with_delegators(vec![(3, 1, DECIMALS)])
// .build()
// .execute_with(|| {
// assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(3), 2,
// DECIMALS)); // note both collators once to set their counter to 2
// StakePallet::note_author(1);
// StakePallet::note_author(2);
// assert_eq!(StakePallet::reward_count(1), 2);
// assert_eq!(StakePallet::reward_count(2), 2);
// assert!(StakePallet::reward_count(3).is_zero());
// (1..=3).for_each(|id| {
// assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
// });

// // only 3 should have non-zero rewards and counter reset
// assert_ok!(StakePallet::leave_delegators(Origin::signed(3)));
// (1..=2).for_each(|id| {
// assert_eq!(StakePallet::reward_count(id), 2, "acc_id {:?}", id);
// assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
// });
// assert!(!StakePallet::rewards(3).is_zero());
// assert_eq!(StakePallet::reward_count(3), 4);
// });
// }

// TODO:
// rewards_delegator_revokes_single_delegation
// rewards_delegator_revokes_all_delegations
// rewards_delegator_delegates_another_candidate
// rewards_delegator_delegates_another_candidate_replacing
// rewards_set_inflation
// rewards_annual_inflation_adjustment
#[test]
fn rewards_delegator_leaves() {
ExtBuilder::default()
.with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, DECIMALS)])
.with_collators(vec![(1, DECIMALS)])
.with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)])
.build()
.execute_with(|| {
// note collator once to set their counter to 1
StakePallet::note_author(1);
assert_eq!(StakePallet::reward_count(1), 1);
assert!(StakePallet::reward_count(2).is_zero());
assert!(StakePallet::reward_count(3).is_zero());
(1..=3).for_each(|id| {
assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
});

// only 3 should have non-zero rewards and their counter reset
assert_ok!(StakePallet::leave_delegators(Origin::signed(3)));
assert_eq!(StakePallet::reward_count(1), 1);
assert!(StakePallet::rewards(1).is_zero());
assert!(StakePallet::reward_count(2).is_zero());
assert!(StakePallet::rewards(2).is_zero());
assert!(!StakePallet::rewards(3).is_zero());
assert_eq!(StakePallet::reward_count(3), 1);
});
}

#[test]
fn rewards_set_inflation() {
let hundred = Perquintill::from_percent(100);
ExtBuilder::default()
.with_balances(vec![
(1, DECIMALS),
(2, DECIMALS),
(3, DECIMALS),
(4, DECIMALS),
(5, DECIMALS),
])
.with_collators(vec![(1, DECIMALS), (2, DECIMALS)])
.with_delegators(vec![(3, 1, DECIMALS), (4, 1, DECIMALS), (5, 2, DECIMALS)])
.build()
.execute_with(|| {
// note collators
StakePallet::note_author(1);
StakePallet::note_author(1);
StakePallet::note_author(2);

// set inflation to trigger reward setting
assert_ok!(StakePallet::set_inflation(
Origin::root(),
hundred,
hundred,
hundred,
hundred
));
// rewards should be set and counter rese
(1..=5).for_each(|id| {
assert!(StakePallet::reward_count(id).is_zero(), "acc_id {:?}", id);
assert!(!StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
});
});
}

#[test]
fn rewards_yearly_inflation_adjustment() {
ExtBuilder::default()
.with_balances(vec![
(1, DECIMALS),
(2, DECIMALS),
(3, DECIMALS),
(4, DECIMALS),
(5, DECIMALS),
])
.with_collators(vec![(1, DECIMALS), (2, DECIMALS)])
.with_delegators(vec![(3, 1, DECIMALS), (4, 1, DECIMALS), (5, 2, DECIMALS)])
.build()
.execute_with(|| {
// init counter and go to next year
StakePallet::note_author(1);
StakePallet::note_author(2);
System::set_block_number(<Test as Config>::BLOCKS_PER_YEAR - 1);
roll_to_claim_rewards(<Test as Config>::BLOCKS_PER_YEAR + 1, vec![]);

// rewards should not be triggered before executing pending adjustment
(1..=5).for_each(|id| {
assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
});

// execute to trigger reward increment
assert_ok!(StakePallet::execute_pending_reward_change(Origin::signed(1)));
(1..=5).for_each(|id| {
assert!(StakePallet::reward_count(id).is_zero(), "acc_id {:?}", id);
assert!(!StakePallet::rewards(id).is_zero(), "acc_id {:?}", id);
});
});
}

#[test]
fn rewards_incrementing_and_claiming() {
ExtBuilder::default()
.with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, DECIMALS)])
.with_collators(vec![(1, DECIMALS)])
.with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)])
.build()
.execute_with(|| {
// claiming or incrementing should not be possible with zero counter
assert_noop!(
StakePallet::increment_collator_rewards(Origin::signed(1)),
Error::<Test>::RewardsNotFound
);
assert_noop!(
StakePallet::increment_delegator_rewards(Origin::signed(2)),
Error::<Test>::RewardsNotFound
);
(1..=3).for_each(|id| {
assert_noop!(
StakePallet::claim_rewards_for(Origin::signed(id), id),
Error::<Test>::RewardsNotFound,
);
});

// note once to set counter to 1
StakePallet::note_author(1);
assert_eq!(StakePallet::reward_count(1), 1);
assert!(StakePallet::reward_count(2).is_zero());

// claiming should not be possible before incrementing rewards
(1..=3).for_each(|id| {
assert_noop!(
StakePallet::claim_rewards_for(Origin::signed(id), id),
Error::<Test>::RewardsNotFound
);
});

// increment rewards for 2 and match counter to collator
assert_ok!(StakePallet::increment_delegator_rewards(Origin::signed(2)));
assert_eq!(StakePallet::reward_count(2), 1);
let rewards_2 = StakePallet::rewards(2);
assert!(!rewards_2.is_zero());
assert!(StakePallet::reward_count(3).is_zero());
assert!(StakePallet::rewards(3).is_zero());

// should set rewards for delegator 3 as well
assert_ok!(StakePallet::increment_collator_rewards(Origin::signed(1)));
assert!(StakePallet::reward_count(1).is_zero());
assert!(!StakePallet::rewards(1).is_zero());
// counter of delegators should be reset to 0 (= cols counter)
assert!(StakePallet::reward_count(2).is_zero());
assert!(StakePallet::reward_count(3).is_zero());
// rewards of 2 should not be changed
assert_eq!(StakePallet::rewards(2), rewards_2);
// 3 should have rewards now (passively)
assert!(!StakePallet::rewards(3).is_zero());

// claim for 1 to move rewards into balance
assert_ok!(StakePallet::claim_rewards_for(Origin::signed(3), 1));
assert!(StakePallet::reward_count(1).is_zero());
assert!(StakePallet::rewards(1).is_zero());
// delegator situation should be unchanged
assert!(Balances::free_balance(&1) > DECIMALS);
assert_eq!(Balances::free_balance(&2), DECIMALS);
assert_eq!(Balances::free_balance(&3), DECIMALS);

// claim for 2 to move rewards into balance
assert_ok!(StakePallet::claim_rewards_for(Origin::signed(1), 2));
assert!(Balances::free_balance(&2) > DECIMALS);
assert!(StakePallet::reward_count(2).is_zero());
assert!(StakePallet::rewards(2).is_zero());
assert_eq!(Balances::free_balance(&3), DECIMALS);

// should not be able to claim for incorrect role
assert_noop!(
StakePallet::increment_collator_rewards(Origin::signed(2)),
Error::<Test>::CandidateNotFound
);
assert_noop!(
StakePallet::increment_delegator_rewards(Origin::signed(1)),
Error::<Test>::DelegatorNotFound
);
});
}