Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add benchmark for new_session hook #1016

Merged
merged 5 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
63 changes: 63 additions & 0 deletions pallets/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use frame_support::{
traits::{Currency, Get},
};
use frame_system::{EventRecord, RawOrigin};
use pallet_parameters::{SignersInfo, SignersSize};
use pallet_staking::{Pallet as FrameStaking, RewardDestination, ValidatorPrefs};
use sp_std::{vec, vec::Vec};

Expand Down Expand Up @@ -226,6 +227,68 @@ benchmarks! {
verify {
assert_last_event::<T>(Event::<T>::SignersRotation(signers.clone()).into());
}

new_session_validators_less_then_signers {
let caller: T::AccountId = whitelisted_caller();
let validator_id_res = <T as pallet_session::Config>::ValidatorId::try_from(caller.clone()).or(Err(Error::<T>::InvalidValidatorId)).unwrap();
Signers::<T>::put(vec![validator_id_res.clone(), validator_id_res.clone()]);

}: {
let _ = Staking::<T>::new_session_handler(&vec![validator_id_res]);
}
verify {
assert!(NextSigners::<T>::get().is_none());
}

new_session_not_adding_new_signer {
let caller: T::AccountId = whitelisted_caller();
let validator_id_res = <T as pallet_session::Config>::ValidatorId::try_from(caller.clone()).or(Err(Error::<T>::InvalidValidatorId)).unwrap();

let second_signer: T::AccountId = account("second_signer", 0, SEED);
let second_signer_id = <T as pallet_session::Config>::ValidatorId::try_from(second_signer.clone()).or(Err(Error::<T>::InvalidValidatorId)).unwrap();
// full signer list leaving room for one extra validator
let mut signers = vec![second_signer_id.clone(); 5];
Signers::<T>::put(signers.clone());
signers.push(validator_id_res.clone());


}: {
let _ = Staking::<T>::new_session_handler(&signers);
}
verify {
assert_eq!(NextSigners::<T>::get().unwrap().next_signers.len(), signers.len() - 2);
}

new_session {
let c in 1 .. MAX_SIGNERS as u32 - 1;
let l in 0 .. MAX_SIGNERS as u32;

let caller: T::AccountId = whitelisted_caller();
let validator_id_res = <T as pallet_session::Config>::ValidatorId::try_from(caller.clone()).or(Err(Error::<T>::InvalidValidatorId)).unwrap();

let second_signer: T::AccountId = account("second_signer", 0, SEED);
let second_signer_id = <T as pallet_session::Config>::ValidatorId::try_from(second_signer.clone()).or(Err(Error::<T>::InvalidValidatorId)).unwrap();
// full signer list leaving room for one extra validator
let mut signers = vec![second_signer_id.clone(); c as usize];

Signers::<T>::put(signers.clone());
signers.push(second_signer_id.clone());
// place new signer in the signers struct in different locations to calculate random selection re-run
signers[l as usize % c as usize] = validator_id_res.clone();

SignersInfo::<T>::put(SignersSize {
total_signers: MAX_SIGNERS,
threshold: 3,
last_session_change: 0
});


}: {
let _ = Staking::<T>::new_session_handler(&signers);
}
verify {
assert!(NextSigners::<T>::get().is_some());
}
}

