referrerpolicy=no-referrer-when-downgrade

pallet_registrar_relay/
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-relay`.
19
20use super::*;
21use frame_benchmarking::v2::*;
22use frame_support::traits::Get;
23use frame_system::RawOrigin;
24use registrar_primitives::{MessageToRelay, MessageToRelayV1};
25use sp_runtime::traits::{BlakeTwo256, Hash};
26
27/// A para id no benchmark setup will collide on.
28const PARA_ID: ParaId = 4_242;
29
30fn code_of(len: u32) -> Vec<u8> {
31	alloc::vec![1u8; len as usize]
32}
33
34/// Park a pending registration for `PARA_ID` expecting exactly `code`.
35///
36/// Written straight to storage rather than pushed through [`Pallet::receive`]: going through the
37/// call would put the whole range at the mercy of whatever minimum code size the configured
38/// [`ParachainRegistrar`] enforces, and `c = 0` would fail setup instead of measuring anything.
39fn park<T: Config>(code: &[u8]) -> Result<(), BenchmarkError> {
40	let genesis_head = alloc::vec![2u8; T::MaxHeadDataSize::get() as usize];
41	let pending = PendingRegistration {
42		message_id: 0,
43		manager: account("manager", 0, 0),
44		genesis_head: genesis_head.try_into().map_err(|_| "head data exceeds its own bound")?,
45		code_hash: BlakeTwo256::hash(code),
46		code_len: code.len() as u32,
47	};
48
49	PendingRegistrations::<T>::insert(PARA_ID, pending);
50	Ok(())
51}
52
53#[benchmarks]
54mod benchmarks {
55	use super::*;
56
57	/// Accepting a registration request. Dominated by writing the head data.
58	#[benchmark]
59	fn receive_register(h: Linear<0, { T::MaxHeadDataSize::get() }>) -> Result<(), BenchmarkError> {
60		let manager: T::AccountId = account("manager", 0, 0);
61		let code = code_of(T::MaxCodeSize::get());
62		let message = MessageToRelay::V1(MessageToRelayV1::Register {
63			para_id: PARA_ID,
64			message_id: 0,
65			manager,
66			genesis_head: alloc::vec![2u8; h as usize],
67			code_hash: BlakeTwo256::hash(&code),
68			code_len: code.len() as u32,
69		});
70
71		#[extrinsic_call]
72		receive(RawOrigin::Root, message);
73
74		assert!(PendingRegistrations::<T>::contains_key(PARA_ID));
75		Ok(())
76	}
77
78	/// Uploading the validation code. Dominated by hashing and onboarding the blob.
79	#[benchmark]
80	fn apply_authorized_code(
81		c: Linear<0, { T::MaxCodeSize::get() }>,
82	) -> Result<(), BenchmarkError> {
83		let code = code_of(c);
84		park::<T>(&code)?;
85
86		#[extrinsic_call]
87		_(RawOrigin::Authorized, PARA_ID, code);
88
89		assert!(!PendingRegistrations::<T>::contains_key(PARA_ID));
90		Ok(())
91	}
92
93	/// Deciding whether an unsigned `apply_authorized_code` may enter the pool.
94	///
95	/// This runs on every node for every candidate transaction, so it is the number that keeps
96	/// the free call from being a cheap way to make everyone hash megabytes.
97	#[benchmark]
98	fn authorize_apply_authorized_code(
99		c: Linear<0, { T::MaxCodeSize::get() }>,
100	) -> Result<(), BenchmarkError> {
101		let code = code_of(c);
102		park::<T>(&code)?;
103		let call = Call::<T>::apply_authorized_code { para_id: PARA_ID, validation_code: code };
104
105		#[block]
106		{
107			use frame_support::pallet_prelude::Authorize;
108			call.authorize(sp_runtime::transaction_validity::TransactionSource::External)
109				.ok_or("call must give some authorization")??;
110		}
111
112		Ok(())
113	}
114
115	/// Dropping an authorization. The worst case carries the largest head data, since that is what
116	/// the entry being removed holds.
117	#[benchmark]
118	fn receive_cancel_registration() -> Result<(), BenchmarkError> {
119		park::<T>(&code_of(T::MaxCodeSize::get()))?;
120		let message = MessageToRelay::V1(MessageToRelayV1::CancelRegistration {
121			para_id: PARA_ID,
122			message_id: 0,
123		});
124
125		#[extrinsic_call]
126		receive(RawOrigin::Root, message);
127
128		assert!(!PendingRegistrations::<T>::contains_key(PARA_ID));
129		Ok(())
130	}
131
132	/// Telling the parachain a para produced its first head.
133	#[benchmark]
134	fn on_new_head() {
135		AwaitingFirstHead::<T>::insert(PARA_ID, ());
136
137		#[block]
138		{
139			<Pallet<T> as OnNewHead>::on_new_head(PARA_ID.into(), &HeadData(alloc::vec![]));
140		}
141
142		assert!(!AwaitingFirstHead::<T>::contains_key(PARA_ID));
143	}
144
145	/// A later head, where the first one has already been reported.
146	#[benchmark]
147	fn on_new_head_already_noted() {
148		#[block]
149		{
150			<Pallet<T> as OnNewHead>::on_new_head(PARA_ID.into(), &HeadData(alloc::vec![]));
151		}
152	}
153
154	impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
155}