Skip to content

Commit

Permalink
[MOON-2552] use new benchmark for staking rewards (#2461)
Browse files Browse the repository at this point in the history
* use new benchmark for staking rewards

* simplify math

* use benchmark server weights

---------

Co-authored-by: Crystalin <alan@moonsonglabs.com>
  • Loading branch information
nbaztec and crystalin authored Aug 30, 2023
1 parent 6d577a3 commit 356e978
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 38 deletions.
112 changes: 111 additions & 1 deletion pallets/parachain-staking/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,116 @@ benchmarks! {
verify {
}

pay_one_collator_reward_best {
// x controls number of delegations
let x in 0..(
T::MaxTopDelegationsPerCandidate::get()
+ T::MaxBottomDelegationsPerCandidate::get() - 1
);
// y controls the number of auto-compounding delegations
let y in 0..(
T::MaxTopDelegationsPerCandidate::get()
+ T::MaxBottomDelegationsPerCandidate::get() - 1
);
// z is the number of scheduled requests per collator
let z in 0..(
T::MaxTopDelegationsPerCandidate::get()
+ T::MaxBottomDelegationsPerCandidate::get() - 1
);

use crate::{
DelayedPayout, DelayedPayouts, AtStake, CollatorSnapshot, BondWithAutoCompound, Points,
AwardedPts,
};

let mut seed = Seed::new();
let prime_candidate = create_account::<T>(
"collator",
seed.take(),
AccountBalance::MinCandidateStake,
AccountAction::JoinCandidates{ amount: Amount::All, candidate_count: 1u32 },
)?;

let mut delegations = Vec::new();
let mut col_del_count = 0u32;
let initial_delegator_balance = T::MinDelegation::get() + 100u32.into();
for i in 0..x {
let auto_compound = if i < y { Percent::from_percent(100) } else { Percent::from_percent(0) };
let delegator = create_account::<T>(
"delegator",
seed.take(),
AccountBalance::Value(initial_delegator_balance),
AccountAction::Delegate{
collator: prime_candidate.clone(),
amount: Amount::All,
auto_compound,
collator_delegation_count: col_del_count,
collator_auto_compound_delegation_count: col_del_count,
},
)?;
col_del_count += 1u32;
if i < z {
Pallet::<T>::schedule_delegator_bond_less(
RawOrigin::Signed(delegator.clone()).into(),
prime_candidate.clone(),
5u32.into(),
)?;
}

delegations.push(BondWithAutoCompound {
owner: delegator.clone(),
amount: initial_delegator_balance,
auto_compound,
});
}

let total_staked = min_candidate_stk::<T>()
+ (Into::<BalanceOf<T>>::into(x) * initial_delegator_balance);
let round_for_payout = 5;
<DelayedPayouts<T>>::insert(&round_for_payout, DelayedPayout {
round_issuance: 1000u32.into(),
total_staking_reward: total_staked,
collator_commission: Perbill::from_rational(1u32, 100u32),
});

<AtStake<T>>::insert(round_for_payout, &prime_candidate, CollatorSnapshot {
bond: 1_000u32.into(),
delegations: delegations.clone(),
total: 1_000_000u32.into(),
});

<Points<T>>::insert(round_for_payout, 100);
<AwardedPts<T>>::insert(round_for_payout, &prime_candidate, 20);

}: {
for BondWithAutoCompound {
owner,
amount,
auto_compound,
} in &delegations
{
<Pallet<T>>::mint_and_compound(
100u32.into(),
auto_compound.clone(),
prime_candidate.clone(),
owner.clone(),
);
}
}
verify {
for BondWithAutoCompound {
owner,
amount,
auto_compound,
} in &delegations
{
assert!(
T::Currency::free_balance(&owner) > initial_delegator_balance,
"delegator should have been paid in pay_one_collator_reward"
);
}
}

pay_one_collator_reward {
// y controls number of delegations, its maximum per collator is the max top delegations
let y in 0..<<T as Config>::MaxTopDelegationsPerCandidate as Get<u32>>::get();
Expand All @@ -1643,7 +1753,7 @@ benchmarks! {
)?;
total_staked += initial_stake_amount;

// generate funded collator accounts
// generate funded delegator accounts
let mut delegators: Vec<T::AccountId> = Vec::new();
for i in 0..y {
let seed = USER_SEED + i;
Expand Down
48 changes: 24 additions & 24 deletions pallets/parachain-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1764,7 +1764,6 @@ pub mod pallet {

let collator_fee = payout_info.collator_commission;
let collator_issuance = collator_fee * payout_info.round_issuance;

if let Some((collator, state)) =
<AtStake<T>>::iter_prefix(paid_for_round).drain().next()
{
Expand All @@ -1787,6 +1786,9 @@ pub mod pallet {
let mut amt_due = total_paid;

let num_delegators = state.delegations.len();
let mut num_paid_delegations = 0u32;
let mut num_auto_compounding = 0u32;
let num_scheduled_requests = <DelegationScheduledRequests<T>>::get(&collator).len();
if state.delegations.is_empty() {
// solo collator with no delegators
extra_weight = extra_weight
Expand Down Expand Up @@ -1828,16 +1830,25 @@ pub mod pallet {
let percent = Perbill::from_rational(amount, state.total);
let due = percent * amt_due;
if !due.is_zero() {
extra_weight = extra_weight.saturating_add(Self::mint_and_compound(
num_auto_compounding += if auto_compound.is_zero() { 0 } else { 1 };
num_paid_delegations += 1u32;
Self::mint_and_compound(
due,
auto_compound.clone(),
collator.clone(),
owner.clone(),
));
);
}
}
}

extra_weight =
extra_weight.saturating_add(T::WeightInfo::pay_one_collator_reward_best(
num_paid_delegations,
num_auto_compounding,
num_scheduled_requests as u32,
));

(
RewardPayment::Paid,
T::WeightInfo::pay_one_collator_reward(num_delegators as u32)
Expand Down Expand Up @@ -2092,8 +2103,7 @@ pub mod pallet {
compound_percent: Percent,
candidate: T::AccountId,
delegator: T::AccountId,
) -> Weight {
let mut weight = T::WeightInfo::mint_collator_reward();
) {
if let Ok(amount_transferred) =
T::Currency::deposit_into_existing(&delegator, amt.clone())
{
Expand All @@ -2104,29 +2114,21 @@ pub mod pallet {

let compound_amount = compound_percent.mul_ceil(amount_transferred.peek());
if compound_amount.is_zero() {
return weight;
return;
}

match Self::delegation_bond_more_without_event(
if let Err(err) = Self::delegation_bond_more_without_event(
delegator.clone(),
candidate.clone(),
compound_amount.clone(),
) {
Err(err) => {
log::debug!(
"skipped compounding staking reward towards candidate '{:?}' for delegator '{:?}': {:?}",
candidate,
delegator,
err
);
return weight.saturating_add(T::WeightInfo::delegator_bond_more(
T::MaxTopDelegationsPerCandidate::get()
+ T::MaxBottomDelegationsPerCandidate::get(),
));
}
Ok((_, weight_consumed)) => {
weight = weight.saturating_add(weight_consumed);
}
log::debug!(
"skipped compounding staking reward towards candidate '{:?}' for delegator '{:?}': {:?}",
candidate,
delegator,
err
);
return;
};

Pallet::<T>::deposit_event(Event::Compounded {
Expand All @@ -2135,8 +2137,6 @@ pub mod pallet {
amount: compound_amount.clone(),
});
};

weight
}
}

Expand Down
83 changes: 83 additions & 0 deletions pallets/parachain-staking/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub trait WeightInfo {
fn prepare_staking_payouts() -> Weight;
fn get_rewardable_delegators(y: u32, ) -> Weight;
fn select_top_candidates(x: u32, y: u32, ) -> Weight;
fn pay_one_collator_reward_best(x: u32, y: u32, z: u32, ) -> Weight;
fn pay_one_collator_reward(y: u32, ) -> Weight;
fn base_on_initialize() -> Weight;
fn set_auto_compound(x: u32, y: u32, ) -> Weight;
Expand Down Expand Up @@ -691,6 +692,47 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
.saturating_add(Weight::from_parts(0, 3975).saturating_mul(x.into()))
.saturating_add(Weight::from_parts(0, 639).saturating_mul(y.into()))
}
/// Storage: System Account (r:349 w:349)
/// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen)
/// Storage: ParachainStaking DelegatorState (r:349 w:349)
/// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:0)
/// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured)
/// Storage: Balances Locks (r:349 w:349)
/// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen)
/// Storage: Balances Freezes (r:349 w:0)
/// Proof: Balances Freezes (max_values: None, max_size: Some(37), added: 2512, mode: MaxEncodedLen)
/// Storage: ParachainStaking CandidateInfo (r:1 w:1)
/// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking TopDelegations (r:1 w:1)
/// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking CandidatePool (r:1 w:1)
/// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: ParachainStaking Total (r:1 w:1)
/// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: ParachainStaking BottomDelegations (r:1 w:1)
/// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured)
/// The range of component `x` is `[0, 349]`.
/// The range of component `y` is `[0, 349]`.
/// The range of component `z` is `[0, 349]`.
fn pay_one_collator_reward_best(x: u32, y: u32, z: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0 + x * (395 ±0) + y * (156 ±0) + z * (41 ±0)`
// Estimated: `125723 + x * (2591 ±1) + y * (2234 ±1) + z * (28 ±0)`
// Minimum execution time: 434_000 picoseconds.
Weight::from_parts(452_000, 125723)
// Standard Error: 785_764
.saturating_add(Weight::from_parts(78_033_998, 0).saturating_mul(x.into()))
// Standard Error: 785_764
.saturating_add(Weight::from_parts(45_998_691, 0).saturating_mul(y.into()))
.saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(x.into())))
.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(y.into())))
.saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(x.into())))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(y.into())))
.saturating_add(Weight::from_parts(0, 2591).saturating_mul(x.into()))
.saturating_add(Weight::from_parts(0, 2234).saturating_mul(y.into()))
.saturating_add(Weight::from_parts(0, 28).saturating_mul(z.into()))
}
/// Storage: ParachainStaking DelayedPayouts (r:1 w:0)
/// Proof Skipped: ParachainStaking DelayedPayouts (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking Points (r:1 w:0)
Expand Down Expand Up @@ -1432,6 +1474,47 @@ impl WeightInfo for () {
.saturating_add(Weight::from_parts(0, 3975).saturating_mul(x.into()))
.saturating_add(Weight::from_parts(0, 639).saturating_mul(y.into()))
}
/// Storage: System Account (r:349 w:349)
/// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen)
/// Storage: ParachainStaking DelegatorState (r:349 w:349)
/// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:0)
/// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured)
/// Storage: Balances Locks (r:349 w:349)
/// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen)
/// Storage: Balances Freezes (r:349 w:0)
/// Proof: Balances Freezes (max_values: None, max_size: Some(37), added: 2512, mode: MaxEncodedLen)
/// Storage: ParachainStaking CandidateInfo (r:1 w:1)
/// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking TopDelegations (r:1 w:1)
/// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking CandidatePool (r:1 w:1)
/// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: ParachainStaking Total (r:1 w:1)
/// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: ParachainStaking BottomDelegations (r:1 w:1)
/// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured)
/// The range of component `x` is `[0, 349]`.
/// The range of component `y` is `[0, 349]`.
/// The range of component `z` is `[0, 349]`.
fn pay_one_collator_reward_best(x: u32, y: u32, z: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0 + x * (395 ±0) + y * (156 ±0) + z * (41 ±0)`
// Estimated: `125723 + x * (2591 ±1) + y * (2234 ±1) + z * (28 ±0)`
// Minimum execution time: 434_000 picoseconds.
Weight::from_parts(452_000, 125723)
// Standard Error: 785_764
.saturating_add(Weight::from_parts(78_033_998, 0).saturating_mul(x.into()))
// Standard Error: 785_764
.saturating_add(Weight::from_parts(45_998_691, 0).saturating_mul(y.into()))
.saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(x.into())))
.saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(y.into())))
.saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(x.into())))
.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(y.into())))
.saturating_add(Weight::from_parts(0, 2591).saturating_mul(x.into()))
.saturating_add(Weight::from_parts(0, 2234).saturating_mul(y.into()))
.saturating_add(Weight::from_parts(0, 28).saturating_mul(z.into()))
}
/// Storage: ParachainStaking DelayedPayouts (r:1 w:0)
/// Proof Skipped: ParachainStaking DelayedPayouts (max_values: None, max_size: None, mode: Measured)
/// Storage: ParachainStaking Points (r:1 w:0)
Expand Down
Loading

0 comments on commit 356e978

Please sign in to comment.