impl_benchmark_test_suite!(Staking, crate::mock::new_test_ext(), crate::mock::Test);
26 changes: 20 additions & 6 deletions pallets/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,30 +538,34 @@ pub mod pallet {

pub fn new_session_handler(
validators: &[<T as pallet_session::Config>::ValidatorId],
) -> Result<(), DispatchError> {
) -> Result<Weight, DispatchError> {
let mut current_signers = Self::signers();
let current_signers_length = current_signers.len();
// Since not enough validators do not allow rotation
// TODO: https://github.com/entropyxyz/entropy-core/issues/943
if validators.len() <= current_signers_length {
return Ok(());
return Ok(<T as Config>::WeightInfo::new_session_validators_less_then_signers());
}

let signers_info = pallet_parameters::Pallet::<T>::signers_info();
let mut new_signer = vec![];
let mut weight: Weight = <T as Config>::WeightInfo::new_session_not_adding_new_signer();

if current_signers_length <= signers_info.total_signers as usize {
let mut randomness = Self::get_randomness();
// grab a current signer to initiate value
let mut next_signer_up = &current_signers[0].clone();
let mut index;
let mut count = 0u32;
// loops to find signer in validator that is not already signer
while current_signers.contains(next_signer_up) {
index = randomness.next_u32() % validators.len() as u32;
next_signer_up = &validators[index as usize];
count += 1;
}
current_signers.push(next_signer_up.clone());
new_signer = next_signer_up.encode();
weight = <T as Config>::WeightInfo::new_session(current_signers.len() as u32, count)
}

// removes first signer and pushes new signer to back if total signers not increased
Expand All @@ -583,7 +587,8 @@ pub mod pallet {
JumpStartProgress::<T>::mutate(|jump_start_details| {
jump_start_details.parent_key_threshold = signers_info.threshold
});
Ok(())

Ok(weight)
}
}

Expand All @@ -600,9 +605,18 @@ pub mod pallet {
fn new_session(new_index: SessionIndex) -> Option<Vec<ValidatorId>> {
let new_session = I::new_session(new_index);
if let Some(validators) = &new_session {
let result = Pallet::<T>::new_session_handler(validators);
if result.is_err() {
log::warn!("Error splitting validators, Session: {:?}", new_index)
let result_weight = Pallet::<T>::new_session_handler(validators);
if let Err(why) = result_weight {
log::warn!(
"Error splitting validators, Session: {:?}, reason: {:?}",
new_index,
why
)
} else {
frame_system::Pallet::<T>::register_extra_weight_unchecked(
result_weight.expect("Error unwraping non error value"),
DispatchClass::Mandatory,
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems really risky to use. From the docs:

Even more dangerous is to note that this function does NOT take any action if the new sum of block weight is more than the block weight limit. This is what the unchecked.

This means we could stall the chain at a session boundary

}
}
new_session
Expand Down
127 changes: 127 additions & 0 deletions pallets/staking/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ pub trait WeightInfo {
fn declare_synced() -> Weight;
fn confirm_key_reshare_confirmed(c: u32) -> Weight;
fn confirm_key_reshare_completed() -> Weight;
fn new_session_validators_less_then_signers() -> Weight;
fn new_session_not_adding_new_signer() -> Weight;
fn new_session(c: u32, l: u32) -> Weight;
}

/// Weights for pallet_staking_extension using the Substrate node and recommended hardware.
Expand Down Expand Up @@ -190,6 +193,68 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: `StakingExtension::Signers` (r:1 w:0)
/// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn new_session_validators_less_then_signers() -> Weight {
// Proof Size summary in bytes:
// Measured: `234`
// Estimated: `1719`
// Minimum execution time: 4_000_000 picoseconds.
Weight::from_parts(4_000_000, 0)
.saturating_add(Weight::from_parts(0, 1719))
.saturating_add(T::DbWeight::get().reads(1))
}
/// Storage: `StakingExtension::Signers` (r:1 w:0)
/// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Parameters::SignersInfo` (r:1 w:0)
/// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Babe::NextRandomness` (r:1 w:0)
/// Proof: `Babe::NextRandomness` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// Storage: `Babe::EpochStart` (r:1 w:0)
/// Proof: `Babe::EpochStart` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
/// Storage: `StakingExtension::JumpStartProgress` (r:1 w:1)
/// Proof: `StakingExtension::JumpStartProgress` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::ReshareData` (r:0 w:1)
/// Proof: `StakingExtension::ReshareData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::NextSigners` (r:0 w:1)
/// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `c` is `[1, 14]`.
/// The range of component `l` is `[0, 15]`.
fn new_session(c: u32, l: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `482 + c * (32 ±0)`
// Estimated: `1966 + c * (32 ±0)`
// Minimum execution time: 13_000_000 picoseconds.
Weight::from_parts(12_791_889, 0)
.saturating_add(Weight::from_parts(0, 1966))
// Standard Error: 22_917
.saturating_add(Weight::from_parts(65_067, 0).saturating_mul(c.into()))
// Standard Error: 19_636
.saturating_add(Weight::from_parts(30_071, 0).saturating_mul(l.into()))
.saturating_add(T::DbWeight::get().reads(5))
.saturating_add(T::DbWeight::get().writes(3))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
}
/// Storage: `StakingExtension::Signers` (r:1 w:0)
/// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Parameters::SignersInfo` (r:1 w:0)
/// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::JumpStartProgress` (r:1 w:1)
/// Proof: `StakingExtension::JumpStartProgress` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::ReshareData` (r:0 w:1)
/// Proof: `StakingExtension::ReshareData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::NextSigners` (r:0 w:1)
/// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn new_session_not_adding_new_signer() -> Weight {
// Proof Size summary in bytes:
// Measured: `439`
// Estimated: `1924`
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(10_000_000, 0)
.saturating_add(Weight::from_parts(0, 1924))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(3))
}
}

// For backwards compatibility and tests
Expand Down Expand Up @@ -320,4 +385,66 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(2))
.saturating_add(RocksDbWeight::get().writes(2))
}
/// Storage: `StakingExtension::Signers` (r:1 w:0)
/// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn new_session_validators_less_then_signers() -> Weight {
// Proof Size summary in bytes:
// Measured: `234`
// Estimated: `1719`
// Minimum execution time: 4_000_000 picoseconds.
Weight::from_parts(4_000_000, 0)
.saturating_add(Weight::from_parts(0, 1719))
.saturating_add(RocksDbWeight::get().reads(1))
}
/// Storage: `StakingExtension::Signers` (r:1 w:0)
/// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Parameters::SignersInfo` (r:1 w:0)
/// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Babe::NextRandomness` (r:1 w:0)
/// Proof: `Babe::NextRandomness` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// Storage: `Babe::EpochStart` (r:1 w:0)
/// Proof: `Babe::EpochStart` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
/// Storage: `StakingExtension::JumpStartProgress` (r:1 w:1)
/// Proof: `StakingExtension::JumpStartProgress` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::ReshareData` (r:0 w:1)
/// Proof: `StakingExtension::ReshareData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::NextSigners` (r:0 w:1)
/// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `c` is `[1, 14]`.
/// The range of component `l` is `[0, 15]`.
fn new_session(c: u32, l: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `482 + c * (32 ±0)`
// Estimated: `1966 + c * (32 ±0)`
// Minimum execution time: 13_000_000 picoseconds.
Weight::from_parts(12_791_889, 0)
.saturating_add(Weight::from_parts(0, 1966))
// Standard Error: 22_917
.saturating_add(Weight::from_parts(65_067, 0).saturating_mul(c.into()))
// Standard Error: 19_636
.saturating_add(Weight::from_parts(30_071, 0).saturating_mul(l.into()))
.saturating_add(RocksDbWeight::get().reads(5))
.saturating_add(RocksDbWeight::get().writes(3))
.saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into()))
}
/// Storage: `StakingExtension::Signers` (r:1 w:0)
/// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Parameters::SignersInfo` (r:1 w:0)
/// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::JumpStartProgress` (r:1 w:1)
/// Proof: `StakingExtension::JumpStartProgress` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::ReshareData` (r:0 w:1)
/// Proof: `StakingExtension::ReshareData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `StakingExtension::NextSigners` (r:0 w:1)
/// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn new_session_not_adding_new_signer() -> Weight {
// Proof Size summary in bytes:
// Measured: `439`
// Estimated: `1924`
// Minimum execution time: 9_000_000 picoseconds.
Weight::from_parts(10_000_000, 0)
.saturating_add(Weight::from_parts(0, 1924))
.saturating_add(RocksDbWeight::get().reads(3))
.saturating_add(RocksDbWeight::get().writes(3))
}
}
Loading
Loading