frame_support/traits/hooks.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//! Traits relating to pallet hooks.
19//!
20//! See [`Hooks`] as the main entry-point.
21
22#![deny(missing_docs)]
23
24use crate::{impl_for_tuples_attr, weights::Weight};
25use sp_runtime::traits::AtLeast32BitUnsigned;
26use sp_weights::WeightMeter;
27
28#[cfg(feature = "try-runtime")]
29use alloc::vec::Vec;
30#[cfg(feature = "try-runtime")]
31use sp_runtime::TryRuntimeError;
32
33/// Provides a callback to execute logic before the all inherents.
34pub trait PreInherents {
35 /// Called before all inherents were applied but after `on_initialize`.
36 fn pre_inherents() {}
37}
38
39impl_for_tuples_attr! {
40 impl PreInherents for Tuple {
41 fn pre_inherents() {
42 for_tuples!( #( Tuple::pre_inherents(); )* );
43 }
44 }
45}
46
47/// Provides a callback to execute logic after the all inherents.
48pub trait PostInherents {
49 /// Called after all inherents were applied.
50 fn post_inherents() {}
51}
52
53impl_for_tuples_attr! {
54 impl PostInherents for Tuple {
55 fn post_inherents() {
56 for_tuples!( #( Tuple::post_inherents(); )* );
57 }
58 }
59}
60
61/// Provides a callback to execute logic after the all transactions.
62pub trait PostTransactions {
63 /// Called after all transactions were applied but before `on_finalize`.
64 fn post_transactions() {}
65}
66
67impl_for_tuples_attr! {
68 impl PostTransactions for Tuple {
69 fn post_transactions() {
70 for_tuples!( #( Tuple::post_transactions(); )* );
71 }
72 }
73}
74
75/// Periodically executes logic. Is not guaranteed to run within a specific timeframe and should
76/// only be used on logic that has no deadline.
77pub trait OnPoll<BlockNumber> {
78 /// Code to execute every now and then at the beginning of the block after inherent application.
79 ///
80 /// The remaining weight limit must be respected.
81 fn on_poll(_n: BlockNumber, _weight: &mut WeightMeter) {}
82}
83
84impl_for_tuples_attr! {
85 impl<BlockNumber: Clone> OnPoll<BlockNumber> for Tuple {
86 fn on_poll(n: BlockNumber, weight: &mut WeightMeter) {
87 for_tuples!( #( Tuple::on_poll(n.clone(), weight); )* );
88 }
89 }
90}
91
92/// See [`Hooks::on_initialize`].
93pub trait OnInitialize<BlockNumber> {
94 /// See [`Hooks::on_initialize`].
95 fn on_initialize(_n: BlockNumber) -> Weight {
96 Weight::zero()
97 }
98}
99
100impl_for_tuples_attr! {
101 impl<BlockNumber: Clone> OnInitialize<BlockNumber> for Tuple {
102 fn on_initialize(n: BlockNumber) -> Weight {
103 let mut weight = Weight::zero();
104 for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(n.clone())); )* );
105 weight
106 }
107 }
108}
109
110impl_for_tuples_attr! {
111 /// See [`Hooks::on_finalize`].
112 pub trait OnFinalize<BlockNumber> {
113 /// See [`Hooks::on_finalize`].
114 fn on_finalize(_n: BlockNumber) {}
115 }
116}
117
118/// See [`Hooks::on_idle`].
119pub trait OnIdle<BlockNumber> {
120 /// See [`Hooks::on_idle`].
121 fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight {
122 Weight::zero()
123 }
124}
125
126impl_for_tuples_attr! {
127 impl<BlockNumber: Copy + AtLeast32BitUnsigned> OnIdle<BlockNumber> for Tuple {
128 fn on_idle(n: BlockNumber, remaining_weight: Weight) -> Weight {
129 let on_idle_functions: &[fn(BlockNumber, Weight) -> Weight] =
130 &[for_tuples!( #( Tuple::on_idle ),* )];
131
132 let mut weight = Weight::zero();
133 let len = on_idle_functions.len();
134
135 if len == 0 {
136 return Weight::zero()
137 }
138
139 let start_index = n % (len as u32).into();
140 let start_index = start_index.try_into().ok().expect(
141 "`start_index % len` always fits into `usize`, because `len` can be in maximum `usize::MAX`; qed"
142 );
143 for on_idle_fn in on_idle_functions.iter().cycle().skip(start_index).take(len) {
144 let adjusted_remaining_weight = remaining_weight.saturating_sub(weight);
145 weight = weight.saturating_add(on_idle_fn(n, adjusted_remaining_weight));
146 }
147 weight
148 }
149 }
150}
151
152impl_for_tuples_attr! {
153 /// A trait that will be called at genesis.
154 ///
155 /// Implementing this trait for a pallet let's you express operations that should
156 /// happen at genesis. It will be called in an externalities provided environment and
157 /// will set the genesis state after all pallets have written their genesis state.
158 pub trait OnGenesis {
159 /// Something that should happen at genesis.
160 fn on_genesis() {}
161 }
162}
163
164/// Implemented by pallets, allows defining logic to run prior to any [`OnRuntimeUpgrade`] logic.
165///
166/// This hook is intended to be used internally in FRAME and not be exposed to FRAME developers.
167///
168/// It is defined as a separate trait from [`OnRuntimeUpgrade`] precisely to not pollute the public
169/// API.
170pub trait BeforeAllRuntimeMigrations {
171 /// Something that should happen before runtime migrations are executed.
172 fn before_all_runtime_migrations() -> Weight {
173 Weight::zero()
174 }
175}
176
177/// See [`Hooks::on_runtime_upgrade`].
178pub trait OnRuntimeUpgrade {
179 /// See [`Hooks::on_runtime_upgrade`].
180 fn on_runtime_upgrade() -> Weight {
181 Weight::zero()
182 }
183
184 /// The expected and default behavior of this method is to handle executing `pre_upgrade` ->
185 /// `on_runtime_upgrade` -> `post_upgrade` hooks for a migration.
186 ///
187 /// Internally, the default implementation
188 /// - Handles passing data from `pre_upgrade` to `post_upgrade`
189 /// - Ensure storage is not modified in `pre_upgrade` and `post_upgrade` hooks.
190 ///
191 /// Combining the `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` logic flow into a
192 /// single method call is helpful for scenarios like testing a tuple of migrations, where the
193 /// tuple contains order-dependent migrations.
194 #[cfg(feature = "try-runtime")]
195 fn try_on_runtime_upgrade(checks: bool) -> Result<Weight, TryRuntimeError> {
196 let maybe_state = if checks {
197 let _guard = frame_support::StorageNoopGuard::default();
198 let state = Self::pre_upgrade()?;
199 Some(state)
200 } else {
201 None
202 };
203
204 let weight = Self::on_runtime_upgrade();
205
206 if let Some(state) = maybe_state {
207 let _guard = frame_support::StorageNoopGuard::default();
208 // we want to panic if any checks fail right here right now.
209 Self::post_upgrade(state)?
210 }
211
212 Ok(weight)
213 }
214
215 /// See [`Hooks::pre_upgrade`].
216 #[cfg(feature = "try-runtime")]
217 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
218 Ok(Vec::new())
219 }
220
221 /// See [`Hooks::post_upgrade`].
222 #[cfg(feature = "try-runtime")]
223 fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
224 Ok(())
225 }
226}
227
228/// This trait is intended for use within `VersionedMigration` to execute storage migrations without
229/// automatic version checks. Implementations should ensure migration logic is safe and idempotent.
230pub trait UncheckedOnRuntimeUpgrade {
231 /// Called within `VersionedMigration` to execute the actual migration. It is also
232 /// expected that no version checks are performed within this function.
233 ///
234 /// See also [`Hooks::on_runtime_upgrade`].
235 fn on_runtime_upgrade() -> Weight {
236 Weight::zero()
237 }
238
239 /// See [`Hooks::pre_upgrade`].
240 #[cfg(feature = "try-runtime")]
241 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
242 Ok(Vec::new())
243 }
244
245 /// See [`Hooks::post_upgrade`].
246 #[cfg(feature = "try-runtime")]
247 fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
248 Ok(())
249 }
250}
251
252impl_for_tuples_attr! {
253 impl BeforeAllRuntimeMigrations for Tuple {
254 /// Implements the default behavior of
255 /// [`BeforeAllRuntimeMigrations::before_all_runtime_migrations`] for tuples.
256 fn before_all_runtime_migrations() -> Weight {
257 let mut weight = Weight::zero();
258 for_tuples!( #( weight = weight.saturating_add(Tuple::before_all_runtime_migrations()); )* );
259 weight
260 }
261 }
262}
263
264impl_for_tuples_attr! {
265 impl OnRuntimeUpgrade for Tuple {
266 /// Implements the default behavior of [`OnRuntimeUpgrade::on_runtime_upgrade`] for tuples.
267 fn on_runtime_upgrade() -> Weight {
268 let mut weight = Weight::zero();
269 for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* );
270 weight
271 }
272
273 /// Implements the default behavior of `try_on_runtime_upgrade` for tuples, logging any errors
274 /// that occur.
275 #[cfg(feature = "try-runtime")]
276 fn try_on_runtime_upgrade(checks: bool) -> Result<Weight, TryRuntimeError> {
277 let mut cumulative_weight = Weight::zero();
278
279 let mut errors = Vec::new();
280
281 for_tuples!(#(
282 match Tuple::try_on_runtime_upgrade(checks) {
283 Ok(weight) => { cumulative_weight.saturating_accrue(weight); },
284 Err(err) => { errors.push(err); },
285 }
286 )*);
287
288 if errors.len() == 1 {
289 return Err(errors[0])
290 } else if !errors.is_empty() {
291 log::error!(
292 target: "try-runtime",
293 "Detected multiple errors while executing `try_on_runtime_upgrade`:",
294 );
295
296 errors.iter().for_each(|err| {
297 log::error!(
298 target: "try-runtime",
299 "{:?}",
300 err
301 );
302 });
303
304 return Err("Detected multiple errors while executing `try_on_runtime_upgrade`, check the logs!".into())
305 }
306
307 Ok(cumulative_weight)
308 }
309
310 /// [`OnRuntimeUpgrade::pre_upgrade`] should not be used on a tuple.
311 ///
312 /// Instead, implementors should use [`OnRuntimeUpgrade::try_on_runtime_upgrade`] which
313 /// internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple
314 /// member in sequence, enabling testing of order-dependent migrations.
315 #[cfg(feature = "try-runtime")]
316 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
317 Err("Usage of `pre_upgrade` with Tuples is not expected. Please use `try_on_runtime_upgrade` instead, which internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple member.".into())
318 }
319
320 /// [`OnRuntimeUpgrade::post_upgrade`] should not be used on a tuple.
321 ///
322 /// Instead, implementors should use [`OnRuntimeUpgrade::try_on_runtime_upgrade`] which
323 /// internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple
324 /// member in sequence, enabling testing of order-dependent migrations.
325 #[cfg(feature = "try-runtime")]
326 fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
327 Err("Usage of `post_upgrade` with Tuples is not expected. Please use `try_on_runtime_upgrade` instead, which internally calls `pre_upgrade` -> `on_runtime_upgrade` -> `post_upgrade` for each tuple member.".into())
328 }
329 }
330}
331
332impl_for_tuples_attr! {
333 /// See [`Hooks::integrity_test`].
334 pub trait IntegrityTest {
335 /// See [`Hooks::integrity_test`].
336 fn integrity_test() {}
337 }
338}
339
340#[cfg_attr(doc, aquamarine::aquamarine)]
341/// The pallet hooks trait. This is merely an umbrella trait for:
342///
343/// - [`OnInitialize`]
344/// - [`OnFinalize`]
345/// - [`OnRuntimeUpgrade`]
346/// - [`crate::traits::misc::OffchainWorker`]
347/// - [`OnIdle`]
348/// - [`IntegrityTest`]
349/// - [`OnPoll`]
350///
351/// ## Ordering
352///
353/// For all hooks, except [`OnIdle`] the order of execution is derived from how the pallets are
354/// ordered in [`crate::construct_runtime`].
355///
356/// ## Summary
357///
358/// In short, the following diagram shows the flow of hooks in a pallet
359///
360/// ```mermaid
361/// graph LR
362/// Optional --> Mandatory
363/// Mandatory --> ExtrinsicsMandatory
364/// ExtrinsicsMandatory --> Poll
365/// Poll --> Extrinsics
366/// Extrinsics --> AfterMandatory
367/// AfterMandatory --> onIdle
368///
369/// subgraph Optional
370/// OnRuntimeUpgrade
371/// end
372///
373/// subgraph Mandatory
374/// OnInitialize
375/// end
376///
377/// subgraph ExtrinsicsMandatory
378/// Inherent1 --> Inherent2
379/// end
380///
381/// subgraph Extrinsics
382/// direction TB
383/// Extrinsic1 --> Extrinsic2
384/// end
385///
386/// subgraph AfterMandatory
387/// OnFinalize
388/// end
389/// ```
390///
391/// * [`OnRuntimeUpgrade`](Hooks::OnRuntimeUpgrade) hooks are only executed when a code change is
392/// detected.
393/// * [`OnRuntimeUpgrade`](Hooks::OnRuntimeUpgrade) hooks are mandatorily executed at the very
394/// beginning of the block body, before any extrinsics are processed.
395/// * [`Inherents`](sp_inherents) are always executed before any other other signed or unsigned
396/// extrinsics.
397/// * [`OnIdle`](Hooks::OnIdle) hooks are executed after extrinsics if there is weight remaining in
398/// the block.
399/// * [`OnFinalize`](Hooks::OnFinalize) hooks are mandatorily executed after
400/// [`OnIdle`](Hooks::OnIdle).
401///
402/// > [`OffchainWorker`](crate::traits::misc::OffchainWorker) hooks are not part of this flow,
403/// > because they are not part of the consensus/main block building logic. See
404/// > [`OffchainWorker`](crate::traits::misc::OffchainWorker) for more information.
405///
406/// To learn more about the execution of hooks see the FRAME `Executive` pallet which is in charge
407/// of dispatching extrinsics and calling hooks in the correct order.
408pub trait Hooks<BlockNumber> {
409 /// Block initialization hook. This is called at the very beginning of block execution.
410 ///
411 /// Must return the non-negotiable weight of both itself and whatever [`Hooks::on_finalize`]
412 /// wishes to consume.
413 ///
414 /// ## Warning
415 ///
416 /// The weight returned by this is treated as `DispatchClass::Mandatory`, meaning that
417 /// it MUST BE EXECUTED. If this is not the case, consider using [`Hooks::on_idle`] instead.
418 ///
419 /// Try to keep any arbitrary execution __deterministic__ and within __minimal__ time
420 /// complexity. For example, do not execute any unbounded iterations.
421 ///
422 /// NOTE: This function is called BEFORE ANY extrinsic in a block is applied, including inherent
423 /// extrinsics. Hence for instance, if you runtime includes `pallet-timestamp`, the `timestamp`
424 /// is not yet up to date at this point.
425 fn on_initialize(_n: BlockNumber) -> Weight {
426 Weight::zero()
427 }
428
429 /// Block finalization hook. This is called at the very end of block execution.
430 ///
431 /// Note that this has nothing to do with finality in the "consensus" sense.
432 ///
433 /// Note that the non-negotiable weight for this has must have already been returned by
434 /// [`Hooks::on_initialize`]. It usage alone is not permitted.
435 ///
436 /// Similar to [`Hooks::on_initialize`] it should only be used when execution is absolutely
437 /// necessary. In other cases, consider using [`Hooks::on_idle`] instead.
438 fn on_finalize(_n: BlockNumber) {}
439
440 /// Hook to consume a block's idle time. This will run when the block is being finalized (before
441 /// [`Hooks::on_finalize`]).
442 ///
443 /// Given that all dispatchables are already executed and noted (and the weight for
444 /// [`Hooks::on_finalize`], which comes next, is also already accounted for via
445 /// `on_initialize`), this hook consumes anything that is leftover.
446 ///
447 /// Each pallet's `on_idle` is chosen to be the first to execute in a round-robin fashion
448 /// indexed by the block number.
449 ///
450 /// Return the weight used, the caller will use this to calculate the remaining weight and then
451 /// call the next pallet `on_idle` hook if there is still weight left.
452 ///
453 /// Any implementation should always respect `_remaining_weight` and never consume (and
454 /// therefore return) more than this amount.
455 fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight {
456 Weight::zero()
457 }
458
459 /// A hook to run logic after inherent application.
460 ///
461 /// Is not guaranteed to execute in a block and should therefore only be used in no-deadline
462 /// scenarios.
463 ///
464 /// This is the non-mandatory version of [`Hooks::on_initialize`].
465 fn on_poll(_n: BlockNumber, _weight: &mut WeightMeter) {}
466
467 /// Hook executed when a code change (aka. a "runtime upgrade") is detected by the FRAME
468 /// `Executive` pallet.
469 ///
470 /// Be aware that this is called before [`Hooks::on_initialize`] of any pallet; therefore, a lot
471 /// of the critical storage items such as `block_number` in system pallet might have not been
472 /// set yet.
473 ///
474 /// Similar to [`Hooks::on_initialize`], any code in this block is mandatory and MUST execute.
475 /// It is strongly recommended to dry-run the execution of these hooks using
476 /// [try-runtime-cli](https://github.com/paritytech/try-runtime-cli) to ensure they will not
477 /// produce and overweight block which can brick your chain. Use with care!
478 ///
479 /// ## Implementation Note: Standalone Migrations
480 ///
481 /// Additional migrations can be created by directly implementing [`OnRuntimeUpgrade`] on
482 /// structs and passing them to `Executive`. Or alternatively, by implementing
483 /// [`UncheckedOnRuntimeUpgrade`], passing it to [`crate::migrations::VersionedMigration`],
484 /// which already implements [`OnRuntimeUpgrade`].
485 ///
486 /// ## Implementation Note: Pallet Versioning
487 ///
488 /// Implementations of this hook are typically wrapped in
489 /// [`crate::migrations::VersionedMigration`] to ensure the migration is executed exactly
490 /// once and only when it is supposed to.
491 ///
492 /// Alternatively, developers can manually implement version checks.
493 ///
494 /// Failure to adequately check storage versions can result in accidental repetitive execution
495 /// of the hook, which can be catastrophic.
496 ///
497 /// ## Implementation Note: Weight
498 ///
499 /// Typically, implementations of this method are simple enough that weights can be calculated
500 /// manually. However, if required, a benchmark can also be used.
501 fn on_runtime_upgrade() -> Weight {
502 Weight::zero()
503 }
504
505 /// Execute the sanity checks of this pallet, per block.
506 ///
507 /// It should focus on certain checks to ensure that the state is sensible. This is never
508 /// executed in a consensus code-path, therefore it can consume as much weight as it needs.
509 ///
510 /// This hook must not alter any storage.
511 #[cfg(feature = "try-runtime")]
512 fn try_state(_n: BlockNumber) -> Result<(), TryRuntimeError> {
513 Ok(())
514 }
515
516 /// Execute some pre-checks prior to a runtime upgrade.
517 ///
518 /// Return a `Vec<u8>` that can contain arbitrary encoded data (usually some pre-upgrade state),
519 /// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector
520 /// should be returned if there is no such need.
521 ///
522 /// This hook is never executed on-chain but instead used by testing tools.
523 #[cfg(feature = "try-runtime")]
524 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
525 Ok(Vec::new())
526 }
527
528 /// Execute some post-checks after a runtime upgrade.
529 ///
530 /// The `state` parameter is the `Vec<u8>` returned by `pre_upgrade` before upgrading, which
531 /// can be used for post-check. NOTE: if `pre_upgrade` is not implemented an empty vector will
532 /// be passed in, in such case `post_upgrade` should ignore it.
533 ///
534 /// This hook is never meant to be executed on-chain but is meant to be used by testing tools.
535 #[cfg(feature = "try-runtime")]
536 fn post_upgrade(_state: Vec<u8>) -> Result<(), TryRuntimeError> {
537 Ok(())
538 }
539
540 /// Implementing this function on a pallet allows you to perform long-running tasks that are
541 /// dispatched as separate threads, and entirely independent of the main blockchain execution.
542 ///
543 /// This function can freely read from the state, but any change it makes to the state is
544 /// meaningless. Writes can be pushed back to the chain by submitting extrinsics from the
545 /// offchain worker to the transaction pool. See `pallet-example-offchain-worker` for more
546 /// details on this.
547 ///
548 /// Moreover, the code in this function has access to a wider range of host functions in
549 /// [`sp_io`], namely [`sp_io::offchain`]. This includes exotic operations such as HTTP calls
550 /// that are not really possible in the rest of the runtime code.
551 ///
552 /// The execution of this hook is entirely optional and is left at the discretion of the
553 /// node-side software and its configuration. In a normal substrate-cli, look for the CLI
554 /// flags related to offchain-workers to learn more.
555 fn offchain_worker(_n: BlockNumber) {}
556
557 /// Check the integrity of this pallet's configuration.
558 ///
559 /// Any code located in this hook is placed in an auto-generated test, and generated as a part
560 /// of [`crate::construct_runtime`]'s expansion. Look for a test case with a name along the
561 /// lines of: `__construct_runtime_integrity_test`.
562 ///
563 /// This hook is the location where the values/types provided to the `Config` trait
564 /// of the pallet can be tested for correctness. For example, if two `type Foo: Get<u32>` and
565 /// `type Bar: Get<u32>` where `Foo::get()` must always be greater than `Bar::get()`, such
566 /// checks can be asserted upon here.
567 ///
568 /// Note that this hook is executed in an externality environment, provided by
569 /// `sp_io::TestExternalities`. This makes it possible to access the storage.
570 fn integrity_test() {}
571}
572
573/// A trait to define the build function of a genesis config for both runtime and pallets.
574///
575/// Replaces deprecated [`GenesisBuild<T,I>`].
576pub trait BuildGenesisConfig: sp_runtime::traits::MaybeSerializeDeserialize {
577 /// The build function puts initial `GenesisConfig` keys/values pairs into the storage.
578 fn build(&self);
579}
580
581impl BuildGenesisConfig for () {
582 fn build(&self) {}
583}
584
585/// A trait to define the build function of a genesis config, T and I are placeholder for pallet
586/// trait and pallet instance.
587#[deprecated(
588 note = "GenesisBuild is planned to be removed in December 2023. Use BuildGenesisConfig instead of it."
589)]
590pub trait GenesisBuild<T, I = ()>: sp_runtime::traits::MaybeSerializeDeserialize {
591 /// The build function is called within an externalities allowing storage APIs.
592 /// Thus one can write to storage using regular pallet storages.
593 fn build(&self);
594
595 /// Build the storage using `build` inside default storage.
596 #[cfg(feature = "std")]
597 fn build_storage(&self) -> Result<sp_runtime::Storage, String> {
598 let mut storage = Default::default();
599 self.assimilate_storage(&mut storage)?;
600 Ok(storage)
601 }
602
603 /// Assimilate the storage for this module into pre-existing overlays.
604 #[cfg(feature = "std")]
605 fn assimilate_storage(&self, storage: &mut sp_runtime::Storage) -> Result<(), String> {
606 sp_state_machine::BasicExternalities::execute_with_storage(storage, || {
607 self.build();
608 Ok(())
609 })
610 }
611}
612
613impl_for_tuples_attr! {
614 /// A trait which is called when the timestamp is set in the runtime.
615 pub trait OnTimestampSet<Moment> {
616 /// Called when the timestamp is set.
617 fn on_timestamp_set(moment: Moment);
618 }
619}
620
621#[cfg(test)]
622mod tests {
623 use super::*;
624 use crate::parameter_types;
625 use alloc::vec::Vec;
626 use sp_io::TestExternalities;
627
628 #[cfg(feature = "try-runtime")]
629 #[test]
630 fn on_runtime_upgrade_pre_post_executed_tuple() {
631 crate::parameter_types! {
632 pub static Pre: Vec<&'static str> = Default::default();
633 pub static Post: Vec<&'static str> = Default::default();
634 }
635
636 macro_rules! impl_test_type {
637 ($name:ident) => {
638 struct $name;
639 impl OnRuntimeUpgrade for $name {
640 fn on_runtime_upgrade() -> Weight {
641 Default::default()
642 }
643
644 #[cfg(feature = "try-runtime")]
645 fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {
646 Pre::mutate(|s| s.push(stringify!($name)));
647 Ok(Vec::new())
648 }
649
650 #[cfg(feature = "try-runtime")]
651 fn post_upgrade(_: Vec<u8>) -> Result<(), TryRuntimeError> {
652 Post::mutate(|s| s.push(stringify!($name)));
653 Ok(())
654 }
655 }
656 };
657 }
658
659 impl_test_type!(Foo);
660 impl_test_type!(Bar);
661 impl_test_type!(Baz);
662
663 TestExternalities::default().execute_with(|| {
664 // try_on_runtime_upgrade works
665 Foo::try_on_runtime_upgrade(true).unwrap();
666 assert_eq!(Pre::take(), vec!["Foo"]);
667 assert_eq!(Post::take(), vec!["Foo"]);
668
669 <(Foo, Bar, Baz)>::try_on_runtime_upgrade(true).unwrap();
670 assert_eq!(Pre::take(), vec!["Foo", "Bar", "Baz"]);
671 assert_eq!(Post::take(), vec!["Foo", "Bar", "Baz"]);
672
673 <((Foo, Bar), Baz)>::try_on_runtime_upgrade(true).unwrap();
674 assert_eq!(Pre::take(), vec!["Foo", "Bar", "Baz"]);
675 assert_eq!(Post::take(), vec!["Foo", "Bar", "Baz"]);
676
677 <(Foo, (Bar, Baz))>::try_on_runtime_upgrade(true).unwrap();
678 assert_eq!(Pre::take(), vec!["Foo", "Bar", "Baz"]);
679 assert_eq!(Post::take(), vec!["Foo", "Bar", "Baz"]);
680
681 // calling pre_upgrade and post_upgrade directly on tuple of pallets fails
682 assert!(<(Foo, (Bar, Baz))>::pre_upgrade().is_err());
683 assert!(<(Foo, (Bar, Baz))>::post_upgrade(vec![]).is_err());
684 });
685 }
686
687 #[test]
688 fn on_initialize_and_on_runtime_upgrade_weight_merge_works() {
689 struct Test;
690
691 impl OnInitialize<u8> for Test {
692 fn on_initialize(_n: u8) -> Weight {
693 Weight::from_parts(10, 0)
694 }
695 }
696 impl OnRuntimeUpgrade for Test {
697 fn on_runtime_upgrade() -> Weight {
698 Weight::from_parts(20, 0)
699 }
700 }
701
702 TestExternalities::default().execute_with(|| {
703 assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_parts(20, 0));
704 assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_parts(40, 0));
705 });
706 }
707
708 #[test]
709 fn on_idle_round_robin_works() {
710 parameter_types! {
711 static OnIdleInvocationOrder: Vec<&'static str> = Vec::new();
712 }
713
714 struct Test1;
715 struct Test2;
716 struct Test3;
717 type TestTuple = (Test1, Test2, Test3);
718 impl OnIdle<u32> for Test1 {
719 fn on_idle(_n: u32, _weight: Weight) -> Weight {
720 OnIdleInvocationOrder::mutate(|o| o.push("Test1"));
721 Weight::zero()
722 }
723 }
724 impl OnIdle<u32> for Test2 {
725 fn on_idle(_n: u32, _weight: Weight) -> Weight {
726 OnIdleInvocationOrder::mutate(|o| o.push("Test2"));
727 Weight::zero()
728 }
729 }
730 impl OnIdle<u32> for Test3 {
731 fn on_idle(_n: u32, _weight: Weight) -> Weight {
732 OnIdleInvocationOrder::mutate(|o| o.push("Test3"));
733 Weight::zero()
734 }
735 }
736
737 TestTuple::on_idle(0, Weight::zero());
738 assert_eq!(OnIdleInvocationOrder::get(), ["Test1", "Test2", "Test3"].to_vec());
739 OnIdleInvocationOrder::mutate(|o| o.clear());
740
741 TestTuple::on_idle(1, Weight::zero());
742 assert_eq!(OnIdleInvocationOrder::get(), ["Test2", "Test3", "Test1"].to_vec());
743 OnIdleInvocationOrder::mutate(|o| o.clear());
744
745 TestTuple::on_idle(2, Weight::zero());
746 assert_eq!(OnIdleInvocationOrder::get(), ["Test3", "Test1", "Test2"].to_vec());
747 OnIdleInvocationOrder::mutate(|o| o.clear());
748
749 TestTuple::on_idle(3, Weight::zero());
750 assert_eq!(OnIdleInvocationOrder::get(), ["Test1", "Test2", "Test3"].to_vec());
751 OnIdleInvocationOrder::mutate(|o| o.clear());
752
753 TestTuple::on_idle(4, Weight::zero());
754 assert_eq!(OnIdleInvocationOrder::get(), ["Test2", "Test3", "Test1"].to_vec());
755 OnIdleInvocationOrder::mutate(|o| o.clear());
756 }
757}