polkadot_runtime_parachains/paras/
benchmarking.rs1use super::*;
18use crate::configuration::HostConfiguration;
19use alloc::vec;
20use frame_benchmarking::v2::*;
21use frame_support::traits::fungible::Mutate;
22use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
23use polkadot_primitives::{
24 HeadData, Id as ParaId, ValidationCode, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE,
25};
26use sp_runtime::traits::{One, Saturating};
27
28pub mod mmr_setup;
29mod pvf_check;
30
31use self::pvf_check::{VoteCause, VoteOutcome};
32
33const SAMPLE_SIZE: u32 = 1024;
38
39fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
40 let events = frame_system::Pallet::<T>::events();
41 let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();
42 let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
44 assert_eq!(event, &system_event);
45}
46
47fn generate_disordered_pruning<T: Config>() {
48 let mut needs_pruning = Vec::new();
49
50 for i in 0..SAMPLE_SIZE {
51 let id = ParaId::from(i);
52 let block_number = BlockNumberFor::<T>::from(1000u32);
53 needs_pruning.push((id, block_number));
54 }
55
56 PastCodePruning::<T>::put(needs_pruning);
57}
58
59pub(crate) fn generate_disordered_upgrades<T: Config>() {
60 let mut upgrades = Vec::new();
61 let mut cooldowns = Vec::new();
62
63 for i in 0..SAMPLE_SIZE {
64 let id = ParaId::from(i);
65 let block_number = BlockNumberFor::<T>::from(1000u32);
66 upgrades.push((id, block_number));
67 cooldowns.push((id, block_number));
68 }
69
70 UpcomingUpgrades::<T>::put(upgrades);
71 UpgradeCooldowns::<T>::put(cooldowns);
72}
73
74fn generate_disordered_actions_queue<T: Config>() {
75 let mut queue = Vec::new();
76 let next_session = shared::CurrentSessionIndex::<T>::get().saturating_add(One::one());
77
78 for _ in 0..SAMPLE_SIZE {
79 let id = ParaId::from(1000);
80 queue.push(id);
81 }
82
83 ActionsQueue::<T>::mutate(next_session, |v| {
84 *v = queue;
85 });
86}
87
88#[benchmarks]
89mod benchmarks {
90 use super::*;
91
92 #[benchmark]
93 fn force_set_current_code(c: Linear<MIN_CODE_SIZE, MAX_CODE_SIZE>) {
94 let new_code = ValidationCode(vec![0; c as usize]);
95 let para_id = ParaId::from(c as u32);
96 CurrentCodeHash::<T>::insert(¶_id, new_code.hash());
97 generate_disordered_pruning::<T>();
98
99 #[extrinsic_call]
100 _(RawOrigin::Root, para_id, new_code);
101
102 assert_last_event::<T>(Event::CurrentCodeUpdated(para_id).into());
103 }
104
105 #[benchmark]
106 fn force_set_current_head(s: Linear<MIN_CODE_SIZE, MAX_HEAD_DATA_SIZE>) {
107 let new_head = HeadData(vec![0; s as usize]);
108 let para_id = ParaId::from(1000);
109
110 #[extrinsic_call]
111 _(RawOrigin::Root, para_id, new_head);
112
113 assert_last_event::<T>(Event::CurrentHeadUpdated(para_id).into());
114 }
115
116 #[benchmark]
117 fn force_set_most_recent_context() {
118 let para_id = ParaId::from(1000);
119 let context = BlockNumberFor::<T>::from(1000u32);
120
121 #[extrinsic_call]
122 _(RawOrigin::Root, para_id, context);
123 }
124
125 #[benchmark]
126 fn force_schedule_code_upgrade(c: Linear<MIN_CODE_SIZE, MAX_CODE_SIZE>) {
127 let new_code = ValidationCode(vec![0; c as usize]);
128 let para_id = ParaId::from(c as u32);
129 let block = BlockNumberFor::<T>::from(c);
130 generate_disordered_upgrades::<T>();
131
132 #[extrinsic_call]
133 _(RawOrigin::Root, para_id, new_code, block);
134
135 assert_last_event::<T>(Event::CodeUpgradeScheduled(para_id).into());
136 }
137
138 #[benchmark]
139 fn force_note_new_head(s: Linear<MIN_CODE_SIZE, MAX_HEAD_DATA_SIZE>) {
140 let para_id = ParaId::from(1000);
141 let new_head = HeadData(vec![0; s as usize]);
142 let old_code_hash = ValidationCode(vec![0]).hash();
143 CurrentCodeHash::<T>::insert(¶_id, old_code_hash);
144 frame_system::Pallet::<T>::set_block_number(10u32.into());
145 let expired = frame_system::Pallet::<T>::block_number().saturating_sub(One::one());
148 let config = HostConfiguration::<BlockNumberFor<T>>::default();
149 generate_disordered_pruning::<T>();
150 Pallet::<T>::schedule_code_upgrade(
151 para_id,
152 ValidationCode(vec![0u8; MIN_CODE_SIZE as usize]),
153 expired,
154 &config,
155 UpgradeStrategy::SetGoAheadSignal,
156 );
157
158 #[extrinsic_call]
159 _(RawOrigin::Root, para_id, new_head);
160
161 assert_last_event::<T>(Event::NewHeadNoted(para_id).into());
162 }
163
164 #[benchmark]
165 fn force_queue_action() {
166 let para_id = ParaId::from(1000);
167 generate_disordered_actions_queue::<T>();
168
169 #[extrinsic_call]
170 _(RawOrigin::Root, para_id);
171
172 let next_session =
173 crate::shared::CurrentSessionIndex::<T>::get().saturating_add(One::one());
174 assert_last_event::<T>(Event::ActionQueued(para_id, next_session).into());
175 }
176
177 #[benchmark]
178 fn add_trusted_validation_code(c: Linear<MIN_CODE_SIZE, MAX_CODE_SIZE>) {
179 let new_code = ValidationCode(vec![0; c as usize]);
180
181 pvf_check::prepare_bypassing_bench::<T>(new_code.clone());
182
183 #[extrinsic_call]
184 _(RawOrigin::Root, new_code);
185 }
186
187 #[benchmark]
188 fn poke_unused_validation_code() {
189 let code_hash = [0; 32].into();
190
191 #[extrinsic_call]
192 _(RawOrigin::Root, code_hash);
193 }
194
195 #[benchmark]
196 fn include_pvf_check_statement() {
197 let (stmt, signature) = pvf_check::prepare_inclusion_bench::<T>();
198
199 #[block]
200 {
201 let _ =
202 Pallet::<T>::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature);
203 }
204 }
205
206 #[benchmark]
207 fn include_pvf_check_statement_finalize_upgrade_accept() {
208 let (stmt, signature) =
209 pvf_check::prepare_finalization_bench::<T>(VoteCause::Upgrade, VoteOutcome::Accept);
210
211 #[block]
212 {
213 let _ =
214 Pallet::<T>::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature);
215 }
216 }
217
218 #[benchmark]
219 fn include_pvf_check_statement_finalize_upgrade_reject() {
220 let (stmt, signature) =
221 pvf_check::prepare_finalization_bench::<T>(VoteCause::Upgrade, VoteOutcome::Reject);
222
223 #[block]
224 {
225 let _ =
226 Pallet::<T>::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature);
227 }
228 }
229
230 #[benchmark]
231 fn include_pvf_check_statement_finalize_onboarding_accept() {
232 let (stmt, signature) =
233 pvf_check::prepare_finalization_bench::<T>(VoteCause::Onboarding, VoteOutcome::Accept);
234
235 #[block]
236 {
237 let _ =
238 Pallet::<T>::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature);
239 }
240 }
241
242 #[benchmark]
243 fn include_pvf_check_statement_finalize_onboarding_reject() {
244 let (stmt, signature) =
245 pvf_check::prepare_finalization_bench::<T>(VoteCause::Onboarding, VoteOutcome::Reject);
246
247 #[block]
248 {
249 let _ =
250 Pallet::<T>::include_pvf_check_statement(RawOrigin::None.into(), stmt, signature);
251 }
252 }
253
254 #[benchmark]
255 fn remove_upgrade_cooldown() -> Result<(), BenchmarkError> {
256 let para_id = ParaId::from(1000);
257 let old_code_hash = ValidationCode(vec![0]).hash();
258 CurrentCodeHash::<T>::insert(¶_id, old_code_hash);
259 frame_system::Pallet::<T>::set_block_number(10u32.into());
260 let inclusion = frame_system::Pallet::<T>::block_number().saturating_add(10u32.into());
261 let config = HostConfiguration::<BlockNumberFor<T>>::default();
262 Pallet::<T>::schedule_code_upgrade(
263 para_id,
264 ValidationCode(vec![0u8; MIN_CODE_SIZE as usize]),
265 inclusion,
266 &config,
267 UpgradeStrategy::SetGoAheadSignal,
268 );
269
270 let who: T::AccountId = whitelisted_caller();
271
272 T::Fungible::mint_into(
273 &who,
274 T::CooldownRemovalMultiplier::get().saturating_mul(1_000_000u32.into()),
275 )?;
276
277 #[extrinsic_call]
278 _(RawOrigin::Signed(who), para_id);
279
280 assert_last_event::<T>(Event::UpgradeCooldownRemoved { para_id }.into());
281
282 Ok(())
283 }
284
285 #[benchmark]
286 fn authorize_force_set_current_code_hash() {
287 let para_id = ParaId::from(1000);
288 let code = ValidationCode(vec![0; 32]);
289 let new_code_hash = code.hash();
290 let valid_period = BlockNumberFor::<T>::from(1_000_000_u32);
291 ParaLifecycles::<T>::insert(¶_id, ParaLifecycle::Parachain);
292
293 #[extrinsic_call]
294 _(RawOrigin::Root, para_id, new_code_hash, valid_period);
295
296 assert_last_event::<T>(
297 Event::CodeAuthorized {
298 para_id,
299 code_hash: new_code_hash,
300 expire_at: frame_system::Pallet::<T>::block_number().saturating_add(valid_period),
301 }
302 .into(),
303 );
304 }
305
306 #[benchmark]
307 fn apply_authorized_force_set_current_code(c: Linear<MIN_CODE_SIZE, MAX_CODE_SIZE>) {
308 let code = ValidationCode(vec![0; c as usize]);
309 let para_id = ParaId::from(1000);
310 let expire_at =
311 frame_system::Pallet::<T>::block_number().saturating_add(BlockNumberFor::<T>::from(c));
312 AuthorizedCodeHash::<T>::insert(
313 ¶_id,
314 AuthorizedCodeHashAndExpiry::from((code.hash(), expire_at)),
315 );
316 generate_disordered_pruning::<T>();
317
318 #[extrinsic_call]
319 _(RawOrigin::Root, para_id, code);
320
321 assert_last_event::<T>(Event::CurrentCodeUpdated(para_id).into());
322 }
323
324 impl_benchmark_test_suite!(
325 Pallet,
326 crate::mock::new_test_ext(Default::default()),
327 crate::mock::Test
328 );
329}