mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Parachains para_inherent.rs to FrameV2 (#3531)
* last parachains migration! * migrate runtimes * disable frame supertrait * add pallet::inherent * mock * cargo +nightly fmt
This commit is contained in:
@@ -1488,7 +1488,7 @@ construct_runtime! {
|
|||||||
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>} = 51,
|
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>} = 51,
|
||||||
ParasShared: parachains_shared::{Pallet, Call, Storage} = 52,
|
ParasShared: parachains_shared::{Pallet, Call, Storage} = 52,
|
||||||
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>} = 53,
|
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>} = 53,
|
||||||
ParasInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 54,
|
ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 54,
|
||||||
ParaScheduler: parachains_scheduler::{Pallet, Storage} = 55,
|
ParaScheduler: parachains_scheduler::{Pallet, Storage} = 55,
|
||||||
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config} = 56,
|
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config} = 56,
|
||||||
Initializer: parachains_initializer::{Pallet, Call, Storage} = 57,
|
Initializer: parachains_initializer::{Pallet, Call, Storage} = 57,
|
||||||
|
|||||||
@@ -1150,6 +1150,9 @@ mod tests {
|
|||||||
while System::block_number() < to {
|
while System::block_number() < to {
|
||||||
let b = System::block_number();
|
let b = System::block_number();
|
||||||
if b != 0 {
|
if b != 0 {
|
||||||
|
// circumvent requirement to have bitfields and headers in block for testing purposes
|
||||||
|
crate::paras_inherent::Included::<Test>::set(Some(()));
|
||||||
|
|
||||||
AllPallets::on_finalize(b);
|
AllPallets::on_finalize(b);
|
||||||
System::finalize();
|
System::finalize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
//! Mocks for all the traits.
|
//! Mocks for all the traits.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
configuration, disputes, dmp, hrmp, inclusion, initializer, paras, scheduler, session_info,
|
configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler,
|
||||||
shared, ump,
|
session_info, shared, ump,
|
||||||
};
|
};
|
||||||
use frame_support::{parameter_types, traits::GenesisBuild};
|
use frame_support::{parameter_types, traits::GenesisBuild};
|
||||||
use frame_support_test::TestRandomness;
|
use frame_support_test::TestRandomness;
|
||||||
@@ -45,6 +45,7 @@ frame_support::construct_runtime!(
|
|||||||
Configuration: configuration::{Pallet, Call, Storage, Config<T>},
|
Configuration: configuration::{Pallet, Call, Storage, Config<T>},
|
||||||
ParasShared: shared::{Pallet, Call, Storage},
|
ParasShared: shared::{Pallet, Call, Storage},
|
||||||
ParaInclusion: inclusion::{Pallet, Call, Storage, Event<T>},
|
ParaInclusion: inclusion::{Pallet, Call, Storage, Event<T>},
|
||||||
|
ParaInherent: paras_inherent::{Pallet, Call, Storage},
|
||||||
Scheduler: scheduler::{Pallet, Storage},
|
Scheduler: scheduler::{Pallet, Storage},
|
||||||
Initializer: initializer::{Pallet, Call, Storage},
|
Initializer: initializer::{Pallet, Call, Storage},
|
||||||
Dmp: dmp::{Pallet, Call, Storage},
|
Dmp: dmp::{Pallet, Call, Storage},
|
||||||
|
|||||||
@@ -28,20 +28,18 @@ use crate::{
|
|||||||
shared, ump,
|
shared, ump,
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
decl_error, decl_module, decl_storage,
|
|
||||||
dispatch::DispatchResultWithPostInfo,
|
|
||||||
ensure,
|
|
||||||
inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent},
|
inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent},
|
||||||
traits::Get,
|
pallet_prelude::*,
|
||||||
weights::{DispatchClass, Weight},
|
|
||||||
};
|
};
|
||||||
use frame_system::ensure_none;
|
use frame_system::pallet_prelude::*;
|
||||||
use primitives::v1::{
|
use primitives::v1::{
|
||||||
BackedCandidate, InherentData as ParachainsInherentData, PARACHAINS_INHERENT_IDENTIFIER,
|
BackedCandidate, InherentData as ParachainsInherentData, PARACHAINS_INHERENT_IDENTIFIER,
|
||||||
};
|
};
|
||||||
use sp_runtime::traits::Header as HeaderT;
|
use sp_runtime::traits::Header as HeaderT;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
|
pub use pallet::*;
|
||||||
|
|
||||||
const LOG_TARGET: &str = "runtime::inclusion-inherent";
|
const LOG_TARGET: &str = "runtime::inclusion-inherent";
|
||||||
// In the future, we should benchmark these consts; these are all untested assumptions for now.
|
// In the future, we should benchmark these consts; these are all untested assumptions for now.
|
||||||
const BACKED_CANDIDATE_WEIGHT: Weight = 100_000;
|
const BACKED_CANDIDATE_WEIGHT: Weight = 100_000;
|
||||||
@@ -49,22 +47,20 @@ const INCLUSION_INHERENT_CLAIMED_WEIGHT: Weight = 1_000_000_000;
|
|||||||
// we assume that 75% of an paras inherent's weight is used processing backed candidates
|
// we assume that 75% of an paras inherent's weight is used processing backed candidates
|
||||||
const MINIMAL_INCLUSION_INHERENT_WEIGHT: Weight = INCLUSION_INHERENT_CLAIMED_WEIGHT / 4;
|
const MINIMAL_INCLUSION_INHERENT_WEIGHT: Weight = INCLUSION_INHERENT_CLAIMED_WEIGHT / 4;
|
||||||
|
|
||||||
pub trait Config: inclusion::Config + scheduler::Config {}
|
#[frame_support::pallet]
|
||||||
|
pub mod pallet {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
decl_storage! {
|
#[pallet::pallet]
|
||||||
trait Store for Module<T: Config> as ParaInherent {
|
#[pallet::generate_store(pub(super) trait Store)]
|
||||||
/// Whether the paras inherent was included within this block.
|
pub struct Pallet<T>(_);
|
||||||
///
|
|
||||||
/// The `Option<()>` is effectively a `bool`, but it never hits storage in the `None` variant
|
|
||||||
/// due to the guarantees of FRAME's storage APIs.
|
|
||||||
///
|
|
||||||
/// If this is `None` at the end of the block, we panic and render the block invalid.
|
|
||||||
Included: Option<()>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
decl_error! {
|
#[pallet::config]
|
||||||
pub enum Error for Module<T: Config> {
|
#[pallet::disable_frame_system_supertrait_check]
|
||||||
|
pub trait Config: inclusion::Config + scheduler::Config {}
|
||||||
|
|
||||||
|
#[pallet::error]
|
||||||
|
pub enum Error<T> {
|
||||||
/// Inclusion inherent called more than once per block.
|
/// Inclusion inherent called more than once per block.
|
||||||
TooManyInclusionInherents,
|
TooManyInclusionInherents,
|
||||||
/// The hash of the submitted parent header doesn't correspond to the saved block hash of
|
/// The hash of the submitted parent header doesn't correspond to the saved block hash of
|
||||||
@@ -73,201 +69,31 @@ decl_error! {
|
|||||||
/// Potentially invalid candidate.
|
/// Potentially invalid candidate.
|
||||||
CandidateCouldBeInvalid,
|
CandidateCouldBeInvalid,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
decl_module! {
|
/// Whether the paras inherent was included within this block.
|
||||||
/// The paras inherent module.
|
///
|
||||||
pub struct Module<T: Config> for enum Call where origin: <T as frame_system::Config>::Origin {
|
/// The `Option<()>` is effectively a `bool`, but it never hits storage in the `None` variant
|
||||||
type Error = Error<T>;
|
/// due to the guarantees of FRAME's storage APIs.
|
||||||
|
///
|
||||||
|
/// If this is `None` at the end of the block, we panic and render the block invalid.
|
||||||
|
#[pallet::storage]
|
||||||
|
pub(crate) type Included<T> = StorageValue<_, ()>;
|
||||||
|
|
||||||
fn on_initialize() -> Weight {
|
#[pallet::hooks]
|
||||||
|
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||||
|
fn on_initialize(_: T::BlockNumber) -> Weight {
|
||||||
T::DbWeight::get().reads_writes(1, 1) // in on_finalize.
|
T::DbWeight::get().reads_writes(1, 1) // in on_finalize.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_finalize() {
|
fn on_finalize(_: T::BlockNumber) {
|
||||||
if Included::take().is_none() {
|
if Included::<T>::take().is_none() {
|
||||||
panic!("Bitfields and heads must be included every block");
|
panic!("Bitfields and heads must be included every block");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enter the paras inherent. This will process bitfields and backed candidates.
|
|
||||||
#[weight = (
|
|
||||||
MINIMAL_INCLUSION_INHERENT_WEIGHT + data.backed_candidates.len() as Weight * BACKED_CANDIDATE_WEIGHT,
|
|
||||||
DispatchClass::Mandatory,
|
|
||||||
)]
|
|
||||||
pub fn enter(
|
|
||||||
origin,
|
|
||||||
data: ParachainsInherentData<T::Header>,
|
|
||||||
) -> DispatchResultWithPostInfo {
|
|
||||||
let ParachainsInherentData {
|
|
||||||
bitfields: signed_bitfields,
|
|
||||||
backed_candidates,
|
|
||||||
parent_header,
|
|
||||||
disputes,
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
ensure_none(origin)?;
|
|
||||||
ensure!(!<Included>::exists(), Error::<T>::TooManyInclusionInherents);
|
|
||||||
|
|
||||||
// Check that the submitted parent header indeed corresponds to the previous block hash.
|
|
||||||
let parent_hash = <frame_system::Pallet<T>>::parent_hash();
|
|
||||||
ensure!(
|
|
||||||
parent_header.hash().as_ref() == parent_hash.as_ref(),
|
|
||||||
Error::<T>::InvalidParentHeader,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle disputes logic.
|
|
||||||
let current_session = <shared::Pallet<T>>::session_index();
|
|
||||||
let freed_disputed: Vec<(_, FreedReason)> = {
|
|
||||||
let fresh_disputes = T::DisputesHandler::provide_multi_dispute_data(disputes)?;
|
|
||||||
if T::DisputesHandler::is_frozen() {
|
|
||||||
// The relay chain we are currently on is invalid. Proceed no further on parachains.
|
|
||||||
Included::set(Some(()));
|
|
||||||
return Ok(Some(
|
|
||||||
MINIMAL_INCLUSION_INHERENT_WEIGHT
|
|
||||||
).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let any_current_session_disputes = fresh_disputes.iter()
|
#[pallet::inherent]
|
||||||
.any(|(s, _)| s == ¤t_session);
|
impl<T: Config> ProvideInherent for Pallet<T> {
|
||||||
|
|
||||||
if any_current_session_disputes {
|
|
||||||
let current_session_disputes: Vec<_> = fresh_disputes.iter()
|
|
||||||
.filter(|(s, _)| s == ¤t_session)
|
|
||||||
.map(|(_, c)| *c)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
<inclusion::Pallet<T>>::collect_disputed(current_session_disputes)
|
|
||||||
.into_iter()
|
|
||||||
.map(|core| (core, FreedReason::Concluded))
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Process new availability bitfields, yielding any availability cores whose
|
|
||||||
// work has now concluded.
|
|
||||||
let expected_bits = <scheduler::Pallet<T>>::availability_cores().len();
|
|
||||||
let freed_concluded = <inclusion::Pallet<T>>::process_bitfields(
|
|
||||||
expected_bits,
|
|
||||||
signed_bitfields,
|
|
||||||
<scheduler::Pallet<T>>::core_para,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Inform the disputes module of all included candidates.
|
|
||||||
let now = <frame_system::Pallet<T>>::block_number();
|
|
||||||
for (_, candidate_hash) in &freed_concluded {
|
|
||||||
T::DisputesHandler::note_included(current_session, *candidate_hash, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle timeouts for any availability core work.
|
|
||||||
let availability_pred = <scheduler::Pallet<T>>::availability_timeout_predicate();
|
|
||||||
let freed_timeout = if let Some(pred) = availability_pred {
|
|
||||||
<inclusion::Pallet<T>>::collect_pending(pred)
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Schedule paras again, given freed cores, and reasons for freeing.
|
|
||||||
let mut freed = freed_disputed.into_iter()
|
|
||||||
.chain(freed_concluded.into_iter().map(|(c, _hash)| (c, FreedReason::Concluded)))
|
|
||||||
.chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut)))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
freed.sort_unstable_by_key(|pair| pair.0); // sort by core index
|
|
||||||
|
|
||||||
<scheduler::Pallet<T>>::clear();
|
|
||||||
<scheduler::Pallet<T>>::schedule(
|
|
||||||
freed,
|
|
||||||
<frame_system::Pallet<T>>::block_number(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let backed_candidates = limit_backed_candidates::<T>(backed_candidates);
|
|
||||||
let backed_candidates_len = backed_candidates.len() as Weight;
|
|
||||||
|
|
||||||
// Refuse to back any candidates that are disputed or invalid.
|
|
||||||
for candidate in &backed_candidates {
|
|
||||||
ensure!(
|
|
||||||
!T::DisputesHandler::could_be_invalid(
|
|
||||||
current_session,
|
|
||||||
candidate.candidate.hash(),
|
|
||||||
),
|
|
||||||
Error::<T>::CandidateCouldBeInvalid,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process backed candidates according to scheduled cores.
|
|
||||||
let parent_storage_root = parent_header.state_root().clone();
|
|
||||||
let occupied = <inclusion::Pallet<T>>::process_candidates(
|
|
||||||
parent_storage_root,
|
|
||||||
backed_candidates,
|
|
||||||
<scheduler::Pallet<T>>::scheduled(),
|
|
||||||
<scheduler::Pallet<T>>::group_validators,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Note which of the scheduled cores were actually occupied by a backed candidate.
|
|
||||||
<scheduler::Pallet<T>>::occupied(&occupied);
|
|
||||||
|
|
||||||
// Give some time slice to dispatch pending upward messages.
|
|
||||||
<ump::Pallet<T>>::process_pending_upward_messages();
|
|
||||||
|
|
||||||
// And track that we've finished processing the inherent for this block.
|
|
||||||
Included::set(Some(()));
|
|
||||||
|
|
||||||
Ok(Some(
|
|
||||||
MINIMAL_INCLUSION_INHERENT_WEIGHT +
|
|
||||||
(backed_candidates_len * BACKED_CANDIDATE_WEIGHT)
|
|
||||||
).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limit the number of backed candidates processed in order to stay within block weight limits.
|
|
||||||
///
|
|
||||||
/// Use a configured assumption about the weight required to process a backed candidate and the
|
|
||||||
/// current block weight as of the execution of this function to ensure that we don't overload
|
|
||||||
/// the block with candidate processing.
|
|
||||||
///
|
|
||||||
/// If the backed candidates exceed the available block weight remaining, then skips all of them.
|
|
||||||
/// This is somewhat less desirable than attempting to fit some of them, but is more fair in the
|
|
||||||
/// even that we can't trust the provisioner to provide a fair / random ordering of candidates.
|
|
||||||
fn limit_backed_candidates<T: Config>(
|
|
||||||
mut backed_candidates: Vec<BackedCandidate<T::Hash>>,
|
|
||||||
) -> Vec<BackedCandidate<T::Hash>> {
|
|
||||||
const MAX_CODE_UPGRADES: usize = 1;
|
|
||||||
|
|
||||||
// Ignore any candidates beyond one that contain code upgrades.
|
|
||||||
//
|
|
||||||
// This is an artificial limitation that does not appear in the guide as it is a practical
|
|
||||||
// concern around execution.
|
|
||||||
{
|
|
||||||
let mut code_upgrades = 0;
|
|
||||||
backed_candidates.retain(|c| {
|
|
||||||
if c.candidate.commitments.new_validation_code.is_some() {
|
|
||||||
if code_upgrades >= MAX_CODE_UPGRADES {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
code_upgrades += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// the weight of the paras inherent is already included in the current block weight,
|
|
||||||
// so our operation is simple: if the block is currently overloaded, make this intrinsic smaller
|
|
||||||
if frame_system::Pallet::<T>::block_weight().total() >
|
|
||||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
|
||||||
{
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
backed_candidates
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Config> ProvideInherent for Module<T> {
|
|
||||||
type Call = Call<T>;
|
type Call = Call<T>;
|
||||||
type Error = MakeFatalError<()>;
|
type Error = MakeFatalError<()>;
|
||||||
const INHERENT_IDENTIFIER: InherentIdentifier = PARACHAINS_INHERENT_IDENTIFIER;
|
const INHERENT_IDENTIFIER: InherentIdentifier = PARACHAINS_INHERENT_IDENTIFIER;
|
||||||
@@ -315,6 +141,183 @@ impl<T: Config> ProvideInherent for Module<T> {
|
|||||||
fn is_inherent(call: &Self::Call) -> bool {
|
fn is_inherent(call: &Self::Call) -> bool {
|
||||||
matches!(call, Call::enter(..))
|
matches!(call, Call::enter(..))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pallet::call]
|
||||||
|
impl<T: Config> Pallet<T> {
|
||||||
|
/// Enter the paras inherent. This will process bitfields and backed candidates.
|
||||||
|
#[pallet::weight((
|
||||||
|
MINIMAL_INCLUSION_INHERENT_WEIGHT + data.backed_candidates.len() as Weight * BACKED_CANDIDATE_WEIGHT,
|
||||||
|
DispatchClass::Mandatory,
|
||||||
|
))]
|
||||||
|
pub fn enter(
|
||||||
|
origin: OriginFor<T>,
|
||||||
|
data: ParachainsInherentData<T::Header>,
|
||||||
|
) -> DispatchResultWithPostInfo {
|
||||||
|
let ParachainsInherentData {
|
||||||
|
bitfields: signed_bitfields,
|
||||||
|
backed_candidates,
|
||||||
|
parent_header,
|
||||||
|
disputes,
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
ensure_none(origin)?;
|
||||||
|
ensure!(!Included::<T>::exists(), Error::<T>::TooManyInclusionInherents);
|
||||||
|
|
||||||
|
// Check that the submitted parent header indeed corresponds to the previous block hash.
|
||||||
|
let parent_hash = <frame_system::Pallet<T>>::parent_hash();
|
||||||
|
ensure!(
|
||||||
|
parent_header.hash().as_ref() == parent_hash.as_ref(),
|
||||||
|
Error::<T>::InvalidParentHeader,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle disputes logic.
|
||||||
|
let current_session = <shared::Pallet<T>>::session_index();
|
||||||
|
let freed_disputed: Vec<(_, FreedReason)> = {
|
||||||
|
let fresh_disputes = T::DisputesHandler::provide_multi_dispute_data(disputes)?;
|
||||||
|
if T::DisputesHandler::is_frozen() {
|
||||||
|
// The relay chain we are currently on is invalid. Proceed no further on parachains.
|
||||||
|
Included::<T>::set(Some(()));
|
||||||
|
return Ok(Some(MINIMAL_INCLUSION_INHERENT_WEIGHT).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
let any_current_session_disputes =
|
||||||
|
fresh_disputes.iter().any(|(s, _)| s == ¤t_session);
|
||||||
|
|
||||||
|
if any_current_session_disputes {
|
||||||
|
let current_session_disputes: Vec<_> = fresh_disputes
|
||||||
|
.iter()
|
||||||
|
.filter(|(s, _)| s == ¤t_session)
|
||||||
|
.map(|(_, c)| *c)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
<inclusion::Pallet<T>>::collect_disputed(current_session_disputes)
|
||||||
|
.into_iter()
|
||||||
|
.map(|core| (core, FreedReason::Concluded))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process new availability bitfields, yielding any availability cores whose
|
||||||
|
// work has now concluded.
|
||||||
|
let expected_bits = <scheduler::Pallet<T>>::availability_cores().len();
|
||||||
|
let freed_concluded = <inclusion::Pallet<T>>::process_bitfields(
|
||||||
|
expected_bits,
|
||||||
|
signed_bitfields,
|
||||||
|
<scheduler::Pallet<T>>::core_para,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Inform the disputes module of all included candidates.
|
||||||
|
let now = <frame_system::Pallet<T>>::block_number();
|
||||||
|
for (_, candidate_hash) in &freed_concluded {
|
||||||
|
T::DisputesHandler::note_included(current_session, *candidate_hash, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle timeouts for any availability core work.
|
||||||
|
let availability_pred = <scheduler::Pallet<T>>::availability_timeout_predicate();
|
||||||
|
let freed_timeout = if let Some(pred) = availability_pred {
|
||||||
|
<inclusion::Pallet<T>>::collect_pending(pred)
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schedule paras again, given freed cores, and reasons for freeing.
|
||||||
|
let mut freed = freed_disputed
|
||||||
|
.into_iter()
|
||||||
|
.chain(freed_concluded.into_iter().map(|(c, _hash)| (c, FreedReason::Concluded)))
|
||||||
|
.chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
freed.sort_unstable_by_key(|pair| pair.0); // sort by core index
|
||||||
|
|
||||||
|
<scheduler::Pallet<T>>::clear();
|
||||||
|
<scheduler::Pallet<T>>::schedule(freed, <frame_system::Pallet<T>>::block_number());
|
||||||
|
|
||||||
|
let backed_candidates = limit_backed_candidates::<T>(backed_candidates);
|
||||||
|
let backed_candidates_len = backed_candidates.len() as Weight;
|
||||||
|
|
||||||
|
// Refuse to back any candidates that are disputed or invalid.
|
||||||
|
for candidate in &backed_candidates {
|
||||||
|
ensure!(
|
||||||
|
!T::DisputesHandler::could_be_invalid(
|
||||||
|
current_session,
|
||||||
|
candidate.candidate.hash(),
|
||||||
|
),
|
||||||
|
Error::<T>::CandidateCouldBeInvalid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process backed candidates according to scheduled cores.
|
||||||
|
let parent_storage_root = parent_header.state_root().clone();
|
||||||
|
let occupied = <inclusion::Pallet<T>>::process_candidates(
|
||||||
|
parent_storage_root,
|
||||||
|
backed_candidates,
|
||||||
|
<scheduler::Pallet<T>>::scheduled(),
|
||||||
|
<scheduler::Pallet<T>>::group_validators,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Note which of the scheduled cores were actually occupied by a backed candidate.
|
||||||
|
<scheduler::Pallet<T>>::occupied(&occupied);
|
||||||
|
|
||||||
|
// Give some time slice to dispatch pending upward messages.
|
||||||
|
<ump::Pallet<T>>::process_pending_upward_messages();
|
||||||
|
|
||||||
|
// And track that we've finished processing the inherent for this block.
|
||||||
|
Included::<T>::set(Some(()));
|
||||||
|
|
||||||
|
Ok(Some(
|
||||||
|
MINIMAL_INCLUSION_INHERENT_WEIGHT +
|
||||||
|
(backed_candidates_len * BACKED_CANDIDATE_WEIGHT),
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Limit the number of backed candidates processed in order to stay within block weight limits.
|
||||||
|
///
|
||||||
|
/// Use a configured assumption about the weight required to process a backed candidate and the
|
||||||
|
/// current block weight as of the execution of this function to ensure that we don't overload
|
||||||
|
/// the block with candidate processing.
|
||||||
|
///
|
||||||
|
/// If the backed candidates exceed the available block weight remaining, then skips all of them.
|
||||||
|
/// This is somewhat less desirable than attempting to fit some of them, but is more fair in the
|
||||||
|
/// even that we can't trust the provisioner to provide a fair / random ordering of candidates.
|
||||||
|
fn limit_backed_candidates<T: Config>(
|
||||||
|
mut backed_candidates: Vec<BackedCandidate<T::Hash>>,
|
||||||
|
) -> Vec<BackedCandidate<T::Hash>> {
|
||||||
|
const MAX_CODE_UPGRADES: usize = 1;
|
||||||
|
|
||||||
|
// Ignore any candidates beyond one that contain code upgrades.
|
||||||
|
//
|
||||||
|
// This is an artificial limitation that does not appear in the guide as it is a practical
|
||||||
|
// concern around execution.
|
||||||
|
{
|
||||||
|
let mut code_upgrades = 0;
|
||||||
|
backed_candidates.retain(|c| {
|
||||||
|
if c.candidate.commitments.new_validation_code.is_some() {
|
||||||
|
if code_upgrades >= MAX_CODE_UPGRADES {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
code_upgrades += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// the weight of the paras inherent is already included in the current block weight,
|
||||||
|
// so our operation is simple: if the block is currently overloaded, make this intrinsic smaller
|
||||||
|
if frame_system::Pallet::<T>::block_weight().total() >
|
||||||
|
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||||
|
{
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
backed_candidates
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ construct_runtime! {
|
|||||||
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>},
|
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>},
|
||||||
ParasShared: parachains_shared::{Pallet, Call, Storage},
|
ParasShared: parachains_shared::{Pallet, Call, Storage},
|
||||||
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>},
|
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>},
|
||||||
ParasInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent},
|
ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent},
|
||||||
ParaScheduler: parachains_scheduler::{Pallet, Storage},
|
ParaScheduler: parachains_scheduler::{Pallet, Storage},
|
||||||
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config},
|
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config},
|
||||||
Initializer: parachains_initializer::{Pallet, Call, Storage},
|
Initializer: parachains_initializer::{Pallet, Call, Storage},
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ construct_runtime! {
|
|||||||
// Parachains runtime modules
|
// Parachains runtime modules
|
||||||
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>},
|
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>},
|
||||||
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>},
|
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>},
|
||||||
ParasInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent},
|
ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent},
|
||||||
Initializer: parachains_initializer::{Pallet, Call, Storage},
|
Initializer: parachains_initializer::{Pallet, Call, Storage},
|
||||||
Paras: parachains_paras::{Pallet, Call, Storage, Origin, Event},
|
Paras: parachains_paras::{Pallet, Call, Storage, Origin, Event},
|
||||||
ParasShared: parachains_shared::{Pallet, Call, Storage},
|
ParasShared: parachains_shared::{Pallet, Call, Storage},
|
||||||
|
|||||||
@@ -1071,7 +1071,7 @@ construct_runtime! {
|
|||||||
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>} = 42,
|
Configuration: parachains_configuration::{Pallet, Call, Storage, Config<T>} = 42,
|
||||||
ParasShared: parachains_shared::{Pallet, Call, Storage} = 43,
|
ParasShared: parachains_shared::{Pallet, Call, Storage} = 43,
|
||||||
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>} = 44,
|
ParaInclusion: parachains_inclusion::{Pallet, Call, Storage, Event<T>} = 44,
|
||||||
ParasInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 45,
|
ParaInherent: parachains_paras_inherent::{Pallet, Call, Storage, Inherent} = 45,
|
||||||
ParaScheduler: parachains_scheduler::{Pallet, Storage} = 46,
|
ParaScheduler: parachains_scheduler::{Pallet, Storage} = 46,
|
||||||
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config} = 47,
|
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config} = 47,
|
||||||
Initializer: parachains_initializer::{Pallet, Call, Storage} = 48,
|
Initializer: parachains_initializer::{Pallet, Call, Storage} = 48,
|
||||||
|
|||||||
Reference in New Issue
Block a user