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::Vec};
22use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput};
23
24use codec::Decode;
25use frame_benchmarking::v2::*;
26use frame_support::{
27	assert_ok,
28	traits::{Get, KeyOwnerProofSystem, OnInitialize},
29};
30use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
31use pallet_session::{historical::Pallet as Historical, Pallet as Session, *};
32use pallet_staking::{
33	benchmarking::create_validator_with_nominators, testing_utils::create_validators,
34	MaxNominationsOf, RewardDestination,
35};
36
37const MAX_VALIDATORS: u32 = 1000;
38
39pub struct Pallet<T: Config>(pallet_session::Pallet<T>);
40pub trait Config:
41	pallet_session::Config + pallet_session::historical::Config + pallet_staking::Config
42{
43}
44
45impl<T: Config> OnInitialize<BlockNumberFor<T>> for Pallet<T> {
46	fn on_initialize(n: BlockNumberFor<T>) -> frame_support::weights::Weight {
47		pallet_session::Pallet::<T>::on_initialize(n)
48	}
49}
50
51#[benchmarks]
52mod benchmarks {
53	use super::*;
54
55	#[benchmark]
56	fn set_keys() -> Result<(), BenchmarkError> {
57		let n = MaxNominationsOf::<T>::get();
58		let (v_stash, _) = create_validator_with_nominators::<T>(
59			n,
60			MaxNominationsOf::<T>::get(),
61			false,
62			true,
63			RewardDestination::Staked,
64		)?;
65		let v_controller = pallet_staking::Pallet::<T>::bonded(&v_stash).ok_or("not stash")?;
66
67		let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap();
68		let proof: Vec<u8> = vec![0, 1, 2, 3];
69		// Whitelist controller account from further DB operations.
70		let v_controller_key = frame_system::Account::<T>::hashed_key_for(&v_controller);
71		frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into());
72		assert_ok!(Session::<T>::ensure_can_pay_key_deposit(&v_controller));
73
74		#[extrinsic_call]
75		_(RawOrigin::Signed(v_controller), keys, proof);
76
77		Ok(())
78	}
79
80	#[benchmark]
81	fn purge_keys() -> Result<(), BenchmarkError> {
82		let n = MaxNominationsOf::<T>::get();
83		let (v_stash, _) = create_validator_with_nominators::<T>(
84			n,
85			MaxNominationsOf::<T>::get(),
86			false,
87			true,
88			RewardDestination::Staked,
89		)?;
90		let v_controller = pallet_staking::Pallet::<T>::bonded(&v_stash).ok_or("not stash")?;
91		let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap();
92		let proof: Vec<u8> = vec![0, 1, 2, 3];
93		assert_ok!(Session::<T>::ensure_can_pay_key_deposit(&v_controller));
94		Session::<T>::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?;
95		// Whitelist controller account from further DB operations.
96		let v_controller_key = frame_system::Account::<T>::hashed_key_for(&v_controller);
97		frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into());
98
99		#[extrinsic_call]
100		_(RawOrigin::Signed(v_controller));
101
102		Ok(())
103	}
104
105	#[benchmark(extra)]
106	fn check_membership_proof_current_session(n: Linear<2, MAX_VALIDATORS>) {
107		let (key, key_owner_proof1) = check_membership_proof_setup::<T>(n);
108		let key_owner_proof2 = key_owner_proof1.clone();
109
110		#[block]
111		{
112			Historical::<T>::check_proof(key, key_owner_proof1);
113		}
114
115		assert!(Historical::<T>::check_proof(key, key_owner_proof2).is_some());
116	}
117
118	#[benchmark(extra)]
119	fn check_membership_proof_historical_session(n: Linear<2, MAX_VALIDATORS>) {
120		let (key, key_owner_proof1) = check_membership_proof_setup::<T>(n);
121
122		// skip to the next session so that the session is historical
123		// and the membership merkle proof must be checked.
124		Session::<T>::rotate_session();
125
126		let key_owner_proof2 = key_owner_proof1.clone();
127
128		#[block]
129		{
130			Historical::<T>::check_proof(key, key_owner_proof1);
131		}
132
133		assert!(Historical::<T>::check_proof(key, key_owner_proof2).is_some());
134	}
135
136	impl_benchmark_test_suite!(
137		Pallet,
138		crate::mock::new_test_ext(),
139		crate::mock::Test,
140		extra = false
141	);
142}
143
144/// Sets up the benchmark for checking a membership proof. It creates the given
145/// number of validators, sets random session keys and then creates a membership
146/// proof for the first authority and returns its key and the proof.
147fn check_membership_proof_setup<T: Config>(
148	n: u32,
149) -> ((sp_runtime::KeyTypeId, &'static [u8; 32]), sp_session::MembershipProof) {
150	pallet_staking::ValidatorCount::<T>::put(n);
151
152	// create validators and set random session keys
153	for (n, who) in create_validators::<T>(n, 1000).unwrap().into_iter().enumerate() {
154		use rand::{RngCore, SeedableRng};
155
156		let validator = T::Lookup::lookup(who).unwrap();
157		let controller = pallet_staking::Pallet::<T>::bonded(&validator).unwrap();
158
159		let keys = {
160			let mut keys = [0u8; 128];
161
162			// we keep the keys for the first validator as 0x00000...
163			if n > 0 {
164				let mut rng = rand::rngs::StdRng::seed_from_u64(n as u64);
165				rng.fill_bytes(&mut keys);
166			}
167
168			keys
169		};
170
171		// TODO: this benchmark is broken, session keys cannot be decoded into 128 bytes anymore,
172		// but not an issue for CI since it is `extra`.
173		let keys: T::Keys = Decode::decode(&mut &keys[..]).unwrap();
174		let proof: Vec<u8> = vec![];
175
176		Session::<T>::set_keys(RawOrigin::Signed(controller).into(), keys, proof).unwrap();
177	}
178
179	Pallet::<T>::on_initialize(frame_system::pallet_prelude::BlockNumberFor::<T>::one());
180
181	// skip sessions until the new validator set is enacted
182	while Validators::<T>::get().len() < n as usize {
183		Session::<T>::rotate_session();
184	}
185
186	let key = (sp_runtime::KeyTypeId(*b"babe"), &[0u8; 32]);
187
188	(key, Historical::<T>::prove(key).unwrap())
189}