subspace_runtime/
signed_extensions.rs

1use crate::{Runtime, RuntimeCall, RuntimeConfigs};
2use frame_support::pallet_prelude::Weight;
3use frame_system::pallet_prelude::{OriginFor, RuntimeCallFor};
4use parity_scale_codec::{Decode, Encode};
5use scale_info::TypeInfo;
6use sp_runtime::impl_tx_ext_default;
7use sp_runtime::traits::{
8    AsSystemOriginSigner, DispatchInfoOf, TransactionExtension, ValidateResult,
9};
10use sp_runtime::transaction_validity::{
11    InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
12    ValidTransaction,
13};
14use sp_std::prelude::*;
15use subspace_runtime_primitives::utility::nested_call_iter;
16
17/// Disable balance transfers, if configured in the runtime.
18#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)]
19pub struct DisablePallets;
20
21impl DisablePallets {
22    fn do_validate_unsigned(call: &RuntimeCall) -> TransactionValidity {
23        if matches!(call, RuntimeCall::Domains(_)) && !RuntimeConfigs::enable_domains() {
24            InvalidTransaction::Call.into()
25        } else {
26            Ok(ValidTransaction::default())
27        }
28    }
29
30    fn do_validate_signed(call: &RuntimeCall) -> TransactionValidity {
31        // Disable normal balance transfers.
32        if !RuntimeConfigs::enable_balance_transfers() && contains_balance_transfer(call) {
33            Err(InvalidTransaction::Call.into())
34        } else {
35            Ok(ValidTransaction::default())
36        }
37    }
38}
39
40impl TransactionExtension<RuntimeCall> for DisablePallets {
41    const IDENTIFIER: &'static str = "DisablePallets";
42    type Implicit = ();
43    type Val = ();
44    type Pre = ();
45
46    // TODO: calculate weight for extension
47    fn weight(&self, _call: &RuntimeCall) -> Weight {
48        // there is always one storage read
49        <Runtime as frame_system::Config>::DbWeight::get().reads(1)
50    }
51
52    fn validate(
53        &self,
54        origin: OriginFor<Runtime>,
55        call: &RuntimeCallFor<Runtime>,
56        _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
57        _len: usize,
58        _self_implicit: Self::Implicit,
59        _inherited_implication: &impl Encode,
60        _source: TransactionSource,
61    ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
62        let validity = if origin.as_system_origin_signer().is_some() {
63            Self::do_validate_signed(call)?
64        } else {
65            ValidTransaction::default()
66        };
67
68        Ok((validity, (), origin))
69    }
70
71    impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare);
72
73    fn bare_validate(
74        call: &RuntimeCallFor<Runtime>,
75        _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
76        _len: usize,
77    ) -> TransactionValidity {
78        Self::do_validate_unsigned(call)
79    }
80
81    fn bare_validate_and_prepare(
82        call: &RuntimeCallFor<Runtime>,
83        _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
84        _len: usize,
85    ) -> Result<(), TransactionValidityError> {
86        Self::do_validate_unsigned(call)?;
87        Ok(())
88    }
89}
90
91fn contains_balance_transfer(call: &RuntimeCall) -> bool {
92    for call in nested_call_iter::<Runtime>(call) {
93        // Any other calls might contain nested calls, so we can only return early if we find a
94        // balance transfer call.
95        if let RuntimeCall::Balances(
96            pallet_balances::Call::transfer_allow_death { .. }
97            | pallet_balances::Call::transfer_keep_alive { .. }
98            | pallet_balances::Call::transfer_all { .. },
99        ) = call
100        {
101            return true;
102        }
103    }
104
105    false
106}