From 8dee4c6e2f9326da47e47f540f6f3f26018ba6c8 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 10:46:04 -0300 Subject: [PATCH 01/11] added set_real_pays_fee extrinsic and tests --- pallets/proxy/src/benchmarking.rs | 23 ++++++ pallets/proxy/src/lib.rs | 69 +++++++++++++++++ pallets/proxy/src/tests.rs | 122 ++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/pallets/proxy/src/benchmarking.rs b/pallets/proxy/src/benchmarking.rs index 9a759e1846..9bf21cb951 100644 --- a/pallets/proxy/src/benchmarking.rs +++ b/pallets/proxy/src/benchmarking.rs @@ -491,5 +491,28 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn set_real_pays_fee(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; + let caller: T::AccountId = whitelisted_caller(); + let delegate: T::AccountId = account("target", 0, SEED); + let delegate_lookup = T::Lookup::unlookup(delegate.clone()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), delegate_lookup, true); + + assert!(RealPaysFee::::contains_key(&caller, &delegate)); + assert_last_event::( + Event::RealPaysFeeSet { + real: caller, + delegate, + pays_fee: true, + } + .into(), + ); + + Ok(()) + } + impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/pallets/proxy/src/lib.rs b/pallets/proxy/src/lib.rs index a255f99b48..1fca855327 100644 --- a/pallets/proxy/src/lib.rs +++ b/pallets/proxy/src/lib.rs @@ -674,6 +674,44 @@ pub mod pallet { Pays::Yes.into() }) } + + /// Set whether the real account pays transaction fees for proxy calls made by a + /// specific delegate. + /// + /// The dispatch origin for this call must be _Signed_ and must be the real (delegator) + /// account that has an existing proxy relationship with the delegate. + /// + /// Parameters: + /// - `delegate`: The proxy account for which to set the fee payment preference. + /// - `pays_fee`: If `true`, the real account will pay fees for proxy calls made by + /// this delegate. If `false`, the delegate pays (default behavior). + #[pallet::call_index(11)] + #[pallet::weight(T::WeightInfo::set_real_pays_fee(T::MaxProxies::get()))] + pub fn set_real_pays_fee( + origin: OriginFor, + delegate: AccountIdLookupOf, + pays_fee: bool, + ) -> DispatchResult { + let real = ensure_signed(origin)?; + let delegate = T::Lookup::lookup(delegate)?; + + // Verify proxy relationship exists + Self::find_proxy(&real, &delegate, None)?; + + if pays_fee { + RealPaysFee::::insert(&real, &delegate, ()); + } else { + RealPaysFee::::remove(&real, &delegate); + } + + Self::deposit_event(Event::RealPaysFeeSet { + real, + delegate, + pays_fee, + }); + + Ok(()) + } } #[pallet::event] @@ -727,6 +765,12 @@ pub mod pallet { old_deposit: BalanceOf, new_deposit: BalanceOf, }, + /// The real-pays-fee setting was updated for a proxy relationship. + RealPaysFeeSet { + real: T::AccountId, + delegate: T::AccountId, + pays_fee: bool, + }, } #[pallet::error] @@ -796,6 +840,21 @@ pub mod pallet { pub type LastCallResult = StorageMap<_, Twox64Concat, T::AccountId, DispatchResult, OptionQuery>; + /// Tracks which (real, delegate) pairs have opted in to the real account paying + /// transaction fees for proxy calls made by the delegate. + /// Existence of an entry means the real account pays; absence means the delegate pays + /// (default). + #[pallet::storage] + pub type RealPaysFee = StorageDoubleMap< + _, + Twox64Concat, + T::AccountId, // real + Twox64Concat, + T::AccountId, // delegate + (), + OptionQuery, + >; + #[pallet::view_functions] impl Pallet { /// Check if a `RuntimeCall` is allowed for a given `ProxyType`. @@ -951,6 +1010,9 @@ impl Pallet { if !proxies.is_empty() { *x = Some((proxies, new_deposit)) } + // Clean up real-pays-fee flag for this specific proxy relationship + RealPaysFee::::remove(delegator, &delegatee); + Self::deposit_event(Event::::ProxyRemoved { delegator: delegator.clone(), delegatee, @@ -1081,5 +1143,12 @@ impl Pallet { pub fn remove_all_proxy_delegates(delegator: &T::AccountId) { let (_, old_deposit) = Proxies::::take(delegator); T::Currency::unreserve(delegator, old_deposit); + // Clean up all real-pays-fee flags for this delegator + let _ = RealPaysFee::::clear_prefix(delegator, u32::MAX, None); + } + + /// Check if the real account has opted in to paying fees for a specific delegate. + pub fn is_real_pays_fee(real: &T::AccountId, delegate: &T::AccountId) -> bool { + RealPaysFee::::contains_key(real, delegate) } } diff --git a/pallets/proxy/src/tests.rs b/pallets/proxy/src/tests.rs index ea64aef030..5bc5be2415 100644 --- a/pallets/proxy/src/tests.rs +++ b/pallets/proxy/src/tests.rs @@ -1251,3 +1251,125 @@ fn poke_deposit_fails_for_unsigned_origin() { ); }); } + +#[test] +fn set_real_pays_fee_works() { + new_test_ext().execute_with(|| { + // Account 1 adds account 3 as proxy + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + + // Account 1 (real) enables real-pays-fee for delegate 3 + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true)); + assert!(Proxy::is_real_pays_fee(&1, &3)); + System::assert_last_event( + ProxyEvent::RealPaysFeeSet { + real: 1, + delegate: 3, + pays_fee: true, + } + .into(), + ); + + // Disable it + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, false)); + assert!(!Proxy::is_real_pays_fee(&1, &3)); + System::assert_last_event( + ProxyEvent::RealPaysFeeSet { + real: 1, + delegate: 3, + pays_fee: false, + } + .into(), + ); + }); +} + +#[test] +fn set_real_pays_fee_fails_without_proxy() { + new_test_ext().execute_with(|| { + // No proxy relationship between 1 and 3 + assert_noop!( + Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true), + Error::::NotProxy, + ); + }); +} + +#[test] +fn set_real_pays_fee_fails_unsigned() { + new_test_ext().execute_with(|| { + assert_noop!( + Proxy::set_real_pays_fee(RuntimeOrigin::none(), 3, true), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn set_real_pays_fee_fails_root() { + new_test_ext().execute_with(|| { + assert_noop!( + Proxy::set_real_pays_fee(RuntimeOrigin::root(), 3, true), + DispatchError::BadOrigin, + ); + }); +} + +#[test] +fn real_pays_fee_cleaned_on_remove_proxy() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true)); + assert!(Proxy::is_real_pays_fee(&1, &3)); + + // Remove the proxy + assert_ok!(Proxy::remove_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + + // Flag should be cleaned up + assert!(!Proxy::is_real_pays_fee(&1, &3)); + }); +} + +#[test] +fn real_pays_fee_cleaned_on_remove_proxies() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 2, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(1), + 3, + ProxyType::Any, + 0 + )); + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 2, true)); + assert_ok!(Proxy::set_real_pays_fee(RuntimeOrigin::signed(1), 3, true)); + assert!(Proxy::is_real_pays_fee(&1, &2)); + assert!(Proxy::is_real_pays_fee(&1, &3)); + + // Remove all proxies + assert_ok!(Proxy::remove_proxies(RuntimeOrigin::signed(1))); + + // Both flags should be cleaned up + assert!(!Proxy::is_real_pays_fee(&1, &2)); + assert!(!Proxy::is_real_pays_fee(&1, &3)); + }); +} From c558c477490deedee222618cb63c113d9e7f69cf Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 11:39:05 -0300 Subject: [PATCH 02/11] updated the ChargeTxPaymentWrapper to handle RealPaysFee for proxies --- runtime/src/transaction_payment_wrapper.rs | 251 +++++++++++++++++---- 1 file changed, 202 insertions(+), 49 deletions(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 96d7f3609b..25b030d1a3 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -3,18 +3,28 @@ use codec::{Decode, DecodeWithMemTracking, Encode}; use frame_election_provider_support::private::sp_arithmetic::traits::SaturatedConversion; use frame_support::dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}; use frame_support::pallet_prelude::TypeInfo; +use frame_support::traits::{IsSubType, IsType}; +use pallet_subtensor_proxy as pallet_proxy; +use pallet_subtensor_utility as pallet_utility; use pallet_transaction_payment::{ChargeTransactionPayment, Config, Pre, Val}; use sp_runtime::DispatchResult; use sp_runtime::traits::{ - DispatchInfoOf, DispatchOriginOf, Dispatchable, Implication, PostDispatchInfoOf, - TransactionExtension, TransactionExtensionMetadata, ValidateResult, + AsSystemOriginSigner, DispatchInfoOf, DispatchOriginOf, Dispatchable, Implication, + PostDispatchInfoOf, StaticLookup, TransactionExtension, TransactionExtensionMetadata, + ValidateResult, }; use sp_runtime::transaction_validity::{ TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, }; +use sp_std::boxed::Box; use sp_std::vec::Vec; use subtensor_macros::freeze_struct; +type RuntimeCallOf = ::RuntimeCall; +type RuntimeOriginOf = ::RuntimeOrigin; +type AccountIdOf = ::AccountId; +type LookupOf = ::Lookup; + #[freeze_struct("5f10cb9db06873c0")] #[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] @@ -41,64 +51,207 @@ impl ChargeTransactionPaymentWrapper { } } -impl TransactionExtension for ChargeTransactionPaymentWrapper +impl ChargeTransactionPaymentWrapper where - T::RuntimeCall: Dispatchable, + RuntimeCallOf: IsSubType> + IsSubType>, + RuntimeOriginOf: AsSystemOriginSigner> + Clone, +{ + /// Extract (real, delegate, inner_call) from a `proxy` or `proxy_announced` call. + /// For `proxy`, `signer` is used as the delegate since it is implicit (the caller). + fn extract_proxy_parts<'a>( + call: &'a RuntimeCallOf, + signer: &AccountIdOf, + ) -> Option<( + AccountIdOf, + AccountIdOf, + &'a Box<::RuntimeCall>, + )> { + match call.is_sub_type()? { + pallet_proxy::Call::proxy { real, call, .. } => { + let real = LookupOf::::lookup(real.clone()).ok()?; + Some((real, signer.clone(), call)) + } + pallet_proxy::Call::proxy_announced { + delegate, + real, + call, + .. + } => { + let real = LookupOf::::lookup(real.clone()).ok()?; + let delegate = LookupOf::::lookup(delegate.clone()).ok()?; + Some((real, delegate, call)) + } + _ => None, + } + } + + /// Determine who should pay the transaction fee for a proxy call. + /// + /// Follows the RealPaysFee chain up to 2 levels deep: + /// - Case 1: `proxy(real=A, call)` → A pays if `RealPaysFee` + /// - Case 2: `proxy(real=B, proxy(real=A, call))` → A pays if both + /// `RealPaysFee` and `RealPaysFee` are set; B pays if only the former. + /// - Case 3: `proxy(real=B, batch([proxy(real=A, ..), ..]))` → A pays if + /// `RealPaysFee`, all batch items are proxy calls with the same real A, + /// and `RealPaysFee` is set; B pays if only the first condition holds. + /// + /// Returns `None` if the signer should pay (no RealPaysFee opt-in). + fn extract_real_fee_payer( + call: &RuntimeCallOf, + origin: &RuntimeOriginOf, + ) -> Option> { + let signer = origin.as_system_origin_signer()?; + let (outer_real, delegate, inner_call) = Self::extract_proxy_parts(call, signer)?; + + // Check if the outer real account has opted in to pay for the delegate. + if !pallet_proxy::Pallet::::is_real_pays_fee(&outer_real, &delegate) { + return None; + } + + // outer_real pays. Try to push the fee deeper into nested proxy structures. + let inner_call: &RuntimeCallOf = (*inner_call).as_ref().into_ref(); + + // Case 2: inner call is another proxy call. + if let Some(inner_payer) = Self::extract_inner_proxy_payer(inner_call, &outer_real) { + return Some(inner_payer); + } + + // Case 3: inner call is a batch of proxy calls with the same real. + if let Some(batch_payer) = Self::extract_batch_proxy_payer(inner_call, &outer_real) { + return Some(batch_payer); + } + + // Case 1: simple proxy, outer_real pays. + Some(outer_real) + } + + /// Check if an inner call is a proxy call where the inner real has opted in to pay. + /// `outer_real` is used as the implicit delegate for `proxy` calls. + fn extract_inner_proxy_payer( + inner_call: &RuntimeCallOf, + outer_real: &AccountIdOf, + ) -> Option> { + let (inner_real, inner_delegate, _call) = + Self::extract_proxy_parts(inner_call, outer_real)?; + + if pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { + Some(inner_real) + } else { + None + } + } + + /// Check if an inner call is a batch where ALL items are proxy calls with the same real + /// account, and that real account has opted in to pay. + /// `outer_real` is used as the implicit delegate for `proxy` calls within the batch. + fn extract_batch_proxy_payer( + inner_call: &RuntimeCallOf, + outer_real: &AccountIdOf, + ) -> Option> { + let calls: &Vec<::RuntimeCall> = + match inner_call.is_sub_type()? { + pallet_utility::Call::batch { calls } + | pallet_utility::Call::batch_all { calls } + | pallet_utility::Call::force_batch { calls } => calls, + _ => return None, + }; + + if calls.is_empty() { + return None; + } + + let mut common_real: Option> = None; + + for call in calls.iter() { + let call_ref: &RuntimeCallOf = call.into_ref(); + let (inner_real, inner_delegate, _) = Self::extract_proxy_parts(call_ref, outer_real)?; + + // All items must share the same real account. + match &common_real { + None => common_real = Some(inner_real.clone()), + Some(existing) if *existing != inner_real => return None, + _ => {} + } + + if !pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { + return None; + } + } + + common_real + } +} + +impl + TransactionExtension> for ChargeTransactionPaymentWrapper +where + RuntimeCallOf: Dispatchable + + IsSubType> + + IsSubType>, + RuntimeOriginOf: AsSystemOriginSigner> + + Clone + + From>>, { const IDENTIFIER: &'static str = "ChargeTransactionPaymentWrapper"; type Implicit = (); type Val = Val; type Pre = Pre; - fn weight(&self, call: &T::RuntimeCall) -> Weight { + fn weight(&self, call: &RuntimeCallOf) -> Weight { self.charge_transaction_payment.weight(call) } fn validate( &self, - origin: DispatchOriginOf, - call: &T::RuntimeCall, - info: &DispatchInfoOf, + origin: DispatchOriginOf>, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, self_implicit: Self::Implicit, inherited_implication: &impl Implication, source: TransactionSource, - ) -> ValidateResult { - let inner_validate = self.charge_transaction_payment.validate( - origin, - call, - info, - len, - self_implicit, - inherited_implication, - source, - ); - - match inner_validate { - Ok((mut valid_transaction, val, origin)) => { - let overridden_priority = { - let base: TransactionPriority = match info.class { - DispatchClass::Normal => NORMAL_DISPATCH_BASE_PRIORITY, - DispatchClass::Mandatory => NORMAL_DISPATCH_BASE_PRIORITY, - DispatchClass::Operational => OPERATIONAL_DISPATCH_PRIORITY, - }; - base.saturated_into::() - }; - - valid_transaction.priority = overridden_priority; - - Ok((valid_transaction, val, origin)) - } - Err(err) => Err(err), - } + ) -> ValidateResult> { + let overridden_priority = { + let base: TransactionPriority = match info.class { + DispatchClass::Normal => NORMAL_DISPATCH_BASE_PRIORITY, + DispatchClass::Mandatory => NORMAL_DISPATCH_BASE_PRIORITY, + DispatchClass::Operational => OPERATIONAL_DISPATCH_PRIORITY, + }; + base.saturated_into::() + }; + + // If a real account opted in to pay fees, create a synthetic origin for fee validation. + // Otherwise, the signer pays as usual. + let fee_origin = if let Some(real) = Self::extract_real_fee_payer(call, &origin) { + frame_system::RawOrigin::Signed(real).into() + } else { + origin.clone() + }; + + let (mut valid_transaction, val, _fee_origin) = + self.charge_transaction_payment.validate( + fee_origin, + call, + info, + len, + self_implicit, + inherited_implication, + source, + )?; + + valid_transaction.priority = overridden_priority; + + // Always return the original origin so the actual signer remains + // the origin for dispatch and all subsequent extensions. + Ok((valid_transaction, val, origin)) } fn prepare( self, val: Self::Val, - origin: &DispatchOriginOf, - call: &T::RuntimeCall, - info: &DispatchInfoOf, + origin: &DispatchOriginOf>, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, ) -> Result { self.charge_transaction_payment @@ -109,8 +262,8 @@ where } fn post_dispatch_details( pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf>, + post_info: &PostDispatchInfoOf>, len: usize, result: &DispatchResult, ) -> Result { @@ -119,8 +272,8 @@ where fn post_dispatch( pre: Self::Pre, - info: &DispatchInfoOf, - post_info: &mut PostDispatchInfoOf, + info: &DispatchInfoOf>, + post_info: &mut PostDispatchInfoOf>, len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { @@ -128,24 +281,24 @@ where } fn bare_validate( - call: &T::RuntimeCall, - info: &DispatchInfoOf, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, ) -> TransactionValidity { ChargeTransactionPayment::::bare_validate(call, info, len) } fn bare_validate_and_prepare( - call: &T::RuntimeCall, - info: &DispatchInfoOf, + call: &RuntimeCallOf, + info: &DispatchInfoOf>, len: usize, ) -> Result<(), TransactionValidityError> { ChargeTransactionPayment::::bare_validate_and_prepare(call, info, len) } fn bare_post_dispatch( - info: &DispatchInfoOf, - post_info: &mut PostDispatchInfoOf, + info: &DispatchInfoOf>, + post_info: &mut PostDispatchInfoOf>, len: usize, result: &DispatchResult, ) -> Result<(), TransactionValidityError> { From abc0baf5071b66efed6e982c7c30d2e1e2b7a402 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 12:40:06 -0300 Subject: [PATCH 03/11] do not handle proxy_announced + memoize storage read --- runtime/src/transaction_payment_wrapper.rs | 39 +++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 25b030d1a3..7f700f92d3 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -56,8 +56,10 @@ where RuntimeCallOf: IsSubType> + IsSubType>, RuntimeOriginOf: AsSystemOriginSigner> + Clone, { - /// Extract (real, delegate, inner_call) from a `proxy` or `proxy_announced` call. - /// For `proxy`, `signer` is used as the delegate since it is implicit (the caller). + /// Extract (real, delegate, inner_call) from a `proxy` call. + /// `signer` is used as the delegate since it is implicit (the caller). + /// `proxy_announced` is intentionally not handled here; fee propagation + /// only applies to `proxy` calls to keep the logic simple. fn extract_proxy_parts<'a>( call: &'a RuntimeCallOf, signer: &AccountIdOf, @@ -71,16 +73,6 @@ where let real = LookupOf::::lookup(real.clone()).ok()?; Some((real, signer.clone(), call)) } - pallet_proxy::Call::proxy_announced { - delegate, - real, - call, - .. - } => { - let real = LookupOf::::lookup(real.clone()).ok()?; - let delegate = LookupOf::::lookup(delegate.clone()).ok()?; - Some((real, delegate, call)) - } _ => None, } } @@ -164,18 +156,27 @@ where for call in calls.iter() { let call_ref: &RuntimeCallOf = call.into_ref(); - let (inner_real, inner_delegate, _) = Self::extract_proxy_parts(call_ref, outer_real)?; + let (inner_real, inner_delegate, _) = + Self::extract_proxy_parts(call_ref, outer_real)?; - // All items must share the same real account. match &common_real { - None => common_real = Some(inner_real.clone()), + None => { + // Check RealPaysFee once on the first item and memoize. For `proxy` + // calls the delegate is always `outer_real`, so a single read covers + // the entire batch; for `proxy_announced` it uses the explicit delegate. + if !pallet_proxy::Pallet::::is_real_pays_fee( + &inner_real, + &inner_delegate, + ) + { + return None; + } + common_real = Some(inner_real); + } + // All items must share the same real account. Some(existing) if *existing != inner_real => return None, _ => {} } - - if !pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { - return None; - } } common_real From cbad8e693322e1d3b6236f800571bdbfd23c80b2 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 12:40:12 -0300 Subject: [PATCH 04/11] added tests --- runtime/tests/transaction_payment_wrapper.rs | 464 +++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 runtime/tests/transaction_payment_wrapper.rs diff --git a/runtime/tests/transaction_payment_wrapper.rs b/runtime/tests/transaction_payment_wrapper.rs new file mode 100644 index 0000000000..99c8254ed8 --- /dev/null +++ b/runtime/tests/transaction_payment_wrapper.rs @@ -0,0 +1,464 @@ +#![allow(clippy::unwrap_used)] + +use frame_support::{ + assert_ok, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, +}; +use node_subtensor_runtime::{ + BuildStorage, Proxy, Runtime, RuntimeCall, RuntimeGenesisConfig, RuntimeOrigin, System, + SystemCall, transaction_payment_wrapper, NORMAL_DISPATCH_BASE_PRIORITY, + OPERATIONAL_DISPATCH_PRIORITY, +}; +use pallet_subtensor_proxy as pallet_proxy; +use pallet_subtensor_utility as pallet_utility; +use pallet_transaction_payment::{ChargeTransactionPayment, Val}; +use sp_runtime::traits::{TransactionExtension, TxBaseImplication}; +use sp_runtime::transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}; +use subtensor_runtime_common::{AccountId, ProxyType}; + +const SIGNER: [u8; 32] = [1_u8; 32]; +const REAL_A: [u8; 32] = [2_u8; 32]; +const REAL_B: [u8; 32] = [3_u8; 32]; +const OTHER: [u8; 32] = [4_u8; 32]; +const BALANCE: u64 = 1_000_000_000_000; + +fn new_test_ext() -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut ext: sp_io::TestExternalities = RuntimeGenesisConfig { + balances: pallet_balances::GenesisConfig { + balances: vec![ + (AccountId::from(SIGNER), BALANCE), + (AccountId::from(REAL_A), BALANCE), + (AccountId::from(REAL_B), BALANCE), + (AccountId::from(OTHER), BALANCE), + ], + dev_accounts: None, + }, + ..Default::default() + } + .build_storage() + .unwrap() + .into(); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +fn signer() -> AccountId { + AccountId::from(SIGNER) +} +fn real_a() -> AccountId { + AccountId::from(REAL_A) +} +fn real_b() -> AccountId { + AccountId::from(REAL_B) +} +fn other() -> AccountId { + AccountId::from(OTHER) +} + +// -- Call builders -- + +fn call_remark() -> RuntimeCall { + RuntimeCall::System(SystemCall::remark { + remark: vec![1, 2, 3], + }) +} + +fn proxy_call(real: AccountId, inner: RuntimeCall) -> RuntimeCall { + RuntimeCall::Proxy(pallet_proxy::Call::proxy { + real: real.into(), + force_proxy_type: None, + call: Box::new(inner), + }) +} + +fn proxy_announced_call(delegate: AccountId, real: AccountId, inner: RuntimeCall) -> RuntimeCall { + RuntimeCall::Proxy(pallet_proxy::Call::proxy_announced { + delegate: delegate.into(), + real: real.into(), + force_proxy_type: None, + call: Box::new(inner), + }) +} + +fn batch_call(calls: Vec) -> RuntimeCall { + RuntimeCall::Utility(pallet_utility::Call::batch { calls }) +} + +fn batch_all_call(calls: Vec) -> RuntimeCall { + RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) +} + +fn force_batch_call(calls: Vec) -> RuntimeCall { + RuntimeCall::Utility(pallet_utility::Call::force_batch { calls }) +} + +// -- Setup helpers -- + +fn add_proxy(real: &AccountId, delegate: &AccountId) { + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(real.clone()), + delegate.clone().into(), + ProxyType::Any, + 0, + )); +} + +fn enable_real_pays_fee(real: &AccountId, delegate: &AccountId) { + assert_ok!(Proxy::set_real_pays_fee( + RuntimeOrigin::signed(real.clone()), + delegate.clone().into(), + true, + )); +} + +// -- Validate helpers -- + +fn validate_call( + origin: RuntimeOrigin, + call: &RuntimeCall, +) -> Result<(ValidTransaction, Val), TransactionValidityError> { + validate_call_with_info(origin, call, &call.get_dispatch_info()) +} + +fn validate_call_with_info( + origin: RuntimeOrigin, + call: &RuntimeCall, + info: &DispatchInfo, +) -> Result<(ValidTransaction, Val), TransactionValidityError> { + let ext = transaction_payment_wrapper::ChargeTransactionPaymentWrapper::::new( + ChargeTransactionPayment::from(0u64), + ); + let (valid_tx, val, _origin) = ext.validate( + origin, + call, + info, + 100, + (), + &TxBaseImplication(()), + TransactionSource::External, + )?; + Ok((valid_tx, val)) +} + +/// Extract the fee payer from the validate result. +fn fee_payer(val: &Val) -> AccountId { + match val { + Val::Charge { who, .. } => who.clone(), + _ => panic!("expected Val::Charge"), + } +} + +// ============================================================ +// Case 0: Non-proxy calls +// ============================================================ + +#[test] +fn non_proxy_call_charges_signer() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +// ============================================================ +// Case 1: Simple proxy (1 level) +// ============================================================ + +#[test] +fn simple_proxy_charges_real_when_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &signer()); + enable_real_pays_fee(&real_a(), &signer()); + + let call = proxy_call(real_a(), call_remark()); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn simple_proxy_charges_signer_when_not_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &signer()); + // No enable_real_pays_fee + + let call = proxy_call(real_a(), call_remark()); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +#[test] +fn proxy_announced_always_charges_signer() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + // Fee propagation intentionally ignores proxy_announced; signer always pays. + let call = proxy_announced_call(real_b(), real_a(), call_remark()); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +// ============================================================ +// Case 2: Nested proxy (2 levels) +// ============================================================ + +#[test] +fn nested_proxy_charges_inner_real_when_both_opted_in() { + new_test_ext().execute_with(|| { + // Chain: signer → real_b → real_a + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn nested_proxy_charges_outer_real_when_only_outer_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // No enable_real_pays_fee for A→B + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn nested_proxy_charges_signer_when_neither_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // No enable_real_pays_fee at all + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), signer()); + }); +} + +#[test] +fn nested_proxy_charges_signer_when_only_inner_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + // No enable_real_pays_fee for B→signer + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let call = proxy_call(real_b(), proxy_call(real_a(), call_remark())); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + // Outer RealPaysFee not set → signer pays (inner opt-in is irrelevant) + assert_eq!(fee_payer(&val), signer()); + }); +} + +// ============================================================ +// Case 3: Batch of proxy calls +// ============================================================ + +#[test] +fn batch_charges_inner_real_when_all_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn batch_all_charges_inner_real_when_all_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let batch = batch_all_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn force_batch_charges_inner_real_when_all_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + + let batch = force_batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_a()); + }); +} + +#[test] +fn batch_charges_outer_real_when_only_outer_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // No enable_real_pays_fee for A→B + + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_mixed_inner_reals() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + enable_real_pays_fee(&real_a(), &real_b()); + add_proxy(&other(), &real_b()); + enable_real_pays_fee(&other(), &real_b()); + + // Different inner reals → can't push deeper + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(other(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_non_proxy_in_batch() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + + // Batch contains a non-proxy call → extract_proxy_parts fails + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + call_remark(), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_empty() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + + let batch = batch_call(vec![]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +#[test] +fn batch_charges_outer_real_when_inner_real_not_opted_in() { + new_test_ext().execute_with(|| { + add_proxy(&real_b(), &signer()); + enable_real_pays_fee(&real_b(), &signer()); + add_proxy(&real_a(), &real_b()); + // real_a has NOT opted in to pay for real_b + + // Even with same real in all batch items, if RealPaysFee not set → outer_real pays + let batch = batch_call(vec![ + proxy_call(real_a(), call_remark()), + proxy_call(real_a(), call_remark()), + ]); + let call = proxy_call(real_b(), batch); + let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(fee_payer(&val), real_b()); + }); +} + +// ============================================================ +// Priority override +// ============================================================ + +#[test] +fn priority_override_normal_dispatch() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let (valid_tx, _val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + assert_eq!(valid_tx.priority, NORMAL_DISPATCH_BASE_PRIORITY); + }); +} + +#[test] +fn priority_override_operational_dispatch() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let mut info = call.get_dispatch_info(); + info.class = DispatchClass::Operational; + + let (valid_tx, _val) = + validate_call_with_info(RuntimeOrigin::signed(signer()), &call, &info).unwrap(); + assert_eq!(valid_tx.priority, OPERATIONAL_DISPATCH_PRIORITY); + }); +} + +#[test] +fn priority_override_mandatory_dispatch() { + new_test_ext().execute_with(|| { + let call = call_remark(); + let mut info = call.get_dispatch_info(); + info.class = DispatchClass::Mandatory; + + let (valid_tx, _val) = + validate_call_with_info(RuntimeOrigin::signed(signer()), &call, &info).unwrap(); + // Mandatory uses the same base as Normal + assert_eq!(valid_tx.priority, NORMAL_DISPATCH_BASE_PRIORITY); + }); +} + +#[test] +fn priority_override_applies_with_real_pays_fee() { + new_test_ext().execute_with(|| { + add_proxy(&real_a(), &signer()); + enable_real_pays_fee(&real_a(), &signer()); + + let call = proxy_call(real_a(), call_remark()); + let (valid_tx, _val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); + // Priority override should still apply when real pays fee + assert_eq!(valid_tx.priority, NORMAL_DISPATCH_BASE_PRIORITY); + }); +} From 8578ad3ba369a730474db84ed98eeda44f03027a Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 13:58:17 -0300 Subject: [PATCH 05/11] added additional weights to extension --- runtime/src/transaction_payment_wrapper.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 7f700f92d3..a9d6f60b76 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -199,7 +199,11 @@ where type Pre = Pre; fn weight(&self, call: &RuntimeCallOf) -> Weight { - self.charge_transaction_payment.weight(call) + // Account for up to 3 storage reads in the worst-case fee payer resolution + // (outer is_real_pays_fee + inner/batch is_real_pays_fee + margin). + self.charge_transaction_payment + .weight(call) + .saturating_add(T::DbWeight::get().reads(3)) } fn validate( From f22315dc34f96243a1405a6313b2560785709b92 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 13:58:36 -0300 Subject: [PATCH 06/11] cargo fmt --- runtime/src/transaction_payment_wrapper.rs | 28 ++++++++------------ runtime/tests/transaction_payment_wrapper.rs | 15 +++++------ 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index a9d6f60b76..6246af6b9e 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -156,19 +156,14 @@ where for call in calls.iter() { let call_ref: &RuntimeCallOf = call.into_ref(); - let (inner_real, inner_delegate, _) = - Self::extract_proxy_parts(call_ref, outer_real)?; + let (inner_real, inner_delegate, _) = Self::extract_proxy_parts(call_ref, outer_real)?; match &common_real { None => { // Check RealPaysFee once on the first item and memoize. For `proxy` // calls the delegate is always `outer_real`, so a single read covers // the entire batch; for `proxy_announced` it uses the explicit delegate. - if !pallet_proxy::Pallet::::is_real_pays_fee( - &inner_real, - &inner_delegate, - ) - { + if !pallet_proxy::Pallet::::is_real_pays_fee(&inner_real, &inner_delegate) { return None; } common_real = Some(inner_real); @@ -233,16 +228,15 @@ where origin.clone() }; - let (mut valid_transaction, val, _fee_origin) = - self.charge_transaction_payment.validate( - fee_origin, - call, - info, - len, - self_implicit, - inherited_implication, - source, - )?; + let (mut valid_transaction, val, _fee_origin) = self.charge_transaction_payment.validate( + fee_origin, + call, + info, + len, + self_implicit, + inherited_implication, + source, + )?; valid_transaction.priority = overridden_priority; diff --git a/runtime/tests/transaction_payment_wrapper.rs b/runtime/tests/transaction_payment_wrapper.rs index 99c8254ed8..639e8b3576 100644 --- a/runtime/tests/transaction_payment_wrapper.rs +++ b/runtime/tests/transaction_payment_wrapper.rs @@ -5,15 +5,17 @@ use frame_support::{ dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, }; use node_subtensor_runtime::{ - BuildStorage, Proxy, Runtime, RuntimeCall, RuntimeGenesisConfig, RuntimeOrigin, System, - SystemCall, transaction_payment_wrapper, NORMAL_DISPATCH_BASE_PRIORITY, - OPERATIONAL_DISPATCH_PRIORITY, + BuildStorage, NORMAL_DISPATCH_BASE_PRIORITY, OPERATIONAL_DISPATCH_PRIORITY, Proxy, Runtime, + RuntimeCall, RuntimeGenesisConfig, RuntimeOrigin, System, SystemCall, + transaction_payment_wrapper, }; use pallet_subtensor_proxy as pallet_proxy; use pallet_subtensor_utility as pallet_utility; use pallet_transaction_payment::{ChargeTransactionPayment, Val}; use sp_runtime::traits::{TransactionExtension, TxBaseImplication}; -use sp_runtime::transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction}; +use sp_runtime::transaction_validity::{ + TransactionSource, TransactionValidityError, ValidTransaction, +}; use subtensor_runtime_common::{AccountId, ProxyType}; const SIGNER: [u8; 32] = [1_u8; 32]; @@ -368,10 +370,7 @@ fn batch_charges_outer_real_when_non_proxy_in_batch() { enable_real_pays_fee(&real_b(), &signer()); // Batch contains a non-proxy call → extract_proxy_parts fails - let batch = batch_call(vec![ - proxy_call(real_a(), call_remark()), - call_remark(), - ]); + let batch = batch_call(vec![proxy_call(real_a(), call_remark()), call_remark()]); let call = proxy_call(real_b(), batch); let (_valid_tx, val) = validate_call(RuntimeOrigin::signed(signer()), &call).unwrap(); assert_eq!(fee_payer(&val), real_b()); From 4ec43ec4eb21cd930a2046e5d30177791f4c648e Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 15:18:15 -0300 Subject: [PATCH 07/11] add missing import --- runtime/src/transaction_payment_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/transaction_payment_wrapper.rs b/runtime/src/transaction_payment_wrapper.rs index 6246af6b9e..7973c44caf 100644 --- a/runtime/src/transaction_payment_wrapper.rs +++ b/runtime/src/transaction_payment_wrapper.rs @@ -3,7 +3,7 @@ use codec::{Decode, DecodeWithMemTracking, Encode}; use frame_election_provider_support::private::sp_arithmetic::traits::SaturatedConversion; use frame_support::dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}; use frame_support::pallet_prelude::TypeInfo; -use frame_support::traits::{IsSubType, IsType}; +use frame_support::traits::{Get, IsSubType, IsType}; use pallet_subtensor_proxy as pallet_proxy; use pallet_subtensor_utility as pallet_utility; use pallet_transaction_payment::{ChargeTransactionPayment, Config, Pre, Val}; From e8436a1b6b6956d2842883183a8505229776676c Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 15:52:23 -0300 Subject: [PATCH 08/11] added pallet proxy to benchmarks --- runtime/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b324934caa..41a00e3f64 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1698,6 +1698,7 @@ mod benches { [pallet_crowdloan, Crowdloan] [pallet_subtensor_swap, Swap] [pallet_shield, MevShield] + [pallet_subtensor_proxy, Proxy] ); } From 57e2796529bced0a54c01cbd5f1162f7995deaa7 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 20:12:27 +0100 Subject: [PATCH 09/11] benchmark the proxy pallet with new extrinsic --- pallets/proxy/src/weights.rs | 529 +++++++++++++++++++---------------- 1 file changed, 290 insertions(+), 239 deletions(-) diff --git a/pallets/proxy/src/weights.rs b/pallets/proxy/src/weights.rs index 6a14c7de2c..d8f463497f 100644 --- a/pallets/proxy/src/weights.rs +++ b/pallets/proxy/src/weights.rs @@ -17,42 +17,40 @@ //! Autogenerated weights for `pallet_proxy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2025-03-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 49.1.0 +//! DATE: 2026-02-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `99fc4dfa9c86`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `Ubuntu-2404-noble-amd64-base`, CPU: `AMD Ryzen 9 5950X 16-Core Processor` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` // Executed Command: -// frame-omni-bencher -// v1 +// ./target/production/node-subtensor // benchmark // pallet // --extrinsic=* -// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm -// --pallet=pallet_proxy -// --header=/__w/polkadot-sdk/polkadot-sdk/substrate/HEADER-APACHE2 -// --output=/__w/polkadot-sdk/polkadot-sdk/substrate/frame/proxy/src/weights.rs +// --runtime=target/production/wbuild/node-subtensor-runtime/node_subtensor_runtime.wasm +// --genesis-builder=runtime +// --genesis-builder-preset=benchmark +// --pallet=pallet_subtensor_proxy +// --output=pallets/proxy/src/weights.rs // --wasm-execution=compiled // --steps=50 // --repeat=20 // --heap-pages=4096 -// --template=substrate/.maintain/frame-umbrella-weight-template.hbs +// --template=.maintain/frame-weight-template.hbs // --no-storage-info // --no-min-squares // --no-median-slopes -// --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic,pallet_nomination_pools,pallet_remark,pallet_transaction_storage,pallet_election_provider_multi_block,pallet_election_provider_multi_block::signed,pallet_election_provider_multi_block::unsigned,pallet_election_provider_multi_block::verifier #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -#![allow(dead_code)] -use crate as pallet_proxy; -use frame::weights_prelude::*; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; -/// Weight functions needed for `pallet_proxy`. +/// Weight functions needed for `pallet_subtensor_proxy`. pub trait WeightInfo { fn proxy(p: u32, ) -> Weight; fn proxy_announced(a: u32, p: u32, ) -> Weight; @@ -65,385 +63,438 @@ pub trait WeightInfo { fn create_pure(p: u32, ) -> Weight; fn kill_pure(p: u32, ) -> Weight; fn poke_deposit() -> Weight; + fn set_real_pays_fee(p: u32, ) -> Weight; } -/// Weights for `pallet_proxy` using the Substrate node and recommended hardware. +/// Weights for `pallet_subtensor_proxy` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `339 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_353_000 picoseconds. - Weight::from_parts(25_084_085, 4706) - // Standard Error: 2_569 - .saturating_add(Weight::from_parts(33_574, 0).saturating_mul(p.into())) + // Measured: `625 + p * (37 ±0)` + // Estimated: `4254 + p * (37 ±0)` + // Minimum execution time: 19_346_000 picoseconds. + Weight::from_parts(19_857_012, 4254) + // Standard Error: 1_610 + .saturating_add(Weight::from_parts(42_156, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `666 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 47_196_000 picoseconds. - Weight::from_parts(48_686_812, 5698) - // Standard Error: 3_711 - .saturating_add(Weight::from_parts(171_107, 0).saturating_mul(a.into())) - // Standard Error: 3_834 - .saturating_add(Weight::from_parts(34_523, 0).saturating_mul(p.into())) + // Measured: `882 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615 + a * (68 ±0) + p * (37 ±0)` + // Minimum execution time: 37_952_000 picoseconds. + Weight::from_parts(37_943_137, 8615) + // Standard Error: 994 + .saturating_add(Weight::from_parts(155_667, 0).saturating_mul(a.into())) + // Standard Error: 3_984 + .saturating_add(Weight::from_parts(20_119, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 68).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 29_341_000 picoseconds. - Weight::from_parts(30_320_504, 5698) - // Standard Error: 1_821 - .saturating_add(Weight::from_parts(158_572, 0).saturating_mul(a.into())) - // Standard Error: 1_881 - .saturating_add(Weight::from_parts(8_433, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 18_064_000 picoseconds. + Weight::from_parts(18_046_024, 8615) + // Standard Error: 690 + .saturating_add(Weight::from_parts(130_637, 0).saturating_mul(a.into())) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(27_361, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 28_422_000 picoseconds. - Weight::from_parts(29_754_384, 5698) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(176_827, 0).saturating_mul(a.into())) - // Standard Error: 1_901 - .saturating_add(Weight::from_parts(9_607, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 17_964_000 picoseconds. + Weight::from_parts(18_288_524, 8615) + // Standard Error: 953 + .saturating_add(Weight::from_parts(136_907, 0).saturating_mul(a.into())) + // Standard Error: 3_819 + .saturating_add(Weight::from_parts(11_084, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `453 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 36_885_000 picoseconds. - Weight::from_parts(38_080_636, 5698) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(157_335, 0).saturating_mul(a.into())) - // Standard Error: 2_730 - .saturating_add(Weight::from_parts(28_872, 0).saturating_mul(p.into())) + // Measured: `308 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615` + // Minimum execution time: 23_855_000 picoseconds. + Weight::from_parts(23_721_196, 8615) + // Standard Error: 813 + .saturating_add(Weight::from_parts(135_522, 0).saturating_mul(a.into())) + // Standard Error: 3_256 + .saturating_add(Weight::from_parts(42_377, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 27_016_000 picoseconds. - Weight::from_parts(28_296_216, 4706) - // Standard Error: 1_643 - .saturating_add(Weight::from_parts(50_271, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_854_000 picoseconds. + Weight::from_parts(18_203_947, 4254) + // Standard Error: 1_051 + .saturating_add(Weight::from_parts(44_781, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 26_955_000 picoseconds. - Weight::from_parts(28_379_566, 4706) - // Standard Error: 1_547 - .saturating_add(Weight::from_parts(45_784, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_815_000 picoseconds. + Weight::from_parts(19_464_499, 4254) + // Standard Error: 1_215 + .saturating_add(Weight::from_parts(44_540, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 24_656_000 picoseconds. - Weight::from_parts(25_821_878, 4706) - // Standard Error: 2_300 - .saturating_add(Weight::from_parts(33_972, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_245_000 picoseconds. + Weight::from_parts(18_987_977, 4254) + // Standard Error: 1_120 + .saturating_add(Weight::from_parts(18_728, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `4706` - // Minimum execution time: 28_416_000 picoseconds. - Weight::from_parts(29_662_728, 4706) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(29_928, 0).saturating_mul(p.into())) + // Measured: `139` + // Estimated: `4254` + // Minimum execution time: 18_836_000 picoseconds. + Weight::from_parts(19_336_942, 4254) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(17_419, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[0, 30]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 18]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `231 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_505_000 picoseconds. - Weight::from_parts(26_780_627, 4706) - // Standard Error: 1_581 - .saturating_add(Weight::from_parts(33_085, 0).saturating_mul(p.into())) + // Measured: `156 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_853_000 picoseconds. + Weight::from_parts(18_593_111, 4254) + // Standard Error: 990 + .saturating_add(Weight::from_parts(23_569, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `519` - // Estimated: `5698` - // Minimum execution time: 46_733_000 picoseconds. - Weight::from_parts(47_972_000, 5698) + // Measured: `412` + // Estimated: `8615` + // Minimum execution time: 31_739_000 picoseconds. + Weight::from_parts(32_491_000, 8615) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. + fn set_real_pays_fee(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 9_568_000 picoseconds. + Weight::from_parts(10_007_076, 4254) + // Standard Error: 854 + .saturating_add(Weight::from_parts(24_307, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests. impl WeightInfo for () { /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `339 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 23_353_000 picoseconds. - Weight::from_parts(25_084_085, 4706) - // Standard Error: 2_569 - .saturating_add(Weight::from_parts(33_574, 0).saturating_mul(p.into())) + // Measured: `625 + p * (37 ±0)` + // Estimated: `4254 + p * (37 ±0)` + // Minimum execution time: 19_346_000 picoseconds. + Weight::from_parts(19_857_012, 4254) + // Standard Error: 1_610 + .saturating_add(Weight::from_parts(42_156, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `TxPause::PausedCalls` (r:1 w:0) - /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Storage: `SubtensorModule::ColdkeySwapAnnouncements` (r:1 w:0) + /// Proof: `SubtensorModule::ColdkeySwapAnnouncements` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Proxy::LastCallResult` (r:0 w:1) + /// Proof: `Proxy::LastCallResult` (`max_values`: None, `max_size`: Some(47), added: 2522, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `666 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 47_196_000 picoseconds. - Weight::from_parts(48_686_812, 5698) - // Standard Error: 3_711 - .saturating_add(Weight::from_parts(171_107, 0).saturating_mul(a.into())) - // Standard Error: 3_834 - .saturating_add(Weight::from_parts(34_523, 0).saturating_mul(p.into())) + // Measured: `882 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615 + a * (68 ±0) + p * (37 ±0)` + // Minimum execution time: 37_952_000 picoseconds. + Weight::from_parts(37_943_137, 8615) + // Standard Error: 994 + .saturating_add(Weight::from_parts(155_667, 0).saturating_mul(a.into())) + // Standard Error: 3_984 + .saturating_add(Weight::from_parts(20_119, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 68).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 29_341_000 picoseconds. - Weight::from_parts(30_320_504, 5698) - // Standard Error: 1_821 - .saturating_add(Weight::from_parts(158_572, 0).saturating_mul(a.into())) - // Standard Error: 1_881 - .saturating_add(Weight::from_parts(8_433, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 18_064_000 picoseconds. + Weight::from_parts(18_046_024, 8615) + // Standard Error: 690 + .saturating_add(Weight::from_parts(130_637, 0).saturating_mul(a.into())) + // Standard Error: 2_766 + .saturating_add(Weight::from_parts(27_361, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `436 + a * (68 ±0)` - // Estimated: `5698` - // Minimum execution time: 28_422_000 picoseconds. - Weight::from_parts(29_754_384, 5698) - // Standard Error: 1_840 - .saturating_add(Weight::from_parts(176_827, 0).saturating_mul(a.into())) - // Standard Error: 1_901 - .saturating_add(Weight::from_parts(9_607, 0).saturating_mul(p.into())) + // Measured: `299 + a * (68 ±0)` + // Estimated: `8615` + // Minimum execution time: 17_964_000 picoseconds. + Weight::from_parts(18_288_524, 8615) + // Standard Error: 953 + .saturating_add(Weight::from_parts(136_907, 0).saturating_mul(a.into())) + // Standard Error: 3_819 + .saturating_add(Weight::from_parts(11_084, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:0) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `a` is `[0, 31]`. - /// The range of component `p` is `[1, 31]`. + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 74]`. + /// The range of component `p` is `[1, 19]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `453 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `5698` - // Minimum execution time: 36_885_000 picoseconds. - Weight::from_parts(38_080_636, 5698) - // Standard Error: 2_642 - .saturating_add(Weight::from_parts(157_335, 0).saturating_mul(a.into())) - // Standard Error: 2_730 - .saturating_add(Weight::from_parts(28_872, 0).saturating_mul(p.into())) + // Measured: `308 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `8615` + // Minimum execution time: 23_855_000 picoseconds. + Weight::from_parts(23_721_196, 8615) + // Standard Error: 813 + .saturating_add(Weight::from_parts(135_522, 0).saturating_mul(a.into())) + // Standard Error: 3_256 + .saturating_add(Weight::from_parts(42_377, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 27_016_000 picoseconds. - Weight::from_parts(28_296_216, 4706) - // Standard Error: 1_643 - .saturating_add(Weight::from_parts(50_271, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_854_000 picoseconds. + Weight::from_parts(18_203_947, 4254) + // Standard Error: 1_051 + .saturating_add(Weight::from_parts(44_781, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 26_955_000 picoseconds. - Weight::from_parts(28_379_566, 4706) - // Standard Error: 1_547 - .saturating_add(Weight::from_parts(45_784, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_815_000 picoseconds. + Weight::from_parts(19_464_499, 4254) + // Standard Error: 1_215 + .saturating_add(Weight::from_parts(44_540, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `194 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 24_656_000 picoseconds. - Weight::from_parts(25_821_878, 4706) - // Standard Error: 2_300 - .saturating_add(Weight::from_parts(33_972, 0).saturating_mul(p.into())) + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 18_245_000 picoseconds. + Weight::from_parts(18_987_977, 4254) + // Standard Error: 1_120 + .saturating_add(Weight::from_parts(18_728, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 31]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `206` - // Estimated: `4706` - // Minimum execution time: 28_416_000 picoseconds. - Weight::from_parts(29_662_728, 4706) - // Standard Error: 1_851 - .saturating_add(Weight::from_parts(29_928, 0).saturating_mul(p.into())) + // Measured: `139` + // Estimated: `4254` + // Minimum execution time: 18_836_000 picoseconds. + Weight::from_parts(19_336_942, 4254) + // Standard Error: 1_099 + .saturating_add(Weight::from_parts(17_419, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) - /// The range of component `p` is `[0, 30]`. + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 18]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `231 + p * (37 ±0)` - // Estimated: `4706` - // Minimum execution time: 25_505_000 picoseconds. - Weight::from_parts(26_780_627, 4706) - // Standard Error: 1_581 - .saturating_add(Weight::from_parts(33_085, 0).saturating_mul(p.into())) + // Measured: `156 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 17_853_000 picoseconds. + Weight::from_parts(18_593_111, 4254) + // Standard Error: 990 + .saturating_add(Weight::from_parts(23_569, 0).saturating_mul(p.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Proxy::Proxies` (r:1 w:1) - /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(104), added: 2579, mode: `MaxEncodedLen`) /// Storage: `Proxy::Announcements` (r:1 w:1) - /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(5150), added: 7625, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `519` - // Estimated: `5698` - // Minimum execution time: 46_733_000 picoseconds. - Weight::from_parts(47_972_000, 5698) + // Measured: `412` + // Estimated: `8615` + // Minimum execution time: 31_739_000 picoseconds. + Weight::from_parts(32_491_000, 8615) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } -} + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(789), added: 3264, mode: `MaxEncodedLen`) + /// Storage: `Proxy::RealPaysFee` (r:0 w:1) + /// Proof: `Proxy::RealPaysFee` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 19]`. + fn set_real_pays_fee(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `119 + p * (37 ±0)` + // Estimated: `4254` + // Minimum execution time: 9_568_000 picoseconds. + Weight::from_parts(10_007_076, 4254) + // Standard Error: 854 + .saturating_add(Weight::from_parts(24_307, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} \ No newline at end of file From eb4072cd0385e7cdf33471db20b3937f24d7250d Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 16:19:37 -0300 Subject: [PATCH 10/11] fix missing imports --- Cargo.lock | 2 ++ pallets/proxy/Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index cfb96c21d6..0b2a387c2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10781,6 +10781,8 @@ dependencies = [ name = "pallet-subtensor-proxy" version = "40.1.0" dependencies = [ + "frame-support", + "frame-system", "pallet-balances", "pallet-subtensor-utility", "parity-scale-codec", diff --git a/pallets/proxy/Cargo.toml b/pallets/proxy/Cargo.toml index 3d8da72029..9a7fd5b78e 100644 --- a/pallets/proxy/Cargo.toml +++ b/pallets/proxy/Cargo.toml @@ -19,6 +19,8 @@ codec = { workspace = true, features = ["max-encoded-len"] } frame = { workspace = true, features = ["runtime"] } scale-info = { workspace = true, features = ["derive"] } subtensor-macros.workspace = true +frame-system.workspace = true +frame-support.workspace = true [dev-dependencies] pallet-balances = { default-features = true, workspace = true } From 727243f27648673f1c77a68fe99f3a6ae43ce397 Mon Sep 17 00:00:00 2001 From: Loris Moulin Date: Fri, 27 Feb 2026 16:51:34 -0300 Subject: [PATCH 11/11] fix zepter check --- pallets/proxy/Cargo.toml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pallets/proxy/Cargo.toml b/pallets/proxy/Cargo.toml index 9a7fd5b78e..9331739325 100644 --- a/pallets/proxy/Cargo.toml +++ b/pallets/proxy/Cargo.toml @@ -28,14 +28,24 @@ pallet-subtensor-utility = { default-features = true, workspace = true } [features] default = ["std"] -std = ["codec/std", "frame/std", "scale-info/std"] +std = [ + "codec/std", + "frame/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", +] runtime-benchmarks = [ "frame/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-subtensor-utility/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", ] try-runtime = [ "frame/try-runtime", "pallet-balances/try-runtime", "pallet-subtensor-utility/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", ]