Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Scheduler to Support Relay Chain Block Number Provider #6362

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f8e5c63
Adds BlockNumberProvider
gupnik Nov 5, 2024
455d765
Adds a Queue to handle non-sequential block numbers
gupnik Nov 5, 2024
762c816
Removes constraint
gupnik Nov 11, 2024
86701cf
Updates benchmarks
gupnik Nov 13, 2024
27d1fa1
Adds migration
gupnik Nov 14, 2024
c79900c
FMT
gupnik Nov 14, 2024
622805d
Adds PrDoc
gupnik Nov 14, 2024
abbd346
Updates PrDoc
gupnik Nov 14, 2024
844662e
Merge branch 'master' into gupnik/scheduler-bnp
gupnik Nov 14, 2024
813e596
Fixes
gupnik Nov 15, 2024
8c40f24
Adds MaxStaleTaskAge
gupnik Nov 15, 2024
b905628
Fixes
gupnik Nov 15, 2024
2ea271a
Minor fix
gupnik Nov 15, 2024
9a73c23
Minor fix
gupnik Nov 15, 2024
ece2027
Removes unused import
gupnik Nov 15, 2024
da116a7
Minor
gupnik Nov 15, 2024
b1b414a
Minor
gupnik Nov 15, 2024
584f98f
Merge branch 'master' of github.com:paritytech/polkadot-sdk into gupn…
gupnik Nov 25, 2024
fe918e5
Merge branch 'master' into gupnik/scheduler-bnp
gupnik Nov 25, 2024
158e86d
Merge branch 'master' into gupnik/scheduler-bnp
seemantaggarwal Jan 21, 2025
346203d
fixing build errors after merging from master
seemantaggarwal Jan 21, 2025
392921a
addressing comments
seemantaggarwal Jan 21, 2025
eb285f6
changing queue to be a btree instead of a bounded vec initial effort
seemantaggarwal Jan 23, 2025
437b117
converting to BoundedBtreeSet
seemantaggarwal Jan 25, 2025
a1667dd
Merge branch 'master' into gupnik/scheduler-bnp
seemantaggarwal Jan 25, 2025
d065a91
cargo + nightly fmt
seemantaggarwal Jan 25, 2025
3ddfdf0
removing unused imports
seemantaggarwal Jan 25, 2025
28fa84b
removing further unused imports
seemantaggarwal Jan 25, 2025
aed2d40
further improvement
seemantaggarwal Jan 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -606,11 +606,15 @@ parameter_types! {
#[cfg(not(feature = "runtime-benchmarks"))]
parameter_types! {
pub const MaxScheduledPerBlock: u32 = 50;
pub const MaxScheduledBlocks: u32 = 50;
pub const MaxStaleTaskAge: u32 = 10;
}

#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub const MaxScheduledPerBlock: u32 = 200;
pub const MaxScheduledBlocks: u32 = 200;
pub const MaxStaleTaskAge: u32 = 40;
}

