diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index a9e93a16f0713..c5b747f333a03 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -356,7 +356,7 @@ impl pallet_scheduler::Config for Runtime { type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = ConstU32<512>; + type MaxScheduledPerBlock = ConstU32<50>; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; @@ -828,10 +828,10 @@ impl pallet_referenda::TracksInfo for TracksInfo { 0u16, pallet_referenda::TrackInfo { name: "root", - max_deciding: 1, + max_deciding: 50, decision_deposit: 10, - prepare_period: 4, - decision_period: 4, + prepare_period: 10, + decision_period: 20, confirm_period: 2, min_enactment_period: 4, min_approval: pallet_referenda::Curve::LinearDecreasing { diff --git a/frame/conviction-voting/src/benchmarking.rs b/frame/conviction-voting/src/benchmarking.rs index 117bb7fe22989..3d306038764ec 100644 --- a/frame/conviction-voting/src/benchmarking.rs +++ b/frame/conviction-voting/src/benchmarking.rs @@ -25,7 +25,7 @@ use frame_support::{ dispatch::RawOrigin, traits::{fungible, Currency, Get}, }; -use sp_runtime::traits::Bounded; +use sp_runtime::traits::{Bounded, One}; use sp_std::collections::btree_map::BTreeMap; use crate::Pallet as ConvictionVoting; @@ -61,6 +61,12 @@ fn account_vote, I: 'static>(b: BalanceOf) -> AccountVote() { + frame_system::Pallet::::set_block_number( + frame_system::Pallet::::block_number() + One::one(), + ); +} + benchmarks_instance_pallet! { where_clause { where T::MaxVotes: core::fmt::Debug } @@ -73,7 +79,11 @@ benchmarks_instance_pallet! { let polls = &all_polls[&class]; let r = polls.len() - 1; // We need to create existing votes - for i in polls.iter().skip(1) { + for (p, i) in polls.iter().skip(1).enumerate() { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + } ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { @@ -100,7 +110,11 @@ benchmarks_instance_pallet! { let polls = &all_polls[&class]; let r = polls.len(); // We need to create existing votes - for i in polls.iter() { + for (p, i) in polls.iter().enumerate() { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + } ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { @@ -128,7 +142,11 @@ benchmarks_instance_pallet! { let polls = &all_polls[&class]; let r = polls.len(); // We need to create existing votes - for i in polls.iter() { + for (p, i) in polls.iter().enumerate() { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + }; ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, old_account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { @@ -157,7 +175,11 @@ benchmarks_instance_pallet! { let polls = &all_polls[&class]; let r = polls.len(); // We need to create existing votes - for i in polls.iter() { + for (p, i) in polls.iter().enumerate() { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + } ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, old_account_vote)?; } let votes = match VotingFor::::get(&caller, &class) { @@ -191,7 +213,11 @@ benchmarks_instance_pallet! { let delegate_vote = account_vote::(delegated_balance); // We need to create existing delegations - for i in polls.iter().take(r as usize) { + for (p, i) in polls.iter().enumerate().take(r as usize) { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + } ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; } assert_matches!( @@ -227,7 +253,11 @@ benchmarks_instance_pallet! { )?; // We need to create delegations - for i in polls.iter().take(r as usize) { + for (p, i) in polls.iter().enumerate().take(r as usize) { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + } ConvictionVoting::::vote(RawOrigin::Signed(voter.clone()).into(), *i, delegate_vote)?; } assert_matches!( @@ -252,7 +282,11 @@ benchmarks_instance_pallet! { assert!(all_polls.len() > 0); for (class, polls) in all_polls.iter() { assert!(polls.len() > 0); - for i in polls.iter() { + for (p, i) in polls.iter().enumerate() { + if p as u32 % T::Polls::max_access_poll_per_block() == 0 { + // move to the next block to not overflow the scheduler agenda. + move_to_next_block::(); + } ConvictionVoting::::vote(RawOrigin::Signed(caller.clone()).into(), *i, normal_account_vote)?; } } diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index e57b5f9859e5b..fabd39c1a4f5a 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -79,9 +79,25 @@ fn fill_queue, I: 'static>( spaces: u32, pass_after: u32, ) -> Vec { + let track_info = info::(index); + // the block number when the decision period of the 'index' referendum ends. + let first_decision_end = now::() + track_info.prepare_period + track_info.decision_period; + + let maybe_move_to_next_block = |others_count| { + // check if scheduler max capacity for the current block is reached. + if (others_count + 1) % (T::Scheduler::max_scheduled_per_block() as usize) == 0 { + let next_block = now::() + One::one(); + // decision period of the first referendum must not end + // after the block number will be set to the referendum's prepare_period. + assert!(next_block + track_info.prepare_period < first_decision_end); + frame_system::Pallet::::set_block_number(next_block); + } + }; + // First, create enough other referendums to fill the track. let mut others = vec![]; - for _ in 0..info::(index).max_deciding { + for _ in 0..track_info.max_deciding { + maybe_move_to_next_block(others.len()); let (_origin, index) = create_referendum::(); place_deposit::(index); others.push(index); @@ -90,21 +106,41 @@ fn fill_queue, I: 'static>( // We will also need enough referenda which are queued and passing, we want `MaxQueued - 1` // in order to force the maximum amount of work to insert ours into the queue. for _ in spaces..T::MaxQueued::get() { + maybe_move_to_next_block(others.len()); let (_origin, index) = create_referendum::(); place_deposit::(index); - make_passing_after::(index, Perbill::from_percent(pass_after)); others.push(index); } - // Skip to when they can start being decided. - skip_prepare_period::(index); + // Skip to when all referendums can start being decided. + frame_system::Pallet::::set_block_number(now::() + track_info.prepare_period); + + // make queued referendums passing. + others + .iter() + .skip(track_info.max_deciding as usize) + .enumerate() + .for_each(|(i, &item)| { + maybe_move_to_next_block(i); + make_passing_after::(item, Perbill::from_percent(pass_after)); + }); + + // Move to the next block to not overflow the scheduler agenda. + frame_system::Pallet::::set_block_number(now::() + One::one()); // Manually nudge the other referenda first to ensure that they begin. - others.iter().for_each(|&i| nudge::(i)); + others.iter().enumerate().for_each(|(i, &item)| { + maybe_move_to_next_block(i); + nudge::(item); + }); others } +fn now() -> T::BlockNumber { + frame_system::Pallet::::block_number() +} + fn info, I: 'static>(index: ReferendumIndex) -> &'static TrackInfoOf { let status = Referenda::::ensure_ongoing(index).unwrap(); T::Tracks::info(status.track).expect("Id value returned from T::Tracks") diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 0b846faf88558..cb5fe5237a37c 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -70,7 +70,7 @@ use frame_support::{ traits::{ schedule::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, - DispatchTime, + ConfigInfo, DispatchTime, }, Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, @@ -163,7 +163,8 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The Scheduler. type Scheduler: ScheduleAnon, PalletsOriginOf> - + ScheduleNamed, PalletsOriginOf>; + + ScheduleNamed, PalletsOriginOf> + + ConfigInfo; /// Currency type for this pallet. type Currency: ReservableCurrency; // Origins and unbalances. @@ -690,6 +691,7 @@ impl, I: 'static> Polling for Pallet { #[cfg(feature = "runtime-benchmarks")] fn create_ongoing(class: Self::Class) -> Result { + use sp_runtime::traits::Bounded; let index = ReferendumCount::::mutate(|x| { let r = *x; *x += 1; @@ -713,7 +715,12 @@ impl, I: 'static> Polling for Pallet { in_queue: false, alarm: None, }; - Self::ensure_alarm_at(&mut status, index, sp_runtime::traits::Bounded::max_value()); + Self::ensure_alarm_at( + &mut status, + index, + // shift the scheduled for block to not overflow the scheduler agenda. + T::BlockNumber::max_value() - T::BlockNumber::from(index), + ); ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); Ok(index) } @@ -741,6 +748,12 @@ impl, I: 'static> Polling for Pallet { .expect("Always one class"); (r.0, r.1.max_deciding) } + + /// The maximum number of the access poll invocations possible per block. + #[cfg(feature = "runtime-benchmarks")] + fn max_access_poll_per_block() -> u32 { + T::Scheduler::max_scheduled_per_block() + } } impl, I: 'static> Pallet { diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index afc4fd66e76cb..a49c7433b45fb 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -1299,3 +1299,12 @@ fn map_err_to_v3_err(err: DispatchError) -> DispatchError { err } } + +/// Implements [schedule::ConfigInfo] trait. +impl schedule::ConfigInfo for Pallet { + /// Return the maximum number of tasks possible to schedule per block. + #[cfg(feature = "runtime-benchmarks")] + fn max_scheduled_per_block() -> u32 { + T::MaxScheduledPerBlock::get() + } +} diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index b8e6a7f807904..1637707a5f649 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -473,3 +473,10 @@ pub mod v3 { } pub use v1::*; + +/// A type that aware about a scheduler configuration. +pub trait ConfigInfo { + /// Return the maximum number of tasks possible to schedule per block. + #[cfg(feature = "runtime-benchmarks")] + fn max_scheduled_per_block() -> u32; +} diff --git a/frame/support/src/traits/voting.rs b/frame/support/src/traits/voting.rs index 49ae3163d0cd1..c2268f6df6ee3 100644 --- a/frame/support/src/traits/voting.rs +++ b/frame/support/src/traits/voting.rs @@ -186,4 +186,10 @@ pub trait Polling { fn max_ongoing() -> (Self::Class, u32) { (Self::classes().into_iter().next().expect("Always one class"), u32::max_value()) } + + /// The maximum number of the access poll invocations possible per block. + #[cfg(feature = "runtime-benchmarks")] + fn max_access_poll_per_block() -> u32 { + u32::max_value() + } }