From 4fda2af73241c7dd07c2d44ef5dd095ffc47ee02 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sat, 28 Mar 2026 11:52:40 -0700 Subject: [PATCH 1/7] add commitment transaction extension --- pallets/commitments/src/lib.rs | 95 ++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index 98e5961708..be7546c508 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -12,16 +12,24 @@ pub mod weights; use ark_serialize::CanonicalDeserialize; use codec::Encode; -use frame_support::IterableStorageDoubleMap; use frame_support::{ - BoundedVec, - traits::{Currency, Get}, + BoundedVec, IterableStorageDoubleMap, + pallet_prelude::{ + Decode, DecodeWithMemTracking, PhantomData, ValidTransaction, ValidateResult, + }, + traits::{Currency, Get, IsSubType}, }; use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; use scale_info::prelude::collections::BTreeSet; -use sp_runtime::SaturatedConversion; -use sp_runtime::{Saturating, Weight, traits::Zero}; +use sp_runtime::{ + SaturatedConversion, Saturating, Weight, + traits::Zero, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, Implication, TransactionExtension, + }, + transaction_validity::{InvalidTransaction, TransactionSource, TransactionValidityError}, +}; use sp_std::{boxed::Box, vec::Vec}; use subtensor_runtime_common::NetUid; use tle::{ @@ -576,6 +584,83 @@ impl Pallet { } } +type CallOf = ::RuntimeCall; +type OriginOf = as Dispatchable>::RuntimeOrigin; + +#[derive(Default, Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct CommitmentsTransactionExtension(PhantomData); + +impl sp_std::fmt::Debug for CommitmentsTransactionExtension { + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "CommitmentsTransactionExtension") + } +} + +impl CommitmentsTransactionExtension +where + T: Config + Send + Sync + TypeInfo, + CallOf: Dispatchable + IsSubType>, +{ + pub fn new() -> Self { + Self(Default::default()) + } +} + +impl TransactionExtension> for CommitmentsTransactionExtension +where + T: Config + Send + Sync + TypeInfo, + CallOf: Dispatchable + IsSubType>, + OriginOf: AsSystemOriginSigner + Clone, +{ + const IDENTIFIER: &'static str = "CommitmentsTransactionExtension"; + + type Implicit = (); + type Val = (); + type Pre = (); + + fn weight(&self, _call: &CallOf) -> Weight { + Weight::from_parts(0, 0) + } + + fn validate( + &self, + origin: OriginOf, + call: &CallOf, + _info: &DispatchInfoOf>, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Implication, + _source: TransactionSource, + ) -> ValidateResult> { + let Some(who) = origin.as_system_origin_signer() else { + return Ok((ValidTransaction::default(), (), origin)); + }; + + match call.is_sub_type() { + Some(pallet::Call::set_commitment { netuid, .. }) => { + if !T::CanCommit::can_commit(*netuid, who) { + return Err(InvalidTransaction::BadSigner.into()); + } + + Ok((ValidTransaction::default(), (), origin)) + } + _ => Ok((ValidTransaction::default(), (), origin)), + } + } + + fn prepare( + self, + _val: Self::Val, + _origin: &OriginOf, + _call: &CallOf, + _info: &DispatchInfoOf>, + _len: usize, + ) -> Result { + Ok(()) + } +} + pub trait GetCommitments { fn get_commitments(netuid: NetUid) -> Vec<(AccountId, Vec)>; } From 7ffa5a75075bc34b1eaa01d57eb54123a983f5df Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sat, 28 Mar 2026 11:52:49 -0700 Subject: [PATCH 2/7] plug tx extension into runtime --- runtime/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index ecb8944aa9..f36205385e 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -204,6 +204,7 @@ impl frame_system::offchain::CreateSignedTransaction pallet_shield::CheckShieldedTxValidity::::new(), pallet_subtensor::SubtensorTransactionExtension::::new(), pallet_drand::drand_priority::DrandPriority::::new(), + pallet_commitments::CommitmentsTransactionExtension::::new(), ), frame_metadata_hash_extension::CheckMetadataHash::::new(true), ); @@ -1681,6 +1682,7 @@ pub type CustomTxExtension = ( pallet_shield::CheckShieldedTxValidity, pallet_subtensor::SubtensorTransactionExtension, pallet_drand::drand_priority::DrandPriority, + pallet_commitments::CommitmentsTransactionExtension, ); pub type TxExtension = ( SystemTxExtension, From 4b981421aea47a8a995a2362d89a4bffb1ab06b1 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sat, 28 Mar 2026 11:59:48 -0700 Subject: [PATCH 3/7] add freeze_struct --- pallets/commitments/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index be7546c508..745efc3f7e 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -31,6 +31,7 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionSource, TransactionValidityError}, }; use sp_std::{boxed::Box, vec::Vec}; +use subtensor_macros::freeze_struct; use subtensor_runtime_common::NetUid; use tle::{ curves::drand::TinyBLS381, @@ -589,6 +590,7 @@ type OriginOf = as Dispatchable>::RuntimeOrigin; #[derive(Default, Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] +#[freeze_struct("7f03f99666ee2c4f")] pub struct CommitmentsTransactionExtension(PhantomData); impl sp_std::fmt::Debug for CommitmentsTransactionExtension { From b99a374163f16d0f491d609cc7f895c26d5103af Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:54:02 -0700 Subject: [PATCH 4/7] fix tx extension benchmarks --- node/src/benchmarking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/src/benchmarking.rs b/node/src/benchmarking.rs index d0c0ac9a40..15023c1245 100644 --- a/node/src/benchmarking.rs +++ b/node/src/benchmarking.rs @@ -141,6 +141,7 @@ pub fn create_benchmark_extrinsic( pallet_shield::CheckShieldedTxValidity::::new(), pallet_subtensor::SubtensorTransactionExtension::::new(), pallet_drand::drand_priority::DrandPriority::::new(), + pallet_commitments::CommitmentsTransactionExtension::::new(), ), frame_metadata_hash_extension::CheckMetadataHash::::new(true), ); @@ -158,7 +159,7 @@ pub fn create_benchmark_extrinsic( (), (), ), - ((), (), (), (), ()), + ((), (), (), (), (), ()), None, ), ); From ff1b5232603ed08fbada7ac413b7bd89dadc6730 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:28:51 -0700 Subject: [PATCH 5/7] add RuntimeDispatchGuard --- pallets/commitments/src/lib.rs | 28 +++++++++++++++++++++++++++- runtime/src/lib.rs | 24 +++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index 745efc3f7e..98c4c37a94 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -14,8 +14,10 @@ use ark_serialize::CanonicalDeserialize; use codec::Encode; use frame_support::{ BoundedVec, IterableStorageDoubleMap, + dispatch::{DispatchGuard, DispatchInfo, PostDispatchInfo}, pallet_prelude::{ - Decode, DecodeWithMemTracking, PhantomData, ValidTransaction, ValidateResult, + Decode, DecodeWithMemTracking, DispatchResultWithPostInfo, OriginTrait, PhantomData, + ValidTransaction, ValidateResult, }, traits::{Currency, Get, IsSubType}, }; @@ -663,6 +665,30 @@ where } } +pub struct CommitmentsDispatchGuard(PhantomData); + +impl DispatchGuard<::RuntimeCall> for CommitmentsDispatchGuard +where + T: Config, + ::RuntimeCall: + Dispatchable + IsSubType>, + OriginOf: OriginTrait, +{ + fn check(origin: &OriginOf, call: &CallOf) -> DispatchResultWithPostInfo { + let Some(who) = origin.as_signer() else { + return Ok(().into()); + }; + + if let Some(pallet::Call::set_commitment { netuid, .. }) = call.is_sub_type() { + if !T::CanCommit::can_commit(*netuid, who) { + return Err(Error::::AccountNotAllowedCommit.into()); + } + } + + Ok(().into()) + } +} + pub trait GetCommitments { fn get_commitments(netuid: NetUid) -> Vec<(AccountId, Vec)>; } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index f36205385e..d52cdbd1e9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -22,10 +22,12 @@ use codec::{Compact, Decode, Encode}; use ethereum::AuthorizationList; use frame_support::{ PalletId, - dispatch::DispatchResult, + dispatch::{ + DispatchGuard, DispatchInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo, + }, genesis_builder_helper::{build_state, get_preset}, pallet_prelude::Get, - traits::{Contains, InsideBoth, LinearStoragePrice, fungible::HoldConsideration}, + traits::{Contains, InsideBoth, LinearStoragePrice, OriginTrait, fungible::HoldConsideration}, }; use frame_system::{EnsureRoot, EnsureRootWithSuccess, EnsureSigned}; use pallet_commitments::{CanCommit, OnMetadataCommitment}; @@ -382,7 +384,7 @@ impl frame_system::Config for Runtime { type PostInherents = (); type PostTransactions = (); type ExtensionsWeightInfo = frame_system::SubstrateExtensionsWeight; - type DispatchGuard = pallet_subtensor::CheckColdkeySwap; + type DispatchGuard = RuntimeDispatchGuard; } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} @@ -1721,6 +1723,22 @@ pub type Executive = frame_executive::Executive< Migrations, >; +type RuntimeDispatchableOrigin = ::RuntimeOrigin; + +pub struct RuntimeDispatchGuard; + +impl DispatchGuard for RuntimeDispatchGuard +where + RuntimeCall: Dispatchable, + RuntimeDispatchableOrigin: OriginTrait, +{ + fn check(origin: &RuntimeDispatchableOrigin, call: &RuntimeCall) -> DispatchResultWithPostInfo { + pallet_subtensor::CheckColdkeySwap::::check(origin, call)?; + pallet_commitments::CommitmentsDispatchGuard::::check(origin, call)?; + Ok(().into()) + } +} + #[cfg(feature = "runtime-benchmarks")] #[macro_use] extern crate frame_benchmarking; From aace24c2950bd8ebc13a5724f88215fec9468af3 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:39:24 -0700 Subject: [PATCH 6/7] rm import --- pallets/commitments/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index 98c4c37a94..9f49313306 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -14,7 +14,7 @@ use ark_serialize::CanonicalDeserialize; use codec::Encode; use frame_support::{ BoundedVec, IterableStorageDoubleMap, - dispatch::{DispatchGuard, DispatchInfo, PostDispatchInfo}, + dispatch::{DispatchInfo, PostDispatchInfo}, pallet_prelude::{ Decode, DecodeWithMemTracking, DispatchResultWithPostInfo, OriginTrait, PhantomData, ValidTransaction, ValidateResult, From b10b1b6f2cd6e482fbe2c670513f482efb580ee7 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:31:06 -0700 Subject: [PATCH 7/7] use DispatchExtension --- pallets/commitments/src/lib.rs | 28 +++++++++++++++-------- runtime/src/lib.rs | 42 +++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index 9f49313306..ee78910044 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -14,12 +14,11 @@ use ark_serialize::CanonicalDeserialize; use codec::Encode; use frame_support::{ BoundedVec, IterableStorageDoubleMap, - dispatch::{DispatchInfo, PostDispatchInfo}, + dispatch::{DispatchErrorWithPostInfo, DispatchExtension, DispatchInfo, PostDispatchInfo}, pallet_prelude::{ - Decode, DecodeWithMemTracking, DispatchResultWithPostInfo, OriginTrait, PhantomData, - ValidTransaction, ValidateResult, + Decode, DecodeWithMemTracking, PhantomData, ValidTransaction, ValidateResult, }, - traits::{Currency, Get, IsSubType}, + traits::{Currency, Get, IsSubType, OriginTrait}, }; use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; @@ -665,18 +664,27 @@ where } } -pub struct CommitmentsDispatchGuard(PhantomData); +pub struct CommitmentsDispatchExtension(PhantomData); -impl DispatchGuard<::RuntimeCall> for CommitmentsDispatchGuard +impl DispatchExtension> for CommitmentsDispatchExtension where T: Config, - ::RuntimeCall: + CallOf: Dispatchable + IsSubType>, OriginOf: OriginTrait, { - fn check(origin: &OriginOf, call: &CallOf) -> DispatchResultWithPostInfo { + type Pre = (); + + fn weight(_call: &CallOf) -> Weight { + T::DbWeight::get().reads(1) + } + + fn pre_dispatch( + origin: &OriginOf, + call: &CallOf, + ) -> Result { let Some(who) = origin.as_signer() else { - return Ok(().into()); + return Ok(()); }; if let Some(pallet::Call::set_commitment { netuid, .. }) = call.is_sub_type() { @@ -685,7 +693,7 @@ where } } - Ok(().into()) + Ok(()) } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 63a2c8736a..da449a2164 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -23,7 +23,8 @@ use ethereum::AuthorizationList; use frame_support::{ PalletId, dispatch::{ - DispatchGuard, DispatchInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo, + DispatchErrorWithPostInfo, DispatchExtension, DispatchInfo, DispatchResult, + PostDispatchInfo, }, genesis_builder_helper::{build_state, get_preset}, pallet_prelude::Get, @@ -384,7 +385,7 @@ impl frame_system::Config for Runtime { type PostInherents = (); type PostTransactions = (); type ExtensionsWeightInfo = frame_system::SubstrateExtensionsWeight; - type DispatchGuard = RuntimeDispatchGuard; + type DispatchExtension = RuntimeDispatchExtension; } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} @@ -1724,18 +1725,43 @@ pub type Executive = frame_executive::Executive< >; type RuntimeDispatchableOrigin = ::RuntimeOrigin; +type ColdkeySwapDispatchPre = + as DispatchExtension>::Pre; +type CommitmentsDispatchPre = + as DispatchExtension>::Pre; -pub struct RuntimeDispatchGuard; +pub struct RuntimeDispatchExtension; -impl DispatchGuard for RuntimeDispatchGuard +impl DispatchExtension for RuntimeDispatchExtension where RuntimeCall: Dispatchable, RuntimeDispatchableOrigin: OriginTrait, { - fn check(origin: &RuntimeDispatchableOrigin, call: &RuntimeCall) -> DispatchResultWithPostInfo { - pallet_subtensor::CheckColdkeySwap::::check(origin, call)?; - pallet_commitments::CommitmentsDispatchGuard::::check(origin, call)?; - Ok(().into()) + type Pre = (ColdkeySwapDispatchPre, CommitmentsDispatchPre); + + fn weight(call: &RuntimeCall) -> Weight { + as DispatchExtension>::weight( + call, + ) + .saturating_add( + as DispatchExtension< + RuntimeCall, + >>::weight(call), + ) + } + + fn pre_dispatch( + origin: &RuntimeDispatchableOrigin, + call: &RuntimeCall, + ) -> Result { + let coldkey_swap_pre = + as DispatchExtension>::pre_dispatch(origin, call)?; + let commitments_pre = + as DispatchExtension< + RuntimeCall, + >>::pre_dispatch(origin, call)?; + + Ok((coldkey_swap_pre, commitments_pre)) } }