impl pallet_scheduler::Config for Runtime {
Expand All @@ -624,6 +628,9 @@ impl pallet_scheduler::Config for Runtime {
type WeightInfo = weights::pallet_scheduler::WeightInfo<Runtime>;
type OriginPrivilegeCmp = EqualOrGreatestRootCmp;
type Preimages = Preimage;
type BlockNumberProvider = frame_system::Pallet<Runtime>;
type MaxScheduledBlocks = MaxScheduledBlocks;
type MaxStaleTaskAge = MaxStaleTaskAge;
}

parameter_types! {
Expand Down
5 changes: 5 additions & 0 deletions polkadot/runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
pub const MaxScheduledPerBlock: u32 = 50;
pub const MaxScheduledBlocks: u32 = 50;
pub const MaxStaleTaskAge: u32 = 10;
pub const NoPreimagePostponement: Option<u32> = Some(10);
}

Expand Down Expand Up @@ -331,6 +333,9 @@ impl pallet_scheduler::Config for Runtime {
type WeightInfo = weights::pallet_scheduler::WeightInfo<Runtime>;
type OriginPrivilegeCmp = OriginPrivilegeCmp;
type Preimages = Preimage;
type BlockNumberProvider = frame_system::Pallet<Runtime>;
type MaxScheduledBlocks = MaxScheduledBlocks;
type MaxStaleTaskAge = MaxStaleTaskAge;
}

parameter_types! {
Expand Down
5 changes: 5 additions & 0 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ parameter_types! {
pub MaximumSchedulerWeight: frame_support::weights::Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
pub const MaxScheduledPerBlock: u32 = 50;
pub const MaxScheduledBlocks: u32 = 50;
pub const MaxStaleTaskAge: u32 = 10;
pub const NoPreimagePostponement: Option<u32> = Some(10);
}

Expand All @@ -248,6 +250,9 @@ impl pallet_scheduler::Config for Runtime {
type WeightInfo = weights::pallet_scheduler::WeightInfo<Runtime>;
type OriginPrivilegeCmp = frame_support::traits::EqualPrivilegeOnly;
type Preimages = Preimage;
type BlockNumberProvider = frame_system::Pallet<Runtime>;
type MaxScheduledBlocks = MaxScheduledBlocks;
type MaxStaleTaskAge = MaxStaleTaskAge;
}

parameter_types! {
Expand Down
23 changes: 23 additions & 0 deletions prdoc/pr_6362.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
title: Update Scheduler to Support Relay Chain Block Number Provider

doc:
- audience: Runtime Dev
description: |
This PR adds the ability for the Scheduler pallet to specify its source of the block number.
This is needed for the scheduler pallet to work on a parachain which does not produce blocks
on a regular schedule, thus can use the relay chain as a block provider. Because blocks are
not produced regularly, we cannot make the assumption that the block number increases
monotonically, and thus have a new logic via a `Queue` to handle multiple blocks with valid
agenda passed between them.

This change only needs a migration for the `Queue`:
1. If the `BlockNumberProvider` continues to use the system pallet's block number
2. When a pallet deployed on the relay chain is moved to a parachain, but still uses the
relay chain's block number

However, we would need migrations if the deployed pallets are upgraded on an existing parachain,
and the `BlockNumberProvider` uses the relay chain block number.

crates:
- name: pallet-scheduler
bump: major
6 changes: 6 additions & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,12 @@ impl pallet_scheduler::Config for Runtime {
type WeightInfo = pallet_scheduler::weights::SubstrateWeight<Runtime>;
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type Preimages = Preimage;
type BlockNumberProvider = frame_system::Pallet<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type MaxScheduledBlocks = ConstU32<512>;
#[cfg(not(feature = "runtime-benchmarks"))]
type MaxScheduledBlocks = ConstU32<50>;
type MaxStaleTaskAge = ConstU32<10>;
}

impl pallet_glutton::Config for Runtime {
Expand Down
3 changes: 3 additions & 0 deletions substrate/frame/democracy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ impl pallet_scheduler::Config for Test {
type WeightInfo = ();
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type Preimages = ();
type BlockNumberProvider = frame_system::Pallet<Test>;
type MaxScheduledBlocks = ConstU32<100>;
type MaxStaleTaskAge = ConstU64<10>;
}

#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
Expand Down
3 changes: 3 additions & 0 deletions substrate/frame/referenda/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ impl pallet_scheduler::Config for Test {
type WeightInfo = ();
type OriginPrivilegeCmp = EqualPrivilegeOnly;
type Preimages = Preimage;
type BlockNumberProvider = frame_system::Pallet<Test>;
type MaxScheduledBlocks = ConstU32<100>;
type MaxStaleTaskAge = ConstU64<10>;
}
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
impl pallet_balances::Config for Test {
Expand Down
82 changes: 57 additions & 25 deletions substrate/frame/scheduler/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use alloc::vec;
use frame_benchmarking::v2::*;
use frame_support::{
ensure,
storage::bounded_vec::BoundedVec,
traits::{schedule::Priority, BoundedInline},
weights::WeightMeter,
};
Expand All @@ -32,7 +33,10 @@ type SystemCall<T> = frame_system::Call<T>;
type SystemOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;

const SEED: u32 = 0;
const BLOCK_NUMBER: u32 = 2;

fn block_number<T: Config>() -> u32 {
T::MaxScheduledBlocks::get()
}

fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
let events = frame_system::Pallet::<T>::events();
Expand All @@ -42,17 +46,23 @@ fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
assert_eq!(event, &system_event);
}

fn fill_queue<T: Config>(n: u32) {
let mut vec = Vec::<BlockNumberFor<T>>::new();
for i in 0..n {
vec.push(i.into());
}
let bounded_vec = BoundedVec::try_from(vec).unwrap();
Queue::<T>::put::<BoundedVec<_, _>>(bounded_vec);
}

/// Add `n` items to the schedule.
///
/// For `resolved`:
/// - `
/// - `None`: aborted (hash without preimage)
/// - `Some(true)`: hash resolves into call if possible, plain call otherwise
/// - `Some(false)`: plain call
fn fill_schedule<T: Config>(
when: frame_system::pallet_prelude::BlockNumberFor<T>,
n: u32,
) -> Result<(), &'static str> {
fn fill_schedule<T: Config>(when: BlockNumberFor<T>, n: u32) -> Result<(), &'static str> {
let t = DispatchTime::At(when);
let origin: <T as Config>::PalletsOrigin = frame_system::RawOrigin::Root.into();
for i in 0..n {
Expand Down Expand Up @@ -136,26 +146,28 @@ fn make_origin<T: Config>(signed: bool) -> <T as Config>::PalletsOrigin {
mod benchmarks {
use super::*;

// `service_agendas` when no work is done.
// `service_agenda` when no work is done.
#[benchmark]
fn service_agendas_base() {
let now = BLOCK_NUMBER.into();
IncompleteSince::<T>::put(now - One::one());
let now = BlockNumberFor::<T>::from(block_number::<T>());
Queue::<T>::put::<BoundedVec<_, _>>(BoundedVec::try_from(vec![now + One::one()]).unwrap());

#[block]
{
Pallet::<T>::service_agendas(&mut WeightMeter::new(), now, 0);
}

assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));
let expected: BoundedVec<BlockNumberFor<T>, T::MaxScheduledBlocks> =
BoundedVec::try_from(vec![now + One::one()]).unwrap();
assert_eq!(Queue::<T>::get(), expected);
}

// `service_agenda` when no work is done.
#[benchmark]
fn service_agenda_base(
s: Linear<0, { T::MaxScheduledPerBlock::get() }>,
) -> Result<(), BenchmarkError> {
let now = BLOCK_NUMBER.into();
let now = block_number::<T>().into();
fill_schedule::<T>(now, s)?;
let mut executed = 0;

Expand All @@ -173,7 +185,7 @@ mod benchmarks {
// dispatched (e.g. due to being overweight).
#[benchmark]
fn service_task_base() {
let now = BLOCK_NUMBER.into();
let now = block_number::<T>().into();
let task = make_task::<T>(false, false, false, None, 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightMeter::with_limit(Weight::zero());
Expand All @@ -196,7 +208,7 @@ mod benchmarks {
fn service_task_fetched(
s: Linear<{ BoundedInline::bound() as u32 }, { T::Preimages::MAX_LENGTH as u32 }>,
) {
let now = BLOCK_NUMBER.into();
let now = block_number::<T>().into();
let task = make_task::<T>(false, false, false, Some(s), 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightMeter::with_limit(Weight::zero());
Expand All @@ -214,7 +226,7 @@ mod benchmarks {
// dispatched (e.g. due to being overweight).
#[benchmark]
fn service_task_named() {
let now = BLOCK_NUMBER.into();
let now = block_number::<T>().into();
let task = make_task::<T>(false, true, false, None, 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightMeter::with_limit(Weight::zero());
Expand All @@ -232,7 +244,7 @@ mod benchmarks {
// dispatched (e.g. due to being overweight).
#[benchmark]
fn service_task_periodic() {
let now = BLOCK_NUMBER.into();
let now = block_number::<T>().into();
let task = make_task::<T>(true, false, false, None, 0);
// prevent any tasks from actually being executed as we only want the surrounding weight.
let mut counter = WeightMeter::with_limit(Weight::zero());
Expand Down Expand Up @@ -286,27 +298,33 @@ mod benchmarks {
fn schedule(
s: Linear<0, { T::MaxScheduledPerBlock::get() - 1 }>,
) -> Result<(), BenchmarkError> {
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();
let periodic = Some((BlockNumberFor::<T>::one(), 100));
let priority = 0;
// Essentially a no-op call.
let call = Box::new(SystemCall::set_storage { items: vec![] }.into());

fill_schedule::<T>(when, s)?;
fill_queue::<T>(T::MaxScheduledBlocks::get() - 1);

#[extrinsic_call]
_(RawOrigin::Root, when, periodic, priority, call);

ensure!(Agenda::<T>::get(when).len() == s as usize + 1, "didn't add to schedule");
ensure!(Agenda::<T>::get(when).len() == (s + 1) as usize, "didn't add to schedule");
ensure!(
Queue::<T>::get().len() == T::MaxScheduledBlocks::get() as usize,
"didn't add to queue"
);

Ok(())
}

#[benchmark]
fn cancel(s: Linear<1, { T::MaxScheduledPerBlock::get() }>) -> Result<(), BenchmarkError> {
let when = BLOCK_NUMBER.into();
let when = (block_number::<T>() - 1).into();

fill_schedule::<T>(when, s)?;
fill_queue::<T>(T::MaxScheduledBlocks::get());
assert_eq!(Agenda::<T>::get(when).len(), s as usize);
let schedule_origin =
T::ScheduleOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
Expand All @@ -327,6 +345,10 @@ mod benchmarks {
s > 1 || Agenda::<T>::get(when).len() == 0,
"remove from schedule if only 1 task scheduled for `when`"
);
ensure!(
s > 1 || Queue::<T>::get().len() == T::MaxScheduledBlocks::get() as usize - 1,
"didn't remove from queue"
);

Ok(())
}
Expand All @@ -336,18 +358,23 @@ mod benchmarks {
s: Linear<0, { T::MaxScheduledPerBlock::get() - 1 }>,
) -> Result<(), BenchmarkError> {
let id = u32_to_name(s);
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();
let periodic = Some((BlockNumberFor::<T>::one(), 100));
let priority = 0;
// Essentially a no-op call.
let call = Box::new(SystemCall::set_storage { items: vec![] }.into());

fill_schedule::<T>(when, s)?;
fill_queue::<T>(T::MaxScheduledBlocks::get() - 1);

#[extrinsic_call]
_(RawOrigin::Root, id, when, periodic, priority, call);

ensure!(Agenda::<T>::get(when).len() == s as usize + 1, "didn't add to schedule");
ensure!(Agenda::<T>::get(when).len() == (s + 1) as usize, "didn't add to schedule");
ensure!(
Queue::<T>::get().len() == T::MaxScheduledBlocks::get() as usize,
"didn't add to queue"
);

Ok(())
}
Expand All @@ -356,9 +383,10 @@ mod benchmarks {
fn cancel_named(
s: Linear<1, { T::MaxScheduledPerBlock::get() }>,
) -> Result<(), BenchmarkError> {
let when = BLOCK_NUMBER.into();
let when = (block_number::<T>() - 1).into();

fill_schedule::<T>(when, s)?;
fill_queue::<T>(T::MaxScheduledBlocks::get());

#[extrinsic_call]
_(RawOrigin::Root, u32_to_name(0));
Expand All @@ -376,6 +404,10 @@ mod benchmarks {
s > 1 || Agenda::<T>::get(when).len() == 0,
"remove from schedule if only 1 task scheduled for `when`"
);
ensure!(
s > 1 || Queue::<T>::get().len() == T::MaxScheduledBlocks::get() as usize - 1,
"didn't remove from queue"
);

Ok(())
}
Expand All @@ -384,7 +416,7 @@ mod benchmarks {
fn schedule_retry(
s: Linear<1, { T::MaxScheduledPerBlock::get() }>,
) -> Result<(), BenchmarkError> {
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();

fill_schedule::<T>(when, s)?;
let name = u32_to_name(s - 1);
Expand Down Expand Up @@ -420,7 +452,7 @@ mod benchmarks {
#[benchmark]
fn set_retry() -> Result<(), BenchmarkError> {
let s = T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();

fill_schedule::<T>(when, s)?;
let name = u32_to_name(s - 1);
Expand All @@ -445,7 +477,7 @@ mod benchmarks {
#[benchmark]
fn set_retry_named() -> Result<(), BenchmarkError> {
let s = T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();

fill_schedule::<T>(when, s)?;
let name = u32_to_name(s - 1);
Expand All @@ -470,7 +502,7 @@ mod benchmarks {
#[benchmark]
fn cancel_retry() -> Result<(), BenchmarkError> {
let s = T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();

fill_schedule::<T>(when, s)?;
let name = u32_to_name(s - 1);
Expand All @@ -491,7 +523,7 @@ mod benchmarks {
#[benchmark]
fn cancel_retry_named() -> Result<(), BenchmarkError> {
let s = T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
let when = block_number::<T>().into();

fill_schedule::<T>(when, s)?;
let name = u32_to_name(s - 1);
Expand Down
Loading
Loading