-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix #6102 #6384
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
Fix #6102 #6384
Changes from 5 commits
80a6c14
e9b0b14
1a0309f
a3c3233
3d9f418
94ecabc
192301c
0f024a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ use crate::{ | |
| }; | ||
|
|
||
| use alloc::{vec, vec::Vec}; | ||
| use core::mem; | ||
| use frame_support::{defensive, pallet_prelude::*}; | ||
| use frame_system::pallet_prelude::*; | ||
| use pallet_broker::CoreAssignment; | ||
|
|
@@ -236,17 +237,9 @@ pub mod pallet { | |
| #[pallet::error] | ||
| pub enum Error<T> { | ||
| AssignmentsEmpty, | ||
| /// Assignments together exceeded 57600. | ||
| OverScheduled, | ||
| /// Assignments together less than 57600 | ||
| UnderScheduled, | ||
| /// assign_core is only allowed to append new assignments at the end of already existing | ||
| /// ones. | ||
| /// ones or update the last entry. | ||
| DisallowedInsert, | ||
| /// Tried to insert a schedule for the same core and block number as an existing schedule | ||
| DuplicateInsert, | ||
| /// Tried to add an unsorted set of assignments | ||
| AssignmentsNotSorted, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -387,67 +380,56 @@ impl<T: Config> Pallet<T> { | |
|
|
||
| /// Append another assignment for a core. | ||
| /// | ||
| /// Important only appending is allowed. Meaning, all already existing assignments must have a | ||
| /// begin smaller than the one passed here. This restriction exists, because it makes the | ||
| /// insertion O(1) and the author could not think of a reason, why this restriction should be | ||
| /// causing any problems. Inserting arbitrarily causes a `DispatchError::DisallowedInsert` | ||
| /// error. This restriction could easily be lifted if need be and in fact an implementation is | ||
| /// available | ||
| /// Important only appending is allowed or insertion into the last item is possible. Meaning, | ||
| /// all already existing assignments must have a begin smaller or equal than the one passed | ||
| /// here. This restriction exists, because it makes the insertion O(1) and the author could not | ||
| /// think of a reason, why this restriction should be causing any problems. Inserting | ||
| /// arbitrarily causes a `DispatchError::DisallowedInsert` error. This restriction could easily | ||
| /// be lifted if need be and in fact an implementation is available | ||
| /// [here](https://github.com/paritytech/polkadot-sdk/pull/1694/commits/c0c23b01fd2830910cde92c11960dad12cdff398#diff-0c85a46e448de79a5452395829986ee8747e17a857c27ab624304987d2dde8baR386). | ||
| /// The problem is that insertion complexity then depends on the size of the existing queue, | ||
| /// which makes determining weights hard and could lead to issues like overweight blocks (at | ||
| /// least in theory). | ||
| /// | ||
| /// Updating the last entry is supported to allow for making a core assignment multiple calls to | ||
| /// assign_core. Thus if you have too much interlacing for e.g. a single UMP message you can | ||
| /// split that up into multiple messages, each triggering a call to `assign_core`, together | ||
| /// forming the total assignment. | ||
| pub fn assign_core( | ||
| core_idx: CoreIndex, | ||
| begin: BlockNumberFor<T>, | ||
| assignments: Vec<(CoreAssignment, PartsOf57600)>, | ||
| mut assignments: Vec<(CoreAssignment, PartsOf57600)>, | ||
| end_hint: Option<BlockNumberFor<T>>, | ||
| ) -> Result<(), DispatchError> { | ||
| // There should be at least one assignment. | ||
| ensure!(!assignments.is_empty(), Error::<T>::AssignmentsEmpty); | ||
|
|
||
| // Checking for sort and unique manually, since we don't have access to iterator tools. | ||
| // This way of checking uniqueness only works since we also check sortedness. | ||
| assignments.iter().map(|x| &x.0).try_fold(None, |prev, cur| { | ||
| if prev.map_or(false, |p| p >= cur) { | ||
| Err(Error::<T>::AssignmentsNotSorted) | ||
| } else { | ||
| Ok(Some(cur)) | ||
| } | ||
| })?; | ||
|
|
||
| // Check that the total parts between all assignments are equal to 57600 | ||
| let parts_sum = assignments | ||
| .iter() | ||
| .map(|assignment| assignment.1) | ||
| .try_fold(PartsOf57600::ZERO, |sum, parts| { | ||
| sum.checked_add(parts).ok_or(Error::<T>::OverScheduled) | ||
|
eskimor marked this conversation as resolved.
|
||
| })?; | ||
| ensure!(parts_sum.is_full(), Error::<T>::UnderScheduled); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if the schedule is split up, but we only receive one message in time? Will it break any assumptions if we don't have the full parts scheduled?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. I checked, the code does not really care whether the schedule is full or not.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably worth a unit test in case this behaviour is changed in future. |
||
|
|
||
| CoreDescriptors::<T>::mutate(core_idx, |core_descriptor| { | ||
| let new_queue = match core_descriptor.queue { | ||
| Some(queue) => { | ||
| ensure!(begin > queue.last, Error::<T>::DisallowedInsert); | ||
|
|
||
| CoreSchedules::<T>::try_mutate((queue.last, core_idx), |schedule| { | ||
| if let Some(schedule) = schedule.as_mut() { | ||
| debug_assert!(schedule.next_schedule.is_none(), "queue.end was supposed to be the end, so the next item must be `None`!"); | ||
| schedule.next_schedule = Some(begin); | ||
| ensure!(begin >= queue.last, Error::<T>::DisallowedInsert); | ||
|
|
||
| // Update queue if we are appending: | ||
| if begin > queue.last { | ||
| CoreSchedules::<T>::mutate((queue.last, core_idx), |schedule| { | ||
| if let Some(schedule) = schedule.as_mut() { | ||
| debug_assert!(schedule.next_schedule.is_none(), "queue.end was supposed to be the end, so the next item must be `None`!"); | ||
| schedule.next_schedule = Some(begin); | ||
| } else { | ||
| defensive!("Queue end entry does not exist?"); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| CoreSchedules::<T>::mutate((begin, core_idx), |schedule| { | ||
| let assignments = if let Some(mut old_schedule) = mem::take(schedule) { | ||
|
eskimor marked this conversation as resolved.
Outdated
|
||
| old_schedule.assignments.append(&mut assignments); | ||
| mem::take(&mut old_schedule.assignments) | ||
|
eskimor marked this conversation as resolved.
Outdated
|
||
| } else { | ||
| defensive!("Queue end entry does not exist?"); | ||
| } | ||
| CoreSchedules::<T>::try_mutate((begin, core_idx), |schedule| { | ||
| // It should already be impossible to overwrite an existing schedule due | ||
| // to strictly increasing block number. But we check here for safety and | ||
| // in case the design changes. | ||
| ensure!(schedule.is_none(), Error::<T>::DuplicateInsert); | ||
| *schedule = | ||
| Some(Schedule { assignments, end_hint, next_schedule: None }); | ||
| Ok::<(), DispatchError>(()) | ||
| })?; | ||
| Ok::<(), DispatchError>(()) | ||
| })?; | ||
| assignments | ||
| }; | ||
| *schedule = Some(Schedule { assignments, end_hint, next_schedule: None }); | ||
| }); | ||
|
|
||
| QueueDescriptor { first: queue.first, last: begin } | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| title: Relax requirements on `assign_core`. | ||
| doc: | ||
| - audience: Runtime Dev | ||
| description: |- | ||
| Relax requirements for `assign_core` so that it accepts updates for the last scheduled entry. | ||
| This will allow the coretime chain to split up assignments into multiple | ||
| messages, which allows for interlacing down to single block granularity. | ||
|
|
||
| Fixes: https://github.com/paritytech/polkadot-sdk/issues/6102 | ||
| crates: | ||
| - name: polkadot-runtime-parachains | ||
| bump: major |
Uh oh!
There was an error while loading. Please reload this page.