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()
}
}