subspace_runtime/
signed_extensions.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
use crate::{Runtime, RuntimeCall, RuntimeConfigs};
use codec::{Decode, Encode};
use frame_support::pallet_prelude::Weight;
use frame_system::pallet_prelude::{OriginFor, RuntimeCallFor};
use scale_info::TypeInfo;
use sp_runtime::impl_tx_ext_default;
use sp_runtime::traits::{
    AsSystemOriginSigner, DispatchInfoOf, TransactionExtension, ValidateResult,
};
use sp_runtime::transaction_validity::{
    InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
    ValidTransaction,
};
use sp_std::prelude::*;
use subspace_runtime_primitives::utility::nested_utility_call_iter;

/// Disable balance transfers, if configured in the runtime.
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)]
pub struct DisablePallets;

impl DisablePallets {
    fn do_validate_unsigned(call: &RuntimeCall) -> TransactionValidity {
        if matches!(call, RuntimeCall::Domains(_)) && !RuntimeConfigs::enable_domains() {
            InvalidTransaction::Call.into()
        } else {
            Ok(ValidTransaction::default())
        }
    }

    fn do_validate_signed(call: &RuntimeCall) -> TransactionValidity {
        // Disable normal balance transfers.
        if !RuntimeConfigs::enable_balance_transfers() && contains_balance_transfer(call) {
            Err(InvalidTransaction::Call.into())
        } else {
            Ok(ValidTransaction::default())
        }
    }
}

impl TransactionExtension<RuntimeCall> for DisablePallets {
    const IDENTIFIER: &'static str = "DisablePallets";
    type Implicit = ();
    type Val = ();
    type Pre = ();

    // TODO: calculate weight for extension
    fn weight(&self, _call: &RuntimeCall) -> Weight {
        // there is always one storage read
        <Runtime as frame_system::Config>::DbWeight::get().reads(1)
    }

    fn validate(
        &self,
        origin: OriginFor<Runtime>,
        call: &RuntimeCallFor<Runtime>,
        _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
        _len: usize,
        _self_implicit: Self::Implicit,
        _inherited_implication: &impl Encode,
        _source: TransactionSource,
    ) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
        let validity = if origin.as_system_origin_signer().is_some() {
            Self::do_validate_signed(call)?
        } else {
            ValidTransaction::default()
        };

        Ok((validity, (), origin))
    }

    impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare);

    fn bare_validate(
        call: &RuntimeCallFor<Runtime>,
        _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
        _len: usize,
    ) -> TransactionValidity {
        Self::do_validate_unsigned(call)
    }

    fn bare_validate_and_prepare(
        call: &RuntimeCallFor<Runtime>,
        _info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
        _len: usize,
    ) -> Result<(), TransactionValidityError> {
        Self::do_validate_unsigned(call)?;
        Ok(())
    }
}

fn contains_balance_transfer(call: &RuntimeCall) -> bool {
    for call in nested_utility_call_iter::<Runtime>(call) {
        // Other calls are inconclusive, they might contain nested calls
        if let RuntimeCall::Balances(
            pallet_balances::Call::transfer_allow_death { .. }
            | pallet_balances::Call::transfer_keep_alive { .. }
            | pallet_balances::Call::transfer_all { .. },
        ) = call
        {
            return true;
        }
    }

    false
}