referrerpolicy=no-referrer-when-downgrade

pallet_registrar_para/
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
18//! Benchmarks for `pallet-registrar-para`.
19
20use super::*;
21use frame_benchmarking::v2::*;
22use frame_support::traits::Get;
23use frame_system::RawOrigin;
24use registrar_primitives::{MessageToPara, MessageToParaV1};
25
26/// An account able to pay every consideration this pallet can ask for.
27fn funded_manager<T: Config>() -> T::AccountId {
28	let who: T::AccountId = account("manager", 0, 0);
29	T::ReservationConsideration::ensure_successful(&who, Footprint::from_parts(1, 0));
30	T::RegistrationConsideration::ensure_successful(
31		&who,
32		Pallet::<T>::registration_footprint(T::MaxHeadDataSize::get(), T::MaxCodeSize::get()),
33	);
34	who
35}
36
37/// Reserve a para id for `who` and return it.
38fn reserve_for<T: Config>(who: &T::AccountId) -> Result<ParaId, BenchmarkError> {
39	Pallet::<T>::reserve(RawOrigin::Signed(who.clone()).into())?;
40	Ok(NextFreeParaId::<T>::get().saturating_sub(1))
41}
42
43/// Reserve a para id and put it into `Pending`.
44fn make_pending<T: Config>(who: &T::AccountId) -> Result<ParaId, BenchmarkError> {
45	let para_id = reserve_for::<T>(who)?;
46	Pallet::<T>::register(
47		RawOrigin::Signed(who.clone()).into(),
48		para_id,
49		alloc::vec![2u8; T::MaxHeadDataSize::get() as usize],
50		T::MaxCodeSize::get(),
51		sp_core::H256::repeat_byte(1),
52	)?;
53	Ok(para_id)
54}
55
56/// Reserve a para id and put it into `Registered`.
57fn make_registered<T: Config>(who: &T::AccountId) -> Result<ParaId, BenchmarkError> {
58	let para_id = make_pending::<T>(who)?;
59	Pallet::<T>::receive(
60		RawOrigin::Root.into(),
61		MessageToPara::V1(MessageToParaV1::RegisterResponse {
62			para_id,
63			message_id: 0,
64			outcome: Ok(()),
65		}),
66	)?;
67	Ok(para_id)
68}
69
70/// Reserve a para id, register it and ask to deregister it. Returns the id and the awaited message.
71fn make_deregistering<T: Config>(who: &T::AccountId) -> Result<(ParaId, u64), BenchmarkError> {
72	let para_id = make_registered::<T>(who)?;
73	Pallet::<T>::deregister(RawOrigin::Signed(who.clone()).into(), para_id)?;
74	match Paras::<T>::get(para_id).map(|i| i.state) {
75		Some(RegistrationState::Deregistering { message_id, .. }) => Ok((para_id, message_id)),
76		_ => Err(BenchmarkError::Stop("not deregistering")),
77	}
78}
79
80/// Reserve a para id, register it and lock it.
81fn make_locked<T: Config>(who: &T::AccountId) -> Result<ParaId, BenchmarkError> {
82	let para_id = make_registered::<T>(who)?;
83	Pallet::<T>::add_lock(RawOrigin::Signed(who.clone()).into(), para_id)?;
84	Ok(para_id)
85}
86
87#[benchmarks]
88mod benchmarks {
89	use super::*;
90
91	#[benchmark]
92	fn reserve() -> Result<(), BenchmarkError> {
93		let who = funded_manager::<T>();
94
95		#[extrinsic_call]
96		_(RawOrigin::Signed(who.clone()));
97
98		let para_id = NextFreeParaId::<T>::get().saturating_sub(1);
99		assert_eq!(Paras::<T>::get(para_id).map(|i| i.manager), Some(who));
100		Ok(())
101	}
102
103	/// Requesting a registration. Dominated by shipping the head data to the relay chain.
104	#[benchmark]
105	fn register(h: Linear<0, { T::MaxHeadDataSize::get() }>) -> Result<(), BenchmarkError> {
106		let who = funded_manager::<T>();
107		let para_id = reserve_for::<T>(&who)?;
108
109		#[extrinsic_call]
110		_(
111			RawOrigin::Signed(who),
112			para_id,
113			alloc::vec![2u8; h as usize],
114			T::MaxCodeSize::get(),
115			sp_core::H256::repeat_byte(1),
116		);
117
118		assert!(matches!(
119			Paras::<T>::get(para_id).map(|i| i.state),
120			Some(RegistrationState::Pending { .. })
121		));
122		Ok(())
123	}
124
125	/// Asking the relay chain to drop an authorization. The deposit stays held, so this is the
126	/// state write plus the message.
127	#[benchmark]
128	fn cancel_registration() -> Result<(), BenchmarkError> {
129		let who = funded_manager::<T>();
130		let para_id = make_pending::<T>(&who)?;
131		T::BlockNumberProvider::set_block_number(
132			T::BlockNumberProvider::current_block_number()
133				.saturating_add(T::PendingDeadline::get())
134				.saturating_add(1u32.into()),
135		);
136
137		#[extrinsic_call]
138		_(RawOrigin::Signed(who), para_id);
139
140		assert!(matches!(
141			Paras::<T>::get(para_id).map(|i| i.state),
142			Some(RegistrationState::Pending { .. })
143		));
144		Ok(())
145	}
146
147	/// Worst case: a confirmed deregistration releases both considerations and removes the entry.
148	#[benchmark]
149	fn receive() -> Result<(), BenchmarkError> {
150		let who = funded_manager::<T>();
151		let (para_id, message_id) = make_deregistering::<T>(&who)?;
152		let message = MessageToPara::V1(MessageToParaV1::DeregisterResponse {
153			para_id,
154			message_id,
155			outcome: Ok(()),
156		});
157
158		#[extrinsic_call]
159		_(RawOrigin::Root, message);
160
161		assert!(Paras::<T>::get(para_id).is_none());
162		Ok(())
163	}
164
165	/// Giving up an id the relay chain never knew: the reservation goes back here and now.
166	#[benchmark]
167	fn deregister_reserved() -> Result<(), BenchmarkError> {
168		let who = funded_manager::<T>();
169		let para_id = reserve_for::<T>(&who)?;
170
171		#[extrinsic_call]
172		deregister(RawOrigin::Signed(who), para_id);
173
174		assert!(Paras::<T>::get(para_id).is_none());
175		Ok(())
176	}
177
178	/// Asking the relay chain to drop a registered para: the state write plus the message.
179	#[benchmark]
180	fn deregister_registered() -> Result<(), BenchmarkError> {
181		let who = funded_manager::<T>();
182		let para_id = make_registered::<T>(&who)?;
183
184		#[extrinsic_call]
185		deregister(RawOrigin::Signed(who), para_id);
186
187		assert!(matches!(
188			Paras::<T>::get(para_id).map(|i| i.state),
189			Some(RegistrationState::Deregistering { .. })
190		));
191		Ok(())
192	}
193
194	/// Asking again after the answer never came: the same, plus reporting the lost answer.
195	#[benchmark]
196	fn deregister_retry() -> Result<(), BenchmarkError> {
197		let who = funded_manager::<T>();
198		let (para_id, awaited) = make_deregistering::<T>(&who)?;
199		T::BlockNumberProvider::set_block_number(
200			T::BlockNumberProvider::current_block_number()
201				.saturating_add(T::PendingDeadline::get()),
202		);
203
204		#[extrinsic_call]
205		deregister(RawOrigin::Signed(who), para_id);
206
207		assert!(matches!(
208			Paras::<T>::get(para_id).map(|i| i.state),
209			Some(RegistrationState::Deregistering { message_id, .. }) if message_id != awaited
210		));
211		Ok(())
212	}
213
214	/// Locking a registered para: one state read and write.
215	#[benchmark]
216	fn add_lock() -> Result<(), BenchmarkError> {
217		let who = funded_manager::<T>();
218		let para_id = make_registered::<T>(&who)?;
219
220		#[extrinsic_call]
221		_(RawOrigin::Signed(who), para_id);
222
223		assert!(Paras::<T>::get(para_id).map(|i| i.is_locked()).unwrap_or(false));
224		Ok(())
225	}
226
227	/// Unlocking, with root standing in for the para itself: both do the same read and write.
228	#[benchmark]
229	fn remove_lock() -> Result<(), BenchmarkError> {
230		let who = funded_manager::<T>();
231		let para_id = make_locked::<T>(&who)?;
232
233		#[extrinsic_call]
234		_(RawOrigin::Root, para_id);
235
236		assert!(!Paras::<T>::get(para_id).map(|i| i.is_locked()).unwrap_or(true));
237		Ok(())
238	}
239
240	impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
241}