diff --git a/pallets/parachain-staking/src/benchmarks.rs b/pallets/parachain-staking/src/benchmarks.rs index e51d9f7980..4b4ccf832b 100644 --- a/pallets/parachain-staking/src/benchmarks.rs +++ b/pallets/parachain-staking/src/benchmarks.rs @@ -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::( + "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::( + "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::::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::() + + (Into::>::into(x) * initial_delegator_balance); + let round_for_payout = 5; + >::insert(&round_for_payout, DelayedPayout { + round_issuance: 1000u32.into(), + total_staking_reward: total_staked, + collator_commission: Perbill::from_rational(1u32, 100u32), + }); + + >::insert(round_for_payout, &prime_candidate, CollatorSnapshot { + bond: 1_000u32.into(), + delegations: delegations.clone(), + total: 1_000_000u32.into(), + }); + + >::insert(round_for_payout, 100); + >::insert(round_for_payout, &prime_candidate, 20); + + }: { + for BondWithAutoCompound { + owner, + amount, + auto_compound, + } in &delegations + { + >::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..<::MaxTopDelegationsPerCandidate as Get>::get(); @@ -1643,7 +1753,7 @@ benchmarks! { )?; total_staked += initial_stake_amount; - // generate funded collator accounts + // generate funded delegator accounts let mut delegators: Vec = Vec::new(); for i in 0..y { let seed = USER_SEED + i; diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 661b01b17e..e61d81ff60 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -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)) = >::iter_prefix(paid_for_round).drain().next() { @@ -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 = >::get(&collator).len(); if state.delegations.is_empty() { // solo collator with no delegators extra_weight = extra_weight @@ -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) @@ -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()) { @@ -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::::deposit_event(Event::Compounded { @@ -2135,8 +2137,6 @@ pub mod pallet { amount: compound_amount.clone(), }); }; - - weight } } diff --git a/pallets/parachain-staking/src/weights.rs b/pallets/parachain-staking/src/weights.rs index 137bba95c0..518dc22cb4 100644 --- a/pallets/parachain-staking/src/weights.rs +++ b/pallets/parachain-staking/src/weights.rs @@ -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; @@ -691,6 +692,47 @@ impl WeightInfo for SubstrateWeight { .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) @@ -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) diff --git a/precompiles/identity/src/lib.rs b/precompiles/identity/src/lib.rs index 1ed2ccc654..fa20af2651 100644 --- a/precompiles/identity/src/lib.rs +++ b/precompiles/identity/src/lib.rs @@ -97,7 +97,7 @@ where }; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -121,7 +121,7 @@ where let call = pallet_identity::Call::::set_subs { subs: call_subs }; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; Ok(()) } @@ -140,7 +140,7 @@ where let call = pallet_identity::Call::::clear_identity {}; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -168,7 +168,7 @@ where let call = pallet_identity::Call::::request_judgement { reg_index, max_fee }; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -189,7 +189,7 @@ where let call = pallet_identity::Call::::cancel_request { reg_index }; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -204,7 +204,7 @@ where let call = pallet_identity::Call::::set_fee { index, fee }; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; Ok(()) } @@ -215,7 +215,7 @@ where let call = pallet_identity::Call::::set_account_id { index, new }; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; Ok(()) } @@ -231,7 +231,7 @@ where let call = pallet_identity::Call::::set_fields { index, fields }; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; Ok(()) } @@ -266,7 +266,7 @@ where }; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -291,7 +291,7 @@ where let call = pallet_identity::Call::::add_sub { sub, data }; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -307,7 +307,7 @@ where let call = pallet_identity::Call::::rename_sub { sub, data }; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; Ok(()) } @@ -327,7 +327,7 @@ where let call = pallet_identity::Call::::remove_sub { sub }; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; @@ -348,7 +348,7 @@ where let call = pallet_identity::Call::::quit_sub {}; let origin = Runtime::AddressMapping::into_account_id(caller); - RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; + RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call, 0)?; event.record(handle)?; diff --git a/precompiles/identity/src/mock.rs b/precompiles/identity/src/mock.rs index d3d66bceac..6ec6ef9ed9 100644 --- a/precompiles/identity/src/mock.rs +++ b/precompiles/identity/src/mock.rs @@ -106,6 +106,8 @@ impl pallet_balances::Config for Runtime { } const MAX_POV_SIZE: u64 = 5 * 1024 * 1024; +/// Block storage limit in bytes. Set to 40 KB. +const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024; parameter_types! { pub BlockGasLimit: U256 = U256::from(u64::MAX); @@ -115,6 +117,10 @@ parameter_types! { let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); block_gas_limit.saturating_div(MAX_POV_SIZE) }; + pub GasLimitStorageGrowthRatio: u64 = { + let block_gas_limit = BlockGasLimit::get().min(u64::MAX.into()).low_u64(); + block_gas_limit.saturating_div(BLOCK_STORAGE_LIMIT) + }; } pub type Precompiles = @@ -141,6 +147,7 @@ impl pallet_evm::Config for Runtime { type FindAuthor = (); type OnCreate = (); type GasLimitPovSizeRatio = GasLimitPovSizeRatio; + type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio; type Timestamp = Timestamp; type WeightInfo = pallet_evm::weights::SubstrateWeight; } diff --git a/runtime/common/src/weights/pallet_parachain_staking.rs b/runtime/common/src/weights/pallet_parachain_staking.rs index 5e5619c80f..dfa4c055f2 100644 --- a/runtime/common/src/weights/pallet_parachain_staking.rs +++ b/runtime/common/src/weights/pallet_parachain_staking.rs @@ -673,6 +673,48 @@ impl pallet_parachain_staking::WeightInfo for WeightInf .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: 63_000 picoseconds. + Weight::from_parts(69_000, 0) + .saturating_add(Weight::from_parts(0, 125723)) + // Standard Error: 600_795 + .saturating_add(Weight::from_parts(38_214_668, 0).saturating_mul(x.into())) + // Standard Error: 600_795 + .saturating_add(Weight::from_parts(20_727_011, 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) diff --git a/test/suites/dev/test-staking/test-rewards-auto-compound-pov.ts b/test/suites/dev/test-staking/test-rewards-auto-compound-pov.ts new file mode 100644 index 0000000000..6eaaf11538 --- /dev/null +++ b/test/suites/dev/test-staking/test-rewards-auto-compound-pov.ts @@ -0,0 +1,118 @@ +import "@moonbeam-network/api-augment"; +import { beforeAll, describeSuite, expect } from "@moonwall/cli"; +import { + GLMR, + KeyringPair, + MIN_GLMR_DELEGATOR, + MIN_GLMR_STAKING, + alith, + generateKeyringPair, +} from "@moonwall/util"; +import { chunk } from "../../../helpers/common.js"; +import { jumpRounds } from "../../../helpers/block.js"; + +describeSuite({ + id: "D3542", + title: "Staking - Rewards Auto-Compound - PoV Size", + foundationMethods: "dev", + testCases: ({ context, it, log }) => { + let newDelegator: KeyringPair; + + beforeAll(async () => { + const maxDelegationCount = + context.polkadotJs().consts.parachainStaking.maxTopDelegationsPerCandidate.toNumber() + + context.polkadotJs().consts.parachainStaking.maxBottomDelegationsPerCandidate.toNumber(); + const [delegator, ...otherDelegators] = new Array(maxDelegationCount) + .fill(0) + .map(() => generateKeyringPair()); + newDelegator = delegator; + + // Setup round and staking parameters + await context.createBlock( + [ + context + .polkadotJs() + .tx.sudo.sudo(context.polkadotJs().tx.parachainStaking.setBlocksPerRound(10)) + .signAsync(alith), + ], + { allowFailures: false } + ); + + // Setup all new delegators accounts + let alithNonce = await context + .viem() + .getTransactionCount({ address: alith.address as `0x${string}` }); + await context.createBlock( + [ + context + .polkadotJs() + .tx.balances.transfer(newDelegator.address, MIN_GLMR_STAKING) + .signAsync(alith, { nonce: alithNonce++ }), + ...otherDelegators.map((d) => + context + .polkadotJs() + .tx.balances.transfer(d.address, MIN_GLMR_STAKING) + .signAsync(alith, { nonce: alithNonce++ }) + ), + ], + { allowFailures: false } + ); + + // fill all delegations, we split this into multiple blocks as it will not fit into one. + // we use a maxDelegationCount here, since the transactions can come out of order. + for (const delChunk of chunk(otherDelegators, 8)) { + await context.createBlock( + delChunk.map((d, i) => + context + .polkadotJs() + .tx.parachainStaking.delegateWithAutoCompound( + alith.address, + MIN_GLMR_DELEGATOR + 10n * GLMR, + 100, + maxDelegationCount, + maxDelegationCount, + 1 + ) + .signAsync(d) + ), + { allowFailures: false } + ); + } + }); + + it({ + id: "T01", + title: "should be under the limit of 3_500_000", + test: async () => { + // Moves to the next payout block + await jumpRounds(context, 1); + const { block } = await context.createBlock(); + + const weights = await context.pjsApi.query.system.blockWeight(); + expect( + weights.mandatory.proofSize.toNumber(), + "proofSize is too low, probably missing payout in the block" + ).to.be.at.least(100_000); + + // block could support ~5_000_000 proofSize but we consider it safer to error when reaching + // 2_500_000 which is already high for a payout + expect( + weights.mandatory.proofSize.toNumber(), + "proofSize is too high, this might lead to empty block" + ).to.be.at.most(2_500_000); + + // block could support ~500ms refTime but we consider it safer to error when reaching + // over 200ms for the payout + expect( + weights.mandatory.refTime.toNumber(), + "refTime over 200ms, very high for a payout" + ).to.be.at.most(200_000_000_000); + + expect( + weights.mandatory.proofSize.toNumber(), + "estimated weight proofSize is over real proofSize, should never happen!" + ).to.be.at.least(block.proofSize!); + }, + }); + }, +});