From 07883fb9f684a583cce05320d3e8ecba565f4e63 Mon Sep 17 00:00:00 2001 From: nasihudeen04 Date: Sat, 18 Jul 2026 10:39:41 +0100 Subject: [PATCH 1/4] Remove deprecated treasury spend_local and remove_approval. These calls (and related getters) were scheduled for removal by May 2025. Keep MaxApprovals and proposal storage so leftover approvals and bounties can still drain via spend_funds. --- .../src/weights/pallet_treasury.rs | 28 --- .../src/weights/pallet_treasury.rs | 28 --- .../rococo/src/weights/pallet_treasury.rs | 28 --- substrate/frame/bounties/src/tests.rs | 40 ++-- substrate/frame/child-bounties/src/tests.rs | 3 +- .../parachain/src/weights/pallet_treasury.rs | 28 --- .../rc/src/weights/pallet_treasury.rs | 28 --- substrate/frame/tips/src/tests.rs | 3 +- substrate/frame/treasury/src/benchmarking.rs | 83 +++----- substrate/frame/treasury/src/lib.rs | 177 ++-------------- substrate/frame/treasury/src/tests.rs | 199 ++++-------------- substrate/frame/treasury/src/weights.rs | 54 ----- 12 files changed, 112 insertions(+), 587 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_treasury.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_treasury.rs index bd90482f8f47..0a470cf4b9cd 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_treasury.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_treasury.rs @@ -47,34 +47,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:0 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `1887` - // Minimum execution time: 177_000_000 picoseconds. - Weight::from_parts(191_000_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1887` - // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(82_000_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } /// Storage: Treasury Deactivated (r:1 w:1) /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Balances InactiveIssuance (r:1 w:1) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs index 5e4a5a8b1edc..27d65277ba78 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs @@ -50,34 +50,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: `FellowshipTreasury::ProposalCount` (r:1 w:1) - /// Proof: `FellowshipTreasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) - /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `FellowshipTreasury::Proposals` (r:0 w:1) - /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1887` - // Minimum execution time: 12_879_000 picoseconds. - Weight::from_parts(13_346_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) - /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `161` - // Estimated: `1887` - // Minimum execution time: 6_978_000 picoseconds. - Weight::from_parts(7_278_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `FellowshipTreasury::Deactivated` (r:1 w:1) diff --git a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs index c875202a22fe..1ae5cbb96c90 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs @@ -51,34 +51,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `1887` - // Minimum execution time: 12_748_000 picoseconds. - Weight::from_parts(13_519_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `227` - // Estimated: `1887` - // Minimum execution time: 7_025_000 picoseconds. - Weight::from_parts(7_385_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } /// Storage: `Treasury::Deactivated` (r:1 w:1) /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Treasury::LastSpendPeriod` (r:1 w:1) diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index 812ae5b8e10a..29e7ba87e7f4 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -52,6 +52,24 @@ fn go_to_block(n: u64) { >::on_initialize(n); } +// Directly insert a proposal into the legacy treasury `ProposalCount`/`Proposals`/`Approvals` +// storage, bypassing the now-removed `spend_local` call. Returns the proposal index. Kept around +// so that spend-period tests exercising the legacy approvals queue still work. +fn add_treasury_proposal(value: u64, beneficiary: u128) -> pallet_treasury::ProposalIndex { + let proposal_index = pallet_treasury::ProposalCount::::get(); + pallet_treasury::Approvals::::try_append(proposal_index) + .expect("too many approvals"); + let proposal = pallet_treasury::Proposal { + proposer: beneficiary, + value, + beneficiary, + bond: Default::default(), + }; + pallet_treasury::Proposals::::insert(proposal_index, proposal); + pallet_treasury::ProposalCount::::put(proposal_index + 1); + proposal_index +} + frame_support::construct_runtime!( pub enum Test { @@ -274,11 +292,10 @@ fn expect_events(e: Vec>) { } #[test] -#[allow(deprecated)] fn genesis_config_works() { ExtBuilder::default().build_and_execute(|| { assert_eq!(Treasury::pot(), 0); - assert_eq!(Treasury::proposal_count(), 0); + assert_eq!(pallet_treasury::ProposalCount::::get(), 0); }); } @@ -292,12 +309,11 @@ fn minting_works() { } #[test] -#[allow(deprecated)] fn accepted_spend_proposal_ignored_outside_spend_period() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 100, 3) }); + add_treasury_proposal(100, 3); go_to_block(1); assert_eq!(Balances::free_balance(3), 0); @@ -319,13 +335,12 @@ fn unused_pot_should_diminish() { } #[test] -#[allow(deprecated)] fn accepted_spend_proposal_enacted_on_spend_period() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 100, 3) }); + add_treasury_proposal(100, 3); go_to_block(2); assert_eq!(Balances::free_balance(3), 100); @@ -334,13 +349,12 @@ fn accepted_spend_proposal_enacted_on_spend_period() { } #[test] -#[allow(deprecated)] fn pot_underflow_should_not_diminish() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 150, 3) }); + add_treasury_proposal(150, 3); go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -355,19 +369,18 @@ fn pot_underflow_should_not_diminish() { // Treasury account doesn't get deleted if amount approved to spend is all its free balance. // i.e. pot should not include existential deposit needed for account survival. #[test] -#[allow(deprecated)] fn treasury_account_doesnt_get_deleted() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), treasury_balance, 3) }); + add_treasury_proposal(treasury_balance, 3); go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), Treasury::pot(), 3) }); + add_treasury_proposal(Treasury::pot(), 3); go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -378,7 +391,6 @@ fn treasury_account_doesnt_get_deleted() { // In case treasury account is not existing then it works fine. // This is useful for chain that will just update runtime. #[test] -#[allow(deprecated)] fn inexistent_account_works() { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { @@ -394,8 +406,8 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 99, 3) }); - assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 1, 3) }); + add_treasury_proposal(99, 3); + add_treasury_proposal(1, 3); go_to_block(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index e0bb1ac6f75a..c7b7e723b5a6 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -169,11 +169,10 @@ fn last_event() -> ChildBountiesEvent { } #[test] -#[allow(deprecated)] fn genesis_config_works() { new_test_ext().execute_with(|| { assert_eq!(Treasury::pot(), 0); - assert_eq!(Treasury::proposal_count(), 0); + assert_eq!(pallet_treasury::ProposalCount::::get(), 0); }); } diff --git a/substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_treasury.rs b/substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_treasury.rs index 80fd80017608..44cbdde1229c 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_treasury.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/weights/pallet_treasury.rs @@ -47,34 +47,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:0 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `1887` - // Minimum execution time: 177_000_000 picoseconds. - Weight::from_parts(191_000_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `127` - // Estimated: `1887` - // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(82_000_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } /// Storage: Treasury Deactivated (r:1 w:1) /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// Storage: Balances InactiveIssuance (r:1 w:1) diff --git a/substrate/frame/staking-async/runtimes/rc/src/weights/pallet_treasury.rs b/substrate/frame/staking-async/runtimes/rc/src/weights/pallet_treasury.rs index 2ff1b7ec304f..2b7c0ac5d8d4 100644 --- a/substrate/frame/staking-async/runtimes/rc/src/weights/pallet_treasury.rs +++ b/substrate/frame/staking-async/runtimes/rc/src/weights/pallet_treasury.rs @@ -51,34 +51,6 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `1887` - // Minimum execution time: 13_064_000 picoseconds. - Weight::from_parts(13_610_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `227` - // Estimated: `1887` - // Minimum execution time: 7_097_000 picoseconds. - Weight::from_parts(7_538_000, 0) - .saturating_add(Weight::from_parts(0, 1887)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Treasury::Deactivated` (r:1 w:1) diff --git a/substrate/frame/tips/src/tests.rs b/substrate/frame/tips/src/tests.rs index 47388a108622..5a1ca6842345 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -212,11 +212,10 @@ fn last_event() -> TipEvent { } #[test] -#[allow(deprecated)] fn genesis_config_works() { build_and_execute(|| { assert_eq!(Treasury::pot(), 0); - assert_eq!(Treasury::proposal_count(), 0); + assert_eq!(pallet_treasury::ProposalCount::::get(), 0); }); } diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index a11723a27b2c..a197319f926d 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -59,16 +59,34 @@ where const SEED: u32 = 0; -// Create the pre-requisite information needed to create a treasury `spend_local`. +// Create the pre-requisite information needed to create a legacy treasury proposal. fn setup_proposal, I: 'static>( u: u32, -) -> (T::AccountId, BalanceOf, AccountIdLookupOf) { +) -> (T::AccountId, BalanceOf, T::AccountId) { let caller = account("caller", u, SEED); let value: BalanceOf = T::Currency::minimum_balance() * 100u32.into(); let _ = T::Currency::make_free_balance_be(&caller, value); let beneficiary = account("beneficiary", u, SEED); - let beneficiary_lookup = T::Lookup::unlookup(beneficiary); - (caller, value, beneficiary_lookup) + (caller, value, beneficiary) +} + +// Directly insert a proposal into the legacy `ProposalCount`/`Proposals`/`Approvals` storage, +// bypassing the now-removed `spend_local` call. Returns the proposal index. +fn add_proposal, I: 'static>( + value: BalanceOf, + beneficiary: T::AccountId, +) -> Result { + let proposal_index = ProposalCount::::get(); + Approvals::::try_append(proposal_index).map_err(|_| "Too many approvals")?; + let proposal = Proposal { + proposer: beneficiary.clone(), + value, + beneficiary, + bond: Default::default(), + }; + Proposals::::insert(proposal_index, proposal); + ProposalCount::::put(proposal_index + 1); + Ok(proposal_index) } // Create proposals that are approved for use in `on_initialize`. @@ -76,11 +94,10 @@ fn create_approved_proposals, I: 'static>(n: u32) -> Result<(), &'s let spender = T::SpendOrigin::try_successful_origin(); for i in 0..n { - let (_, value, lookup) = setup_proposal::(i); + let (_, value, beneficiary) = setup_proposal::(i); - #[allow(deprecated)] - if let Ok(origin) = &spender { - Treasury::::spend_local(origin.clone(), value, lookup)?; + if spender.is_ok() { + add_proposal::(value, beneficiary)?; } } @@ -114,56 +131,6 @@ fn create_spend_arguments, I: 'static>( mod benchmarks { use super::*; - /// This benchmark is short-circuited if `SpendOrigin` cannot provide - /// a successful origin, in which case `spend` is un-callable and can use weight=0. - #[benchmark] - fn spend_local() -> Result<(), BenchmarkError> { - let (_, value, beneficiary_lookup) = setup_proposal::(SEED); - let origin = - T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap(); - - #[extrinsic_call] - _(origin as T::RuntimeOrigin, value, beneficiary_lookup); - - assert_last_event::( - Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into(), - ); - Ok(()) - } - - #[benchmark] - fn remove_approval() -> Result<(), BenchmarkError> { - let (spend_exists, proposal_id) = - if let Ok(origin) = T::SpendOrigin::try_successful_origin() { - let (_, value, beneficiary_lookup) = setup_proposal::(SEED); - #[allow(deprecated)] - Treasury::::spend_local(origin, value, beneficiary_lookup)?; - let proposal_id = ProposalCount::::get() - 1; - - (true, proposal_id) - } else { - (false, 0) - }; - - let reject_origin = - T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - - #[block] - { - #[allow(deprecated)] - let res = Treasury::::remove_approval(reject_origin as T::RuntimeOrigin, proposal_id); - - if spend_exists { - assert_ok!(res); - } else { - assert_err!(res, Error::::ProposalNotApproved); - } - } - - Ok(()) - } - #[benchmark] fn on_initialize_proposals( p: Linear<0, { T::MaxApprovals::get() - 1 }>, diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 91c58e14e52e..377d2723b72b 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -48,9 +48,7 @@ //! //! ### Example //! -//! 1. Multiple local spends approved by spend origins and received by a beneficiary. -#![doc = docify::embed!("src/tests.rs", spend_local_origin_works)] -//! 2. Approve a spend of some asset kind and claim it. +//! 1. Approve a spend of some asset kind and claim it. #![doc = docify::embed!("src/tests.rs", spend_payout_works)] //! ## Pallet API //! @@ -59,14 +57,16 @@ //! //! ## Low Level / Implementation Details //! -//! Spends can be initiated using either the `spend_local` or `spend` dispatchable. The -//! `spend_local` dispatchable enables the creation of spends using the native currency of the -//! chain, utilizing the funds stored in the pot. These spends are automatically paid out every -//! [`pallet::Config::SpendPeriod`]. On the other hand, the `spend` dispatchable allows spending of -//! any asset kind managed by the treasury, with payment facilitated by a designated +//! Spends are initiated using the `spend` dispatchable, which allows spending of any asset kind +//! managed by the treasury, with payment facilitated by a designated //! [`pallet::Config::Paymaster`]. To claim these spends, the `payout` dispatchable should be called //! within some temporal bounds, starting from the moment they become valid and within one //! [`pallet::Config::PayoutPeriod`]. +//! +//! A legacy queue of approvals (see [`Approvals`]) may still exist from before the removal of the +//! deprecated `spend_local` call. Any entries left in that queue continue to be drained and paid +//! out from [`Pallet::spend_funds`] every [`pallet::Config::SpendPeriod`]; the bounties pallet also +//! relies on the same queue (bounded by [`pallet::Config::MaxApprovals`]) to schedule its payouts. #![cfg_attr(not(feature = "std"), no_std)] @@ -118,7 +118,6 @@ pub type PositiveImbalanceOf = <>::Currency as Currenc pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; type BeneficiaryLookupOf = <>::BeneficiaryLookup as StaticLookup>::Source; pub type BlockNumberFor = <>::BlockNumberProvider as BlockNumberProvider>::BlockNumber; @@ -247,8 +246,7 @@ pub mod pallet { /// Runtime hooks to external pallet using treasury to compute spend funds. type SpendFunds: SpendFunds; - /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. - /// Refer to for migration to `spend`. + /// Legacy leftover from the removed `spend_local` call. /// /// The maximum number of approvals that can wait in the spending queue. /// @@ -302,15 +300,13 @@ pub mod pallet { } } - /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. - /// Refer to for migration to `spend`. + /// Legacy leftover from the removed `spend_local` call. /// /// Number of proposals that have been made. #[pallet::storage] pub type ProposalCount = StorageValue<_, ProposalIndex, ValueQuery>; - /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. - /// Refer to for migration to `spend`. + /// Legacy leftover from the removed `spend_local` call. /// /// Proposals that have been made. #[pallet::storage] @@ -327,8 +323,9 @@ pub mod pallet { pub type Deactivated, I: 'static = ()> = StorageValue<_, BalanceOf, ValueQuery>; - /// DEPRECATED: associated with `spend_local` call and will be removed in May 2025. - /// Refer to for migration to `spend`. + /// Legacy leftover from the removed `spend_local` call. Still drained by + /// [`Pallet::spend_funds`] every spend period, and used by the Bounties Pallet extension to + /// schedule bounty payouts (bounded by [`Config::MaxApprovals`]). /// /// Proposal indices that have been approved but not yet awarded. #[pallet::storage] @@ -502,124 +499,6 @@ pub mod pallet { #[pallet::call] impl, I: 'static> Pallet { - /// Propose and approve a spend of treasury funds. - /// - /// ## Dispatch Origin - /// - /// Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`. - /// - /// ### Details - /// NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the - /// beneficiary. - /// - /// ### Parameters - /// - `amount`: The amount to be transferred from the treasury to the `beneficiary`. - /// - `beneficiary`: The destination account for the transfer. - /// - /// ## Events - /// - /// Emits [`Event::SpendApproved`] if successful. - #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::spend_local())] - #[deprecated( - note = "The `spend_local` call will be removed by May 2025. Migrate to the new flow and use the `spend` call." - )] - #[allow(deprecated)] - pub fn spend_local( - origin: OriginFor, - #[pallet::compact] amount: BalanceOf, - beneficiary: AccountIdLookupOf, - ) -> DispatchResult { - let max_amount = T::SpendOrigin::ensure_origin(origin)?; - ensure!(amount <= max_amount, Error::::InsufficientPermission); - - with_context::>, _>(|v| { - let context = v.or_default(); - - // We group based on `max_amount`, to distinguish between different kind of - // origins. (assumes that all origins have different `max_amount`) - // - // Worst case is that we reject some "valid" request. - let spend = context.spend_in_context.entry(max_amount).or_default(); - - // Ensure that we don't overflow nor use more than `max_amount` - if spend.checked_add(&amount).map(|s| s > max_amount).unwrap_or(true) { - Err(Error::::InsufficientPermission) - } else { - *spend = spend.saturating_add(amount); - - Ok(()) - } - }) - .unwrap_or(Ok(()))?; - - let beneficiary = T::Lookup::lookup(beneficiary)?; - #[allow(deprecated)] - let proposal_index = ProposalCount::::get(); - #[allow(deprecated)] - Approvals::::try_append(proposal_index) - .map_err(|_| Error::::TooManyApprovals)?; - let proposal = Proposal { - proposer: beneficiary.clone(), - value: amount, - beneficiary: beneficiary.clone(), - bond: Default::default(), - }; - #[allow(deprecated)] - Proposals::::insert(proposal_index, proposal); - #[allow(deprecated)] - ProposalCount::::put(proposal_index + 1); - - Self::deposit_event(Event::SpendApproved { proposal_index, amount, beneficiary }); - Ok(()) - } - - /// Force a previously approved proposal to be removed from the approval queue. - /// - /// ## Dispatch Origin - /// - /// Must be [`Config::RejectOrigin`]. - /// - /// ## Details - /// - /// The original deposit will no longer be returned. - /// - /// ### Parameters - /// - `proposal_id`: The index of a proposal - /// - /// ### Complexity - /// - O(A) where `A` is the number of approvals - /// - /// ### Errors - /// - [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the - /// approval queue, i.e., the proposal has not been approved. This could also mean the - /// proposal does not exist altogether, thus there is no way it would have been approved - /// in the first place. - #[pallet::call_index(4)] - #[pallet::weight((T::WeightInfo::remove_approval(), DispatchClass::Operational))] - #[deprecated( - note = "The `remove_approval` call will be removed by May 2025. It associated with the deprecated `spend_local` call." - )] - #[allow(deprecated)] - pub fn remove_approval( - origin: OriginFor, - #[pallet::compact] proposal_id: ProposalIndex, - ) -> DispatchResult { - T::RejectOrigin::ensure_origin(origin)?; - - #[allow(deprecated)] - Approvals::::try_mutate(|v| -> DispatchResult { - if let Some(index) = v.iter().position(|x| x == &proposal_id) { - v.remove(index); - Ok(()) - } else { - Err(Error::::ProposalNotApproved.into()) - } - })?; - - Ok(()) - } - /// Propose and approve a spend of treasury funds. /// /// ## Dispatch Origin @@ -876,33 +755,6 @@ impl, I: 'static> Pallet { last_spend_period } - /// Public function to proposal_count storage. - #[deprecated( - note = "This function will be removed by May 2025. Configure pallet to use PayFromAccount for Paymaster type instead" - )] - pub fn proposal_count() -> ProposalIndex { - #[allow(deprecated)] - ProposalCount::::get() - } - - /// Public function to proposals storage. - #[deprecated( - note = "This function will be removed by May 2025. Configure pallet to use PayFromAccount for Paymaster type instead" - )] - pub fn proposals(index: ProposalIndex) -> Option>> { - #[allow(deprecated)] - Proposals::::get(index) - } - - /// Public function to approvals storage. - #[deprecated( - note = "This function will be removed by May 2025. Configure pallet to use PayFromAccount for Paymaster type instead" - )] - #[allow(deprecated)] - pub fn approvals() -> BoundedVec { - Approvals::::get() - } - /// Spend some money! returns number of approvals before spend. pub fn spend_funds( spend_periods_passed: BlockNumberFor, @@ -917,7 +769,6 @@ impl, I: 'static> Pallet { let mut missed_any = false; let mut imbalance = PositiveImbalanceOf::::zero(); - #[allow(deprecated)] let proposals_len = Approvals::::mutate(|v| { let proposals_approvals_len = v.len() as u32; v.retain(|&index| { diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index 41a37cf98918..df2a1daf4ee0 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -21,7 +21,7 @@ use core::{cell::RefCell, marker::PhantomData}; use sp_runtime::{ - traits::{BadOrigin, Dispatchable, IdentityLookup}, + traits::{Dispatchable, IdentityLookup}, BuildStorage, }; @@ -242,61 +242,24 @@ fn get_payment_id(i: SpendIndex) -> Option { } } -#[test] -fn genesis_config_works() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(Treasury::pot(), 0); - assert_eq!(ProposalCount::::get(), 0); - }); -} - -#[test] -fn spend_local_origin_permissioning_works() { - #[allow(deprecated)] - ExtBuilder::default().build().execute_with(|| { - assert_noop!(Treasury::spend_local(RuntimeOrigin::signed(1), 1, 1), BadOrigin); - assert_noop!( - Treasury::spend_local(RuntimeOrigin::signed(10), 6, 1), - Error::::InsufficientPermission - ); - assert_noop!( - Treasury::spend_local(RuntimeOrigin::signed(11), 11, 1), - Error::::InsufficientPermission - ); - assert_noop!( - Treasury::spend_local(RuntimeOrigin::signed(12), 21, 1), - Error::::InsufficientPermission - ); - assert_noop!( - Treasury::spend_local(RuntimeOrigin::signed(13), 51, 1), - Error::::InsufficientPermission - ); - }); +// Directly insert a proposal into the legacy `ProposalCount`/`Proposals`/`Approvals` storage, +// bypassing the now-removed `spend_local` call. Returns the proposal index. Kept around so that +// spend-period / integrity tests exercising the legacy approvals queue still work. +fn add_proposal(value: u64, beneficiary: u128) -> ProposalIndex { + let proposal_index = ProposalCount::::get(); + Approvals::::try_append(proposal_index).expect("too many approvals"); + let proposal = + Proposal { proposer: beneficiary, value, beneficiary, bond: Default::default() }; + Proposals::::insert(proposal_index, proposal); + ProposalCount::::put(proposal_index + 1); + proposal_index } -#[docify::export] #[test] -fn spend_local_origin_works() { - #[allow(deprecated)] +fn genesis_config_works() { ExtBuilder::default().build().execute_with(|| { - // Check that accumulate works when we have Some value in Dummy already. - Balances::make_free_balance_be(&Treasury::account_id(), 102); - // approve spend of some amount to beneficiary `6`. - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(11), 10, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(12), 20, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(13), 50, 6)); - // free balance of `6` is zero, spend period has not passed. - go_to_block(1); - assert_eq!(Balances::free_balance(6), 0); - // free balance of `6` is `100`, spend period has passed. - go_to_block(2); - assert_eq!(Balances::free_balance(6), 100); - // `100` spent, `1` burned, `1` in ED. assert_eq!(Treasury::pot(), 0); + assert_eq!(ProposalCount::::get(), 0); }); } @@ -314,10 +277,7 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); - } + add_proposal(100, 3); go_to_block(1); assert_eq!(Balances::free_balance(3), 0); @@ -344,10 +304,7 @@ fn accepted_spend_proposal_enacted_on_spend_period() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); - } + add_proposal(100, 3); go_to_block(2); assert_eq!(Balances::free_balance(3), 100); @@ -361,10 +318,7 @@ fn pot_underflow_should_not_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 150, 3)); - } + add_proposal(150, 3); go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -384,19 +338,17 @@ fn treasury_account_doesnt_get_deleted() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), treasury_balance, 3)); - >::on_initialize(2); - assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), treasury_balance, 3)); + add_proposal(treasury_balance, 3); + >::on_initialize(2); + assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - go_to_block(2); - assert_eq!(Treasury::pot(), 100); // Pot hasn't changed + add_proposal(treasury_balance, 3); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), Treasury::pot(), 3)); - } + go_to_block(2); + assert_eq!(Treasury::pot(), 100); // Pot hasn't changed + + add_proposal(Treasury::pot(), 3); go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -422,11 +374,8 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 99, 3)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); - } + add_proposal(99, 3); + add_proposal(1, 3); go_to_block(2); @@ -466,67 +415,21 @@ fn genesis_funding_works() { #[test] fn max_approvals_limited() { - #[allow(deprecated)] ExtBuilder::default().build().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), u64::MAX); Balances::make_free_balance_be(&0, u64::MAX); for _ in 0..::MaxApprovals::get() { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); + add_proposal(100, 3); } - // One too many will fail - assert_noop!( - Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3), - Error::::TooManyApprovals - ); + // One too many will fail: the `Approvals` bound is enforced directly since there is no + // dispatchable left that can grow the legacy approvals queue. + let proposal_index = ProposalCount::::get(); + assert!(Approvals::::try_append(proposal_index).is_err()); }); } -#[test] -fn remove_already_removed_approval_fails() { - #[allow(deprecated)] - ExtBuilder::default().build().execute_with(|| { - Balances::make_free_balance_be(&Treasury::account_id(), 101); - - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 100, 3)); - - assert_eq!(Approvals::::get(), vec![0]); - assert_ok!(Treasury::remove_approval(RuntimeOrigin::root(), 0)); - assert_eq!(Approvals::::get(), vec![]); - - assert_noop!( - Treasury::remove_approval(RuntimeOrigin::root(), 0), - Error::::ProposalNotApproved - ); - }); -} - -#[test] -fn spending_local_in_batch_respects_max_total() { - ExtBuilder::default().build().execute_with(|| { - // Respect the `max_total` for the given origin. - assert_ok!(RuntimeCall::from(UtilityCall::batch_all { - calls: vec![ - RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 100 }), - RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 101 }) - ] - }) - .dispatch(RuntimeOrigin::signed(10))); - - assert_err_ignore_postinfo!( - RuntimeCall::from(UtilityCall::batch_all { - calls: vec![ - RuntimeCall::from(TreasuryCall::spend_local { amount: 2, beneficiary: 100 }), - RuntimeCall::from(TreasuryCall::spend_local { amount: 4, beneficiary: 101 }) - ] - }) - .dispatch(RuntimeOrigin::signed(10)), - Error::::InsufficientPermission - ); - }) -} - #[test] fn spending_in_batch_respects_max_total() { ExtBuilder::default().build().execute_with(|| { @@ -853,11 +756,8 @@ fn check_status_works() { fn try_state_proposals_invariant_1_works() { ExtBuilder::default().build().execute_with(|| { use frame_support::pallet_prelude::DispatchError::Other; - // Add a proposal and approve using `spend_local` - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); - } + // Add a proposal and approve it + add_proposal(1, 3); assert_eq!(Proposals::::iter().count(), 1); assert_eq!(ProposalCount::::get(), 1); @@ -877,11 +777,8 @@ fn try_state_proposals_invariant_1_works() { fn try_state_proposals_invariant_2_works() { ExtBuilder::default().build().execute_with(|| { use frame_support::pallet_prelude::DispatchError::Other; - #[allow(deprecated)] - { - // Add a proposal and approve using `spend_local` - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 1, 3)); - } + // Add a proposal and approve it + add_proposal(1, 3); assert_eq!(Proposals::::iter().count(), 1); assert_eq!(Approvals::::get().len(), 1); @@ -909,11 +806,8 @@ fn try_state_proposals_invariant_2_works() { fn try_state_proposals_invariant_3_works() { ExtBuilder::default().build().execute_with(|| { use frame_support::pallet_prelude::DispatchError::Other; - // Add a proposal and approve using `spend_local` - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(14), 10, 3)); - } + // Add a proposal and approve it + add_proposal(10, 3); assert_eq!(Proposals::::iter().count(), 1); assert_eq!(Approvals::::get().len(), 1); @@ -1019,16 +913,13 @@ fn multiple_spend_periods_work() { // 100 will be spent, 1024 will be the burn amount, 1 for ED Balances::make_free_balance_be(&Treasury::account_id(), 100 + 1024 + 1); // approve spend of total amount 100 to beneficiary `6`. - #[allow(deprecated)] - { - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(11), 10, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(12), 20, 6)); - assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(13), 50, 6)); - } + add_proposal(5, 6); + add_proposal(5, 6); + add_proposal(5, 6); + add_proposal(5, 6); + add_proposal(10, 6); + add_proposal(20, 6); + add_proposal(50, 6); // free balance of `6` is zero, spend period has not passed. go_to_block(1); assert_eq!(Balances::free_balance(6), 0); diff --git a/substrate/frame/treasury/src/weights.rs b/substrate/frame/treasury/src/weights.rs index b2c9da1ffddb..61c9ad5441e1 100644 --- a/substrate/frame/treasury/src/weights.rs +++ b/substrate/frame/treasury/src/weights.rs @@ -72,8 +72,6 @@ use core::marker::PhantomData; /// Weight functions needed for `pallet_treasury`. pub trait WeightInfo { - fn spend_local() -> Weight; - fn remove_approval() -> Weight; fn on_initialize_proposals(p: u32, ) -> Weight; fn spend() -> Weight; fn payout() -> Weight; @@ -84,32 +82,6 @@ pub trait WeightInfo { /// Weights for `pallet_treasury` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1887` - // Minimum execution time: 9_084_000 picoseconds. - Weight::from_parts(9_260_000, 1887) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1887` - // Minimum execution time: 5_149_000 picoseconds. - Weight::from_parts(5_358_000, 1887) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } /// Storage: `Treasury::Deactivated` (r:1 w:1) /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Treasury::LastSpendPeriod` (r:1 w:1) @@ -184,32 +156,6 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: `Treasury::ProposalCount` (r:1 w:1) - /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - /// Storage: `Treasury::Proposals` (r:0 w:1) - /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) - fn spend_local() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1887` - // Minimum execution time: 9_084_000 picoseconds. - Weight::from_parts(9_260_000, 1887) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: `Treasury::Approvals` (r:1 w:1) - /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) - fn remove_approval() -> Weight { - // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1887` - // Minimum execution time: 5_149_000 picoseconds. - Weight::from_parts(5_358_000, 1887) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: `Treasury::Deactivated` (r:1 w:1) /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Treasury::LastSpendPeriod` (r:1 w:1) From 772ac3a395670af1688bef15eee970658a8721e0 Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 09:43:44 +0000 Subject: [PATCH 2/4] Update from github-actions[bot] running command 'prdoc --audience runtime_dev --bump major' --- prdoc/pr_12683.prdoc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 prdoc/pr_12683.prdoc diff --git a/prdoc/pr_12683.prdoc b/prdoc/pr_12683.prdoc new file mode 100644 index 000000000000..2822c64b845b --- /dev/null +++ b/prdoc/pr_12683.prdoc @@ -0,0 +1,26 @@ +title: Remove deprecated treasury spend_local and remove_approval +doc: +- audience: Runtime Dev + description: |- + ## Summary + + - Removed `spend_local` and `remove_approval` (deprecated by May 2025), plus the related public getters. + - Keeped `MaxApprovals` and `ProposalCount` / `Proposals` / `Approvals` so leftover approvals still pay out via `spend_funds`, and so bounties can keep using `MaxApprovals`. + - Updated tests/benchmarks to seed legacy proposal storage directly; drop weight methods from runtime weight files. + + Part of #11561 +crates: +- name: asset-hub-westend-runtime + bump: major +- name: collectives-westend-runtime + bump: major +- name: rococo-runtime + bump: major +- name: pallet-bounties + bump: major +- name: pallet-child-bounties + bump: major +- name: pallet-tips + bump: major +- name: pallet-treasury + bump: major From 6b318e9e6aae7bc1236d57a6efc87eaa82463c70 Mon Sep 17 00:00:00 2001 From: Nasihudeen Jimoh Date: Sat, 18 Jul 2026 11:28:16 +0100 Subject: [PATCH 3/4] clean prdoc --- prdoc/pr_12683.prdoc | 3 --- 1 file changed, 3 deletions(-) diff --git a/prdoc/pr_12683.prdoc b/prdoc/pr_12683.prdoc index 2822c64b845b..0b511d5462f2 100644 --- a/prdoc/pr_12683.prdoc +++ b/prdoc/pr_12683.prdoc @@ -3,12 +3,9 @@ doc: - audience: Runtime Dev description: |- ## Summary - - Removed `spend_local` and `remove_approval` (deprecated by May 2025), plus the related public getters. - Keeped `MaxApprovals` and `ProposalCount` / `Proposals` / `Approvals` so leftover approvals still pay out via `spend_funds`, and so bounties can keep using `MaxApprovals`. - Updated tests/benchmarks to seed legacy proposal storage directly; drop weight methods from runtime weight files. - - Part of #11561 crates: - name: asset-hub-westend-runtime bump: major From 11b64ad707c6656bb24981ad05958ec7e153a486 Mon Sep 17 00:00:00 2001 From: nasihudeen04 Date: Sat, 18 Jul 2026 12:48:56 +0100 Subject: [PATCH 4/4] fmt: fix treasury spend_local removal formatting --- substrate/frame/bounties/src/tests.rs | 3 +-- substrate/frame/treasury/src/benchmarking.rs | 8 ++------ substrate/frame/treasury/src/tests.rs | 3 +-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index 29e7ba87e7f4..c0142cc5eb2c 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -57,8 +57,7 @@ fn go_to_block(n: u64) { // so that spend-period tests exercising the legacy approvals queue still work. fn add_treasury_proposal(value: u64, beneficiary: u128) -> pallet_treasury::ProposalIndex { let proposal_index = pallet_treasury::ProposalCount::::get(); - pallet_treasury::Approvals::::try_append(proposal_index) - .expect("too many approvals"); + pallet_treasury::Approvals::::try_append(proposal_index).expect("too many approvals"); let proposal = pallet_treasury::Proposal { proposer: beneficiary, value, diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index a197319f926d..b3eea6d155aa 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -78,12 +78,8 @@ fn add_proposal, I: 'static>( ) -> Result { let proposal_index = ProposalCount::::get(); Approvals::::try_append(proposal_index).map_err(|_| "Too many approvals")?; - let proposal = Proposal { - proposer: beneficiary.clone(), - value, - beneficiary, - bond: Default::default(), - }; + let proposal = + Proposal { proposer: beneficiary.clone(), value, beneficiary, bond: Default::default() }; Proposals::::insert(proposal_index, proposal); ProposalCount::::put(proposal_index + 1); Ok(proposal_index) diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index df2a1daf4ee0..54a37d9a5edf 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -248,8 +248,7 @@ fn get_payment_id(i: SpendIndex) -> Option { fn add_proposal(value: u64, beneficiary: u128) -> ProposalIndex { let proposal_index = ProposalCount::::get(); Approvals::::try_append(proposal_index).expect("too many approvals"); - let proposal = - Proposal { proposer: beneficiary, value, beneficiary, bond: Default::default() }; + let proposal = Proposal { proposer: beneficiary, value, beneficiary, bond: Default::default() }; Proposals::::insert(proposal_index, proposal); ProposalCount::::put(proposal_index + 1); proposal_index