From b059f6726b9fb7c0b4bccb6c140bb48d91fcbdd9 Mon Sep 17 00:00:00 2001 From: Daniel Olano Date: Sat, 28 Oct 2023 16:15:07 +0200 Subject: [PATCH] Change TracksInfo::tracks to return an iterator Using an iterator instead of a static slice allows for more flexible implementations of `TracksInfo` that can use the chain storage without compromising a lot on the performance/memory penalty if we were to return an owned `Vec` instead. --- .../rococo/src/governance/fellowship.rs | 27 +++++++------ .../runtime/rococo/src/governance/tracks.rs | 39 ++++++++++--------- .../runtime/westend/src/governance/tracks.rs | 39 ++++++++++--------- substrate/frame/referenda/src/benchmarking.rs | 2 +- substrate/frame/referenda/src/lib.rs | 34 +++++++--------- substrate/frame/referenda/src/mock.rs | 11 ++++-- substrate/frame/referenda/src/tests.rs | 5 ++- substrate/frame/referenda/src/types.rs | 21 ++++++---- 8 files changed, 95 insertions(+), 83 deletions(-) diff --git a/polkadot/runtime/rococo/src/governance/fellowship.rs b/polkadot/runtime/rococo/src/governance/fellowship.rs index b5df6cf2df341..c7a247b871166 100644 --- a/polkadot/runtime/rococo/src/governance/fellowship.rs +++ b/polkadot/runtime/rococo/src/governance/fellowship.rs @@ -18,6 +18,7 @@ use frame_support::traits::{MapSuccess, TryMapSuccess}; use sp_runtime::traits::{CheckedReduceBy, ConstU16, Replace}; +use sp_std::borrow::Cow::Borrowed; use super::*; use crate::{CENTS, DAYS}; @@ -32,12 +33,14 @@ pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { type Id = u16; type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + type TracksIter = pallet_referenda::StaticTracksIter; + + fn tracks() -> Self::TracksIter { static DATA: [(u16, pallet_referenda::TrackInfo); 10] = [ ( 0u16, pallet_referenda::TrackInfo { - name: "candidates", + name: Borrowed("candidates"), max_deciding: 10, decision_deposit: 100 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -59,7 +62,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 1u16, pallet_referenda::TrackInfo { - name: "members", + name: Borrowed("members"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -81,7 +84,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 2u16, pallet_referenda::TrackInfo { - name: "proficients", + name: Borrowed("proficients"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -103,7 +106,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 3u16, pallet_referenda::TrackInfo { - name: "fellows", + name: Borrowed("fellows"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -125,7 +128,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 4u16, pallet_referenda::TrackInfo { - name: "senior fellows", + name: Borrowed("senior fellows"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -147,7 +150,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 5u16, pallet_referenda::TrackInfo { - name: "experts", + name: Borrowed("experts"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -169,7 +172,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 6u16, pallet_referenda::TrackInfo { - name: "senior experts", + name: Borrowed("senior experts"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -191,7 +194,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 7u16, pallet_referenda::TrackInfo { - name: "masters", + name: Borrowed("masters"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -213,7 +216,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 8u16, pallet_referenda::TrackInfo { - name: "senior masters", + name: Borrowed("senior masters"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -235,7 +238,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { ( 9u16, pallet_referenda::TrackInfo { - name: "grand masters", + name: Borrowed("grand masters"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -255,7 +258,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { }, ), ]; - &DATA[..] + DATA.iter().cloned() } fn track_for(id: &Self::RuntimeOrigin) -> Result { use super::origins::Origin; diff --git a/polkadot/runtime/rococo/src/governance/tracks.rs b/polkadot/runtime/rococo/src/governance/tracks.rs index 3765569f183e0..1f48f713037c3 100644 --- a/polkadot/runtime/rococo/src/governance/tracks.rs +++ b/polkadot/runtime/rococo/src/governance/tracks.rs @@ -21,7 +21,8 @@ use super::*; const fn percent(x: i32) -> sp_arithmetic::FixedI64 { sp_arithmetic::FixedI64::from_rational(x as u128, 100) } -use pallet_referenda::Curve; +use pallet_referenda::{Curve, StaticTracksIter}; +use sp_std::borrow::Cow::Borrowed; const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); const APP_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); @@ -69,7 +70,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 0, pallet_referenda::TrackInfo { - name: "root", + name: Borrowed("root"), max_deciding: 1, decision_deposit: 100 * GRAND, prepare_period: 8 * MINUTES, @@ -83,7 +84,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 1, pallet_referenda::TrackInfo { - name: "whitelisted_caller", + name: Borrowed("whitelisted_caller"), max_deciding: 100, decision_deposit: 10 * GRAND, prepare_period: 6 * MINUTES, @@ -97,7 +98,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 10, pallet_referenda::TrackInfo { - name: "staking_admin", + name: Borrowed("staking_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -111,7 +112,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 11, pallet_referenda::TrackInfo { - name: "treasurer", + name: Borrowed("treasurer"), max_deciding: 10, decision_deposit: 1 * GRAND, prepare_period: 8 * MINUTES, @@ -125,7 +126,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 12, pallet_referenda::TrackInfo { - name: "lease_admin", + name: Borrowed("lease_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -139,7 +140,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 13, pallet_referenda::TrackInfo { - name: "fellowship_admin", + name: Borrowed("fellowship_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -153,7 +154,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 14, pallet_referenda::TrackInfo { - name: "general_admin", + name: Borrowed("general_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -167,7 +168,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 15, pallet_referenda::TrackInfo { - name: "auction_admin", + name: Borrowed("auction_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -181,7 +182,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 20, pallet_referenda::TrackInfo { - name: "referendum_canceller", + name: Borrowed("referendum_canceller"), max_deciding: 1_000, decision_deposit: 10 * GRAND, prepare_period: 8 * MINUTES, @@ -195,7 +196,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 21, pallet_referenda::TrackInfo { - name: "referendum_killer", + name: Borrowed("referendum_killer"), max_deciding: 1_000, decision_deposit: 50 * GRAND, prepare_period: 8 * MINUTES, @@ -209,7 +210,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 30, pallet_referenda::TrackInfo { - name: "small_tipper", + name: Borrowed("small_tipper"), max_deciding: 200, decision_deposit: 1 * 3 * CENTS, prepare_period: 1 * MINUTES, @@ -223,7 +224,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 31, pallet_referenda::TrackInfo { - name: "big_tipper", + name: Borrowed("big_tipper"), max_deciding: 100, decision_deposit: 10 * 3 * CENTS, prepare_period: 4 * MINUTES, @@ -237,7 +238,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 32, pallet_referenda::TrackInfo { - name: "small_spender", + name: Borrowed("small_spender"), max_deciding: 50, decision_deposit: 100 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -251,7 +252,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 33, pallet_referenda::TrackInfo { - name: "medium_spender", + name: Borrowed("medium_spender"), max_deciding: 50, decision_deposit: 200 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -265,7 +266,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 34, pallet_referenda::TrackInfo { - name: "big_spender", + name: Borrowed("big_spender"), max_deciding: 50, decision_deposit: 400 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -282,8 +283,10 @@ pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { type Id = u16; type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - &TRACKS_DATA[..] + type TracksIter = StaticTracksIter; + + fn tracks() -> Self::TracksIter { + TRACKS_DATA.iter().cloned() } fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { diff --git a/polkadot/runtime/westend/src/governance/tracks.rs b/polkadot/runtime/westend/src/governance/tracks.rs index 3765569f183e0..1f48f713037c3 100644 --- a/polkadot/runtime/westend/src/governance/tracks.rs +++ b/polkadot/runtime/westend/src/governance/tracks.rs @@ -21,7 +21,8 @@ use super::*; const fn percent(x: i32) -> sp_arithmetic::FixedI64 { sp_arithmetic::FixedI64::from_rational(x as u128, 100) } -use pallet_referenda::Curve; +use pallet_referenda::{Curve, StaticTracksIter}; +use sp_std::borrow::Cow::Borrowed; const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); const APP_STAKING_ADMIN: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); @@ -69,7 +70,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 0, pallet_referenda::TrackInfo { - name: "root", + name: Borrowed("root"), max_deciding: 1, decision_deposit: 100 * GRAND, prepare_period: 8 * MINUTES, @@ -83,7 +84,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 1, pallet_referenda::TrackInfo { - name: "whitelisted_caller", + name: Borrowed("whitelisted_caller"), max_deciding: 100, decision_deposit: 10 * GRAND, prepare_period: 6 * MINUTES, @@ -97,7 +98,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 10, pallet_referenda::TrackInfo { - name: "staking_admin", + name: Borrowed("staking_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -111,7 +112,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 11, pallet_referenda::TrackInfo { - name: "treasurer", + name: Borrowed("treasurer"), max_deciding: 10, decision_deposit: 1 * GRAND, prepare_period: 8 * MINUTES, @@ -125,7 +126,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 12, pallet_referenda::TrackInfo { - name: "lease_admin", + name: Borrowed("lease_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -139,7 +140,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 13, pallet_referenda::TrackInfo { - name: "fellowship_admin", + name: Borrowed("fellowship_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -153,7 +154,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 14, pallet_referenda::TrackInfo { - name: "general_admin", + name: Borrowed("general_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -167,7 +168,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 15, pallet_referenda::TrackInfo { - name: "auction_admin", + name: Borrowed("auction_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -181,7 +182,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 20, pallet_referenda::TrackInfo { - name: "referendum_canceller", + name: Borrowed("referendum_canceller"), max_deciding: 1_000, decision_deposit: 10 * GRAND, prepare_period: 8 * MINUTES, @@ -195,7 +196,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 21, pallet_referenda::TrackInfo { - name: "referendum_killer", + name: Borrowed("referendum_killer"), max_deciding: 1_000, decision_deposit: 50 * GRAND, prepare_period: 8 * MINUTES, @@ -209,7 +210,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 30, pallet_referenda::TrackInfo { - name: "small_tipper", + name: Borrowed("small_tipper"), max_deciding: 200, decision_deposit: 1 * 3 * CENTS, prepare_period: 1 * MINUTES, @@ -223,7 +224,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 31, pallet_referenda::TrackInfo { - name: "big_tipper", + name: Borrowed("big_tipper"), max_deciding: 100, decision_deposit: 10 * 3 * CENTS, prepare_period: 4 * MINUTES, @@ -237,7 +238,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 32, pallet_referenda::TrackInfo { - name: "small_spender", + name: Borrowed("small_spender"), max_deciding: 50, decision_deposit: 100 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -251,7 +252,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 33, pallet_referenda::TrackInfo { - name: "medium_spender", + name: Borrowed("medium_spender"), max_deciding: 50, decision_deposit: 200 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -265,7 +266,7 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 15 ( 34, pallet_referenda::TrackInfo { - name: "big_spender", + name: Borrowed("big_spender"), max_deciding: 50, decision_deposit: 400 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -282,8 +283,10 @@ pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { type Id = u16; type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - &TRACKS_DATA[..] + type TracksIter = StaticTracksIter; + + fn tracks() -> Self::TracksIter { + TRACKS_DATA.iter().cloned() } fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs index 47d43cc0600c0..3fbf200b6beba 100644 --- a/substrate/frame/referenda/src/benchmarking.rs +++ b/substrate/frame/referenda/src/benchmarking.rs @@ -105,7 +105,7 @@ fn fill_queue, I: 'static>( others } -fn info, I: 'static>(index: ReferendumIndex) -> &'static TrackInfoOf { +fn info, I: 'static>(index: ReferendumIndex) -> TrackInfoOf { let status = Referenda::::ensure_ongoing(index).unwrap(); T::Tracks::info(status.track).expect("Id value returned from T::Tracks") } diff --git a/substrate/frame/referenda/src/lib.rs b/substrate/frame/referenda/src/lib.rs index be21375f526f0..4d8b54b026147 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -97,8 +97,8 @@ pub use self::{ types::{ BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, - ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, - TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, + ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, + StaticTracksIter, TallyOf, TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, }, weights::WeightInfo, }; @@ -129,7 +129,7 @@ macro_rules! impl_tracksinfo_get { <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, $crate::TrackInfo<$balance, $blocknumber>, )> { - <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::tracks().to_vec() + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::tracks().collect() } } }; @@ -504,7 +504,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let mut status = Self::ensure_ongoing(index)?; ensure!(status.decision_deposit.is_none(), Error::::HasDeposit); - let track = Self::track(status.track).ok_or(Error::::NoTrack)?; + let track = T::Tracks::info(status.track).ok_or(Error::::NoTrack)?; status.decision_deposit = Some(Self::take_deposit(who.clone(), track.decision_deposit)?); let now = frame_system::Pallet::::block_number(); @@ -640,7 +640,7 @@ pub mod pallet { if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) { let now = frame_system::Pallet::::block_number(); let (maybe_alarm, branch) = - Self::begin_deciding(&mut status, index, now, track_info); + Self::begin_deciding(&mut status, index, now, &track_info); if let Some(set_alarm) = maybe_alarm { Self::ensure_alarm_at(&mut status, index, set_alarm); } @@ -728,7 +728,7 @@ impl, I: 'static> Polling for Pallet { type Class = TrackIdOf; fn classes() -> Vec { - T::Tracks::tracks().iter().map(|x| x.0).collect() + T::Tracks::tracks().map(|x| x.0).collect() } fn access_poll( @@ -821,7 +821,6 @@ impl, I: 'static> Polling for Pallet { #[cfg(feature = "runtime-benchmarks")] fn max_ongoing() -> (Self::Class, u32) { let r = T::Tracks::tracks() - .iter() .max_by_key(|(_, info)| info.max_deciding) .expect("Always one class"); (r.0, r.1.max_deciding) @@ -846,7 +845,7 @@ impl, I: 'static> Pallet { let info = ReferendumInfoFor::::get(ref_index).ok_or(Error::::BadReferendum)?; match info { ReferendumInfo::Ongoing(status) => { - let track = Self::track(status.track).ok_or(Error::::NoTrack)?; + let track = T::Tracks::info(status.track).ok_or(Error::::NoTrack)?; let elapsed = if let Some(deciding) = status.deciding { frame_system::Pallet::::block_number().saturating_sub(deciding.since) } else { @@ -1075,7 +1074,7 @@ impl, I: 'static> Pallet { ) -> (ReferendumInfoOf, bool, ServiceBranch) { let mut dirty = false; // Should it begin being decided? - let track = match Self::track(status.track) { + let track = match T::Tracks::info(status.track) { Some(x) => x, None => return (ReferendumInfo::Ongoing(status), false, ServiceBranch::Fail), }; @@ -1111,7 +1110,7 @@ impl, I: 'static> Pallet { let prepare_end = status.submitted.saturating_add(track.prepare_period); if now >= prepare_end { let (maybe_alarm, branch) = - Self::ready_for_deciding(now, track, index, &mut status); + Self::ready_for_deciding(now, &track, index, &mut status); if let Some(set_alarm) = maybe_alarm { alarm = alarm.min(set_alarm); } @@ -1158,7 +1157,7 @@ impl, I: 'static> Pallet { Self::ensure_no_alarm(&mut status); Self::note_one_fewer_deciding(status.track); let (desired, call) = (status.enactment, status.proposal); - Self::schedule_enactment(index, track, desired, status.origin, call); + Self::schedule_enactment(index, &track, desired, status.origin, call); Self::deposit_event(Event::::Confirmed { index, tally: status.tally, @@ -1208,7 +1207,7 @@ impl, I: 'static> Pallet { ServiceBranch::ContinueNotConfirming } }; - alarm = Self::decision_time(deciding, &status.tally, status.track, track); + alarm = Self::decision_time(deciding, &status.tally, status.track, &track); }, } @@ -1274,13 +1273,6 @@ impl, I: 'static> Pallet { } } - /// Get the track info value for the track `id`. - fn track(id: TrackIdOf) -> Option<&'static TrackInfoOf> { - let tracks = T::Tracks::tracks(); - let index = tracks.binary_search_by_key(&id, |x| x.0).unwrap_or_else(|x| x); - Some(&tracks[index].1) - } - /// Determine whether the given `tally` would result in a referendum passing at `elapsed` blocks /// into a total decision `period`, given the two curves for `support_needed` and /// `approval_needed`. @@ -1349,7 +1341,7 @@ impl, I: 'static> Pallet { match referendum { ReferendumInfo::Ongoing(status) => { ensure!( - Self::track(status.track).is_some(), + T::Tracks::info(status.track).is_some(), "No track info for the track of the referendum." ); @@ -1373,7 +1365,7 @@ impl, I: 'static> Pallet { /// [`ReferendumInfoFor`] storage map. #[cfg(any(feature = "try-runtime", test))] fn try_state_tracks() -> Result<(), sp_runtime::TryRuntimeError> { - T::Tracks::tracks().iter().try_for_each(|track| { + T::Tracks::tracks().try_for_each(|track| { TrackQueue::::get(track.0).iter().try_for_each( |(referendum_index, _)| -> Result<(), sp_runtime::TryRuntimeError> { ensure!( diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index 345accbe268f7..0a17906c85590 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -34,6 +34,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Hash, IdentityLookup}, BuildStorage, DispatchResult, Perbill, }; +use sp_std::borrow::Cow::Borrowed; type Block = frame_system::mocking::MockBlock; @@ -143,12 +144,14 @@ pub struct TestTracksInfo; impl TracksInfo for TestTracksInfo { type Id = u8; type RuntimeOrigin = ::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, TrackInfo)] { + type TracksIter = StaticTracksIter; + + fn tracks() -> Self::TracksIter { static DATA: [(u8, TrackInfo); 2] = [ ( 0u8, TrackInfo { - name: "root", + name: Borrowed("root"), max_deciding: 1, decision_deposit: 10, prepare_period: 4, @@ -170,7 +173,7 @@ impl TracksInfo for TestTracksInfo { ( 1u8, TrackInfo { - name: "none", + name: Borrowed("none"), max_deciding: 3, decision_deposit: 1, prepare_period: 2, @@ -190,7 +193,7 @@ impl TracksInfo for TestTracksInfo { }, ), ]; - &DATA[..] + DATA.iter().cloned() } fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs index 8f51136de0bfd..0f2015277afbf 100644 --- a/substrate/frame/referenda/src/tests.rs +++ b/substrate/frame/referenda/src/tests.rs @@ -289,11 +289,12 @@ fn alarm_interval_works() { fn decision_time_is_correct() { ExtBuilder::default().build_and_execute(|| { let decision_time = |since: u64| { + let track = TestTracksInfo::tracks().next().unwrap(); Pallet::::decision_time( &DecidingStatus { since: since.into(), confirming: None }, &Tally { ayes: 100, nays: 5 }, - TestTracksInfo::tracks()[0].0, - &TestTracksInfo::tracks()[0].1, + track.0, + &track.1, ) }; diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs index 8d6a13ef27c98..c08649c82b275 100644 --- a/substrate/frame/referenda/src/types.rs +++ b/substrate/frame/referenda/src/types.rs @@ -26,7 +26,7 @@ use frame_support::{ use scale_info::TypeInfo; use sp_arithmetic::{Rounding::*, SignedRounding::*}; use sp_runtime::{FixedI64, PerThing, RuntimeDebug}; -use sp_std::fmt::Debug; +use sp_std::{borrow::Cow, fmt::Debug}; pub type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; @@ -111,10 +111,10 @@ pub struct Deposit { pub amount: Balance, } -#[derive(Clone, Encode, TypeInfo)] +#[derive(Clone, Encode, Decode, TypeInfo)] pub struct TrackInfo { /// Name of this track. - pub name: &'static str, + pub name: Cow<'static, str>, /// A limit for the number of referenda on this track that can be being decided at once. /// For Root origin this should generally be just one. pub max_deciding: u32, @@ -136,6 +136,10 @@ pub struct TrackInfo { pub min_support: Curve, } +/// Shorthand for the common case of tracks defined statically with `SOME_ARRAY.iter().cloned()` +pub type StaticTracksIter = + core::iter::Cloned)>>; + /// Information on the voting tracks. pub trait TracksInfo { /// The identifier for a track. @@ -144,15 +148,18 @@ pub trait TracksInfo { /// The origin type from which a track is implied. type RuntimeOrigin; - /// Return the array of known tracks and their information. - fn tracks() -> &'static [(Self::Id, TrackInfo)]; + /// The iterator returned by `Self::tracks()` to lazily traverse the available tracks + type TracksIter: Iterator)>; + + /// Return the iterable list of known tracks and their information. + fn tracks() -> Self::TracksIter; /// Determine the voting track for the given `origin`. fn track_for(origin: &Self::RuntimeOrigin) -> Result; /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. - fn info(id: Self::Id) -> Option<&'static TrackInfo> { - Self::tracks().iter().find(|x| x.0 == id).map(|x| &x.1) + fn info(id: Self::Id) -> Option> { + Self::tracks().find_map(|x| x.0.eq(&id).then_some(x.1)) } }