pallet_migrations/
benchmarking.rs1#![cfg(feature = "runtime-benchmarks")]
19
20use super::*;
21
22use core::array;
23use frame_benchmarking::{v2::*, BenchmarkError};
24use frame_system::{Pallet as System, RawOrigin};
25use sp_core::Get;
26use sp_crypto_hashing::twox_128;
27use sp_io::{storage, KillStorageResult};
28use sp_runtime::traits::One;
29
30fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
31 frame_system::Pallet::<T>::assert_has_event(generic_event.into());
32}
33
34fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
35 frame_system::Pallet::<T>::assert_last_event(generic_event.into());
36}
37
38#[benchmarks]
39mod benches {
40 use super::*;
41 use frame_support::traits::Hooks;
42
43 #[benchmark]
44 fn onboard_new_mbms() {
45 T::Migrations::set_fail_after(0); assert!(!Cursor::<T>::exists());
47
48 #[block]
49 {
50 Pallet::<T>::onboard_new_mbms();
51 }
52
53 assert_last_event::<T>(Event::UpgradeStarted { migrations: 1 }.into());
54 }
55
56 #[benchmark]
57 fn progress_mbms_none() {
58 T::Migrations::set_fail_after(0); assert!(!Cursor::<T>::exists());
60
61 #[block]
62 {
63 Pallet::<T>::progress_mbms(One::one());
64 }
65 }
66
67 #[benchmark]
69 fn exec_migration_completed() -> Result<(), BenchmarkError> {
70 T::Migrations::set_fail_after(0); assert_eq!(T::Migrations::len(), 1, "Setup failed");
72 let c = ActiveCursor { index: 1, inner_cursor: None, started_at: 0u32.into() };
73 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
74 System::<T>::set_block_number(1u32.into());
75
76 #[block]
77 {
78 Pallet::<T>::exec_migration(c, false, &mut meter);
79 }
80
81 assert_last_event::<T>(Event::UpgradeCompleted {}.into());
82
83 Ok(())
84 }
85
86 #[benchmark]
88 fn exec_migration_skipped_historic() -> Result<(), BenchmarkError> {
89 T::Migrations::set_fail_after(0); assert_eq!(T::Migrations::len(), 1, "Setup failed");
91 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
92
93 let id: IdentifierOf<T> = T::Migrations::nth_id(0).unwrap().try_into().unwrap();
94 Historic::<T>::insert(id, ());
95
96 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
97 System::<T>::set_block_number(1u32.into());
98
99 #[block]
100 {
101 Pallet::<T>::exec_migration(c, false, &mut meter);
102 }
103
104 assert_last_event::<T>(Event::MigrationSkipped { index: 0 }.into());
105
106 Ok(())
107 }
108
109 #[benchmark]
111 fn exec_migration_advance() -> Result<(), BenchmarkError> {
112 T::Migrations::set_success_after(1);
113 assert_eq!(T::Migrations::len(), 1, "Setup failed");
114 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
115 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
116 System::<T>::set_block_number(1u32.into());
117
118 #[block]
119 {
120 Pallet::<T>::exec_migration(c, false, &mut meter);
121 }
122
123 assert_last_event::<T>(Event::MigrationAdvanced { index: 0, took: One::one() }.into());
124
125 Ok(())
126 }
127
128 #[benchmark]
130 fn exec_migration_complete() -> Result<(), BenchmarkError> {
131 T::Migrations::set_success_after(0);
132 assert_eq!(T::Migrations::len(), 1, "Setup failed");
133 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
134 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
135 System::<T>::set_block_number(1u32.into());
136
137 #[block]
138 {
139 Pallet::<T>::exec_migration(c, false, &mut meter);
140 }
141
142 assert_last_event::<T>(Event::MigrationCompleted { index: 0, took: One::one() }.into());
143
144 Ok(())
145 }
146
147 #[benchmark]
148 fn exec_migration_fail() -> Result<(), BenchmarkError> {
149 T::Migrations::set_fail_after(0);
150 assert_eq!(T::Migrations::len(), 1, "Setup failed");
151 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
152 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
153 System::<T>::set_block_number(1u32.into());
154
155 #[block]
156 {
157 Pallet::<T>::exec_migration(c, false, &mut meter);
158 }
159
160 assert_has_event::<T>(Event::UpgradeFailed {}.into());
161
162 Ok(())
163 }
164
165 #[benchmark]
166 fn on_init_loop() {
167 T::Migrations::set_fail_after(0); System::<T>::set_block_number(1u32.into());
169 <Pallet<T> as Hooks<BlockNumberFor<T>>>::on_runtime_upgrade();
170
171 #[block]
172 {
173 Pallet::<T>::on_initialize(1u32.into());
174 }
175 }
176
177 #[benchmark]
178 fn force_set_cursor() {
179 #[extrinsic_call]
180 _(RawOrigin::Root, Some(cursor::<T>()));
181 }
182
183 #[benchmark]
184 fn force_set_active_cursor() {
185 #[extrinsic_call]
186 _(RawOrigin::Root, 0, None, None);
187 }
188
189 #[benchmark]
190 fn force_onboard_mbms() {
191 #[extrinsic_call]
192 _(RawOrigin::Root);
193 }
194
195 #[benchmark]
196 fn clear_historic(n: Linear<0, { DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 }>) {
197 let id_max_len = <T as Config>::IdentifierMaxLen::get();
198 assert!(id_max_len >= 4, "Precondition violated");
199
200 for i in 0..DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 {
201 let id = IdentifierOf::<T>::truncate_from(
202 i.encode().into_iter().cycle().take(id_max_len as usize).collect::<Vec<_>>(),
203 );
204
205 Historic::<T>::insert(&id, ());
206 }
207
208 #[extrinsic_call]
209 _(
210 RawOrigin::Root,
211 HistoricCleanupSelector::Wildcard { limit: n.into(), previous_cursor: None },
212 );
213 }
214
215 #[benchmark(skip_meta, pov_mode = Measured)]
216 fn reset_pallet_migration(n: Linear<0, 2048>) -> Result<(), BenchmarkError> {
217 let prefix: [u8; 16] = twox_128(b"__ResetPalletBenchmarkPrefix__");
218
219 for i in 0..n {
220 let mut iter = prefix.into_iter().chain(i.to_le_bytes());
222 let key: [u8; 20] = array::from_fn(|_| iter.next().unwrap());
223 storage::set(&key, &[0u8; 32]);
226 }
227
228 let result;
229 #[block]
230 {
231 result = storage::clear_prefix(&prefix, None);
232 }
233
234 match result {
238 KillStorageResult::AllRemoved(_i) => {
239 #[cfg(not(test))]
241 ensure!(_i == n, "Not all keys are removed");
242 },
243 _ => Err("Not all keys were removed")?,
244 }
245
246 Ok(())
247 }
248
249 fn cursor<T: Config>() -> CursorOf<T> {
250 MigrationCursor::Active(ActiveCursor {
255 index: u32::MAX,
256 inner_cursor: None,
257 started_at: 0u32.into(),
258 })
259 }
260
261 impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
264}