Skip to content
This repository was archived by the owner on Mar 13, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions bin/node/runtime/pangolin/src/weights/darwinia_staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ impl<T: frame_system::Trait> darwinia_staking::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().writes(3 as Weight))
.saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight)))
}
fn rebond(l: u32) -> Weight {
(46_569_000 as Weight)
Comment thread
aurexav marked this conversation as resolved.
.saturating_add((104_000 as Weight).saturating_mul(l as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
fn set_history_depth(e: u32) -> Weight {
(0 as Weight)
.saturating_add((36_641_000 as Weight).saturating_mul(e as Weight))
Expand Down
7 changes: 7 additions & 0 deletions frame/staking/src/default_weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ impl crate::WeightInfo for () {
.saturating_add(DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight)))
.saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight)))
}
fn rebond(l: u32) -> Weight {
(71316000 as Weight)
Comment thread
aurexav marked this conversation as resolved.
.saturating_add((142000 as Weight).saturating_mul(l as Weight))
.saturating_add(DbWeight::get().reads(4 as Weight))
.saturating_add(DbWeight::get().writes(3 as Weight))
}

fn set_history_depth(e: u32) -> Weight {
(0 as Weight)
.saturating_add((51901000 as Weight).saturating_mul(e as Weight))
Expand Down
193 changes: 134 additions & 59 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,10 @@ use frame_support::{
Currency, EnsureOrigin, EstimateNextNewSession, ExistenceRequirement::KeepAlive, Get,
Imbalance, OnUnbalanced, UnixTime,
},
weights::{constants::WEIGHT_PER_MICROS, Weight},
weights::{
constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS},
Weight,
},
};
use frame_system::{ensure_none, ensure_root, ensure_signed, offchain::SendTransactionTypes};
use sp_npos_elections::{
Expand Down Expand Up @@ -576,6 +579,8 @@ pub trait WeightInfo {
fn cancel_deferred_slash(s: u32) -> Weight;
fn payout_stakers_alive_staked(n: u32) -> Weight;
fn payout_stakers_dead_controller(n: u32) -> Weight;

fn rebond(l: u32) -> Weight;
fn set_history_depth(e: u32) -> Weight;
fn reap_stash(s: u32) -> Weight;
fn new_era(v: u32, n: u32) -> Weight;
Expand Down Expand Up @@ -899,6 +904,8 @@ decl_error! {
InsufficientValue,
/// Can not schedule more unlock chunks.
NoMoreChunks,
/// Can not rebond without unlocking chunks.
NoUnlockChunk,
/// Attempting to target a stash that still has funds.
FundedTarget,
/// Invalid era to reward.
Expand Down Expand Up @@ -1297,7 +1304,7 @@ decl_module! {
/// - Read: Era Election Status, Bonded, Ledger, [Origin Account]
/// - Write: [Origin Account], Ledger
/// # </weight>
#[weight = T::WeightInfo::unbond()]
#[weight = T::WeightInfo::deposit_extra()]
fn deposit_extra(origin, value: RingBalance<T>, promise_month: u8) {
let stash = ensure_signed(origin)?;
let controller = Self::bonded(&stash).ok_or(<Error<T>>::NotStash)?;
Expand Down Expand Up @@ -1385,8 +1392,6 @@ decl_module! {
kton_staking_lock,
..
} = &mut ledger;
let origin_active_ring = *active_ring;
let origin_active_kton = *active_kton;
let now = <frame_system::Module<T>>::block_number();

ring_staking_lock.update(now);
Expand Down Expand Up @@ -1480,12 +1485,7 @@ decl_module! {
},
}

Self::update_ledger(
&controller,
Some(origin_active_ring),
Some(origin_active_kton),
&mut ledger
);
Self::update_ledger(&controller, &mut ledger);

// TODO: https://github.com/darwinia-network/darwinia-common/issues/96
// FIXME: https://github.com/darwinia-network/darwinia-common/issues/121
Expand Down Expand Up @@ -1984,6 +1984,55 @@ decl_module! {
Self::do_payout_stakers(validator_stash, era)
}

/// Rebond a portion of the stash scheduled to be unlocked.
///
/// The dispatch origin must be signed by the controller, and it can be only called when
/// [`EraElectionStatus`] is `Closed`.
///
/// # <weight>
/// - Time complexity: O(L), where L is unlocking chunks
/// - Bounded by `MAX_UNLOCKING_CHUNKS`.
/// - Storage changes: Can't increase storage, only decrease it.
/// ---------------
/// - DB Weight:
/// - Reads: EraElectionStatus, Ledger, Locks, [Origin Account]
/// - Writes: [Origin Account], Locks, Ledger
/// # </weight>
#[weight = T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32)]
fn rebond(
origin,
#[compact] plan_to_rebond_ring: RingBalance<T>,
#[compact] plan_to_rebond_kton: KtonBalance<T>
) -> DispatchResultWithPostInfo {
ensure!(Self::era_election_status().is_closed(), <Error<T>>::CallNotAllowed);

let controller = ensure_signed(origin)?;
let mut ledger = Self::ledger(&controller).ok_or(<Error<T>>::NotController)?;
let now = <frame_system::Module<T>>::block_number();

ledger.ring_staking_lock.update(now);
ledger.kton_staking_lock.update(now);

ensure!(
!ledger.ring_staking_lock.unbondings.is_empty()
|| !ledger.kton_staking_lock.unbondings.is_empty(),
<Error<T>>::NoUnlockChunk
);

ledger.rebond(plan_to_rebond_ring, plan_to_rebond_kton);
Comment thread
hackfisher marked this conversation as resolved.

Self::update_ledger(&controller, &mut ledger);

Ok(Some(
35 * WEIGHT_PER_MICROS
+ 50 * WEIGHT_PER_NANOS * (
ledger.ring_staking_lock.unbondings.len() as Weight
+ ledger.kton_staking_lock.unbondings.len() as Weight
)
+ T::DbWeight::get().reads_writes(3, 2)
).into())
}

/// Set `HistoryDepth` value. This function will delete any history information
/// when `HistoryDepth` is reduced.
///
Expand Down Expand Up @@ -2185,7 +2234,6 @@ impl<T: Trait> Module<T> {
deposit_items,
..
} = &mut ledger;
let origin_active_ring = *active_ring;

let start_time = T::UnixTime::now().as_millis().saturated_into::<TsInMs>();
let mut expire_time = start_time;
Expand All @@ -2208,18 +2256,16 @@ impl<T: Trait> Module<T> {
});
}

Self::update_ledger(&controller, Some(origin_active_ring), None, &mut ledger);
Self::update_ledger(&controller, &mut ledger);

(start_time, expire_time)
}

/// Update the ledger while bonding controller with *KTON*
fn bond_kton(controller: &T::AccountId, value: KtonBalance<T>, mut ledger: StakingLedgerT<T>) {
let origin_active_kton = ledger.active_kton;

ledger.active_kton += value;

Self::update_ledger(&controller, None, Some(origin_active_kton), &mut ledger);
Self::update_ledger(&controller, &mut ledger);
}

/// Turn the expired deposit items into normal bond
Expand Down Expand Up @@ -2458,19 +2504,10 @@ impl<T: Trait> Module<T> {

/// Update the ledger for a controller.
///
/// This will also update the stash lock.
fn update_ledger(
controller: &T::AccountId,
// The origin active ring, none means
// there's no change on this field during this update,
// just ignore it
maybe_origin_active_ring: Option<RingBalance<T>>,
// The origin active kton, none means
// there's no change on this field during this update,
// just ignore it
maybe_origin_active_kton: Option<KtonBalance<T>>,
ledger: &mut StakingLedgerT<T>,
) {
/// BE CAREFUL:
/// This will also update the stash lock.
/// DO NOT modify the locks' staking amount outside this function.
fn update_ledger(controller: &T::AccountId, ledger: &mut StakingLedgerT<T>) {
let StakingLedger {
active_ring,
active_kton,
Expand All @@ -2480,19 +2517,17 @@ impl<T: Trait> Module<T> {
} = ledger;

if *active_ring != ring_staking_lock.staking_amount {
let origin_active_ring = ring_staking_lock.staking_amount;
Comment thread
hackfisher marked this conversation as resolved.

ring_staking_lock.staking_amount = *active_ring;
Comment thread
hackfisher marked this conversation as resolved.

// If the active ring != staking amount, there must be a difference
// The origin active ring MUST be some, but better safe here
if let Some(origin_active_ring) = maybe_origin_active_ring {
<RingPool<T>>::mutate(|pool| {
if origin_active_ring > *active_ring {
*pool = pool.saturating_sub(origin_active_ring - *active_ring);
} else {
*pool = pool.saturating_add(*active_ring - origin_active_ring);
}
});
}
<RingPool<T>>::mutate(|pool| {
if origin_active_ring > *active_ring {
*pool = pool.saturating_sub(origin_active_ring - *active_ring);
} else {
*pool = pool.saturating_add(*active_ring - origin_active_ring);
}
});

T::RingCurrency::set_lock(
STAKING_ID,
Expand All @@ -2503,19 +2538,17 @@ impl<T: Trait> Module<T> {
}

if *active_kton != kton_staking_lock.staking_amount {
let origin_active_kton = kton_staking_lock.staking_amount;

kton_staking_lock.staking_amount = *active_kton;

// If the active kton != staking amount, there must be a difference
// The origin active kton MUST be some, but better safe here
if let Some(origin_active_kton) = maybe_origin_active_kton {
<KtonPool<T>>::mutate(|pool| {
if origin_active_kton > *active_kton {
*pool = pool.saturating_sub(origin_active_kton - *active_kton);
} else {
*pool = pool.saturating_add(*active_kton - origin_active_kton);
}
});
}
<KtonPool<T>>::mutate(|pool| {
if origin_active_kton > *active_kton {
*pool = pool.saturating_sub(origin_active_kton - *active_kton);
} else {
*pool = pool.saturating_add(*active_kton - origin_active_kton);
}
});

T::KtonCurrency::set_lock(
STAKING_ID,
Expand Down Expand Up @@ -2552,11 +2585,9 @@ impl<T: Trait> Module<T> {
let r = T::RingCurrency::deposit_into_existing(stash, amount).ok();

if r.is_some() {
let origin_active_ring = l.active_ring;

l.active_ring += amount;

Self::update_ledger(&c, Some(origin_active_ring), None, &mut l);
Self::update_ledger(&c, &mut l);
}

r
Expand Down Expand Up @@ -2669,12 +2700,12 @@ impl<T: Trait> Module<T> {
// candidates.
let snapshot_validators_length = <SnapshotValidators<T>>::decode_len()
.map(|l| l as u32)
.ok_or_else(|| Error::<T>::SnapshotUnavailable)?;
.ok_or_else(|| <Error<T>>::SnapshotUnavailable)?;

// size of the solution must be correct.
ensure!(
snapshot_validators_length == u32::from(election_size.validators),
Error::<T>::OffchainElectionBogusElectionSize,
<Error<T>>::OffchainElectionBogusElectionSize,
);

// check the winner length only here and when we know the length of the snapshot validators
Expand Down Expand Up @@ -2801,7 +2832,7 @@ impl<T: Trait> Module<T> {

// build the support map thereof in order to evaluate.
let supports = build_support_map::<T::AccountId>(&winners, &staked_assignments)
.map_err(|_| Error::<T>::OffchainElectionBogusEdge)?;
.map_err(|_| <Error<T>>::OffchainElectionBogusEdge)?;

// Check if the score is the same as the claimed one.
let submitted_score = evaluate_support(&supports);
Expand Down Expand Up @@ -3565,7 +3596,6 @@ impl<T: Trait> OnDepositRedeem<T::AccountId, RingBalance<T>> for Module<T> {
deposit_items,
..
} = &mut ledger;
let origin_active_ring = *active_ring;

*active_ring = active_ring.saturating_add(amount);
*active_deposit_ring = active_deposit_ring.saturating_add(amount);
Expand All @@ -3575,7 +3605,7 @@ impl<T: Trait> OnDepositRedeem<T::AccountId, RingBalance<T>> for Module<T> {
expire_time,
});

Self::update_ledger(&controller, Some(origin_active_ring), None, &mut ledger);
Self::update_ledger(&controller, &mut ledger);
} else {
ensure!(
!<Bonded<T>>::contains_key(&stash),
Expand Down Expand Up @@ -3613,7 +3643,7 @@ impl<T: Trait> OnDepositRedeem<T::AccountId, RingBalance<T>> for Module<T> {
..Default::default()
};

Self::update_ledger(controller, Some(0.into()), None, &mut ledger);
Self::update_ledger(controller, &mut ledger);
};

Self::deposit_event(RawEvent::BondRing(amount, start_time, expire_time));
Expand Down Expand Up @@ -3980,6 +4010,51 @@ where
self.kton_staking_lock.locked_amount(at)
}

/// Re-bond funds that were scheduled for unlocking.
fn rebond(&mut self, plan_to_rebond_ring: RingBalance, plan_to_rebond_kton: KtonBalance) {
fn update<Balance, _M>(
bonded: &mut Balance,
lock: &mut StakingLock<Balance, _M>,
plan_to_rebond: Balance,
) where
Balance: Copy + AtLeast32BitUnsigned + Saturating,
{
let mut rebonded = Balance::zero();

while let Some(Unbonding { amount, .. }) = lock.unbondings.last_mut() {
let new_rebonded = rebonded.saturating_add(*amount);

if new_rebonded <= plan_to_rebond {
rebonded = new_rebonded;
*bonded = bonded.saturating_add(*amount);

lock.unbondings.pop();
} else {
let diff = plan_to_rebond.saturating_sub(rebonded);

rebonded = rebonded.saturating_add(diff);
*bonded = bonded.saturating_add(diff);
*amount = amount.saturating_sub(diff);
}

if rebonded >= plan_to_rebond {
break;
Comment thread
hackfisher marked this conversation as resolved.
}
}
}

update(
&mut self.active_ring,
&mut self.ring_staking_lock,
plan_to_rebond_ring,
);
update(
&mut self.active_kton,
&mut self.kton_staking_lock,
plan_to_rebond_kton,
);
}

/// Slash the validator for a given amount of balance. This can grow the value
/// of the slash in the case that the validator has less than `minimum_balance`
/// active funds. Returns the amount of funds actually slashed.
Expand Down
3 changes: 3 additions & 0 deletions frame/staking/src/offchain_election.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@ mod test {
fn payout_stakers_alive_staked(n: u32) -> Weight {
unimplemented!()
}
fn rebond(l: u32) -> Weight {
unimplemented!()
}
fn set_history_depth(e: u32) -> Weight {
unimplemented!()
}
Expand Down
Loading