subspace_runtime_primitives/
utility.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Runtime primitives for pallet-utility.

use core::marker::PhantomData;
use frame_support::pallet_prelude::TypeInfo;
use frame_system::pallet_prelude::RuntimeCallFor;
use scale_info::prelude::collections::VecDeque;
use scale_info::prelude::vec;
use sp_runtime::traits::{BlockNumberProvider, Get};
use sp_runtime::Vec;

/// Trait used to convert from a generated `RuntimeCall` type to `pallet_utility::Call<Runtime>`.
pub trait MaybeUtilityCall<Runtime>
where
    Runtime: pallet_utility::Config,
    for<'call> &'call RuntimeCallFor<Runtime>:
        From<&'call <Runtime as pallet_utility::Config>::RuntimeCall>,
{
    /// If this call is a `pallet_utility::Call<Runtime>` call, returns the inner `pallet_utility::Call`.
    fn maybe_utility_call(&self) -> Option<&pallet_utility::Call<Runtime>>;

    /// If this call is a `pallet_utility::Call<Runtime>` call, returns the inner `RuntimeCall`.
    ///
    /// Runtimes can override this default implementation if they want to ignore (or not ignore)
    /// certain utility calls. For example, a stack limit check shouldn't ignore `Call::__Ignore`.
    fn maybe_nested_utility_calls(&self) -> Option<Vec<&RuntimeCallFor<Runtime>>> {
        if let Some(call) = self.maybe_utility_call() {
            match call {
                pallet_utility::Call::batch { calls }
                | pallet_utility::Call::batch_all { calls }
                | pallet_utility::Call::force_batch { calls } => {
                    Some(calls.iter().map(Into::into).collect())
                }
                pallet_utility::Call::as_derivative { call, .. }
                | pallet_utility::Call::dispatch_as { call, .. }
                | pallet_utility::Call::with_weight { call, .. } => {
                    Some(vec![call.as_ref().into()])
                }
                pallet_utility::Call::__Ignore(..) => None,
            }
        } else {
            None
        }
    }
}

/// Trait used to convert from a generated `RuntimeCall` type to `pallet_multisig::Call<Runtime>`.
pub trait MaybeMultisigCall<Runtime>
where
    Runtime: pallet_multisig::Config,
    for<'call> &'call RuntimeCallFor<Runtime>:
        From<&'call <Runtime as pallet_multisig::Config>::RuntimeCall>,
{
    /// If this call is a `pallet_multisig::Call<Runtime>` call, returns the inner `pallet_multisig::Call`.
    fn maybe_multisig_call(&self) -> Option<&pallet_multisig::Call<Runtime>>;

    /// If this call is a `pallet_multisig::Call<Runtime>` call, returns the inner `RuntimeCall`.
    ///
    /// Runtimes can override this default implementation if they want to ignore (or not ignore)
    /// certain multisig calls.
    fn maybe_nested_multisig_calls(&self) -> Option<Vec<&RuntimeCallFor<Runtime>>> {
        if let Some(call) = self.maybe_multisig_call() {
            match call {
                pallet_multisig::Call::as_multi { call, .. }
                | pallet_multisig::Call::as_multi_threshold_1 { call, .. } => Some(vec![call.as_ref().into()]),
                // Doesn't contain any actual calls
                pallet_multisig::Call::approve_as_multi {  .. }
                | pallet_multisig::Call::cancel_as_multi { .. }
                // Ignored calls
                | pallet_multisig::Call::__Ignore(..) => None,
            }
        } else {
            None
        }
    }
}

/// Trait used to extract nested `RuntimeCall`s from a `RuntimeCall` type.
/// Each runtime has a different set of pallets which can nest calls.
pub trait MaybeNestedCall<Runtime: frame_system::Config> {
    /// If this call is a nested runtime call, returns the inner call(s).
    ///
    /// Ignored calls (such as `pallet_utility::Call::__Ignore`) should be yielded themsevles, but
    /// their contents should not be yielded.
    fn maybe_nested_call(&self) -> Option<Vec<&RuntimeCallFor<Runtime>>>;
}

/// Returns an interator over `call`, and any calls nested within it.
///
/// The iterator yields all calls in depth-first order, including calls which contain other calls.
/// Ignored calls (such as `pallet_utility::Call::__Ignore`) are yielded themsevles, but their
/// contents are not.
///
/// This function doesn't use stack recursion, so there's no need to check the recursion depth.
pub fn nested_call_iter<Runtime>(
    call: &RuntimeCallFor<Runtime>,
) -> impl Iterator<Item = &RuntimeCallFor<Runtime>>
where
    Runtime: frame_system::Config,
    RuntimeCallFor<Runtime>: MaybeNestedCall<Runtime>,
{
    // Instead of using recursion, we allocate references to each call on the heap.
    let mut new_calls = VecDeque::from([call]);

    core::iter::from_fn(move || {
        let call = new_calls.pop_front()?;

        for call in call.maybe_nested_call().into_iter().flatten() {
            new_calls.push_front(call);
        }

        Some(call)
    })
}

// `DefaultNonceProvider` uses the current block number as the nonce of the new account,
// this is used to prevent the replay attack see https://wiki.polkadot.network/docs/transaction-attacks#replay-attack
// for more detail.
#[derive(Debug, TypeInfo)]
pub struct DefaultNonceProvider<T, N>(PhantomData<(T, N)>);

impl<N, T: BlockNumberProvider<BlockNumber = N>> Get<N> for DefaultNonceProvider<T, N> {
    fn get() -> N {
        T::current_block_number()
    }
}