referrerpolicy=no-referrer-when-downgrade

pallet_election_provider_multi_block/verifier/
benchmarking.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
18use crate::{
19	verifier::{Config, Event, FeasibilityError, Pallet, Status, StatusStorage},
20	CurrentPhase, Phase,
21};
22use frame_benchmarking::v2::*;
23use frame_election_provider_support::{ElectionProvider, NposSolution};
24use frame_support::pallet_prelude::*;
25use sp_std::prelude::*;
26
27#[benchmarks(where
28	T: crate::Config + crate::signed::Config + crate::unsigned::Config,
29	<T as frame_system::Config>::RuntimeEvent: TryInto<crate::verifier::Event<T>>
30)]
31mod benchmarks {
32	use super::*;
33
34	fn events_for<T: Config>() -> Vec<Event<T>>
35	where
36		<T as frame_system::Config>::RuntimeEvent: TryInto<Event<T>>,
37	{
38		frame_system::Pallet::<T>::read_events_for_pallet::<Event<T>>()
39	}
40
41	#[benchmark(pov_mode = Measured)]
42	fn on_initialize_valid_non_terminal() -> Result<(), BenchmarkError> {
43		#[cfg(test)]
44		crate::mock::ElectionStart::set(sp_runtime::traits::Bounded::max_value());
45		crate::Pallet::<T>::start().unwrap();
46
47		// roll to signed validation, with a solution stored in the signed pallet
48		crate::Pallet::<T>::roll_to_signed_and_submit_full_solution()?;
49
50		// roll to verification
51		crate::Pallet::<T>::roll_until_matches(|| {
52			matches!(CurrentPhase::<T>::get(), Phase::SignedValidation(_))
53		});
54		// send start signal
55		crate::Pallet::<T>::roll_next(true, false);
56
57		// start signal must have been sent by now
58		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::msp()));
59
60		#[block]
61		{
62			crate::Pallet::<T>::roll_next(true, false);
63		}
64		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::msp() - 1));
65
66		Ok(())
67	}
68
69	#[benchmark(pov_mode = Measured)]
70	fn on_initialize_valid_terminal() -> Result<(), BenchmarkError> {
71		#[cfg(test)]
72		crate::mock::ElectionStart::set(sp_runtime::traits::Bounded::max_value());
73		crate::Pallet::<T>::start().unwrap();
74
75		// roll to signed validation, with a solution stored in the signed pallet
76		assert!(
77			T::SignedValidationPhase::get() >= T::Pages::get().into(),
78			"Signed validation phase must be larger than the number of pages"
79		);
80
81		crate::Pallet::<T>::roll_to_signed_and_submit_full_solution()?;
82		// roll to before the last page of verification
83		crate::Pallet::<T>::roll_until_matches(|| {
84			matches!(CurrentPhase::<T>::get(), Phase::SignedValidation(_))
85		});
86		// send start signal
87		crate::Pallet::<T>::roll_next(true, false);
88
89		// start signal must have been sent by now
90		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::msp()));
91		for _ in 0..(T::Pages::get() - 1) {
92			crate::Pallet::<T>::roll_next(true, false);
93		}
94
95		// we must have verified all pages by now, minus the last one.
96		assert!(matches!(
97			&events_for::<T>()[..],
98			[Event::Verified(_, _), .., Event::Verified(1, _)]
99		));
100
101		// verify the last page.
102		#[block]
103		{
104			crate::Pallet::<T>::roll_next(true, false);
105		}
106
107		// we are done
108		assert_eq!(StatusStorage::<T>::get(), Status::Nothing);
109		// last event is success
110		assert!(matches!(
111			&events_for::<T>()[..],
112			[Event::Verified(_, _), .., Event::Verified(0, _), Event::Queued(_, None)]
113		));
114
115		Ok(())
116	}
117
118	#[benchmark(pov_mode = Measured)]
119	fn on_initialize_invalid_terminal() -> Result<(), BenchmarkError> {
120		// this is the verification of the current page + removing all of the previously valid
121		// pages. The worst case is therefore when the last page is invalid, for example the final
122		// score.
123		assert!(T::Pages::get() >= 2, "benchmark only works if we have more than 2 pages");
124
125		#[cfg(test)]
126		crate::mock::ElectionStart::set(sp_runtime::traits::Bounded::max_value());
127		crate::Pallet::<T>::start().unwrap();
128
129		// roll to signed validation, with a solution stored in the signed pallet
130
131		// but this solution is corrupt
132		let mut paged_solution = crate::Pallet::<T>::roll_to_signed_and_mine_full_solution();
133		paged_solution.score.minimal_stake -= 1;
134		crate::Pallet::<T>::submit_full_solution(paged_solution)?;
135
136		// roll to verification
137		crate::Pallet::<T>::roll_until_matches(|| {
138			matches!(CurrentPhase::<T>::get(), Phase::SignedValidation(_))
139		});
140		// send start signal
141		crate::Pallet::<T>::roll_next(true, false);
142
143		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::msp()));
144		// verify all pages, except for the last one.
145		for i in 0..T::Pages::get() - 1 {
146			crate::Pallet::<T>::roll_next(true, false);
147			assert_eq!(
148				StatusStorage::<T>::get(),
149				Status::Ongoing(crate::Pallet::<T>::msp() - 1 - i)
150			);
151		}
152
153		// next page to be verified is the last one
154		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::lsp()));
155		assert!(matches!(
156			&events_for::<T>()[..],
157			[Event::Verified(_, _), .., Event::Verified(1, _)]
158		));
159
160		#[block]
161		{
162			crate::Pallet::<T>::roll_next(true, false);
163		}
164
165		// we are now reset.
166		assert_eq!(StatusStorage::<T>::get(), Status::Nothing);
167		assert!(matches!(
168			&events_for::<T>()[..],
169			[
170				..,
171				Event::Verified(0, _),
172				Event::VerificationFailed(0, FeasibilityError::InvalidScore)
173			]
174		));
175
176		Ok(())
177	}
178
179	#[benchmark(pov_mode = Measured)]
180	fn on_initialize_invalid_non_terminal(
181		// number of valid pages that have been verified, before we verify the non-terminal invalid
182		// page.
183		v: Linear<0, { T::Pages::get() - 1 }>,
184	) -> Result<(), BenchmarkError> {
185		assert!(T::Pages::get() >= 2, "benchmark only works if we have more than 2 pages");
186
187		#[cfg(test)]
188		crate::mock::ElectionStart::set(sp_runtime::traits::Bounded::max_value());
189		crate::Pallet::<T>::start().unwrap();
190
191		// roll to signed validation, with a solution stored in the signed pallet, but this solution
192		// is corrupt in its msp.
193		let mut paged_solution = crate::Pallet::<T>::roll_to_signed_and_mine_full_solution();
194		let page_to_corrupt = crate::Pallet::<T>::msp() - v;
195		crate::log!(
196			info,
197			"pages of solution: {:?}, to corrupt {}, v {}",
198			paged_solution.solution_pages.len(),
199			page_to_corrupt,
200			v
201		);
202		paged_solution.solution_pages[page_to_corrupt as usize].corrupt();
203		crate::Pallet::<T>::submit_full_solution(paged_solution)?;
204
205		// roll to verification
206		crate::Pallet::<T>::roll_until_matches(|| {
207			matches!(CurrentPhase::<T>::get(), Phase::SignedValidation(_))
208		});
209		// send start signal
210		crate::Pallet::<T>::roll_next(true, false);
211
212		// we should be ready to go
213		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::msp()));
214
215		// validate the the parameterized number of valid pages.
216		for _ in 0..v {
217			crate::Pallet::<T>::roll_next(true, false);
218		}
219
220		// we are still ready to continue
221		assert_eq!(StatusStorage::<T>::get(), Status::Ongoing(crate::Pallet::<T>::msp() - v));
222
223		// verify one page, which will be invalid.
224		#[block]
225		{
226			crate::Pallet::<T>::roll_next(true, false);
227		}
228
229		// we are now reset, because this page was invalid.
230		assert_eq!(StatusStorage::<T>::get(), Status::Nothing);
231
232		assert!(matches!(
233			&events_for::<T>()[..],
234			[.., Event::VerificationFailed(_, FeasibilityError::NposElection(_))]
235		));
236
237		Ok(())
238	}
239
240	impl_benchmark_test_suite!(
241		Pallet,
242		crate::mock::ExtBuilder::full().build_unchecked(),
243		crate::mock::Runtime
244	);
245}