From c078d2f41cf8ecd28ff5279fcebb22da418a14b9 Mon Sep 17 00:00:00 2001 From: Daniel Olano <daniel@olanod.com> Date: Mon, 17 Feb 2025 13:18:01 +0100 Subject: [PATCH] Change pallet referenda TracksInfo::tracks to return an iterator (#2072) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning an iterator in `TracksInfo::tracks()` 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. --------- Co-authored-by: Pablo Andrés Dorado Suárez <hola@pablodorado.com> --- .../src/ambassador/tracks.rs | 106 ++++----- .../src/fellowship/tracks.rs | 223 +++++++++--------- .../rococo/src/governance/fellowship.rs | 115 ++++----- .../runtime/rococo/src/governance/tracks.rs | 163 ++++++------- .../runtime/westend/src/governance/tracks.rs | 163 ++++++------- prdoc/pr_2072.prdoc | 23 ++ substrate/bin/node/runtime/src/lib.rs | 90 ++++--- substrate/frame/referenda/src/benchmarking.rs | 4 +- substrate/frame/referenda/src/lib.rs | 81 +++---- substrate/frame/referenda/src/mock.rs | 42 ++-- substrate/frame/referenda/src/tests.rs | 5 +- substrate/frame/referenda/src/types.rs | 101 +++++--- 12 files changed, 592 insertions(+), 524 deletions(-) create mode 100644 prdoc/pr_2072.prdoc diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/tracks.rs index d4a2d3bbf1c..aa1f67d18af 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/tracks.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/ambassador/tracks.rs @@ -17,7 +17,8 @@ use super::Origin; use crate::{Balance, BlockNumber, RuntimeOrigin, DAYS, DOLLARS, HOURS}; -use sp_runtime::Perbill; +use sp_runtime::{str_array as s, Perbill}; +use sp_std::borrow::Cow; /// Referendum `TrackId` type. pub type TrackId = u16; @@ -46,13 +47,15 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; - /// Return the array of available tracks and their information. - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] { - static DATA: [(TrackId, pallet_referenda::TrackInfo<Balance, BlockNumber>); 9] = [ - ( - constants::AMBASSADOR_TIER_1, - pallet_referenda::TrackInfo { - name: "ambassador tier 1", + /// Return the list of available tracks and their information. + fn tracks( + ) -> impl Iterator<Item = Cow<'static, pallet_referenda::Track<Self::Id, Balance, BlockNumber>>> + { + static DATA: [pallet_referenda::Track<TrackId, Balance, BlockNumber>; 9] = [ + pallet_referenda::Track { + id: constants::AMBASSADOR_TIER_1, + info: pallet_referenda::TrackInfo { + name: s("ambassador tier 1"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -70,11 +73,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::AMBASSADOR_TIER_2, - pallet_referenda::TrackInfo { - name: "ambassador tier 2", + }, + pallet_referenda::Track { + id: constants::AMBASSADOR_TIER_2, + info: pallet_referenda::TrackInfo { + name: s("ambassador tier 2"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -92,11 +95,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::SENIOR_AMBASSADOR_TIER_3, - pallet_referenda::TrackInfo { - name: "senior ambassador tier 3", + }, + pallet_referenda::Track { + id: constants::SENIOR_AMBASSADOR_TIER_3, + info: pallet_referenda::TrackInfo { + name: s("senior ambassador tier 3"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -114,11 +117,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::SENIOR_AMBASSADOR_TIER_4, - pallet_referenda::TrackInfo { - name: "senior ambassador tier 4", + }, + pallet_referenda::Track { + id: constants::SENIOR_AMBASSADOR_TIER_4, + info: pallet_referenda::TrackInfo { + name: s("senior ambassador tier 4"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -136,11 +139,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::HEAD_AMBASSADOR_TIER_5, - pallet_referenda::TrackInfo { - name: "head ambassador tier 5", + }, + pallet_referenda::Track { + id: constants::HEAD_AMBASSADOR_TIER_5, + info: pallet_referenda::TrackInfo { + name: s("head ambassador tier 5"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -158,11 +161,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::HEAD_AMBASSADOR_TIER_6, - pallet_referenda::TrackInfo { - name: "head ambassador tier 6", + }, + pallet_referenda::Track { + id: constants::HEAD_AMBASSADOR_TIER_6, + info: pallet_referenda::TrackInfo { + name: s("head ambassador tier 6"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -180,11 +183,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::HEAD_AMBASSADOR_TIER_7, - pallet_referenda::TrackInfo { - name: "head ambassador tier 7", + }, + pallet_referenda::Track { + id: constants::HEAD_AMBASSADOR_TIER_7, + info: pallet_referenda::TrackInfo { + name: s("head ambassador tier 7"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -202,11 +205,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::MASTER_AMBASSADOR_TIER_8, - pallet_referenda::TrackInfo { - name: "master ambassador tier 8", + }, + pallet_referenda::Track { + id: constants::MASTER_AMBASSADOR_TIER_8, + info: pallet_referenda::TrackInfo { + name: s("master ambassador tier 8"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -224,11 +227,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - constants::MASTER_AMBASSADOR_TIER_9, - pallet_referenda::TrackInfo { - name: "master ambassador tier 9", + }, + pallet_referenda::Track { + id: constants::MASTER_AMBASSADOR_TIER_9, + info: pallet_referenda::TrackInfo { + name: s("master ambassador tier 9"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 24 * HOURS, @@ -246,9 +249,9 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), + }, ]; - &DATA[..] + DATA.iter().map(Cow::Borrowed) } /// Determine the voting track for the given `origin`. @@ -277,6 +280,3 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { } } } - -// implements [`frame_support::traits::Get`] for [`TracksInfo`] -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs index d7959f77244..6c3c88935dd 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/tracks.rs @@ -18,7 +18,8 @@ use crate::{Balance, BlockNumber, RuntimeOrigin, DAYS, DOLLARS, HOURS, MINUTES}; use pallet_ranked_collective::Rank; -use sp_runtime::{traits::Convert, Perbill}; +use sp_runtime::{str_array as s, traits::Convert, Perbill}; +use sp_std::borrow::Cow; /// Referendum `TrackId` type. pub type TrackId = u16; @@ -114,13 +115,16 @@ pub struct TracksInfo; impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { type Id = TrackId; type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] { + + fn tracks( + ) -> impl Iterator<Item = Cow<'static, pallet_referenda::Track<Self::Id, Balance, BlockNumber>>> + { use constants as tracks; - static DATA: [(TrackId, pallet_referenda::TrackInfo<Balance, BlockNumber>); 21] = [ - ( - tracks::MEMBERS, - pallet_referenda::TrackInfo { - name: "members", + static DATA: [pallet_referenda::Track<TrackId, Balance, BlockNumber>; 21] = [ + pallet_referenda::Track { + id: tracks::MEMBERS, + info: pallet_referenda::TrackInfo { + name: s("members"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -138,11 +142,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::PROFICIENTS, - pallet_referenda::TrackInfo { - name: "proficient members", + }, + pallet_referenda::Track { + id: tracks::PROFICIENTS, + info: pallet_referenda::TrackInfo { + name: s("proficient members"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -160,11 +164,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::FELLOWS, - pallet_referenda::TrackInfo { - name: "fellows", + }, + pallet_referenda::Track { + id: tracks::FELLOWS, + info: pallet_referenda::TrackInfo { + name: s("fellows"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -182,11 +186,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::ARCHITECTS, - pallet_referenda::TrackInfo { - name: "architects", + }, + pallet_referenda::Track { + id: tracks::ARCHITECTS, + info: pallet_referenda::TrackInfo { + name: s("architects"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -204,11 +208,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::ARCHITECTS_ADEPT, - pallet_referenda::TrackInfo { - name: "architects adept", + }, + pallet_referenda::Track { + id: tracks::ARCHITECTS_ADEPT, + info: pallet_referenda::TrackInfo { + name: s("architects adept"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -226,11 +230,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::GRAND_ARCHITECTS, - pallet_referenda::TrackInfo { - name: "grand architects", + }, + pallet_referenda::Track { + id: tracks::GRAND_ARCHITECTS, + info: pallet_referenda::TrackInfo { + name: s("grand architects"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -248,11 +252,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::MASTERS, - pallet_referenda::TrackInfo { - name: "masters", + }, + pallet_referenda::Track { + id: tracks::MASTERS, + info: pallet_referenda::TrackInfo { + name: s("masters"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -270,11 +274,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::MASTERS_CONSTANT, - pallet_referenda::TrackInfo { - name: "masters constant", + }, + pallet_referenda::Track { + id: tracks::MASTERS_CONSTANT, + info: pallet_referenda::TrackInfo { + name: s("masters constant"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -292,11 +296,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::GRAND_MASTERS, - pallet_referenda::TrackInfo { - name: "grand masters", + }, + pallet_referenda::Track { + id: tracks::GRAND_MASTERS, + info: pallet_referenda::TrackInfo { + name: s("grand masters"), max_deciding: 10, decision_deposit: 5 * DOLLARS, prepare_period: 30 * MINUTES, @@ -314,11 +318,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - tracks::RETAIN_AT_1DAN, - pallet_referenda::TrackInfo { - name: "retain at I Dan", + }, + pallet_referenda::Track { + id: tracks::RETAIN_AT_1DAN, + info: pallet_referenda::TrackInfo { + name: s("retain at I Dan"), max_deciding: RETAIN_MAX_DECIDING, decision_deposit: RETAIN_DECISION_DEPOSIT, prepare_period: RETAIN_PREPARE_PERIOD, @@ -328,11 +332,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: RETAIN_MIN_APPROVAL, min_support: RETAIN_MIN_SUPPORT, }, - ), - ( - tracks::RETAIN_AT_2DAN, - pallet_referenda::TrackInfo { - name: "retain at II Dan", + }, + pallet_referenda::Track { + id: tracks::RETAIN_AT_2DAN, + info: pallet_referenda::TrackInfo { + name: s("retain at II Dan"), max_deciding: RETAIN_MAX_DECIDING, decision_deposit: RETAIN_DECISION_DEPOSIT, prepare_period: RETAIN_PREPARE_PERIOD, @@ -342,11 +346,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: RETAIN_MIN_APPROVAL, min_support: RETAIN_MIN_SUPPORT, }, - ), - ( - tracks::RETAIN_AT_3DAN, - pallet_referenda::TrackInfo { - name: "retain at III Dan", + }, + pallet_referenda::Track { + id: tracks::RETAIN_AT_3DAN, + info: pallet_referenda::TrackInfo { + name: s("retain at III Dan"), max_deciding: RETAIN_MAX_DECIDING, decision_deposit: RETAIN_DECISION_DEPOSIT, prepare_period: RETAIN_PREPARE_PERIOD, @@ -356,11 +360,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: RETAIN_MIN_APPROVAL, min_support: RETAIN_MIN_SUPPORT, }, - ), - ( - tracks::RETAIN_AT_4DAN, - pallet_referenda::TrackInfo { - name: "retain at IV Dan", + }, + pallet_referenda::Track { + id: tracks::RETAIN_AT_4DAN, + info: pallet_referenda::TrackInfo { + name: s("retain at IV Dan"), max_deciding: RETAIN_MAX_DECIDING, decision_deposit: RETAIN_DECISION_DEPOSIT, prepare_period: RETAIN_PREPARE_PERIOD, @@ -370,11 +374,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: RETAIN_MIN_APPROVAL, min_support: RETAIN_MIN_SUPPORT, }, - ), - ( - tracks::RETAIN_AT_5DAN, - pallet_referenda::TrackInfo { - name: "retain at V Dan", + }, + pallet_referenda::Track { + id: tracks::RETAIN_AT_5DAN, + info: pallet_referenda::TrackInfo { + name: s("retain at V Dan"), max_deciding: RETAIN_MAX_DECIDING, decision_deposit: RETAIN_DECISION_DEPOSIT, prepare_period: RETAIN_PREPARE_PERIOD, @@ -384,11 +388,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: RETAIN_MIN_APPROVAL, min_support: RETAIN_MIN_SUPPORT, }, - ), - ( - tracks::RETAIN_AT_6DAN, - pallet_referenda::TrackInfo { - name: "retain at VI Dan", + }, + pallet_referenda::Track { + id: tracks::RETAIN_AT_6DAN, + info: pallet_referenda::TrackInfo { + name: s("retain at VI Dan"), max_deciding: RETAIN_MAX_DECIDING, decision_deposit: RETAIN_DECISION_DEPOSIT, prepare_period: RETAIN_PREPARE_PERIOD, @@ -398,11 +402,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: RETAIN_MIN_APPROVAL, min_support: RETAIN_MIN_SUPPORT, }, - ), - ( - tracks::PROMOTE_TO_1DAN, - pallet_referenda::TrackInfo { - name: "promote to I Dan", + }, + pallet_referenda::Track { + id: tracks::PROMOTE_TO_1DAN, + info: pallet_referenda::TrackInfo { + name: s("promote to I Dan"), max_deciding: PROMOTE_MAX_DECIDING, decision_deposit: PROMOTE_DECISION_DEPOSIT, prepare_period: PROMOTE_PREPARE_PERIOD, @@ -412,11 +416,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: PROMOTE_MIN_APPROVAL, min_support: PROMOTE_MIN_SUPPORT, }, - ), - ( - tracks::PROMOTE_TO_2DAN, - pallet_referenda::TrackInfo { - name: "promote to II Dan", + }, + pallet_referenda::Track { + id: tracks::PROMOTE_TO_2DAN, + info: pallet_referenda::TrackInfo { + name: s("promote to II Dan"), max_deciding: PROMOTE_MAX_DECIDING, decision_deposit: PROMOTE_DECISION_DEPOSIT, prepare_period: PROMOTE_PREPARE_PERIOD, @@ -426,11 +430,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: PROMOTE_MIN_APPROVAL, min_support: PROMOTE_MIN_SUPPORT, }, - ), - ( - tracks::PROMOTE_TO_3DAN, - pallet_referenda::TrackInfo { - name: "promote to III Dan", + }, + pallet_referenda::Track { + id: tracks::PROMOTE_TO_3DAN, + info: pallet_referenda::TrackInfo { + name: s("promote to III Dan"), max_deciding: PROMOTE_MAX_DECIDING, decision_deposit: PROMOTE_DECISION_DEPOSIT, prepare_period: PROMOTE_PREPARE_PERIOD, @@ -440,11 +444,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: PROMOTE_MIN_APPROVAL, min_support: PROMOTE_MIN_SUPPORT, }, - ), - ( - tracks::PROMOTE_TO_4DAN, - pallet_referenda::TrackInfo { - name: "promote to IV Dan", + }, + pallet_referenda::Track { + id: tracks::PROMOTE_TO_4DAN, + info: pallet_referenda::TrackInfo { + name: s("promote to IV Dan"), max_deciding: PROMOTE_MAX_DECIDING, decision_deposit: PROMOTE_DECISION_DEPOSIT, prepare_period: PROMOTE_PREPARE_PERIOD, @@ -454,11 +458,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: PROMOTE_MIN_APPROVAL, min_support: PROMOTE_MIN_SUPPORT, }, - ), - ( - tracks::PROMOTE_TO_5DAN, - pallet_referenda::TrackInfo { - name: "promote to V Dan", + }, + pallet_referenda::Track { + id: tracks::PROMOTE_TO_5DAN, + info: pallet_referenda::TrackInfo { + name: s("promote to V Dan"), max_deciding: PROMOTE_MAX_DECIDING, decision_deposit: PROMOTE_DECISION_DEPOSIT, prepare_period: PROMOTE_PREPARE_PERIOD, @@ -468,11 +472,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: PROMOTE_MIN_APPROVAL, min_support: PROMOTE_MIN_SUPPORT, }, - ), - ( - tracks::PROMOTE_TO_6DAN, - pallet_referenda::TrackInfo { - name: "promote to VI Dan", + }, + pallet_referenda::Track { + id: tracks::PROMOTE_TO_6DAN, + info: pallet_referenda::TrackInfo { + name: s("promote to VI Dan"), max_deciding: PROMOTE_MAX_DECIDING, decision_deposit: PROMOTE_DECISION_DEPOSIT, prepare_period: PROMOTE_PREPARE_PERIOD, @@ -482,9 +486,9 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { min_approval: PROMOTE_MIN_APPROVAL, min_support: PROMOTE_MIN_SUPPORT, }, - ), + }, ]; - &DATA[..] + DATA.iter().map(Cow::Borrowed) } fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { use super::origins::Origin; @@ -529,4 +533,3 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { } } } -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/polkadot/runtime/rococo/src/governance/fellowship.rs b/polkadot/runtime/rococo/src/governance/fellowship.rs index 231defab6aa..cb194e05e9c 100644 --- a/polkadot/runtime/rococo/src/governance/fellowship.rs +++ b/polkadot/runtime/rococo/src/governance/fellowship.rs @@ -16,8 +16,13 @@ //! Elements of governance concerning the Rococo Fellowship. +use alloc::borrow::Cow; use frame_support::traits::{MapSuccess, TryMapSuccess}; -use sp_runtime::traits::{CheckedReduceBy, ConstU16, Replace, ReplaceWithDefault}; +use pallet_referenda::{Track, TrackInfo}; +use sp_runtime::{ + str_array as s, + traits::{CheckedReduceBy, ConstU16, Replace, ReplaceWithDefault}, +}; use super::*; use crate::{CENTS, DAYS}; @@ -32,12 +37,13 @@ pub struct TracksInfo; impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { type Id = u16; type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] { - static DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 10] = [ - ( - 0u16, - pallet_referenda::TrackInfo { - name: "candidates", + + fn tracks() -> impl Iterator<Item = Cow<'static, Track<Self::Id, Balance, BlockNumber>>> { + static DATA: [Track<u16, Balance, BlockNumber>; 10] = [ + Track { + id: 0u16, + info: TrackInfo { + name: s("candidates"), max_deciding: 10, decision_deposit: 100 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -55,11 +61,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 1u16, - pallet_referenda::TrackInfo { - name: "members", + }, + Track { + id: 1u16, + info: TrackInfo { + name: s("members"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -77,11 +83,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 2u16, - pallet_referenda::TrackInfo { - name: "proficients", + }, + Track { + id: 2u16, + info: TrackInfo { + name: s("proficients"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -99,11 +105,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 3u16, - pallet_referenda::TrackInfo { - name: "fellows", + }, + Track { + id: 3u16, + info: TrackInfo { + name: s("fellows"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -121,11 +127,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 4u16, - pallet_referenda::TrackInfo { - name: "senior fellows", + }, + Track { + id: 4u16, + info: TrackInfo { + name: s("senior fellows"), max_deciding: 10, decision_deposit: 10 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -143,11 +149,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 5u16, - pallet_referenda::TrackInfo { - name: "experts", + }, + Track { + id: 5u16, + info: TrackInfo { + name: s("experts"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -165,11 +171,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 6u16, - pallet_referenda::TrackInfo { - name: "senior experts", + }, + Track { + id: 6u16, + info: TrackInfo { + name: s("senior experts"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -187,11 +193,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 7u16, - pallet_referenda::TrackInfo { - name: "masters", + }, + Track { + id: 7u16, + info: TrackInfo { + name: s("masters"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -209,11 +215,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 8u16, - pallet_referenda::TrackInfo { - name: "senior masters", + }, + Track { + id: 8u16, + info: TrackInfo { + name: s("senior masters"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -231,11 +237,11 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), - ( - 9u16, - pallet_referenda::TrackInfo { - name: "grand masters", + }, + Track { + id: 9u16, + info: TrackInfo { + name: s("grand masters"), max_deciding: 10, decision_deposit: 1 * 3 * CENTS, prepare_period: 30 * MINUTES, @@ -253,9 +259,9 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { ceil: Perbill::from_percent(50), }, }, - ), + }, ]; - &DATA[..] + DATA.iter().map(Cow::Borrowed) } fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { use super::origins::Origin; @@ -285,7 +291,6 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { } } } -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); pub type FellowshipReferendaInstance = pallet_referenda::Instance2; diff --git a/polkadot/runtime/rococo/src/governance/tracks.rs b/polkadot/runtime/rococo/src/governance/tracks.rs index 3765569f183..62229ff5ef5 100644 --- a/polkadot/runtime/rococo/src/governance/tracks.rs +++ b/polkadot/runtime/rococo/src/governance/tracks.rs @@ -18,6 +18,9 @@ use super::*; +use alloc::borrow::Cow; +use sp_runtime::str_array as s; + const fn percent(x: i32) -> sp_arithmetic::FixedI64 { sp_arithmetic::FixedI64::from_rational(x as u128, 100) } @@ -65,11 +68,11 @@ const APP_WHITELISTED_CALLER: Curve = const SUP_WHITELISTED_CALLER: Curve = Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); -const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15] = [ - ( - 0, - pallet_referenda::TrackInfo { - name: "root", +const TRACKS_DATA: [pallet_referenda::Track<u16, Balance, BlockNumber>; 15] = [ + pallet_referenda::Track { + id: 0, + info: pallet_referenda::TrackInfo { + name: s("root"), max_deciding: 1, decision_deposit: 100 * GRAND, prepare_period: 8 * MINUTES, @@ -79,11 +82,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_ROOT, min_support: SUP_ROOT, }, - ), - ( - 1, - pallet_referenda::TrackInfo { - name: "whitelisted_caller", + }, + pallet_referenda::Track { + id: 1, + info: pallet_referenda::TrackInfo { + name: s("whitelisted_caller"), max_deciding: 100, decision_deposit: 10 * GRAND, prepare_period: 6 * MINUTES, @@ -93,11 +96,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_WHITELISTED_CALLER, min_support: SUP_WHITELISTED_CALLER, }, - ), - ( - 10, - pallet_referenda::TrackInfo { - name: "staking_admin", + }, + pallet_referenda::Track { + id: 10, + info: pallet_referenda::TrackInfo { + name: s("staking_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -107,11 +110,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_STAKING_ADMIN, min_support: SUP_STAKING_ADMIN, }, - ), - ( - 11, - pallet_referenda::TrackInfo { - name: "treasurer", + }, + pallet_referenda::Track { + id: 11, + info: pallet_referenda::TrackInfo { + name: s("treasurer"), max_deciding: 10, decision_deposit: 1 * GRAND, prepare_period: 8 * MINUTES, @@ -121,11 +124,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_TREASURER, min_support: SUP_TREASURER, }, - ), - ( - 12, - pallet_referenda::TrackInfo { - name: "lease_admin", + }, + pallet_referenda::Track { + id: 12, + info: pallet_referenda::TrackInfo { + name: s("lease_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -135,11 +138,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_LEASE_ADMIN, min_support: SUP_LEASE_ADMIN, }, - ), - ( - 13, - pallet_referenda::TrackInfo { - name: "fellowship_admin", + }, + pallet_referenda::Track { + id: 13, + info: pallet_referenda::TrackInfo { + name: s("fellowship_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -149,11 +152,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_FELLOWSHIP_ADMIN, min_support: SUP_FELLOWSHIP_ADMIN, }, - ), - ( - 14, - pallet_referenda::TrackInfo { - name: "general_admin", + }, + pallet_referenda::Track { + id: 14, + info: pallet_referenda::TrackInfo { + name: s("general_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -163,11 +166,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_GENERAL_ADMIN, min_support: SUP_GENERAL_ADMIN, }, - ), - ( - 15, - pallet_referenda::TrackInfo { - name: "auction_admin", + }, + pallet_referenda::Track { + id: 15, + info: pallet_referenda::TrackInfo { + name: s("auction_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -177,11 +180,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_AUCTION_ADMIN, min_support: SUP_AUCTION_ADMIN, }, - ), - ( - 20, - pallet_referenda::TrackInfo { - name: "referendum_canceller", + }, + pallet_referenda::Track { + id: 20, + info: pallet_referenda::TrackInfo { + name: s("referendum_canceller"), max_deciding: 1_000, decision_deposit: 10 * GRAND, prepare_period: 8 * MINUTES, @@ -191,11 +194,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_REFERENDUM_CANCELLER, min_support: SUP_REFERENDUM_CANCELLER, }, - ), - ( - 21, - pallet_referenda::TrackInfo { - name: "referendum_killer", + }, + pallet_referenda::Track { + id: 21, + info: pallet_referenda::TrackInfo { + name: s("referendum_killer"), max_deciding: 1_000, decision_deposit: 50 * GRAND, prepare_period: 8 * MINUTES, @@ -205,11 +208,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_REFERENDUM_KILLER, min_support: SUP_REFERENDUM_KILLER, }, - ), - ( - 30, - pallet_referenda::TrackInfo { - name: "small_tipper", + }, + pallet_referenda::Track { + id: 30, + info: pallet_referenda::TrackInfo { + name: s("small_tipper"), max_deciding: 200, decision_deposit: 1 * 3 * CENTS, prepare_period: 1 * MINUTES, @@ -219,11 +222,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_SMALL_TIPPER, min_support: SUP_SMALL_TIPPER, }, - ), - ( - 31, - pallet_referenda::TrackInfo { - name: "big_tipper", + }, + pallet_referenda::Track { + id: 31, + info: pallet_referenda::TrackInfo { + name: s("big_tipper"), max_deciding: 100, decision_deposit: 10 * 3 * CENTS, prepare_period: 4 * MINUTES, @@ -233,11 +236,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_BIG_TIPPER, min_support: SUP_BIG_TIPPER, }, - ), - ( - 32, - pallet_referenda::TrackInfo { - name: "small_spender", + }, + pallet_referenda::Track { + id: 32, + info: pallet_referenda::TrackInfo { + name: s("small_spender"), max_deciding: 50, decision_deposit: 100 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -247,11 +250,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_SMALL_SPENDER, min_support: SUP_SMALL_SPENDER, }, - ), - ( - 33, - pallet_referenda::TrackInfo { - name: "medium_spender", + }, + pallet_referenda::Track { + id: 33, + info: pallet_referenda::TrackInfo { + name: s("medium_spender"), max_deciding: 50, decision_deposit: 200 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -261,11 +264,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_MEDIUM_SPENDER, min_support: SUP_MEDIUM_SPENDER, }, - ), - ( - 34, - pallet_referenda::TrackInfo { - name: "big_spender", + }, + pallet_referenda::Track { + id: 34, + info: pallet_referenda::TrackInfo { + name: s("big_spender"), max_deciding: 50, decision_deposit: 400 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -275,15 +278,18 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_BIG_SPENDER, min_support: SUP_BIG_SPENDER, }, - ), + }, ]; pub struct TracksInfo; impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { type Id = u16; type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] { - &TRACKS_DATA[..] + + fn tracks( + ) -> impl Iterator<Item = Cow<'static, pallet_referenda::Track<Self::Id, Balance, BlockNumber>>> + { + TRACKS_DATA.iter().map(Cow::Borrowed) } fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { @@ -317,4 +323,3 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { } } } -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/polkadot/runtime/westend/src/governance/tracks.rs b/polkadot/runtime/westend/src/governance/tracks.rs index 3765569f183..62229ff5ef5 100644 --- a/polkadot/runtime/westend/src/governance/tracks.rs +++ b/polkadot/runtime/westend/src/governance/tracks.rs @@ -18,6 +18,9 @@ use super::*; +use alloc::borrow::Cow; +use sp_runtime::str_array as s; + const fn percent(x: i32) -> sp_arithmetic::FixedI64 { sp_arithmetic::FixedI64::from_rational(x as u128, 100) } @@ -65,11 +68,11 @@ const APP_WHITELISTED_CALLER: Curve = const SUP_WHITELISTED_CALLER: Curve = Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); -const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15] = [ - ( - 0, - pallet_referenda::TrackInfo { - name: "root", +const TRACKS_DATA: [pallet_referenda::Track<u16, Balance, BlockNumber>; 15] = [ + pallet_referenda::Track { + id: 0, + info: pallet_referenda::TrackInfo { + name: s("root"), max_deciding: 1, decision_deposit: 100 * GRAND, prepare_period: 8 * MINUTES, @@ -79,11 +82,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_ROOT, min_support: SUP_ROOT, }, - ), - ( - 1, - pallet_referenda::TrackInfo { - name: "whitelisted_caller", + }, + pallet_referenda::Track { + id: 1, + info: pallet_referenda::TrackInfo { + name: s("whitelisted_caller"), max_deciding: 100, decision_deposit: 10 * GRAND, prepare_period: 6 * MINUTES, @@ -93,11 +96,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_WHITELISTED_CALLER, min_support: SUP_WHITELISTED_CALLER, }, - ), - ( - 10, - pallet_referenda::TrackInfo { - name: "staking_admin", + }, + pallet_referenda::Track { + id: 10, + info: pallet_referenda::TrackInfo { + name: s("staking_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -107,11 +110,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_STAKING_ADMIN, min_support: SUP_STAKING_ADMIN, }, - ), - ( - 11, - pallet_referenda::TrackInfo { - name: "treasurer", + }, + pallet_referenda::Track { + id: 11, + info: pallet_referenda::TrackInfo { + name: s("treasurer"), max_deciding: 10, decision_deposit: 1 * GRAND, prepare_period: 8 * MINUTES, @@ -121,11 +124,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_TREASURER, min_support: SUP_TREASURER, }, - ), - ( - 12, - pallet_referenda::TrackInfo { - name: "lease_admin", + }, + pallet_referenda::Track { + id: 12, + info: pallet_referenda::TrackInfo { + name: s("lease_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -135,11 +138,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_LEASE_ADMIN, min_support: SUP_LEASE_ADMIN, }, - ), - ( - 13, - pallet_referenda::TrackInfo { - name: "fellowship_admin", + }, + pallet_referenda::Track { + id: 13, + info: pallet_referenda::TrackInfo { + name: s("fellowship_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -149,11 +152,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_FELLOWSHIP_ADMIN, min_support: SUP_FELLOWSHIP_ADMIN, }, - ), - ( - 14, - pallet_referenda::TrackInfo { - name: "general_admin", + }, + pallet_referenda::Track { + id: 14, + info: pallet_referenda::TrackInfo { + name: s("general_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -163,11 +166,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_GENERAL_ADMIN, min_support: SUP_GENERAL_ADMIN, }, - ), - ( - 15, - pallet_referenda::TrackInfo { - name: "auction_admin", + }, + pallet_referenda::Track { + id: 15, + info: pallet_referenda::TrackInfo { + name: s("auction_admin"), max_deciding: 10, decision_deposit: 5 * GRAND, prepare_period: 8 * MINUTES, @@ -177,11 +180,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_AUCTION_ADMIN, min_support: SUP_AUCTION_ADMIN, }, - ), - ( - 20, - pallet_referenda::TrackInfo { - name: "referendum_canceller", + }, + pallet_referenda::Track { + id: 20, + info: pallet_referenda::TrackInfo { + name: s("referendum_canceller"), max_deciding: 1_000, decision_deposit: 10 * GRAND, prepare_period: 8 * MINUTES, @@ -191,11 +194,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_REFERENDUM_CANCELLER, min_support: SUP_REFERENDUM_CANCELLER, }, - ), - ( - 21, - pallet_referenda::TrackInfo { - name: "referendum_killer", + }, + pallet_referenda::Track { + id: 21, + info: pallet_referenda::TrackInfo { + name: s("referendum_killer"), max_deciding: 1_000, decision_deposit: 50 * GRAND, prepare_period: 8 * MINUTES, @@ -205,11 +208,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_REFERENDUM_KILLER, min_support: SUP_REFERENDUM_KILLER, }, - ), - ( - 30, - pallet_referenda::TrackInfo { - name: "small_tipper", + }, + pallet_referenda::Track { + id: 30, + info: pallet_referenda::TrackInfo { + name: s("small_tipper"), max_deciding: 200, decision_deposit: 1 * 3 * CENTS, prepare_period: 1 * MINUTES, @@ -219,11 +222,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_SMALL_TIPPER, min_support: SUP_SMALL_TIPPER, }, - ), - ( - 31, - pallet_referenda::TrackInfo { - name: "big_tipper", + }, + pallet_referenda::Track { + id: 31, + info: pallet_referenda::TrackInfo { + name: s("big_tipper"), max_deciding: 100, decision_deposit: 10 * 3 * CENTS, prepare_period: 4 * MINUTES, @@ -233,11 +236,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_BIG_TIPPER, min_support: SUP_BIG_TIPPER, }, - ), - ( - 32, - pallet_referenda::TrackInfo { - name: "small_spender", + }, + pallet_referenda::Track { + id: 32, + info: pallet_referenda::TrackInfo { + name: s("small_spender"), max_deciding: 50, decision_deposit: 100 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -247,11 +250,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_SMALL_SPENDER, min_support: SUP_SMALL_SPENDER, }, - ), - ( - 33, - pallet_referenda::TrackInfo { - name: "medium_spender", + }, + pallet_referenda::Track { + id: 33, + info: pallet_referenda::TrackInfo { + name: s("medium_spender"), max_deciding: 50, decision_deposit: 200 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -261,11 +264,11 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_MEDIUM_SPENDER, min_support: SUP_MEDIUM_SPENDER, }, - ), - ( - 34, - pallet_referenda::TrackInfo { - name: "big_spender", + }, + pallet_referenda::Track { + id: 34, + info: pallet_referenda::TrackInfo { + name: s("big_spender"), max_deciding: 50, decision_deposit: 400 * 3 * CENTS, prepare_period: 10 * MINUTES, @@ -275,15 +278,18 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 15 min_approval: APP_BIG_SPENDER, min_support: SUP_BIG_SPENDER, }, - ), + }, ]; pub struct TracksInfo; impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { type Id = u16; type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] { - &TRACKS_DATA[..] + + fn tracks( + ) -> impl Iterator<Item = Cow<'static, pallet_referenda::Track<Self::Id, Balance, BlockNumber>>> + { + TRACKS_DATA.iter().map(Cow::Borrowed) } fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { @@ -317,4 +323,3 @@ impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { } } } -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/prdoc/pr_2072.prdoc b/prdoc/pr_2072.prdoc new file mode 100644 index 00000000000..fdc1a373938 --- /dev/null +++ b/prdoc/pr_2072.prdoc @@ -0,0 +1,23 @@ +title: "Return iterator in pallet_referenda::TracksInfo::tracks" + +doc: + - audience: Runtime Dev + description: | + Change the return type of the trait method `pallet_referenda::TracksInfo::tracks` to return an + iterator of `Cow<'static, Tracks<_, _, _>>` instead of a static slice in order to support more + flexible implementations that can define referenda tracks dynamically. + - audience: Runtime User + description: | + There is a change in `pallet-referenda`. Now, the tracks are retrieved as a list of `Track`s. Also, the names of + the tracks might have some trailing null values (`\0`). This means display representation of the tracks' names + must be sanitized. + +crates: + - name: pallet-referenda + bump: major + - name: westend-runtime + bump: major + - name: rococo-runtime + bump: major + - name: collectives-westend-runtime + bump: major \ No newline at end of file diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index e0404fdc2bc..bebf48618ba 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -107,7 +107,7 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ curve::PiecewiseLinear, - generic, impl_opaque_keys, + generic, impl_opaque_keys, str_array as s, traits::{ self, AccountIdConversion, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, MaybeConvert, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, @@ -116,6 +116,7 @@ use sp_runtime::{ ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perbill, Percent, Permill, Perquintill, RuntimeDebug, }; +use sp_std::{borrow::Cow, prelude::*}; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -1280,43 +1281,20 @@ pub struct TracksInfo; impl pallet_referenda::TracksInfo<Balance, BlockNumber> for TracksInfo { type Id = u16; type RuntimeOrigin = <RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo<Balance, BlockNumber>)] { - static DATA: [(u16, pallet_referenda::TrackInfo<Balance, BlockNumber>); 1] = [( - 0u16, - pallet_referenda::TrackInfo { - name: "root", - max_deciding: 1, - decision_deposit: 10, - prepare_period: 4, - decision_period: 4, - confirm_period: 2, - min_enactment_period: 4, - min_approval: pallet_referenda::Curve::LinearDecreasing { - length: Perbill::from_percent(100), - floor: Perbill::from_percent(50), - ceil: Perbill::from_percent(100), - }, - min_support: pallet_referenda::Curve::LinearDecreasing { - length: Perbill::from_percent(100), - floor: Perbill::from_percent(0), - ceil: Perbill::from_percent(100), - }, - }, - )]; - &DATA[..] + + fn tracks( + ) -> impl Iterator<Item = Cow<'static, pallet_referenda::Track<Self::Id, Balance, BlockNumber>>> + { + dynamic_params::referenda::Tracks::get().into_iter().map(Cow::Owned) } fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { - if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { - match system_origin { - frame_system::RawOrigin::Root => Ok(0), - _ => Err(()), - } - } else { - Err(()) - } + dynamic_params::referenda::Origins::get() + .iter() + .find(|(o, _)| id == o) + .map(|(_, track_id)| *track_id) + .ok_or(()) } } -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); impl pallet_referenda::Config for Runtime { type WeightInfo = pallet_referenda::weights::SubstrateWeight<Self>; @@ -2676,6 +2654,46 @@ pub mod dynamic_params { #[codec(index = 1)] pub static ByteDeposit: Balance = 1 * CENTS; } + + #[dynamic_pallet_params] + #[codec(index = 1)] + pub mod referenda { + /// The configuration for the tracks + #[codec(index = 0)] + pub static Tracks: BoundedVec< + pallet_referenda::Track<u16, Balance, BlockNumber>, + ConstU32<100>, + > = BoundedVec::truncate_from(vec![pallet_referenda::Track { + id: 0u16, + info: pallet_referenda::TrackInfo { + name: s("root"), + max_deciding: 1, + decision_deposit: 10, + prepare_period: 4, + decision_period: 4, + confirm_period: 2, + min_enactment_period: 4, + min_approval: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(50), + ceil: Perbill::from_percent(100), + }, + min_support: pallet_referenda::Curve::LinearDecreasing { + length: Perbill::from_percent(100), + floor: Perbill::from_percent(0), + ceil: Perbill::from_percent(100), + }, + }, + }]); + + /// A list mapping every origin with a track Id + #[codec(index = 1)] + pub static Origins: BoundedVec<(OriginCaller, u16), ConstU32<100>> = + BoundedVec::truncate_from(vec![( + OriginCaller::system(frame_system::RawOrigin::Root), + 0, + )]); + } } #[cfg(feature = "runtime-benchmarks")] @@ -2701,6 +2719,10 @@ impl EnsureOriginWithArg<RuntimeOrigin, RuntimeParametersKey> for DynamicParamet frame_system::ensure_root(origin.clone()).map_err(|_| origin)?; return Ok(()) }, + RuntimeParametersKey::Referenda(_) => { + frame_system::ensure_root(origin.clone()).map_err(|_| origin)?; + return Ok(()) + }, } } diff --git a/substrate/frame/referenda/src/benchmarking.rs b/substrate/frame/referenda/src/benchmarking.rs index 895f95dbec5..59499d9c8bf 100644 --- a/substrate/frame/referenda/src/benchmarking.rs +++ b/substrate/frame/referenda/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; use crate::Pallet as Referenda; -use alloc::{vec, vec::Vec}; +use alloc::{borrow::Cow, vec, vec::Vec}; use assert_matches::assert_matches; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelist_account, BenchmarkError, @@ -110,7 +110,7 @@ fn fill_queue<T: Config<I>, I: 'static>( others } -fn info<T: Config<I>, I: 'static>(index: ReferendumIndex) -> &'static TrackInfoOf<T, I> { +fn info<T: Config<I>, I: 'static>(index: ReferendumIndex) -> Cow<'static, TrackInfoOf<T, I>> { let status = Referenda::<T, I>::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 e6a895f9c59..b58baa341cf 100644 --- a/substrate/frame/referenda/src/lib.rs +++ b/substrate/frame/referenda/src/lib.rs @@ -100,7 +100,7 @@ pub use self::{ BalanceOf, BlockNumberFor, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, - TallyOf, TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, + TallyOf, Track, TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, }, weights::WeightInfo, }; @@ -117,27 +117,6 @@ pub mod benchmarking; pub use frame_support::traits::Get; -#[macro_export] -macro_rules! impl_tracksinfo_get { - ($tracksinfo:ty, $balance:ty, $blocknumber:ty) => { - impl - $crate::Get< - $crate::Vec<( - <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, - $crate::TrackInfo<$balance, $blocknumber>, - )>, - > for $tracksinfo - { - fn get() -> $crate::Vec<( - <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, - $crate::TrackInfo<$balance, $blocknumber>, - )> { - <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::tracks().to_vec() - } - } - }; -} - const ASSEMBLY_ID: LockIdentifier = *b"assembly"; #[frame_support::pallet] @@ -228,17 +207,11 @@ pub mod pallet { // The other stuff. /// Information concerning the different referendum tracks. - #[pallet::constant] - type Tracks: Get< - Vec<( - <Self::Tracks as TracksInfo<BalanceOf<Self, I>, BlockNumberFor<Self, I>>>::Id, - TrackInfo<BalanceOf<Self, I>, BlockNumberFor<Self, I>>, - )>, - > + TracksInfo< - BalanceOf<Self, I>, - BlockNumberFor<Self, I>, - RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin, - >; + type Tracks: TracksInfo< + BalanceOf<Self, I>, + BlockNumberFor<Self, I>, + RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin, + >; /// The preimage provider. type Preimages: QueryPreimage<H = Self::Hashing> + StorePreimage; @@ -249,6 +222,14 @@ pub mod pallet { type BlockNumberProvider: BlockNumberProvider; } + #[pallet::extra_constants] + impl<T: Config<I>, I: 'static> Pallet<T, I> { + #[pallet::constant_name(Tracks)] + fn tracks() -> Vec<Track<TrackIdOf<T, I>, BalanceOf<T, I>, BlockNumberFor<T, I>>> { + T::Tracks::tracks().map(|t| t.into_owned()).collect() + } + } + /// The next free referendum index, aka the number of referenda started so far. #[pallet::storage] pub type ReferendumCount<T, I = ()> = StorageValue<_, ReferendumIndex, ValueQuery>; @@ -532,7 +513,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let mut status = Self::ensure_ongoing(index)?; ensure!(status.decision_deposit.is_none(), Error::<T, I>::HasDeposit); - let track = Self::track(status.track).ok_or(Error::<T, I>::NoTrack)?; + let track = T::Tracks::info(status.track).ok_or(Error::<T, I>::NoTrack)?; status.decision_deposit = Some(Self::take_deposit(who.clone(), track.decision_deposit)?); let now = T::BlockNumberProvider::current_block_number(); @@ -668,7 +649,7 @@ pub mod pallet { if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) { let now = T::BlockNumberProvider::current_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); } @@ -756,7 +737,7 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> { type Class = TrackIdOf<T, I>; fn classes() -> Vec<Self::Class> { - T::Tracks::tracks().iter().map(|x| x.0).collect() + T::Tracks::track_ids().collect() } fn access_poll<R>( @@ -849,10 +830,9 @@ impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> { #[cfg(feature = "runtime-benchmarks")] fn max_ongoing() -> (Self::Class, u32) { let r = T::Tracks::tracks() - .iter() - .max_by_key(|(_, info)| info.max_deciding) + .max_by_key(|t| t.info.max_deciding) .expect("Always one class"); - (r.0, r.1.max_deciding) + (r.id, r.info.max_deciding) } } @@ -874,7 +854,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { let info = ReferendumInfoFor::<T, I>::get(ref_index).ok_or(Error::<T, I>::BadReferendum)?; match info { ReferendumInfo::Ongoing(status) => { - let track = Self::track(status.track).ok_or(Error::<T, I>::NoTrack)?; + let track = T::Tracks::info(status.track).ok_or(Error::<T, I>::NoTrack)?; let elapsed = if let Some(deciding) = status.deciding { T::BlockNumberProvider::current_block_number().saturating_sub(deciding.since) } else { @@ -1104,7 +1084,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { ) -> (ReferendumInfoOf<T, I>, 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), }; @@ -1140,7 +1120,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { 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); } @@ -1187,7 +1167,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { 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::<T, I>::Confirmed { index, tally: status.tally, @@ -1237,7 +1217,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { ServiceBranch::ContinueNotConfirming } }; - alarm = Self::decision_time(deciding, &status.tally, status.track, track); + alarm = Self::decision_time(deciding, &status.tally, status.track, &track); }, } @@ -1303,13 +1283,6 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { } } - /// Get the track info value for the track `id`. - fn track(id: TrackIdOf<T, I>) -> Option<&'static TrackInfoOf<T, I>> { - 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`. @@ -1378,7 +1351,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { 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." ); @@ -1404,8 +1377,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { /// [`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| { - TrackQueue::<T, I>::get(track.0).iter().try_for_each( + T::Tracks::tracks().try_for_each(|track| { + TrackQueue::<T, I>::get(track.id).iter().try_for_each( |(referendum_index, _)| -> Result<(), sp_runtime::TryRuntimeError> { ensure!( ReferendumInfoFor::<T, I>::contains_key(referendum_index), diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index 10e5f35bbab..5c9c12dee44 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -18,7 +18,8 @@ //! The crate's tests. use super::*; -use crate as pallet_referenda; +use crate::{self as pallet_referenda, types::Track}; +use alloc::borrow::Cow; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, @@ -29,6 +30,7 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_runtime::{ + str_array as s, traits::{BlakeTwo256, Hash}, BuildStorage, DispatchResult, Perbill, }; @@ -103,12 +105,13 @@ pub struct TestTracksInfo; impl TracksInfo<u64, u64> for TestTracksInfo { type Id = u8; type RuntimeOrigin = <RuntimeOrigin as OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, TrackInfo<u64, u64>)] { - static DATA: [(u8, TrackInfo<u64, u64>); 3] = [ - ( - 0u8, - TrackInfo { - name: "root", + + fn tracks() -> impl Iterator<Item = Cow<'static, Track<Self::Id, u64, u64>>> { + static DATA: [Track<u8, u64, u64>; 3] = [ + Track { + id: 0u8, + info: TrackInfo { + name: s("root"), max_deciding: 1, decision_deposit: 10, prepare_period: 4, @@ -126,11 +129,11 @@ impl TracksInfo<u64, u64> for TestTracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - 1u8, - TrackInfo { - name: "none", + }, + Track { + id: 1u8, + info: TrackInfo { + name: s("none"), max_deciding: 3, decision_deposit: 1, prepare_period: 2, @@ -148,11 +151,11 @@ impl TracksInfo<u64, u64> for TestTracksInfo { ceil: Perbill::from_percent(100), }, }, - ), - ( - 2u8, - TrackInfo { - name: "none", + }, + Track { + id: 2u8, + info: TrackInfo { + name: s("none"), max_deciding: 3, decision_deposit: 1, prepare_period: 2, @@ -170,9 +173,9 @@ impl TracksInfo<u64, u64> for TestTracksInfo { ceil: Perbill::from_percent(100), }, }, - ), + }, ]; - &DATA[..] + DATA.iter().map(Cow::Borrowed) } fn track_for(id: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { @@ -187,7 +190,6 @@ impl TracksInfo<u64, u64> for TestTracksInfo { } } } -impl_tracksinfo_get!(TestTracksInfo, u64, u64); impl Config for Test { type WeightInfo = (); diff --git a/substrate/frame/referenda/src/tests.rs b/substrate/frame/referenda/src/tests.rs index 9f851992496..d556d10c44a 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::<Test>::decision_time( &DecidingStatus { since: since.into(), confirming: None }, &Tally { ayes: 100, nays: 5 }, - TestTracksInfo::tracks()[0].0, - &TestTracksInfo::tracks()[0].1, + track.id, + &track.info, ) }; diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs index e97e7cc8df6..6a1eb8e82e4 100644 --- a/substrate/frame/referenda/src/types.rs +++ b/substrate/frame/referenda/src/types.rs @@ -18,6 +18,7 @@ //! Miscellaneous additional datatypes. use super::*; +use alloc::borrow::Cow; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use core::fmt::Debug; use frame_support::{ @@ -115,10 +116,13 @@ pub struct Deposit<AccountId, Balance> { pub amount: Balance, } -#[derive(Clone, Encode, TypeInfo)] -pub struct TrackInfo<Balance, Moment> { +pub const DEFAULT_MAX_TRACK_NAME_LEN: usize = 25; + +/// Detailed information about the configuration of a referenda track +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Debug)] +pub struct TrackInfo<Balance, Moment, const N: usize = DEFAULT_MAX_TRACK_NAME_LEN> { /// Name of this track. - pub name: &'static str, + pub name: [u8; N], /// 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, @@ -140,42 +144,67 @@ pub struct TrackInfo<Balance, Moment> { pub min_support: Curve, } +/// Track groups the information of a voting track with its corresponding identifier +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Debug)] +pub struct Track<Id, Balance, Moment, const N: usize = DEFAULT_MAX_TRACK_NAME_LEN> { + pub id: Id, + pub info: TrackInfo<Balance, Moment, N>, +} + /// Information on the voting tracks. -pub trait TracksInfo<Balance, Moment> { +pub trait TracksInfo<Balance, Moment, const N: usize = DEFAULT_MAX_TRACK_NAME_LEN> +where + Balance: Clone + Debug + Eq + 'static, + Moment: Clone + Debug + Eq + 'static, +{ /// The identifier for a track. type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static + MaxEncodedLen; /// The origin type from which a track is implied. type RuntimeOrigin; - /// Sorted array of known tracks and their information. + /// Return the sorted iterable list of known tracks and their information. /// - /// The array MUST be sorted by `Id`. Consumers of this trait are advised to assert + /// The iterator MUST be sorted by `Id`. Consumers of this trait are advised to assert /// [`Self::check_integrity`] prior to any use. - fn tracks() -> &'static [(Self::Id, TrackInfo<Balance, Moment>)]; + fn tracks() -> impl Iterator<Item = Cow<'static, Track<Self::Id, Balance, Moment, N>>>; /// Determine the voting track for the given `origin`. fn track_for(origin: &Self::RuntimeOrigin) -> Result<Self::Id, ()>; - /// 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<Balance, Moment>> { - let tracks = Self::tracks(); - let maybe_index = tracks.binary_search_by_key(&id, |t| t.0).ok()?; + /// Return the list of identifiers of the known tracks. + fn track_ids() -> impl Iterator<Item = Self::Id> { + Self::tracks().map(|x| x.id) + } - tracks.get(maybe_index).map(|(_, info)| info) + /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. + fn info(id: Self::Id) -> Option<Cow<'static, TrackInfo<Balance, Moment, N>>> { + Self::tracks().find(|x| x.id == id).map(|t| match t { + Cow::Borrowed(x) => Cow::Borrowed(&x.info), + Cow::Owned(x) => Cow::Owned(x.info), + }) } /// Check assumptions about the static data that this trait provides. - fn check_integrity() -> Result<(), &'static str> - where - Balance: 'static, - Moment: 'static, - { - if Self::tracks().windows(2).all(|w| w[0].0 < w[1].0) { - Ok(()) - } else { - Err("The tracks that were returned by `tracks` were not sorted by `Id`") - } + fn check_integrity() -> Result<(), &'static str> { + use core::cmp::Ordering; + // Adapted from Iterator::is_sorted implementation available in nightly + // https://github.com/rust-lang/rust/issues/53485 + let mut iter = Self::tracks(); + let mut last = match iter.next() { + Some(ref e) => e.id, + None => return Ok(()), + }; + iter.all(|curr| { + let curr = curr.as_ref().id; + if let Ordering::Greater = last.cmp(&curr) { + return false; + } + last = curr; + true + }) + .then_some(()) + .ok_or("The tracks that were returned by `tracks` were not sorted by `Id`") } } @@ -551,7 +580,7 @@ impl Debug for Curve { mod tests { use super::*; use frame_support::traits::ConstU32; - use sp_runtime::PerThing; + use sp_runtime::{str_array as s, PerThing}; const fn percent(x: u128) -> FixedI64 { FixedI64::from_rational(x, 100) @@ -703,12 +732,12 @@ mod tests { impl TracksInfo<u64, u64> for BadTracksInfo { type Id = u8; type RuntimeOrigin = <RuntimeOrigin as OriginTrait>::PalletsOrigin; - fn tracks() -> &'static [(Self::Id, TrackInfo<u64, u64>)] { - static DATA: [(u8, TrackInfo<u64, u64>); 2] = [ - ( - 1u8, - TrackInfo { - name: "root", + fn tracks() -> impl Iterator<Item = Cow<'static, Track<Self::Id, u64, u64>>> { + static DATA: [Track<u8, u64, u64>; 2] = [ + Track { + id: 1u8, + info: TrackInfo { + name: s("root"), max_deciding: 1, decision_deposit: 10, prepare_period: 4, @@ -726,11 +755,11 @@ mod tests { ceil: Perbill::from_percent(100), }, }, - ), - ( - 0u8, - TrackInfo { - name: "none", + }, + Track { + id: 0u8, + info: TrackInfo { + name: s("none"), max_deciding: 3, decision_deposit: 1, prepare_period: 2, @@ -748,9 +777,9 @@ mod tests { ceil: Perbill::from_percent(100), }, }, - ), + }, ]; - &DATA[..] + DATA.iter().map(Cow::Borrowed) } fn track_for(_: &Self::RuntimeOrigin) -> Result<Self::Id, ()> { unimplemented!() -- GitLab