Skip to content
This repository has been archived by the owner on Jul 4, 2022. It is now read-only.

Commit

Permalink
Cherry-pick the upstream feature "Staking Payout to Any Account" (#137)
Browse files Browse the repository at this point in the history
* Support Staking Payout to Any Account (#6832)

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
  • Loading branch information
Alex Sed and shawntabrizi committed Sep 16, 2020
1 parent 27b815f commit d047cb3
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 39 deletions.
15 changes: 10 additions & 5 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,16 +334,18 @@ pub enum StakerStatus<AccountId> {

/// A destination account for payment.
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug)]
pub enum RewardDestination {
pub enum RewardDestination<AccountId> {
/// Pay into the stash account, increasing the amount at stake accordingly.
Staked,
/// Pay into the stash account, not increasing the amount at stake.
Stash,
/// Pay into the controller account.
Controller,
/// Pay into a specified account.
Account(AccountId),
}

impl Default for RewardDestination {
impl<AccountId> Default for RewardDestination<AccountId> {
fn default() -> Self {
RewardDestination::Staked
}
Expand Down Expand Up @@ -725,7 +727,7 @@ decl_storage! {
=> Option<StakingLedger<T::AccountId, BalanceOf<T>>>;

/// Where the reward payment should be made. Keyed by stash.
pub Payee get(fn payee): map hasher(twox_64_concat) T::AccountId => RewardDestination;
pub Payee get(fn payee): map hasher(twox_64_concat) T::AccountId => RewardDestination<T::AccountId>;

/// The map from (wannabe) validator stash key to the preferences of that validator.
pub Validators get(fn validators):
Expand Down Expand Up @@ -993,7 +995,7 @@ decl_module! {
fn bond(origin,
controller: <T::Lookup as StaticLookup>::Source,
#[compact] value: BalanceOf<T>,
payee: RewardDestination
payee: RewardDestination<T::AccountId>,
) {
let stash = ensure_signed(origin)?;

Expand Down Expand Up @@ -1249,7 +1251,7 @@ decl_module! {
/// - Writes are limited to the `origin` account key.
/// # </weight>
#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
fn set_payee(origin, payee: RewardDestination) {
fn set_payee(origin, payee: RewardDestination<T::AccountId>) {
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
let stash = &ledger.stash;
Expand Down Expand Up @@ -1636,6 +1638,9 @@ impl<T: Trait> Module<T> {
Self::update_ledger(&controller, &l);
r
}),
RewardDestination::Account(dest_account) => {
Some(T::Currency::deposit_creating(&dest_account, amount))
}
}
}

Expand Down
57 changes: 35 additions & 22 deletions frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ pub struct ExtBuilder {
fair: bool,
num_validators: Option<u32>,
invulnerables: Vec<u64>,
stakers: bool,
has_stakers: bool,
}

impl Default for ExtBuilder {
Expand All @@ -250,7 +250,7 @@ impl Default for ExtBuilder {
fair: true,
num_validators: None,
invulnerables: vec![],
stakers: true,
has_stakers: true,
}
}
}
Expand Down Expand Up @@ -296,11 +296,8 @@ impl ExtBuilder {
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
SLASH_DEFER_DURATION.with(|v| *v.borrow_mut() = self.slash_defer_duration);
}

// TODO re-evaluate if the following "allow" is still necessary after merging upstream in
#[allow(dead_code)]
pub fn stakers(mut self, has_stakers: bool) -> Self {
self.stakers = has_stakers;
pub fn has_stakers(mut self, has: bool) -> Self {
self.has_stakers = has;
self
}
pub fn build(self) -> sp_io::TestExternalities {
Expand Down Expand Up @@ -339,7 +336,7 @@ impl ExtBuilder {
}.assimilate_storage(&mut storage);

let mut stakers = vec![];
if self.stakers {
if self.has_stakers {
let stake_21 = if self.fair { 1000 } else { 2000 };
let stake_31 = if self.validator_pool { balance_factor * 1000 } else { 1 };
let status_41 = if self.validator_pool {
Expand Down Expand Up @@ -444,20 +441,36 @@ pub fn assert_ledger_consistent(stash: AccountId) {
assert_eq!(real_total, ledger.total);
}

pub fn bond_validator(acc: u64, val: u64) {
// a = controller
// a + 1 = stash
let _ = Balances::make_free_balance_be(&(acc + 1), val);
assert_ok!(Staking::bond(Origin::signed(acc + 1), acc, val, RewardDestination::Controller));
assert_ok!(Staking::validate(Origin::signed(acc), ValidatorPrefs::default()));
}

pub fn bond_nominator(acc: u64, val: u64, target: Vec<u64>) {
// a = controller
// a + 1 = stash
let _ = Balances::make_free_balance_be(&(acc + 1), val);
assert_ok!(Staking::bond(Origin::signed(acc + 1), acc, val, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(acc), target));
pub(crate) fn bond_validator(stash: AccountId, ctrl: AccountId, val: Balance) {
let _ = Balances::make_free_balance_be(&stash, val);
let _ = Balances::make_free_balance_be(&ctrl, val);
assert_ok!(Staking::bond(
Origin::signed(stash),
ctrl,
val,
RewardDestination::Controller,
));
assert_ok!(Staking::validate(
Origin::signed(ctrl),
ValidatorPrefs::default()
));
}

pub(crate) fn bond_nominator(
stash: AccountId,
ctrl: AccountId,
val: Balance,
target: Vec<AccountId>,
) {
let _ = Balances::make_free_balance_be(&stash, val);
let _ = Balances::make_free_balance_be(&ctrl, val);
assert_ok!(Staking::bond(
Origin::signed(stash),
ctrl,
val,
RewardDestination::Controller,
));
assert_ok!(Staking::nominate(Origin::signed(ctrl), target));
}

pub fn advance_session() {
Expand Down
53 changes: 41 additions & 12 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1733,11 +1733,11 @@ fn phragmen_should_not_overflow_validators() {
let _ = Staking::chill(Origin::signed(10));
let _ = Staking::chill(Origin::signed(20));

bond_validator(2, u64::max_value());
bond_validator(4, u64::max_value());
bond_validator(3, 2, u64::max_value());
bond_validator(5, 4, u64::max_value());

bond_nominator(6, u64::max_value() / 2, vec![3, 5]);
bond_nominator(8, u64::max_value() / 2, vec![3, 5]);
bond_nominator(7, 6, u64::max_value() / 2, vec![3, 5]);
bond_nominator(9, 8, u64::max_value() / 2, vec![3, 5]);

start_era(1);

Expand All @@ -1756,11 +1756,11 @@ fn phragmen_should_not_overflow_nominators() {
let _ = Staking::chill(Origin::signed(10));
let _ = Staking::chill(Origin::signed(20));

bond_validator(2, u64::max_value() / 2);
bond_validator(4, u64::max_value() / 2);
bond_validator(3, 2, u64::max_value() / 2);
bond_validator(5, 4, u64::max_value() / 2);

bond_nominator(6, u64::max_value(), vec![3, 5]);
bond_nominator(8, u64::max_value(), vec![3, 5]);
bond_nominator(7, 6, u64::max_value(), vec![3, 5]);
bond_nominator(9, 8, u64::max_value(), vec![3, 5]);

start_era(1);

Expand All @@ -1775,11 +1775,11 @@ fn phragmen_should_not_overflow_nominators() {
#[test]
fn phragmen_should_not_overflow_ultimate() {
ExtBuilder::default().nominate(false).build().execute_with(|| {
bond_validator(2, u64::max_value());
bond_validator(4, u64::max_value());
bond_validator(3, 2, u64::max_value());
bond_validator(5, 4, u64::max_value());

bond_nominator(6, u64::max_value(), vec![3, 5]);
bond_nominator(8, u64::max_value(), vec![3, 5]);
bond_nominator(7, 6, u64::max_value(), vec![3, 5]);
bond_nominator(9, 8, u64::max_value(), vec![3, 5]);

start_era(1);

Expand Down Expand Up @@ -3043,3 +3043,32 @@ fn assert_migration_is_noop() {
assert_eq!(era.index, 586);
assert_eq!(era.start, Some(1585135674000));
}

#[test]
fn payout_to_any_account_works() {
ExtBuilder::default().has_stakers(false).build().execute_with(|| {
let balance = 1000;
// Create a validator:
bond_validator(11, 10, balance); // Default(64)

// Create a stash/controller pair
bond_nominator(1234, 1337, 100, vec![11]);

// Update payout location
assert_ok!(Staking::set_payee(Origin::signed(1337), RewardDestination::Account(42)));

// Reward Destination account doesn't exist
assert_eq!(Balances::free_balance(42), 0);

mock::start_era(1);
Staking::reward_by_ids(vec![(11, 1)]);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(3 * 1000);
assert!(total_payout_0 > 100); // Test is meaningful if reward something
mock::start_era(2);
assert_ok!(Staking::payout_nominator(Origin::signed(1337), 1, vec![(11, 0)]));

// Payment is successful
assert!(Balances::free_balance(42) > 0);
})
}

0 comments on commit d047cb3

Please sign in to comment.