diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 2a33262073..eda6b6a489 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1685,7 +1685,7 @@ pub mod pallet { #[pallet::weight(( Weight::from_parts(3_918_000, 0) // TODO: add benchmarks .saturating_add(T::DbWeight::get().writes(1_u64)), - DispatchClass::Operational, + DispatchClass::Normal, Pays::Yes ))] pub fn sudo_set_subnet_owner_hotkey( diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 2a362783ef..6555434757 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -2413,7 +2413,7 @@ mod dispatches { Weight::from_parts(5_711_000, 0) .saturating_add(T::DbWeight::get().reads(0_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)), - DispatchClass::Operational, + DispatchClass::Normal, Pays::Yes ))] pub fn sudo_set_root_claim_threshold( diff --git a/runtime/src/sudo_wrapper.rs b/runtime/src/sudo_wrapper.rs index 154fbcb89d..6ff7ee6ca0 100644 --- a/runtime/src/sudo_wrapper.rs +++ b/runtime/src/sudo_wrapper.rs @@ -1,7 +1,9 @@ use codec::{Decode, DecodeWithMemTracking, Encode}; -use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_support::dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}; use frame_support::traits::IsSubType; use frame_system::Config; +use pallet_shield::AuthorityOriginExt; +use pallet_shield::Call as MevShieldCall; use pallet_sudo::Call as SudoCall; use scale_info::TypeInfo; use sp_runtime::impl_tx_ext_default; @@ -34,12 +36,12 @@ impl SudoTransactionExtension { } } -impl - TransactionExtension<::RuntimeCall> for SudoTransactionExtension +impl TransactionExtension<::RuntimeCall> for SudoTransactionExtension where + T: Config + Send + Sync + TypeInfo + pallet_sudo::Config + pallet_shield::Config, ::RuntimeCall: Dispatchable, ::RuntimeOrigin: AsSystemOriginSigner + Clone, - ::RuntimeCall: IsSubType>, + ::RuntimeCall: IsSubType> + IsSubType>, { const IDENTIFIER: &'static str = "SudoTransactionExtension"; @@ -53,30 +55,73 @@ where &self, origin: ::RuntimeOrigin, call: &::RuntimeCall, - _info: &DispatchInfoOf<::RuntimeCall>, + info: &DispatchInfoOf<::RuntimeCall>, _len: usize, _self_implicit: Self::Implicit, _inherited_implication: &impl Implication, _source: TransactionSource, ) -> ValidateResult::RuntimeCall> { - // Ensure the transaction is signed, else we just skip the extension. - let Some(who) = origin.as_system_origin_signer() else { - return Ok((Default::default(), (), origin)); - }; + // -------------------------------------------------------------------- + // 1) pallet_sudo exception: + // If this is a sudo call, require it be signed by the configured sudo key. + // -------------------------------------------------------------------- + if let Some(_sudo_call) = IsSubType::>::is_sub_type(call) { + // Sudo extrinsics must be signed. + let Some(who) = origin.as_system_origin_signer() else { + return Err(InvalidTransaction::BadSigner.into()); + }; - // Check validity of the signer for sudo call - if let Some(_sudo_call) = IsSubType::>::is_sub_type(call) { let sudo_key = pallet_sudo::pallet::Key::::get(); - // No sudo key configured → reject + // No sudo key configured → reject. let Some(expected_who) = sudo_key else { return Err(InvalidTransaction::BadSigner.into()); }; - // Signer does not match the sudo key → reject + // Signer does not match the sudo key → reject. if *who != expected_who { return Err(InvalidTransaction::BadSigner.into()); } + + // Valid sudo transaction → allow into pool. + return Ok((Default::default(), (), origin)); + } + + // -------------------------------------------------------------------- + // 2) Generic BadOrigin spam prevention for *all pallets*: + // + // Default rule: + // - If DispatchClass is Operational, only allow Root-origin transactions. + // - If a *signed* tx is Operational but NOT Root → reject from the pool. + // + // Remaining exception (Operational but NOT Root-only): + // - MevShield::announce_next_key : must pass T::AuthorityOrigin::ensure_validator(origin) + // -------------------------------------------------------------------- + if info.class == DispatchClass::Operational { + // Always allow true Root origins. + if frame_system::ensure_root(origin.clone()).is_ok() { + return Ok((Default::default(), (), origin)); + } + + // Exception: MevShield::announce_next_key (Operational, but signed-validator origin) + if let Some(mev_call) = IsSubType::>::is_sub_type(call) { + match mev_call { + MevShieldCall::announce_next_key { .. } => { + // Only a current Aura validator may call this. + if T::AuthorityOrigin::ensure_validator(origin.clone()).is_err() { + return Err(InvalidTransaction::BadSigner.into()); + } + return Ok((Default::default(), (), origin)); + } + _ => {} + } + } + + // Default Operational rule: signed Operational txs that aren't Root and aren't + // one of the allowed exceptions are rejected from the pool. + if origin.as_system_origin_signer().is_some() { + return Err(InvalidTransaction::Call.into()); + } } Ok((Default::default(), (), origin))