referrerpolicy=no-referrer-when-downgrade

pallet_session_benchmarking/
inner.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Benchmarks for the Session Pallet.
19// This is separated into its own crate due to cyclic dependency issues.
20
21use alloc::vec::Vec;
22use sp_runtime::traits::{One, StaticLookup};
23
24use frame_benchmarking::v2::*;
25use frame_support::{
26	assert_ok,
27	traits::{Get, KeyOwnerProofSystem, OnInitialize},
28};
29use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
30use pallet_session::{historical::Pallet as Historical, Pallet as Session, *};
31use pallet_staking::{
32	benchmarking::create_validator_with_nominators, testing_utils::create_validators,
33	MaxNominationsOf, RewardDestination,
34};
35
36const MAX_VALIDATORS: u32 = 1000;
37
38pub struct Pallet<T: Config>(pallet_session::Pallet<T>);
39/// Configuration trait for the benchmarking of `pallet-session`.
40pub trait Config:
41	pallet_session::Config + pallet_session::historical::Config + pallet_staking::Config
42{
43	/// Generate a session key and a proof of ownership.
44	///
45	/// The given `owner` is the account that will call `set_keys` using the returned session keys
46	/// and proof. This means that the proof should prove the ownership of `owner` over the private
47	/// keys associated to the session keys.
48	fn generate_session_keys_and_proof(owner: Self::AccountId) -> (Self::Keys, Vec<u8>);
49}
50
51impl<T: Config> OnInitialize<BlockNumberFor<T>> for Pallet<T> {
52	fn on_initialize(n: BlockNumberFor<T>) -> frame_support::weights::Weight {
53		pallet_session::Pallet::<T>::on_initialize(n)
54	}
55}
56
57#[benchmarks]
58mod benchmarks {
59	use super::*;
60
61	#[benchmark]
62	fn set_keys() -> Result<(), BenchmarkError> {
63		let n = MaxNominationsOf::<T>::get();
64		let (v_stash, _) = create_validator_with_nominators::<T>(
65			n,
66			MaxNominationsOf::<T>::get(),
67			false,
68			true,
69			RewardDestination::Staked,
70		)?;
71		let v_controller = pallet_staking::Pallet::<T>::bonded(&v_stash).ok_or("not stash")?;
72
73		let (keys, proof) = T::generate_session_keys_and_proof(v_controller.clone());
74		// Whitelist controller account from further DB operations.
75		let v_controller_key = frame_system::Account::<T>::hashed_key_for(&v_controller);
76		frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into());
77		assert_ok!(Session::<T>::ensure_can_pay_key_deposit(&v_controller));
78
79		#[extrinsic_call]
80		_(RawOrigin::Signed(v_controller), keys, proof);
81
82		Ok(())
83	}
84
85	#[benchmark]
86	fn purge_keys() -> Result<(), BenchmarkError> {
87		let n = MaxNominationsOf::<T>::get();
88		let (v_stash, _) = create_validator_with_nominators::<T>(
89			n,
90			MaxNominationsOf::<T>::get(),
91			false,
92			true,
93			RewardDestination::Staked,
94		)?;
95		let v_controller = pallet_staking::Pallet::<T>::bonded(&v_stash).ok_or("not stash")?;
96		let (keys, proof) = T::generate_session_keys_and_proof(v_controller.clone());
97		assert_ok!(Session::<T>::ensure_can_pay_key_deposit(&v_controller));
98		Session::<T>::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?;
99		// Whitelist controller account from further DB operations.
100		let v_controller_key = frame_system::Account::<T>::hashed_key_for(&v_controller);
101		frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into());
102
103		#[extrinsic_call]
104		_(RawOrigin::Signed(v_controller));
105
106		Ok(())
107	}
108
109	#[benchmark(extra)]
110	fn check_membership_proof_current_session(n: Linear<2, MAX_VALIDATORS>) {
111		let (key, key_owner_proof1) = check_membership_proof_setup::<T>(n);
112		let key_owner_proof2 = key_owner_proof1.clone();
113
114		#[block]
115		{
116			Historical::<T>::check_proof(key, key_owner_proof1);
117		}
118
119		assert!(Historical::<T>::check_proof(key, key_owner_proof2).is_some());
120	}
121
122	#[benchmark(extra)]
123	fn check_membership_proof_historical_session(n: Linear<2, MAX_VALIDATORS>) {
124		let (key, key_owner_proof1) = check_membership_proof_setup::<T>(n);
125
126		// skip to the next session so that the session is historical
127		// and the membership merkle proof must be checked.
128		Session::<T>::rotate_session();
129
130		let key_owner_proof2 = key_owner_proof1.clone();
131
132		#[block]
133		{
134			Historical::<T>::check_proof(key, key_owner_proof1);
135		}
136
137		assert!(Historical::<T>::check_proof(key, key_owner_proof2).is_some());
138	}
139
140	impl_benchmark_test_suite!(
141		Pallet,
142		crate::mock::new_test_ext(),
143		crate::mock::Test,
144		extra = false
145	);
146}
147
148/// Sets up the benchmark for checking a membership proof. It creates the given
149/// number of validators, sets random session keys and then creates a membership
150/// proof for the first authority and returns its key and the proof.
151fn check_membership_proof_setup<T: Config>(
152	n: u32,
153) -> ((sp_runtime::KeyTypeId, &'static [u8; 32]), sp_session::MembershipProof) {
154	pallet_staking::ValidatorCount::<T>::put(n);
155
156	// create validators and set random session keys
157	for (n, who) in create_validators::<T>(n, 1000).unwrap().into_iter().enumerate() {
158		use rand::{RngCore, SeedableRng};
159
160		let validator = T::Lookup::lookup(who).unwrap();
161		let controller = pallet_staking::Pallet::<T>::bonded(&validator).unwrap();
162
163		let _keys = {
164			let mut keys = [0u8; 128];
165
166			// we keep the keys for the first validator as 0x00000...
167			if n > 0 {
168				let mut rng = rand::rngs::StdRng::seed_from_u64(n as u64);
169				rng.fill_bytes(&mut keys);
170			}
171
172			keys
173		};
174
175		// TODO: this benchmark is broken, session keys cannot be decoded into 128 bytes anymore,
176		// but not an issue for CI since it is `extra`.
177		let (keys, proof) = T::generate_session_keys_and_proof(controller.clone());
178
179		Session::<T>::set_keys(RawOrigin::Signed(controller).into(), keys, proof).unwrap();
180	}
181
182	Pallet::<T>::on_initialize(frame_system::pallet_prelude::BlockNumberFor::<T>::one());
183
184	// skip sessions until the new validator set is enacted
185	while Validators::<T>::get().len() < n as usize {
186		Session::<T>::rotate_session();
187	}
188
189	let key = (sp_runtime::KeyTypeId(*b"babe"), &[0u8; 32]);
190
191	(key, Historical::<T>::prove(key).unwrap())
192}