mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 05:11:02 +00:00
Asynchronous backing PR (#2300)
* Update substrate & polkadot * min changes to make async backing compile * (async backing) parachain-system: track limitations for unincluded blocks (#2438) * unincluded segment draft * read para head from storage proof * read_para_head -> read_included_para_head * Provide pub interface * add errors * fix unincluded segment update * BlockTracker -> Ancestor * add a dmp limit * Read para head depending on the storage switch * doc comments * storage items docs * add a sanity check on block initialize * Check watermark * append to the segment on block finalize * Move segment update into set_validation_data * Resolve para head todo * option watermark * fix comment * Drop dmq check * fix weight * doc-comments on inherent invariant * Remove TODO * add todo * primitives tests * pallet tests * doc comments * refactor unincluded segment length into a ConsensusHook (#2501) * refactor unincluded segment length into a ConsensusHook * add docs * refactor bandwidth_out calculation Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * test for limits from impl * fmt * make tests compile * update comment * uncomment test * fix collator test by adding parent to state proof * patch HRMP watermark rules for unincluded segment * get consensus-common tests to pass, using unincluded segment * fix unincluded segment tests * get all tests passing * fmt * rustdoc CI * aura-ext: limit the number of authored blocks per slot (#2551) * aura_ext consensus hook * reverse dependency * include weight into hook * fix tests * remove stray println Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> * fix test warning * fix doc link --------- Co-authored-by: Chris Sosnin <48099298+slumber@users.noreply.github.com> Co-authored-by: Chris Sosnin <chris125_@live.com> * parachain-system: ignore go ahead signal once upgrade is processed (#2594) * handle goahead signal for unincluded segment * doc comment * add test * parachain-system: drop processed messages from inherent data (#2590) * implement `drop_processed_messages` * drop messages based on relay parent number * adjust tests * drop changes to mqc * fix comment * drop test * drop more dead code * clippy * aura-ext: check slot in consensus hook and remove all `CheckInherents` logic (#2658) * aura-ext: check slot in consensus hook * convert relay chain slot * Make relay chain slot duration generic * use fixed velocity hook for pallets with aura * purge timestamp inherent * fix warning * adjust runtime tests * fix slots in tests * Make `xcm-emulator` test pass for new consensus hook (#2722) * add pallets on_initialize * tests pass * add AuraExt on_init * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <> --------- Co-authored-by: Ignacio Palacios <ignacio.palacios.santos@gmail.com> * update polkadot git refs * CollationGenerationConfig closure is now optional (#2772) * CollationGenerationConfig closure is now optional * fix test * propagate network-protocol-staging feature (#2899) * Feature Flagging Consensus Hook Type Parameter (#2911) * First pass * fmt * Added as default feature in tomls * Changed to direct dependency feature * Dealing with clippy error * Update pallets/parachain-system/src/lib.rs Co-authored-by: asynchronous rob <rphmeier@gmail.com> --------- Co-authored-by: asynchronous rob <rphmeier@gmail.com> * fmt * bump deps and remove warning * parachain-system: update RelevantMessagingState according to the unincluded segment (#2948) * mostly address 2471 with a bug introduced * adjust relevant messaging state after computing total * fmt * max -> min * fix test implementation of xcmp source * add test * fix test message sending logic * fix + test * add more to unincluded segment test * fmt --------- Co-authored-by: Chris Sosnin <chris125_@live.com> * Integrate new Aura / Parachain Consensus Logic in Parachain-Template / Polkadot-Parachain (#2864) * add a comment * refactor client/service utilities * deprecate start_collator * update parachain-template * update test-service in the same way * update polkadot-parachain crate * fmt * wire up new SubmitCollation message * some runtime utilities for implementing unincluded segment runtime APIs * allow parachains to configure their level of sybil-resistance when starting the network * make aura-ext compile * update to specify sybil resistance levels * fmt * specify relay chain slot duration in milliseconds * update Aura to explicitly produce Send futures also, make relay_chain_slot_duration a Duration * add authoring duration to basic collator and document params * integrate new basic collator into parachain-template * remove assert_send used for testing * basic-aura: only author when parent included * update polkadot-parachain-bin * fmt * some fixes * fixes * add a RelayNumberMonotonicallyIncreases * add a utility function for initializing subsystems * some logging for timestamp adjustment * fmt * some fixes for lookahead collator * add a log * update `find_potential_parents` to account for sessions * bound the loop * restore & deprecate old start_collator and start_full_node functions. * remove unnecessary await calls * fix warning * clippy * more clippy * remove unneeded logic * ci * update comment Co-authored-by: Marcin S. <marcin@bytedude.com> * (async backing) restore `CheckInherents` for backwards-compatibility (#2977) * bring back timestamp * Restore CheckInherents * revert to empty CheckInherents * make CheckInherents optional * attempt * properly end system blocks * add some more comments * ignore failing system parachain tests * update refs after main feature branch merge * comment out the offending tests because CI runs ignored tests * fix warnings * fmt * revert to polkadot master * cargo update -p polkadot-primitives -p sp-io --------- Co-authored-by: asynchronous rob <rphmeier@gmail.com> Co-authored-by: Ignacio Palacios <ignacio.palacios.santos@gmail.com> Co-authored-by: Bradley Olson <34992650+BradleyOlson64@users.noreply.github.com> Co-authored-by: Marcin S. <marcin@bytedude.com> Co-authored-by: eskimor <eskimor@users.noreply.github.com> Co-authored-by: Andronik <write@reusable.software>
This commit is contained in:
@@ -58,12 +58,22 @@ use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
|
||||
use xcm::latest::XcmHash;
|
||||
|
||||
pub mod migration;
|
||||
mod relay_state_snapshot;
|
||||
#[macro_use]
|
||||
pub mod validate_block;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod unincluded_segment;
|
||||
|
||||
pub mod consensus_hook;
|
||||
pub mod relay_state_snapshot;
|
||||
#[macro_use]
|
||||
pub mod validate_block;
|
||||
|
||||
use unincluded_segment::{
|
||||
Ancestor, HrmpChannelUpdate, HrmpWatermarkUpdate, OutboundBandwidthLimits, SegmentTracker,
|
||||
UsedBandwidth,
|
||||
};
|
||||
|
||||
pub use consensus_hook::{ConsensusHook, ExpectParentIncluded};
|
||||
/// Register the `validate_block` function that is used by parachains to validate blocks on a
|
||||
/// validator.
|
||||
///
|
||||
@@ -136,6 +146,23 @@ impl CheckAssociatedRelayNumber for AnyRelayNumber {
|
||||
fn check_associated_relay_number(_: RelayChainBlockNumber, _: RelayChainBlockNumber) {}
|
||||
}
|
||||
|
||||
/// Provides an implementation of [`CheckAssociatedRelayNumber`].
|
||||
///
|
||||
/// It will ensure that the associated relay block number monotonically increases between Parachain
|
||||
/// blocks. This should be used when asynchronous backing is enabled.
|
||||
pub struct RelayNumberMonotonicallyIncreases;
|
||||
|
||||
impl CheckAssociatedRelayNumber for RelayNumberMonotonicallyIncreases {
|
||||
fn check_associated_relay_number(
|
||||
current: RelayChainBlockNumber,
|
||||
previous: RelayChainBlockNumber,
|
||||
) {
|
||||
if current < previous {
|
||||
panic!("Relay chain block number needs to monotonically increase between Parachain blocks!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information needed when a new runtime binary is submitted and needs to be authorized before
|
||||
/// replacing the current runtime.
|
||||
#[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)]
|
||||
@@ -193,6 +220,22 @@ pub mod pallet {
|
||||
|
||||
/// Something that can check the associated relay parent block number.
|
||||
type CheckAssociatedRelayNumber: CheckAssociatedRelayNumber;
|
||||
|
||||
/// An entry-point for higher-level logic to manage the backlog of unincluded parachain
|
||||
/// blocks and authorship rights for those blocks.
|
||||
///
|
||||
/// Typically, this should be a hook tailored to the collator-selection/consensus mechanism
|
||||
/// that is used for this chain.
|
||||
///
|
||||
/// However, to maintain the same behavior as prior to asynchronous backing, provide the
|
||||
/// [`consensus_hook::ExpectParentIncluded`] here. This is only necessary in the case
|
||||
/// that collators aren't expected to have node versions that supply the included block
|
||||
/// in the relay-chain state proof.
|
||||
///
|
||||
/// This config type is only available when the `parameterized-consensus-hook` crate feature
|
||||
/// is activated.
|
||||
#[cfg(feature = "parameterized-consensus-hook")]
|
||||
type ConsensusHook: ConsensusHook;
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
@@ -200,6 +243,7 @@ pub mod pallet {
|
||||
fn on_finalize(_: BlockNumberFor<T>) {
|
||||
<DidSetValidationCode<T>>::kill();
|
||||
<UpgradeRestrictionSignal<T>>::kill();
|
||||
let relay_upgrade_go_ahead = <UpgradeGoAhead<T>>::take();
|
||||
|
||||
assert!(
|
||||
<ValidationData<T>>::exists(),
|
||||
@@ -216,8 +260,12 @@ pub mod pallet {
|
||||
return
|
||||
},
|
||||
};
|
||||
let relevant_messaging_state = match Self::relevant_messaging_state() {
|
||||
Some(ok) => ok,
|
||||
|
||||
// Before updating the relevant messaging state, we need to extract
|
||||
// the total bandwidth limits for the purpose of updating the unincluded
|
||||
// segment.
|
||||
let total_bandwidth_out = match Self::relevant_messaging_state() {
|
||||
Some(s) => OutboundBandwidthLimits::from_relay_chain_state(&s),
|
||||
None => {
|
||||
debug_assert!(
|
||||
false,
|
||||
@@ -228,35 +276,57 @@ pub mod pallet {
|
||||
},
|
||||
};
|
||||
|
||||
<PendingUpwardMessages<T>>::mutate(|up| {
|
||||
let queue_size = relevant_messaging_state.relay_dispatch_queue_remaining_capacity;
|
||||
// After this point, the `RelevantMessagingState` in storage reflects the
|
||||
// unincluded segment.
|
||||
Self::adjust_egress_bandwidth_limits();
|
||||
|
||||
let available_capacity = cmp::min(
|
||||
queue_size.remaining_count,
|
||||
host_config.max_upward_message_num_per_candidate.into(),
|
||||
);
|
||||
let available_size = queue_size.remaining_size;
|
||||
let (ump_msg_count, ump_total_bytes) = <PendingUpwardMessages<T>>::mutate(|up| {
|
||||
let (available_capacity, available_size) = match Self::relevant_messaging_state() {
|
||||
Some(limits) => (
|
||||
limits.relay_dispatch_queue_remaining_capacity.remaining_count,
|
||||
limits.relay_dispatch_queue_remaining_capacity.remaining_size,
|
||||
),
|
||||
None => {
|
||||
debug_assert!(
|
||||
false,
|
||||
"relevant messaging state is promised to be set until `on_finalize`; \
|
||||
qed",
|
||||
);
|
||||
return (0, 0)
|
||||
},
|
||||
};
|
||||
|
||||
let available_capacity =
|
||||
cmp::min(available_capacity, host_config.max_upward_message_num_per_candidate);
|
||||
|
||||
// Count the number of messages we can possibly fit in the given constraints, i.e.
|
||||
// available_capacity and available_size.
|
||||
let num = up
|
||||
let (num, total_size) = up
|
||||
.iter()
|
||||
.scan((available_capacity as usize, available_size as usize), |state, msg| {
|
||||
let (cap_left, size_left) = *state;
|
||||
match (cap_left.checked_sub(1), size_left.checked_sub(msg.len())) {
|
||||
(Some(new_cap), Some(new_size)) => {
|
||||
.scan((0u32, 0u32), |state, msg| {
|
||||
let (cap_used, size_used) = *state;
|
||||
let new_cap = cap_used.saturating_add(1);
|
||||
let new_size = size_used.saturating_add(msg.len() as u32);
|
||||
match available_capacity
|
||||
.checked_sub(new_cap)
|
||||
.and(available_size.checked_sub(new_size))
|
||||
{
|
||||
Some(_) => {
|
||||
*state = (new_cap, new_size);
|
||||
Some(())
|
||||
Some(*state)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.count();
|
||||
.last()
|
||||
.unwrap_or_default();
|
||||
|
||||
// TODO: #274 Return back messages that do not longer fit into the queue.
|
||||
|
||||
UpwardMessages::<T>::put(&up[..num]);
|
||||
*up = up.split_off(num);
|
||||
UpwardMessages::<T>::put(&up[..num as usize]);
|
||||
*up = up.split_off(num as usize);
|
||||
|
||||
(num, total_size)
|
||||
});
|
||||
|
||||
// Sending HRMP messages is a little bit more involved. There are the following
|
||||
@@ -272,12 +342,54 @@ pub mod pallet {
|
||||
.hrmp_max_message_num_per_candidate
|
||||
.min(<AnnouncedHrmpMessagesPerCandidate<T>>::take()) as usize;
|
||||
|
||||
// Note: this internally calls the `GetChannelInfo` implementation for this
|
||||
// pallet, which draws on the `RelevantMessagingState`. That in turn has
|
||||
// been adjusted above to reflect the correct limits in all channels.
|
||||
let outbound_messages =
|
||||
T::OutboundXcmpMessageSource::take_outbound_messages(maximum_channels)
|
||||
.into_iter()
|
||||
.map(|(recipient, data)| OutboundHrmpMessage { recipient, data })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Update the unincluded segment length; capacity checks were done previously in
|
||||
// `set_validation_data`, so this can be done unconditionally.
|
||||
{
|
||||
let hrmp_outgoing = outbound_messages
|
||||
.iter()
|
||||
.map(|msg| {
|
||||
(
|
||||
msg.recipient,
|
||||
HrmpChannelUpdate { msg_count: 1, total_bytes: msg.data.len() as u32 },
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let used_bandwidth =
|
||||
UsedBandwidth { ump_msg_count, ump_total_bytes, hrmp_outgoing };
|
||||
|
||||
let mut aggregated_segment =
|
||||
AggregatedUnincludedSegment::<T>::get().unwrap_or_default();
|
||||
let consumed_go_ahead_signal =
|
||||
if aggregated_segment.consumed_go_ahead_signal().is_some() {
|
||||
// Some ancestor within the segment already processed this signal --
|
||||
// validated during inherent creation.
|
||||
None
|
||||
} else {
|
||||
relay_upgrade_go_ahead
|
||||
};
|
||||
// The bandwidth constructed was ensured to satisfy relay chain constraints.
|
||||
let ancestor = Ancestor::new_unchecked(used_bandwidth, consumed_go_ahead_signal);
|
||||
|
||||
let watermark = HrmpWatermark::<T>::get();
|
||||
let watermark_update =
|
||||
HrmpWatermarkUpdate::new(watermark, LastRelayChainBlockNumber::<T>::get());
|
||||
|
||||
aggregated_segment
|
||||
.append(&ancestor, watermark_update, &total_bandwidth_out)
|
||||
.expect("unincluded segment limits exceeded");
|
||||
AggregatedUnincludedSegment::<T>::put(aggregated_segment);
|
||||
// Check in `on_initialize` guarantees there's space for this block.
|
||||
UnincludedSegment::<T>::append(ancestor);
|
||||
}
|
||||
HrmpOutboundMessages::<T>::put(outbound_messages);
|
||||
}
|
||||
|
||||
@@ -292,6 +404,22 @@ pub mod pallet {
|
||||
weight += T::DbWeight::get().writes(1);
|
||||
}
|
||||
|
||||
// The parent hash was unknown during block finalization. Update it here.
|
||||
{
|
||||
<UnincludedSegment<T>>::mutate(|chain| {
|
||||
if let Some(ancestor) = chain.last_mut() {
|
||||
let parent = frame_system::Pallet::<T>::parent_hash();
|
||||
// Ancestor is the latest finalized block, thus current parent is
|
||||
// its output head.
|
||||
ancestor.replace_para_head_hash(parent);
|
||||
}
|
||||
});
|
||||
weight += T::DbWeight::get().reads_writes(1, 1);
|
||||
|
||||
// Weight used during finalization.
|
||||
weight += T::DbWeight::get().reads_writes(3, 2);
|
||||
}
|
||||
|
||||
// Remove the validation from the old block.
|
||||
ValidationData::<T>::kill();
|
||||
ProcessedDownwardMessages::<T>::kill();
|
||||
@@ -332,6 +460,12 @@ pub mod pallet {
|
||||
4 + hrmp_max_message_num_per_candidate as u64,
|
||||
);
|
||||
|
||||
// Weight for adjusting the unincluded segment in `on_finalize`.
|
||||
weight += T::DbWeight::get().reads_writes(6, 3);
|
||||
|
||||
// Always try to read `UpgradeGoAhead` in `on_finalize`.
|
||||
weight += T::DbWeight::get().reads(1);
|
||||
|
||||
weight
|
||||
}
|
||||
}
|
||||
@@ -360,6 +494,15 @@ pub mod pallet {
|
||||
"ValidationData must be updated only once in a block",
|
||||
);
|
||||
|
||||
// TODO: This is more than zero, but will need benchmarking to figure out what.
|
||||
let mut total_weight = Weight::zero();
|
||||
|
||||
// NOTE: the inherent data is expected to be unique, even if this block is built
|
||||
// in the context of the same relay parent as the previous one. In particular,
|
||||
// the inherent shouldn't contain messages that were already processed by any of the
|
||||
// ancestors.
|
||||
//
|
||||
// This invariant should be upheld by the `ProvideInherent` implementation.
|
||||
let ParachainInherentData {
|
||||
validation_data: vfp,
|
||||
relay_chain_state,
|
||||
@@ -381,6 +524,13 @@ pub mod pallet {
|
||||
)
|
||||
.expect("Invalid relay chain state proof");
|
||||
|
||||
// Update the desired maximum capacity according to the consensus hook.
|
||||
#[cfg(feature = "parameterized-consensus-hook")]
|
||||
let (consensus_hook_weight, capacity) = T::ConsensusHook::on_state_proof(&relay_state_proof);
|
||||
#[cfg(not(feature = "parameterized-consensus-hook"))]
|
||||
let (consensus_hook_weight, capacity) = ExpectParentIncluded::on_state_proof(&relay_state_proof);
|
||||
total_weight += consensus_hook_weight;
|
||||
total_weight += Self::maybe_drop_included_ancestors(&relay_state_proof, capacity);
|
||||
// Deposit a log indicating the relay-parent storage root.
|
||||
// TODO: remove this in favor of the relay-parent's hash after
|
||||
// https://github.com/paritytech/cumulus/issues/303
|
||||
@@ -397,7 +547,19 @@ pub mod pallet {
|
||||
let upgrade_go_ahead_signal = relay_state_proof
|
||||
.read_upgrade_go_ahead_signal()
|
||||
.expect("Invalid upgrade go ahead signal");
|
||||
|
||||
let upgrade_signal_in_segment = AggregatedUnincludedSegment::<T>::get()
|
||||
.as_ref()
|
||||
.and_then(SegmentTracker::consumed_go_ahead_signal);
|
||||
if let Some(signal_in_segment) = upgrade_signal_in_segment.as_ref() {
|
||||
// Unincluded ancestor consuming upgrade signal is still within the segment,
|
||||
// sanity check that it matches with the signal from relay chain.
|
||||
assert_eq!(upgrade_go_ahead_signal, Some(*signal_in_segment));
|
||||
}
|
||||
match upgrade_go_ahead_signal {
|
||||
Some(_signal) if upgrade_signal_in_segment.is_some() => {
|
||||
// Do nothing, processing logic was executed by unincluded ancestor.
|
||||
},
|
||||
Some(relay_chain::UpgradeGoAhead::GoAhead) => {
|
||||
assert!(
|
||||
<PendingValidationCode<T>>::exists(),
|
||||
@@ -422,10 +584,12 @@ pub mod pallet {
|
||||
.read_upgrade_restriction_signal()
|
||||
.expect("Invalid upgrade restriction signal"),
|
||||
);
|
||||
<UpgradeGoAhead<T>>::put(upgrade_go_ahead_signal);
|
||||
|
||||
let host_config = relay_state_proof
|
||||
.read_abridged_host_configuration()
|
||||
.expect("Invalid host configuration in relay chain state proof");
|
||||
|
||||
let relevant_messaging_state = relay_state_proof
|
||||
.read_messaging_state_snapshot(&host_config)
|
||||
.expect("Invalid messaging state in relay chain state proof");
|
||||
@@ -437,8 +601,6 @@ pub mod pallet {
|
||||
|
||||
<T::OnSystemEvent as OnSystemEvent>::on_validation_data(&vfp);
|
||||
|
||||
// TODO: This is more than zero, but will need benchmarking to figure out what.
|
||||
let mut total_weight = Weight::zero();
|
||||
total_weight += Self::process_inbound_downward_messages(
|
||||
relevant_messaging_state.dmq_mqc_head,
|
||||
downward_messages,
|
||||
@@ -547,6 +709,23 @@ pub mod pallet {
|
||||
Unauthorized,
|
||||
}
|
||||
|
||||
/// Latest included block descendants the runtime accepted. In other words, these are
|
||||
/// ancestors of the currently executing block which have not been included in the observed
|
||||
/// relay-chain state.
|
||||
///
|
||||
/// The segment length is limited by the capacity returned from the [`ConsensusHook`] configured
|
||||
/// in the pallet.
|
||||
#[pallet::storage]
|
||||
pub(super) type UnincludedSegment<T: Config> =
|
||||
StorageValue<_, Vec<Ancestor<T::Hash>>, ValueQuery>;
|
||||
|
||||
/// Storage field that keeps track of bandwidth used by the unincluded segment along with the
|
||||
/// latest the latest HRMP watermark. Used for limiting the acceptance of new blocks with
|
||||
/// respect to relay chain constraints.
|
||||
#[pallet::storage]
|
||||
pub(super) type AggregatedUnincludedSegment<T: Config> =
|
||||
StorageValue<_, SegmentTracker<T::Hash>, OptionQuery>;
|
||||
|
||||
/// In case of a scheduled upgrade, this storage field contains the validation code to be
|
||||
/// applied.
|
||||
///
|
||||
@@ -592,6 +771,15 @@ pub mod pallet {
|
||||
pub(super) type UpgradeRestrictionSignal<T: Config> =
|
||||
StorageValue<_, Option<relay_chain::UpgradeRestriction>, ValueQuery>;
|
||||
|
||||
/// Optional upgrade go-ahead signal from the relay-chain.
|
||||
///
|
||||
/// This storage item is a mirror of the corresponding value for the current parachain from the
|
||||
/// relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is
|
||||
/// set after the inherent.
|
||||
#[pallet::storage]
|
||||
pub(super) type UpgradeGoAhead<T: Config> =
|
||||
StorageValue<_, Option<relay_chain::UpgradeGoAhead>, ValueQuery>;
|
||||
|
||||
/// The state proof for the last relay parent block.
|
||||
///
|
||||
/// This field is meant to be updated each block with the validation data inherent. Therefore,
|
||||
@@ -702,11 +890,13 @@ pub mod pallet {
|
||||
cumulus_primitives_parachain_inherent::INHERENT_IDENTIFIER;
|
||||
|
||||
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
|
||||
let data: ParachainInherentData =
|
||||
let mut data: ParachainInherentData =
|
||||
data.get_data(&Self::INHERENT_IDENTIFIER).ok().flatten().expect(
|
||||
"validation function params are always injected into inherent data; qed",
|
||||
);
|
||||
|
||||
Self::drop_processed_messages_from_inherent(&mut data);
|
||||
|
||||
Some(Call::set_validation_data { data })
|
||||
}
|
||||
|
||||
@@ -769,6 +959,18 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
Ok(actual_hash)
|
||||
}
|
||||
|
||||
/// Get the unincluded segment size after the given hash.
|
||||
///
|
||||
/// If the unincluded segment doesn't contain the given hash, this returns the
|
||||
/// length of the entire unincluded segment.
|
||||
///
|
||||
/// This is intended to be used for determining how long the unincluded segment _would be_
|
||||
/// in runtime APIs related to authoring.
|
||||
pub fn unincluded_segment_size_after(included_hash: T::Hash) -> u32 {
|
||||
let segment = UnincludedSegment::<T>::get();
|
||||
crate::unincluded_segment::size_after_included(included_hash, &segment)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> GetChannelInfo for Pallet<T> {
|
||||
@@ -822,6 +1024,37 @@ impl<T: Config> GetChannelInfo for Pallet<T> {
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Updates inherent data to only contain messages that weren't already processed
|
||||
/// by the runtime based on last relay chain block number.
|
||||
///
|
||||
/// This method doesn't check for mqc heads mismatch.
|
||||
fn drop_processed_messages_from_inherent(para_inherent: &mut ParachainInherentData) {
|
||||
let ParachainInherentData { downward_messages, horizontal_messages, .. } = para_inherent;
|
||||
|
||||
// Last relay chain block number. Any message with sent-at block number less
|
||||
// than or equal to this value is assumed to be processed previously.
|
||||
let last_relay_block_number = LastRelayChainBlockNumber::<T>::get();
|
||||
|
||||
// DMQ.
|
||||
let dmq_processed_num = downward_messages
|
||||
.iter()
|
||||
.take_while(|message| message.sent_at <= last_relay_block_number)
|
||||
.count();
|
||||
downward_messages.drain(..dmq_processed_num);
|
||||
|
||||
// HRMP.
|
||||
for horizontal in horizontal_messages.values_mut() {
|
||||
let horizontal_processed_num = horizontal
|
||||
.iter()
|
||||
.take_while(|message| message.sent_at <= last_relay_block_number)
|
||||
.count();
|
||||
horizontal.drain(..horizontal_processed_num);
|
||||
}
|
||||
|
||||
// If MQC doesn't match after dropping messages, the runtime will panic when creating
|
||||
// inherent.
|
||||
}
|
||||
|
||||
/// Process all inbound downward messages relayed by the collator.
|
||||
///
|
||||
/// Checks if the sequence of the messages is valid, dispatches them and communicates the
|
||||
@@ -966,6 +1199,122 @@ impl<T: Config> Pallet<T> {
|
||||
weight_used
|
||||
}
|
||||
|
||||
/// Drop blocks from the unincluded segment with respect to the latest parachain head.
|
||||
fn maybe_drop_included_ancestors(
|
||||
relay_state_proof: &RelayChainStateProof,
|
||||
capacity: consensus_hook::UnincludedSegmentCapacity,
|
||||
) -> Weight {
|
||||
let mut weight_used = Weight::zero();
|
||||
// If the unincluded segment length is nonzero, then the parachain head must be present.
|
||||
let para_head =
|
||||
relay_state_proof.read_included_para_head().ok().map(|h| T::Hashing::hash(&h.0));
|
||||
|
||||
let unincluded_segment_len = <UnincludedSegment<T>>::decode_len().unwrap_or(0);
|
||||
weight_used += T::DbWeight::get().reads(1);
|
||||
|
||||
// Clean up unincluded segment if nonempty.
|
||||
let included_head = match (para_head, capacity.is_expecting_included_parent()) {
|
||||
(Some(h), true) => {
|
||||
assert_eq!(
|
||||
h,
|
||||
frame_system::Pallet::<T>::parent_hash(),
|
||||
"expected parent to be included"
|
||||
);
|
||||
|
||||
h
|
||||
},
|
||||
(Some(h), false) => h,
|
||||
(None, true) => {
|
||||
// All this logic is essentially a workaround to support collators which
|
||||
// might still not provide the included block with the state proof.
|
||||
frame_system::Pallet::<T>::parent_hash()
|
||||
},
|
||||
(None, false) => panic!("included head not present in relay storage proof"),
|
||||
};
|
||||
|
||||
let new_len = {
|
||||
let para_head_hash = included_head;
|
||||
let dropped: Vec<Ancestor<T::Hash>> = <UnincludedSegment<T>>::mutate(|chain| {
|
||||
// Drop everything up to (inclusive) the block with an included para head, if
|
||||
// present.
|
||||
let idx = chain
|
||||
.iter()
|
||||
.position(|block| {
|
||||
let head_hash = block
|
||||
.para_head_hash()
|
||||
.expect("para head hash is updated during block initialization; qed");
|
||||
head_hash == ¶_head_hash
|
||||
})
|
||||
.map_or(0, |idx| idx + 1); // inclusive.
|
||||
|
||||
chain.drain(..idx).collect()
|
||||
});
|
||||
weight_used += T::DbWeight::get().reads_writes(1, 1);
|
||||
|
||||
let new_len = unincluded_segment_len - dropped.len();
|
||||
if !dropped.is_empty() {
|
||||
<AggregatedUnincludedSegment<T>>::mutate(|agg| {
|
||||
let agg = agg.as_mut().expect(
|
||||
"dropped part of the segment wasn't empty, hence value exists; qed",
|
||||
);
|
||||
for block in dropped {
|
||||
agg.subtract(&block);
|
||||
}
|
||||
});
|
||||
weight_used += T::DbWeight::get().reads_writes(1, 1);
|
||||
}
|
||||
|
||||
new_len as u32
|
||||
};
|
||||
|
||||
// Current block validity check: ensure there is space in the unincluded segment.
|
||||
//
|
||||
// If this fails, the parachain needs to wait for ancestors to be included before
|
||||
// a new block is allowed.
|
||||
assert!(new_len < capacity.get(), "no space left for the block in the unincluded segment");
|
||||
weight_used
|
||||
}
|
||||
|
||||
/// This adjusts the `RelevantMessagingState` according to the bandwidth limits in the
|
||||
/// unincluded segment.
|
||||
//
|
||||
// Reads: 2
|
||||
// Writes: 1
|
||||
fn adjust_egress_bandwidth_limits() {
|
||||
let unincluded_segment = match AggregatedUnincludedSegment::<T>::get() {
|
||||
None => return,
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
<RelevantMessagingState<T>>::mutate(|messaging_state| {
|
||||
let messaging_state = match messaging_state {
|
||||
None => return,
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
let used_bandwidth = unincluded_segment.used_bandwidth();
|
||||
|
||||
let channels = &mut messaging_state.egress_channels;
|
||||
for (para_id, used) in used_bandwidth.hrmp_outgoing.iter() {
|
||||
let i = match channels.binary_search_by_key(para_id, |item| item.0) {
|
||||
Ok(i) => i,
|
||||
Err(_) => continue, // indicates channel closed.
|
||||
};
|
||||
|
||||
let c = &mut channels[i].1;
|
||||
|
||||
c.total_size = (c.total_size + used.total_bytes).min(c.max_total_size);
|
||||
c.msg_count = (c.msg_count + used.msg_count).min(c.max_capacity);
|
||||
}
|
||||
|
||||
let upward_capacity = &mut messaging_state.relay_dispatch_queue_remaining_capacity;
|
||||
upward_capacity.remaining_count =
|
||||
upward_capacity.remaining_count.saturating_sub(used_bandwidth.ump_msg_count);
|
||||
upward_capacity.remaining_size =
|
||||
upward_capacity.remaining_size.saturating_sub(used_bandwidth.ump_total_bytes);
|
||||
});
|
||||
}
|
||||
|
||||
/// Put a new validation function into a particular location where polkadot
|
||||
/// monitors for updates. Calling this function notifies polkadot that a new
|
||||
/// upgrade has been scheduled.
|
||||
@@ -1157,6 +1506,10 @@ impl<T: Config> UpwardMessageSender for Pallet<T> {
|
||||
}
|
||||
|
||||
/// Something that can check the inherents of a block.
|
||||
#[cfg_attr(
|
||||
feature = "parameterized-consensus-hook",
|
||||
deprecated = "consider switching to `cumulus-pallet-parachain-system::ConsensusHook`"
|
||||
)]
|
||||
pub trait CheckInherents<Block: BlockT> {
|
||||
/// Check all inherents of the block.
|
||||
///
|
||||
@@ -1168,6 +1521,20 @@ pub trait CheckInherents<Block: BlockT> {
|
||||
) -> frame_support::inherent::CheckInherentsResult;
|
||||
}
|
||||
|
||||
/// Struct that always returns `Ok` on inherents check, needed for backwards-compatibility.
|
||||
#[doc(hidden)]
|
||||
pub struct DummyCheckInherents<Block>(sp_std::marker::PhantomData<Block>);
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<Block: BlockT> CheckInherents<Block> for DummyCheckInherents<Block> {
|
||||
fn check_inherents(
|
||||
_: &Block,
|
||||
_: &RelayChainStateProof,
|
||||
) -> frame_support::inherent::CheckInherentsResult {
|
||||
sp_inherents::CheckInherentsResult::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that should be informed about system related events.
|
||||
///
|
||||
/// This includes events like [`on_validation_data`](Self::on_validation_data) that is being
|
||||
|
||||
Reference in New Issue
Block a user