mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 05:51:02 +00:00
cargo +nightly fmt (#3540)
* cargo +nightly fmt * add cargo-fmt check to ci * update ci * fmt * fmt * skip macro * ignore bridges
This commit is contained in:
@@ -18,13 +18,13 @@
|
||||
//!
|
||||
//! Configuration can change only at session boundaries and is buffered until then.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use primitives::v1::{Balance, SessionIndex, MAX_CODE_SIZE, MAX_POV_SIZE};
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use frame_system::pallet_prelude::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use sp_runtime::traits::Zero;
|
||||
use crate::shared;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use primitives::v1::{Balance, SessionIndex, MAX_CODE_SIZE, MAX_POV_SIZE};
|
||||
use sp_runtime::traits::Zero;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -38,7 +38,6 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
// A parachain requested this struct can only depend on the subset of this struct. Specifically,
|
||||
// only a first few fields can be depended upon. These fields cannot be changed without
|
||||
// corresponding migration of the parachains.
|
||||
|
||||
/**
|
||||
* The parameters that are required for the parachains.
|
||||
*/
|
||||
@@ -244,8 +243,7 @@ impl<BlockNumber: Zero> HostConfiguration<BlockNumber> {
|
||||
if self.max_code_size > MAX_CODE_SIZE {
|
||||
panic!(
|
||||
"`max_code_size` ({}) is bigger than allowed by the client ({})",
|
||||
self.max_code_size,
|
||||
MAX_CODE_SIZE,
|
||||
self.max_code_size, MAX_CODE_SIZE,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -275,32 +273,23 @@ pub mod pallet {
|
||||
/// The active configuration for the current session.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn config)]
|
||||
pub(crate) type ActiveConfig<T: Config> = StorageValue<
|
||||
_,
|
||||
HostConfiguration<T::BlockNumber>,
|
||||
ValueQuery
|
||||
>;
|
||||
pub(crate) type ActiveConfig<T: Config> =
|
||||
StorageValue<_, HostConfiguration<T::BlockNumber>, ValueQuery>;
|
||||
|
||||
/// Pending configuration (if any) for the next session.
|
||||
#[pallet::storage]
|
||||
pub(crate) type PendingConfig<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
SessionIndex,
|
||||
HostConfiguration<T::BlockNumber>
|
||||
>;
|
||||
pub(crate) type PendingConfig<T: Config> =
|
||||
StorageMap<_, Twox64Concat, SessionIndex, HostConfiguration<T::BlockNumber>>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub config: HostConfiguration<T::BlockNumber>
|
||||
pub config: HostConfiguration<T::BlockNumber>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Config> Default for GenesisConfig<T> {
|
||||
fn default() -> Self {
|
||||
GenesisConfig {
|
||||
config: Default::default()
|
||||
}
|
||||
GenesisConfig { config: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +305,10 @@ pub mod pallet {
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Set the validation upgrade frequency.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_validation_upgrade_frequency(origin: OriginFor<T>, new: T::BlockNumber) -> DispatchResult {
|
||||
pub fn set_validation_upgrade_frequency(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.validation_upgrade_frequency, new) != new
|
||||
@@ -326,7 +318,10 @@ pub mod pallet {
|
||||
|
||||
/// Set the validation upgrade delay.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_validation_upgrade_delay(origin: OriginFor<T>, new: T::BlockNumber) -> DispatchResult {
|
||||
pub fn set_validation_upgrade_delay(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.validation_upgrade_delay, new) != new
|
||||
@@ -336,7 +331,10 @@ pub mod pallet {
|
||||
|
||||
/// Set the acceptance period for an included candidate.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_code_retention_period(origin: OriginFor<T>, new: T::BlockNumber) -> DispatchResult {
|
||||
pub fn set_code_retention_period(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.code_retention_period, new) != new
|
||||
@@ -396,10 +394,12 @@ pub mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// Set the parachain validator-group rotation frequency
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_group_rotation_frequency(origin: OriginFor<T>, new: T::BlockNumber) -> DispatchResult {
|
||||
pub fn set_group_rotation_frequency(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
ensure!(!new.is_zero(), Error::<T>::InvalidNewValue);
|
||||
@@ -412,7 +412,10 @@ pub mod pallet {
|
||||
|
||||
/// Set the availability period for parachains.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_chain_availability_period(origin: OriginFor<T>, new: T::BlockNumber) -> DispatchResult {
|
||||
pub fn set_chain_availability_period(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
ensure!(!new.is_zero(), Error::<T>::InvalidNewValue);
|
||||
@@ -425,7 +428,10 @@ pub mod pallet {
|
||||
|
||||
/// Set the availability period for parathreads.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_thread_availability_period(origin: OriginFor<T>, new: T::BlockNumber) -> DispatchResult {
|
||||
pub fn set_thread_availability_period(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
|
||||
ensure!(!new.is_zero(), Error::<T>::InvalidNewValue);
|
||||
@@ -448,7 +454,10 @@ pub mod pallet {
|
||||
|
||||
/// Set the maximum number of validators to assign to any core.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_max_validators_per_core(origin: OriginFor<T>, new: Option<u32>) -> DispatchResult {
|
||||
pub fn set_max_validators_per_core(
|
||||
origin: OriginFor<T>,
|
||||
new: Option<u32>,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.max_validators_per_core, new) != new
|
||||
@@ -484,7 +493,8 @@ pub mod pallet {
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.dispute_post_conclusion_acceptance_period, new) != new
|
||||
sp_std::mem::replace(&mut config.dispute_post_conclusion_acceptance_period, new) !=
|
||||
new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -501,9 +511,10 @@ pub mod pallet {
|
||||
|
||||
/// Set the dispute conclusion by time out period.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_dispute_conclusion_by_time_out_period(origin: OriginFor<T>, new: T::BlockNumber)
|
||||
-> DispatchResult
|
||||
{
|
||||
pub fn set_dispute_conclusion_by_time_out_period(
|
||||
origin: OriginFor<T>,
|
||||
new: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.dispute_conclusion_by_time_out_period, new) != new
|
||||
@@ -617,7 +628,10 @@ pub mod pallet {
|
||||
|
||||
/// Sets the maximum number of messages that a candidate can contain.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_max_upward_message_num_per_candidate(origin: OriginFor<T>, new: u32) -> DispatchResult {
|
||||
pub fn set_max_upward_message_num_per_candidate(
|
||||
origin: OriginFor<T>,
|
||||
new: u32,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.max_upward_message_num_per_candidate, new) != new
|
||||
@@ -678,7 +692,10 @@ pub mod pallet {
|
||||
|
||||
/// Sets the maximum number of inbound HRMP channels a parachain is allowed to accept.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_hrmp_max_parachain_inbound_channels(origin: OriginFor<T>, new: u32) -> DispatchResult {
|
||||
pub fn set_hrmp_max_parachain_inbound_channels(
|
||||
origin: OriginFor<T>,
|
||||
new: u32,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parachain_inbound_channels, new) != new
|
||||
@@ -688,7 +705,10 @@ pub mod pallet {
|
||||
|
||||
/// Sets the maximum number of inbound HRMP channels a parathread is allowed to accept.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_hrmp_max_parathread_inbound_channels(origin: OriginFor<T>, new: u32) -> DispatchResult {
|
||||
pub fn set_hrmp_max_parathread_inbound_channels(
|
||||
origin: OriginFor<T>,
|
||||
new: u32,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parathread_inbound_channels, new) != new
|
||||
@@ -708,7 +728,10 @@ pub mod pallet {
|
||||
|
||||
/// Sets the maximum number of outbound HRMP channels a parachain is allowed to open.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_hrmp_max_parachain_outbound_channels(origin: OriginFor<T>, new: u32) -> DispatchResult {
|
||||
pub fn set_hrmp_max_parachain_outbound_channels(
|
||||
origin: OriginFor<T>,
|
||||
new: u32,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parachain_outbound_channels, new) != new
|
||||
@@ -718,7 +741,10 @@ pub mod pallet {
|
||||
|
||||
/// Sets the maximum number of outbound HRMP channels a parathread is allowed to open.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_hrmp_max_parathread_outbound_channels(origin: OriginFor<T>, new: u32) -> DispatchResult {
|
||||
pub fn set_hrmp_max_parathread_outbound_channels(
|
||||
origin: OriginFor<T>,
|
||||
new: u32,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parathread_outbound_channels, new) != new
|
||||
@@ -728,7 +754,10 @@ pub mod pallet {
|
||||
|
||||
/// Sets the maximum number of outbound HRMP messages can be sent by a candidate.
|
||||
#[pallet::weight((1_000, DispatchClass::Operational))]
|
||||
pub fn set_hrmp_max_message_num_per_candidate(origin: OriginFor<T>, new: u32) -> DispatchResult {
|
||||
pub fn set_hrmp_max_message_num_per_candidate(
|
||||
origin: OriginFor<T>,
|
||||
new: u32,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_message_num_per_candidate, new) != new
|
||||
@@ -745,12 +774,10 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
/// Called by the initializer to finalize the configuration module.
|
||||
pub(crate) fn initializer_finalize() { }
|
||||
pub(crate) fn initializer_finalize() {}
|
||||
|
||||
/// Called by the initializer to note that a new session has started.
|
||||
pub(crate) fn initializer_on_new_session(
|
||||
session_index: &SessionIndex,
|
||||
) {
|
||||
pub(crate) fn initializer_on_new_session(session_index: &SessionIndex) {
|
||||
if let Some(pending) = <Self as Store>::PendingConfig::take(session_index) {
|
||||
<Self as Store>::ActiveConfig::set(pending);
|
||||
}
|
||||
@@ -773,9 +800,7 @@ impl<T: Config> Pallet<T> {
|
||||
// duplicated code (making this function to show up in the top of heaviest functions) only for
|
||||
// the sake of essentially avoiding an indirect call. Doesn't worth it.
|
||||
#[inline(never)]
|
||||
fn update_config_member(
|
||||
updater: impl FnOnce(&mut HostConfiguration<T::BlockNumber>) -> bool,
|
||||
) {
|
||||
fn update_config_member(updater: impl FnOnce(&mut HostConfiguration<T::BlockNumber>) -> bool) {
|
||||
let scheduled_session = Self::scheduled_session();
|
||||
let pending = <Self as Store>::PendingConfig::get(scheduled_session);
|
||||
let mut prev = pending.unwrap_or_else(Self::config);
|
||||
@@ -867,138 +892,172 @@ mod tests {
|
||||
assert!(<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY).is_none());
|
||||
|
||||
Configuration::set_validation_upgrade_frequency(
|
||||
Origin::root(), new_config.validation_upgrade_frequency,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.validation_upgrade_frequency,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_validation_upgrade_delay(
|
||||
Origin::root(), new_config.validation_upgrade_delay,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.validation_upgrade_delay,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_code_retention_period(
|
||||
Origin::root(), new_config.code_retention_period,
|
||||
).unwrap();
|
||||
Configuration::set_max_code_size(
|
||||
Origin::root(), new_config.max_code_size,
|
||||
).unwrap();
|
||||
Configuration::set_max_pov_size(
|
||||
Origin::root(), new_config.max_pov_size,
|
||||
).unwrap();
|
||||
Configuration::set_max_head_data_size(
|
||||
Origin::root(), new_config.max_head_data_size,
|
||||
).unwrap();
|
||||
Configuration::set_parathread_cores(
|
||||
Origin::root(), new_config.parathread_cores,
|
||||
).unwrap();
|
||||
Configuration::set_parathread_retries(
|
||||
Origin::root(), new_config.parathread_retries,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.code_retention_period,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_code_size(Origin::root(), new_config.max_code_size).unwrap();
|
||||
Configuration::set_max_pov_size(Origin::root(), new_config.max_pov_size).unwrap();
|
||||
Configuration::set_max_head_data_size(Origin::root(), new_config.max_head_data_size)
|
||||
.unwrap();
|
||||
Configuration::set_parathread_cores(Origin::root(), new_config.parathread_cores)
|
||||
.unwrap();
|
||||
Configuration::set_parathread_retries(Origin::root(), new_config.parathread_retries)
|
||||
.unwrap();
|
||||
Configuration::set_group_rotation_frequency(
|
||||
Origin::root(), new_config.group_rotation_frequency,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.group_rotation_frequency,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_chain_availability_period(
|
||||
Origin::root(), new_config.chain_availability_period,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.chain_availability_period,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_thread_availability_period(
|
||||
Origin::root(), new_config.thread_availability_period,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.thread_availability_period,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_scheduling_lookahead(
|
||||
Origin::root(), new_config.scheduling_lookahead,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.scheduling_lookahead,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_validators_per_core(
|
||||
Origin::root(), new_config.max_validators_per_core,
|
||||
).unwrap();
|
||||
Configuration::set_max_validators(
|
||||
Origin::root(), new_config.max_validators,
|
||||
).unwrap();
|
||||
Configuration::set_dispute_period(
|
||||
Origin::root(), new_config.dispute_period,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.max_validators_per_core,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_validators(Origin::root(), new_config.max_validators).unwrap();
|
||||
Configuration::set_dispute_period(Origin::root(), new_config.dispute_period).unwrap();
|
||||
Configuration::set_dispute_post_conclusion_acceptance_period(
|
||||
Origin::root(), new_config.dispute_post_conclusion_acceptance_period,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.dispute_post_conclusion_acceptance_period,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_dispute_max_spam_slots(
|
||||
Origin::root(), new_config.dispute_max_spam_slots,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.dispute_max_spam_slots,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_dispute_conclusion_by_time_out_period(
|
||||
Origin::root(), new_config.dispute_conclusion_by_time_out_period,
|
||||
).unwrap();
|
||||
Configuration::set_no_show_slots(
|
||||
Origin::root(), new_config.no_show_slots,
|
||||
).unwrap();
|
||||
Configuration::set_n_delay_tranches(
|
||||
Origin::root(), new_config.n_delay_tranches,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.dispute_conclusion_by_time_out_period,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_no_show_slots(Origin::root(), new_config.no_show_slots).unwrap();
|
||||
Configuration::set_n_delay_tranches(Origin::root(), new_config.n_delay_tranches)
|
||||
.unwrap();
|
||||
Configuration::set_zeroth_delay_tranche_width(
|
||||
Origin::root(), new_config.zeroth_delay_tranche_width,
|
||||
).unwrap();
|
||||
Configuration::set_needed_approvals(
|
||||
Origin::root(), new_config.needed_approvals,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.zeroth_delay_tranche_width,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_needed_approvals(Origin::root(), new_config.needed_approvals)
|
||||
.unwrap();
|
||||
Configuration::set_relay_vrf_modulo_samples(
|
||||
Origin::root(), new_config.relay_vrf_modulo_samples,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.relay_vrf_modulo_samples,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_upward_queue_count(
|
||||
Origin::root(), new_config.max_upward_queue_count,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.max_upward_queue_count,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_upward_queue_size(
|
||||
Origin::root(), new_config.max_upward_queue_size,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.max_upward_queue_size,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_downward_message_size(
|
||||
Origin::root(), new_config.max_downward_message_size,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.max_downward_message_size,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_ump_service_total_weight(
|
||||
Origin::root(), new_config.ump_service_total_weight,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.ump_service_total_weight,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_upward_message_size(
|
||||
Origin::root(), new_config.max_upward_message_size,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.max_upward_message_size,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_max_upward_message_num_per_candidate(
|
||||
Origin::root(), new_config.max_upward_message_num_per_candidate,
|
||||
).unwrap();
|
||||
Origin::root(),
|
||||
new_config.max_upward_message_num_per_candidate,
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_open_request_ttl(
|
||||
Origin::root(),
|
||||
new_config.hrmp_open_request_ttl,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_sender_deposit(
|
||||
Origin::root(),
|
||||
new_config.hrmp_sender_deposit,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_sender_deposit(Origin::root(), new_config.hrmp_sender_deposit)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_recipient_deposit(
|
||||
Origin::root(),
|
||||
new_config.hrmp_recipient_deposit,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_channel_max_capacity(
|
||||
Origin::root(),
|
||||
new_config.hrmp_channel_max_capacity,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_channel_max_total_size(
|
||||
Origin::root(),
|
||||
new_config.hrmp_channel_max_total_size,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_max_parachain_inbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parachain_inbound_channels,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_max_parathread_inbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parathread_inbound_channels,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_channel_max_message_size(
|
||||
Origin::root(),
|
||||
new_config.hrmp_channel_max_message_size,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_max_parachain_outbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parachain_outbound_channels,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_max_parathread_outbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parathread_outbound_channels,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
Configuration::set_hrmp_max_message_num_per_candidate(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_message_num_per_candidate,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY), Some(new_config));
|
||||
assert_eq!(
|
||||
<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY),
|
||||
Some(new_config)
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1012,7 +1071,8 @@ mod tests {
|
||||
#[test]
|
||||
fn setting_config_to_same_as_current_is_noop() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
Configuration::set_validation_upgrade_delay(Origin::root(), Default::default()).unwrap();
|
||||
Configuration::set_validation_upgrade_delay(Origin::root(), Default::default())
|
||||
.unwrap();
|
||||
assert!(<Configuration as Store>::PendingConfig::get(shared::SESSION_DELAY).is_none())
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@ use crate::{
|
||||
initializer,
|
||||
};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use sp_std::{fmt, prelude::*};
|
||||
use primitives::v1::{DownwardMessage, Hash, Id as ParaId, InboundDownwardMessage};
|
||||
use sp_runtime::traits::{BlakeTwo256, Hash as HashT, SaturatedConversion};
|
||||
use primitives::v1::{Id as ParaId, DownwardMessage, InboundDownwardMessage, Hash};
|
||||
use sp_std::{fmt, prelude::*};
|
||||
use xcm::v0::Error as XcmError;
|
||||
|
||||
pub use pallet::*;
|
||||
@@ -47,24 +47,16 @@ pub enum ProcessedDownwardMessagesAcceptanceErr {
|
||||
/// If there are pending messages then `processed_downward_messages` should be at least 1,
|
||||
AdvancementRule,
|
||||
/// `processed_downward_messages` should not be greater than the number of pending messages.
|
||||
Underflow {
|
||||
processed_downward_messages: u32,
|
||||
dmq_length: u32,
|
||||
},
|
||||
Underflow { processed_downward_messages: u32, dmq_length: u32 },
|
||||
}
|
||||
|
||||
impl fmt::Debug for ProcessedDownwardMessagesAcceptanceErr {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
use ProcessedDownwardMessagesAcceptanceErr::*;
|
||||
match *self {
|
||||
AdvancementRule => write!(
|
||||
fmt,
|
||||
"DMQ is not empty, but processed_downward_messages is 0",
|
||||
),
|
||||
Underflow {
|
||||
processed_downward_messages,
|
||||
dmq_length,
|
||||
} => write!(
|
||||
AdvancementRule =>
|
||||
write!(fmt, "DMQ is not empty, but processed_downward_messages is 0",),
|
||||
Underflow { processed_downward_messages, dmq_length } => write!(
|
||||
fmt,
|
||||
"processed_downward_messages = {}, but dmq_length is only {}",
|
||||
processed_downward_messages, dmq_length,
|
||||
@@ -91,7 +83,7 @@ pub mod pallet {
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
Vec<InboundDownwardMessage<T::BlockNumber>>,
|
||||
ValueQuery
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
/// A mapping that stores the downward message queue MQC head for each para.
|
||||
@@ -102,13 +94,8 @@ pub mod pallet {
|
||||
/// - `B`: is the relay-chain block number in which a message was appended.
|
||||
/// - `H(M)`: is the hash of the message being appended.
|
||||
#[pallet::storage]
|
||||
pub(crate) type DownwardMessageQueueHeads<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
Hash,
|
||||
ValueQuery,
|
||||
>;
|
||||
pub(crate) type DownwardMessageQueueHeads<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, Hash, ValueQuery>;
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
@@ -161,13 +148,11 @@ impl<T: Config> Pallet<T> {
|
||||
) -> Result<(), QueueDownwardMessageError> {
|
||||
let serialized_len = msg.len() as u32;
|
||||
if serialized_len > config.max_downward_message_size {
|
||||
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize);
|
||||
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize)
|
||||
}
|
||||
|
||||
let inbound = InboundDownwardMessage {
|
||||
msg,
|
||||
sent_at: <frame_system::Pallet<T>>::block_number(),
|
||||
};
|
||||
let inbound =
|
||||
InboundDownwardMessage { msg, sent_at: <frame_system::Pallet<T>>::block_number() };
|
||||
|
||||
// obtain the new link in the MQC and update the head.
|
||||
<Self as Store>::DownwardMessageQueueHeads::mutate(para, |head| {
|
||||
@@ -191,13 +176,13 @@ impl<T: Config> Pallet<T> {
|
||||
let dmq_length = Self::dmq_length(para);
|
||||
|
||||
if dmq_length > 0 && processed_downward_messages == 0 {
|
||||
return Err(ProcessedDownwardMessagesAcceptanceErr::AdvancementRule);
|
||||
return Err(ProcessedDownwardMessagesAcceptanceErr::AdvancementRule)
|
||||
}
|
||||
if dmq_length < processed_downward_messages {
|
||||
return Err(ProcessedDownwardMessagesAcceptanceErr::Underflow {
|
||||
processed_downward_messages,
|
||||
dmq_length,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -245,10 +230,10 @@ impl<T: Config> Pallet<T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{new_test_ext, Configuration, Dmp, MockGenesisConfig, Paras, System};
|
||||
use hex_literal::hex;
|
||||
use primitives::v1::BlockNumber;
|
||||
use parity_scale_codec::Encode;
|
||||
use crate::mock::{Configuration, new_test_ext, System, Dmp, MockGenesisConfig, Paras};
|
||||
use primitives::v1::BlockNumber;
|
||||
|
||||
pub(crate) fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) {
|
||||
while System::block_number() < to {
|
||||
@@ -413,8 +398,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn verify_dmq_mqc_head_is_externally_accessible() {
|
||||
use primitives::v1::well_known_keys;
|
||||
use hex_literal::hex;
|
||||
use primitives::v1::well_known_keys;
|
||||
|
||||
let a = ParaId::from(2020);
|
||||
|
||||
@@ -427,7 +412,10 @@ mod tests {
|
||||
let head = sp_io::storage::get(&well_known_keys::dmq_mqc_head(a));
|
||||
assert_eq!(
|
||||
head,
|
||||
Some(hex!["434f8579a2297dfea851bf6be33093c83a78b655a53ae141a7894494c0010589"].to_vec())
|
||||
Some(
|
||||
hex!["434f8579a2297dfea851bf6be33093c83a78b655a53ae141a7894494c0010589"]
|
||||
.to_vec()
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,22 +15,20 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
ensure_parachain,
|
||||
configuration::{self, HostConfiguration},
|
||||
initializer, paras, dmp,
|
||||
dmp, ensure_parachain, initializer, paras,
|
||||
};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_support::traits::ReservableCurrency;
|
||||
use frame_support::{pallet_prelude::*, traits::ReservableCurrency};
|
||||
use frame_system::pallet_prelude::*;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use primitives::v1::{
|
||||
Balance, Hash, HrmpChannelId, Id as ParaId, InboundHrmpMessage, OutboundHrmpMessage,
|
||||
SessionIndex,
|
||||
};
|
||||
use sp_runtime::traits::{UniqueSaturatedInto, AccountIdConversion, BlakeTwo256, Hash as HashT};
|
||||
use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash as HashT, UniqueSaturatedInto};
|
||||
use sp_std::{
|
||||
mem, fmt,
|
||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||
fmt, mem,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
@@ -63,7 +61,6 @@ pub struct HrmpChannel {
|
||||
// A parachain requested this struct can only depend on the subset of this struct. Specifically,
|
||||
// only a first few fields can be depended upon (See `AbridgedHrmpChannel`). These fields cannot
|
||||
// be changed without corresponding migration of parachains.
|
||||
|
||||
/// The maximum number of messages that can be pending in the channel at once.
|
||||
pub max_capacity: u32,
|
||||
/// The maximum total size of the messages that can be pending in the channel at once.
|
||||
@@ -93,48 +90,20 @@ pub struct HrmpChannel {
|
||||
/// An error returned by [`check_hrmp_watermark`] that indicates an acceptance criteria check
|
||||
/// didn't pass.
|
||||
pub enum HrmpWatermarkAcceptanceErr<BlockNumber> {
|
||||
AdvancementRule {
|
||||
new_watermark: BlockNumber,
|
||||
last_watermark: BlockNumber,
|
||||
},
|
||||
AheadRelayParent {
|
||||
new_watermark: BlockNumber,
|
||||
relay_chain_parent_number: BlockNumber,
|
||||
},
|
||||
LandsOnBlockWithNoMessages {
|
||||
new_watermark: BlockNumber,
|
||||
},
|
||||
AdvancementRule { new_watermark: BlockNumber, last_watermark: BlockNumber },
|
||||
AheadRelayParent { new_watermark: BlockNumber, relay_chain_parent_number: BlockNumber },
|
||||
LandsOnBlockWithNoMessages { new_watermark: BlockNumber },
|
||||
}
|
||||
|
||||
/// An error returned by [`check_outbound_hrmp`] that indicates an acceptance criteria check
|
||||
/// didn't pass.
|
||||
pub enum OutboundHrmpAcceptanceErr {
|
||||
MoreMessagesThanPermitted {
|
||||
sent: u32,
|
||||
permitted: u32,
|
||||
},
|
||||
NotSorted {
|
||||
idx: u32,
|
||||
},
|
||||
NoSuchChannel {
|
||||
idx: u32,
|
||||
channel_id: HrmpChannelId,
|
||||
},
|
||||
MaxMessageSizeExceeded {
|
||||
idx: u32,
|
||||
msg_size: u32,
|
||||
max_size: u32,
|
||||
},
|
||||
TotalSizeExceeded {
|
||||
idx: u32,
|
||||
total_size: u32,
|
||||
limit: u32,
|
||||
},
|
||||
CapacityExceeded {
|
||||
idx: u32,
|
||||
count: u32,
|
||||
limit: u32,
|
||||
},
|
||||
MoreMessagesThanPermitted { sent: u32, permitted: u32 },
|
||||
NotSorted { idx: u32 },
|
||||
NoSuchChannel { idx: u32, channel_id: HrmpChannelId },
|
||||
MaxMessageSizeExceeded { idx: u32, msg_size: u32, max_size: u32 },
|
||||
TotalSizeExceeded { idx: u32, total_size: u32, limit: u32 },
|
||||
CapacityExceeded { idx: u32, count: u32, limit: u32 },
|
||||
}
|
||||
|
||||
impl<BlockNumber> fmt::Debug for HrmpWatermarkAcceptanceErr<BlockNumber>
|
||||
@@ -144,18 +113,12 @@ where
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
use HrmpWatermarkAcceptanceErr::*;
|
||||
match self {
|
||||
AdvancementRule {
|
||||
new_watermark,
|
||||
last_watermark,
|
||||
} => write!(
|
||||
AdvancementRule { new_watermark, last_watermark } => write!(
|
||||
fmt,
|
||||
"the HRMP watermark is not advanced relative to the last watermark ({:?} > {:?})",
|
||||
new_watermark, last_watermark,
|
||||
),
|
||||
AheadRelayParent {
|
||||
new_watermark,
|
||||
relay_chain_parent_number,
|
||||
} => write!(
|
||||
AheadRelayParent { new_watermark, relay_chain_parent_number } => write!(
|
||||
fmt,
|
||||
"the HRMP watermark is ahead the relay-parent ({:?} > {:?})",
|
||||
new_watermark, relay_chain_parent_number
|
||||
@@ -178,30 +141,19 @@ impl fmt::Debug for OutboundHrmpAcceptanceErr {
|
||||
"more HRMP messages than permitted by config ({} > {})",
|
||||
sent, permitted,
|
||||
),
|
||||
NotSorted { idx } => write!(
|
||||
fmt,
|
||||
"the HRMP messages are not sorted (first unsorted is at index {})",
|
||||
idx,
|
||||
),
|
||||
NotSorted { idx } =>
|
||||
write!(fmt, "the HRMP messages are not sorted (first unsorted is at index {})", idx,),
|
||||
NoSuchChannel { idx, channel_id } => write!(
|
||||
fmt,
|
||||
"the HRMP message at index {} is sent to a non existent channel {:?}->{:?}",
|
||||
idx, channel_id.sender, channel_id.recipient,
|
||||
),
|
||||
MaxMessageSizeExceeded {
|
||||
idx,
|
||||
msg_size,
|
||||
max_size,
|
||||
} => write!(
|
||||
MaxMessageSizeExceeded { idx, msg_size, max_size } => write!(
|
||||
fmt,
|
||||
"the HRMP message at index {} exceeds the negotiated channel maximum message size ({} > {})",
|
||||
idx, msg_size, max_size,
|
||||
),
|
||||
TotalSizeExceeded {
|
||||
idx,
|
||||
total_size,
|
||||
limit,
|
||||
} => write!(
|
||||
TotalSizeExceeded { idx, total_size, limit } => write!(
|
||||
fmt,
|
||||
"sending the HRMP message at index {} would exceed the neogitiated channel total size ({} > {})",
|
||||
idx, total_size, limit,
|
||||
@@ -219,13 +171,14 @@ impl fmt::Debug for OutboundHrmpAcceptanceErr {
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config + configuration::Config + paras::Config + dmp::Config {
|
||||
pub trait Config:
|
||||
frame_system::Config + configuration::Config + paras::Config + dmp::Config
|
||||
{
|
||||
/// The outer event type.
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
|
||||
@@ -294,39 +247,26 @@ pub mod pallet {
|
||||
/// Invariant:
|
||||
/// - There are no channels that exists in list but not in the set and vice versa.
|
||||
#[pallet::storage]
|
||||
pub type HrmpOpenChannelRequests<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
HrmpChannelId,
|
||||
HrmpOpenChannelRequest
|
||||
>;
|
||||
pub type HrmpOpenChannelRequests<T: Config> =
|
||||
StorageMap<_, Twox64Concat, HrmpChannelId, HrmpOpenChannelRequest>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub type HrmpOpenChannelRequestsList<T: Config> = StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
|
||||
pub type HrmpOpenChannelRequestsList<T: Config> =
|
||||
StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
|
||||
|
||||
/// This mapping tracks how many open channel requests are initiated by a given sender para.
|
||||
/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items that has `(X, _)`
|
||||
/// as the number of `HrmpOpenChannelRequestCount` for `X`.
|
||||
#[pallet::storage]
|
||||
pub type HrmpOpenChannelRequestCount<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
u32,
|
||||
ValueQuery
|
||||
>;
|
||||
pub type HrmpOpenChannelRequestCount<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, u32, ValueQuery>;
|
||||
|
||||
/// This mapping tracks how many open channel requests were accepted by a given recipient para.
|
||||
/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items `(_, X)` with
|
||||
/// `confirmed` set to true, as the number of `HrmpAcceptedChannelRequestCount` for `X`.
|
||||
#[pallet::storage]
|
||||
pub type HrmpAcceptedChannelRequestCount<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
u32,
|
||||
ValueQuery
|
||||
>;
|
||||
pub type HrmpAcceptedChannelRequestCount<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, u32, ValueQuery>;
|
||||
|
||||
/// A set of pending HRMP close channel requests that are going to be closed during the session change.
|
||||
/// Used for checking if a given channel is registered for closure.
|
||||
@@ -339,7 +279,8 @@ pub mod pallet {
|
||||
pub type HrmpCloseChannelRequests<T: Config> = StorageMap<_, Twox64Concat, HrmpChannelId, ()>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub type HrmpCloseChannelRequestsList<T: Config> = StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
|
||||
pub type HrmpCloseChannelRequestsList<T: Config> =
|
||||
StorageValue<_, Vec<HrmpChannelId>, ValueQuery>;
|
||||
|
||||
/// The HRMP watermark associated with each para.
|
||||
/// Invariant:
|
||||
@@ -367,24 +308,14 @@ pub mod pallet {
|
||||
/// - there should be no other dangling channels in `HrmpChannels`.
|
||||
/// - the vectors are sorted.
|
||||
#[pallet::storage]
|
||||
pub type HrmpIngressChannelsIndex<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
Vec<ParaId>,
|
||||
ValueQuery
|
||||
>;
|
||||
pub type HrmpIngressChannelsIndex<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, Vec<ParaId>, ValueQuery>;
|
||||
|
||||
// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
|
||||
// the format will require migration of parachains.
|
||||
#[pallet::storage]
|
||||
pub type HrmpEgressChannelsIndex<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
Vec<ParaId>,
|
||||
ValueQuery
|
||||
>;
|
||||
pub type HrmpEgressChannelsIndex<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, Vec<ParaId>, ValueQuery>;
|
||||
|
||||
/// Storage for the messages for each channel.
|
||||
/// Invariant: cannot be non-empty if the corresponding channel in `HrmpChannels` is `None`.
|
||||
@@ -394,7 +325,7 @@ pub mod pallet {
|
||||
Twox64Concat,
|
||||
HrmpChannelId,
|
||||
Vec<InboundHrmpMessage<T::BlockNumber>>,
|
||||
ValueQuery
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
/// Maintains a mapping that can be used to answer the question:
|
||||
@@ -405,13 +336,8 @@ pub mod pallet {
|
||||
/// - The outer vector is sorted ascending by block number and cannot store two items with the same
|
||||
/// block number.
|
||||
#[pallet::storage]
|
||||
pub type HrmpChannelDigests<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
Vec<(T::BlockNumber, Vec<ParaId>)>,
|
||||
ValueQuery
|
||||
>;
|
||||
pub type HrmpChannelDigests<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, Vec<(T::BlockNumber, Vec<ParaId>)>, ValueQuery>;
|
||||
|
||||
/// Preopen the given HRMP channels.
|
||||
///
|
||||
@@ -432,9 +358,7 @@ pub mod pallet {
|
||||
#[cfg(feature = "std")]
|
||||
impl Default for GenesisConfig {
|
||||
fn default() -> Self {
|
||||
GenesisConfig {
|
||||
preopen_hrmp_channels: Default::default(),
|
||||
}
|
||||
GenesisConfig { preopen_hrmp_channels: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,13 +393,13 @@ pub mod pallet {
|
||||
origin,
|
||||
recipient,
|
||||
proposed_max_capacity,
|
||||
proposed_max_message_size
|
||||
proposed_max_message_size,
|
||||
)?;
|
||||
Self::deposit_event(Event::OpenChannelRequested(
|
||||
origin,
|
||||
recipient,
|
||||
proposed_max_capacity,
|
||||
proposed_max_message_size
|
||||
proposed_max_message_size,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -496,7 +420,10 @@ pub mod pallet {
|
||||
///
|
||||
/// The closure can only happen on a session change.
|
||||
#[pallet::weight(0)]
|
||||
pub fn hrmp_close_channel(origin: OriginFor<T>, channel_id: HrmpChannelId) -> DispatchResult {
|
||||
pub fn hrmp_close_channel(
|
||||
origin: OriginFor<T>,
|
||||
channel_id: HrmpChannelId,
|
||||
) -> DispatchResult {
|
||||
let origin = ensure_parachain(<T as Config>::Origin::from(origin))?;
|
||||
Self::close_channel(origin, channel_id.clone())?;
|
||||
Self::deposit_event(Event::ChannelClosed(origin, channel_id));
|
||||
@@ -544,7 +471,9 @@ pub mod pallet {
|
||||
fn initialize_storage<T: Config>(preopen_hrmp_channels: &[(ParaId, ParaId, u32, u32)]) {
|
||||
let host_config = configuration::Pallet::<T>::config();
|
||||
for &(sender, recipient, max_capacity, max_message_size) in preopen_hrmp_channels {
|
||||
if let Err(err) = preopen_hrmp_channel::<T>(sender, recipient, max_capacity, max_message_size) {
|
||||
if let Err(err) =
|
||||
preopen_hrmp_channel::<T>(sender, recipient, max_capacity, max_message_size)
|
||||
{
|
||||
panic!("failed to initialize the genesis storage: {:?}", err);
|
||||
}
|
||||
}
|
||||
@@ -556,14 +485,9 @@ fn preopen_hrmp_channel<T: Config>(
|
||||
sender: ParaId,
|
||||
recipient: ParaId,
|
||||
max_capacity: u32,
|
||||
max_message_size: u32
|
||||
max_message_size: u32,
|
||||
) -> DispatchResult {
|
||||
<Pallet<T>>::init_open_channel(
|
||||
sender,
|
||||
recipient,
|
||||
max_capacity,
|
||||
max_message_size,
|
||||
)?;
|
||||
<Pallet<T>>::init_open_channel(sender, recipient, max_capacity, max_message_size)?;
|
||||
<Pallet<T>>::accept_open_channel(recipient, sender)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -603,16 +527,10 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
let ingress = <Self as Store>::HrmpIngressChannelsIndex::take(outgoing_para)
|
||||
.into_iter()
|
||||
.map(|sender| HrmpChannelId {
|
||||
sender,
|
||||
recipient: outgoing_para.clone(),
|
||||
});
|
||||
.map(|sender| HrmpChannelId { sender, recipient: outgoing_para.clone() });
|
||||
let egress = <Self as Store>::HrmpEgressChannelsIndex::take(outgoing_para)
|
||||
.into_iter()
|
||||
.map(|recipient| HrmpChannelId {
|
||||
sender: outgoing_para.clone(),
|
||||
recipient,
|
||||
});
|
||||
.map(|recipient| HrmpChannelId { sender: outgoing_para.clone(), recipient });
|
||||
let mut to_close = ingress.chain(egress).collect::<Vec<_>>();
|
||||
to_close.sort();
|
||||
to_close.dedup();
|
||||
@@ -629,7 +547,7 @@ impl<T: Config> Pallet<T> {
|
||||
fn process_hrmp_open_channel_requests(config: &HostConfiguration<T::BlockNumber>) {
|
||||
let mut open_req_channels = <Self as Store>::HrmpOpenChannelRequestsList::get();
|
||||
if open_req_channels.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// iterate the vector starting from the end making our way to the beginning. This way we
|
||||
@@ -638,7 +556,7 @@ impl<T: Config> Pallet<T> {
|
||||
loop {
|
||||
// bail if we've iterated over all items.
|
||||
if idx == 0 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
idx -= 1;
|
||||
@@ -648,8 +566,8 @@ impl<T: Config> Pallet<T> {
|
||||
);
|
||||
|
||||
if request.confirmed {
|
||||
if <paras::Pallet<T>>::is_valid_para(channel_id.sender)
|
||||
&& <paras::Pallet<T>>::is_valid_para(channel_id.recipient)
|
||||
if <paras::Pallet<T>>::is_valid_para(channel_id.sender) &&
|
||||
<paras::Pallet<T>>::is_valid_para(channel_id.recipient)
|
||||
{
|
||||
<Self as Store>::HrmpChannels::insert(
|
||||
&channel_id,
|
||||
@@ -745,11 +663,8 @@ impl<T: Config> Pallet<T> {
|
||||
/// This function is idempotent, meaning that after the first application it should have no
|
||||
/// effect (i.e. it won't return the deposits twice).
|
||||
fn close_hrmp_channel(channel_id: &HrmpChannelId) {
|
||||
if let Some(HrmpChannel {
|
||||
sender_deposit,
|
||||
recipient_deposit,
|
||||
..
|
||||
}) = <Self as Store>::HrmpChannels::take(channel_id)
|
||||
if let Some(HrmpChannel { sender_deposit, recipient_deposit, .. }) =
|
||||
<Self as Store>::HrmpChannels::take(channel_id)
|
||||
{
|
||||
T::Currency::unreserve(
|
||||
&channel_id.sender.into_account(),
|
||||
@@ -793,14 +708,14 @@ impl<T: Config> Pallet<T> {
|
||||
return Err(HrmpWatermarkAcceptanceErr::AdvancementRule {
|
||||
new_watermark: new_hrmp_watermark,
|
||||
last_watermark,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
if new_hrmp_watermark > relay_chain_parent_number {
|
||||
return Err(HrmpWatermarkAcceptanceErr::AheadRelayParent {
|
||||
new_watermark: new_hrmp_watermark,
|
||||
relay_chain_parent_number,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// Second, check where the watermark CAN land. It's one of the following:
|
||||
@@ -817,7 +732,7 @@ impl<T: Config> Pallet<T> {
|
||||
{
|
||||
return Err(HrmpWatermarkAcceptanceErr::LandsOnBlockWithNoMessages {
|
||||
new_watermark: new_hrmp_watermark,
|
||||
});
|
||||
})
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -832,36 +747,28 @@ impl<T: Config> Pallet<T> {
|
||||
return Err(OutboundHrmpAcceptanceErr::MoreMessagesThanPermitted {
|
||||
sent: out_hrmp_msgs.len() as u32,
|
||||
permitted: config.hrmp_max_message_num_per_candidate,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
let mut last_recipient = None::<ParaId>;
|
||||
|
||||
for (idx, out_msg) in out_hrmp_msgs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, out_msg)| (idx as u32, out_msg))
|
||||
for (idx, out_msg) in
|
||||
out_hrmp_msgs.iter().enumerate().map(|(idx, out_msg)| (idx as u32, out_msg))
|
||||
{
|
||||
match last_recipient {
|
||||
// the messages must be sorted in ascending order and there must be no two messages sent
|
||||
// to the same recipient. Thus we can check that every recipient is strictly greater than
|
||||
// the previous one.
|
||||
Some(last_recipient) if out_msg.recipient <= last_recipient => {
|
||||
return Err(OutboundHrmpAcceptanceErr::NotSorted { idx });
|
||||
}
|
||||
Some(last_recipient) if out_msg.recipient <= last_recipient =>
|
||||
return Err(OutboundHrmpAcceptanceErr::NotSorted { idx }),
|
||||
_ => last_recipient = Some(out_msg.recipient),
|
||||
}
|
||||
|
||||
let channel_id = HrmpChannelId {
|
||||
sender,
|
||||
recipient: out_msg.recipient,
|
||||
};
|
||||
let channel_id = HrmpChannelId { sender, recipient: out_msg.recipient };
|
||||
|
||||
let channel = match <Self as Store>::HrmpChannels::get(&channel_id) {
|
||||
Some(channel) => channel,
|
||||
None => {
|
||||
return Err(OutboundHrmpAcceptanceErr::NoSuchChannel { channel_id, idx });
|
||||
}
|
||||
None => return Err(OutboundHrmpAcceptanceErr::NoSuchChannel { channel_id, idx }),
|
||||
};
|
||||
|
||||
let msg_size = out_msg.data.len() as u32;
|
||||
@@ -870,7 +777,7 @@ impl<T: Config> Pallet<T> {
|
||||
idx,
|
||||
msg_size,
|
||||
max_size: channel.max_message_size,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
let new_total_size = channel.total_size + out_msg.data.len() as u32;
|
||||
@@ -879,7 +786,7 @@ impl<T: Config> Pallet<T> {
|
||||
idx,
|
||||
total_size: new_total_size,
|
||||
limit: channel.max_total_size,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
let new_msg_count = channel.msg_count + 1;
|
||||
@@ -888,7 +795,7 @@ impl<T: Config> Pallet<T> {
|
||||
idx,
|
||||
count: new_msg_count,
|
||||
limit: channel.max_capacity,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,9 +823,8 @@ impl<T: Config> Pallet<T> {
|
||||
weight += T::DbWeight::get().reads_writes(1, 1);
|
||||
|
||||
// having all senders we can trivially find out the channels which we need to prune.
|
||||
let channels_to_prune = senders
|
||||
.into_iter()
|
||||
.map(|sender| HrmpChannelId { sender, recipient });
|
||||
let channels_to_prune =
|
||||
senders.into_iter().map(|sender| HrmpChannelId { sender, recipient });
|
||||
for channel_id in channels_to_prune {
|
||||
// prune each channel up to the new watermark keeping track how many messages we removed
|
||||
// and what is the total byte size of them.
|
||||
@@ -968,24 +874,18 @@ impl<T: Config> Pallet<T> {
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
|
||||
for out_msg in out_hrmp_msgs {
|
||||
let channel_id = HrmpChannelId {
|
||||
sender,
|
||||
recipient: out_msg.recipient,
|
||||
};
|
||||
let channel_id = HrmpChannelId { sender, recipient: out_msg.recipient };
|
||||
|
||||
let mut channel = match <Self as Store>::HrmpChannels::get(&channel_id) {
|
||||
Some(channel) => channel,
|
||||
None => {
|
||||
// apparently, that since acceptance of this candidate the recipient was
|
||||
// offboarded and the channel no longer exists.
|
||||
continue;
|
||||
}
|
||||
continue
|
||||
},
|
||||
};
|
||||
|
||||
let inbound = InboundHrmpMessage {
|
||||
sent_at: now,
|
||||
data: out_msg.data,
|
||||
};
|
||||
let inbound = InboundHrmpMessage { sent_at: now, data: out_msg.data };
|
||||
|
||||
// book keeping
|
||||
channel.msg_count += 1;
|
||||
@@ -1052,27 +952,18 @@ impl<T: Config> Pallet<T> {
|
||||
);
|
||||
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
ensure!(
|
||||
proposed_max_capacity > 0,
|
||||
Error::<T>::OpenHrmpChannelZeroCapacity,
|
||||
);
|
||||
ensure!(proposed_max_capacity > 0, Error::<T>::OpenHrmpChannelZeroCapacity,);
|
||||
ensure!(
|
||||
proposed_max_capacity <= config.hrmp_channel_max_capacity,
|
||||
Error::<T>::OpenHrmpChannelCapacityExceedsLimit,
|
||||
);
|
||||
ensure!(
|
||||
proposed_max_message_size > 0,
|
||||
Error::<T>::OpenHrmpChannelZeroMessageSize,
|
||||
);
|
||||
ensure!(proposed_max_message_size > 0, Error::<T>::OpenHrmpChannelZeroMessageSize,);
|
||||
ensure!(
|
||||
proposed_max_message_size <= config.hrmp_channel_max_message_size,
|
||||
Error::<T>::OpenHrmpChannelMessageSizeExceedsLimit,
|
||||
);
|
||||
|
||||
let channel_id = HrmpChannelId {
|
||||
sender: origin,
|
||||
recipient,
|
||||
};
|
||||
let channel_id = HrmpChannelId { sender: origin, recipient };
|
||||
ensure!(
|
||||
<Self as Store>::HrmpOpenChannelRequests::get(&channel_id).is_none(),
|
||||
Error::<T>::OpenHrmpChannelAlreadyExists,
|
||||
@@ -1115,8 +1006,8 @@ impl<T: Config> Pallet<T> {
|
||||
<Self as Store>::HrmpOpenChannelRequestsList::append(channel_id);
|
||||
|
||||
let notification_bytes = {
|
||||
use xcm::opaque::{v0::Xcm, VersionedXcm};
|
||||
use parity_scale_codec::Encode as _;
|
||||
use xcm::opaque::{v0::Xcm, VersionedXcm};
|
||||
|
||||
VersionedXcm::from(Xcm::HrmpNewChannelOpenRequest {
|
||||
sender: u32::from(origin),
|
||||
@@ -1141,16 +1032,10 @@ impl<T: Config> Pallet<T> {
|
||||
/// Basically the same as [`hrmp_accept_open_channel`](Pallet::hrmp_accept_open_channel) but
|
||||
/// intendend for calling directly from other pallets rather than dispatched.
|
||||
pub fn accept_open_channel(origin: ParaId, sender: ParaId) -> DispatchResult {
|
||||
let channel_id = HrmpChannelId {
|
||||
sender,
|
||||
recipient: origin,
|
||||
};
|
||||
let channel_id = HrmpChannelId { sender, recipient: origin };
|
||||
let mut channel_req = <Self as Store>::HrmpOpenChannelRequests::get(&channel_id)
|
||||
.ok_or(Error::<T>::AcceptHrmpChannelDoesntExist)?;
|
||||
ensure!(
|
||||
!channel_req.confirmed,
|
||||
Error::<T>::AcceptHrmpChannelAlreadyConfirmed,
|
||||
);
|
||||
ensure!(!channel_req.confirmed, Error::<T>::AcceptHrmpChannelAlreadyConfirmed,);
|
||||
|
||||
// check if by accepting this open channel request, this parachain would exceed the
|
||||
// number of inbound channels.
|
||||
@@ -1183,10 +1068,7 @@ impl<T: Config> Pallet<T> {
|
||||
use parity_scale_codec::Encode as _;
|
||||
use xcm::opaque::{v0::Xcm, VersionedXcm};
|
||||
|
||||
VersionedXcm::from(Xcm::HrmpChannelAccepted {
|
||||
recipient: u32::from(origin),
|
||||
})
|
||||
.encode()
|
||||
VersionedXcm::from(Xcm::HrmpChannelAccepted { recipient: u32::from(origin) }).encode()
|
||||
};
|
||||
if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) =
|
||||
<dmp::Pallet<T>>::queue_downward_message(&config, sender, notification_bytes)
|
||||
@@ -1233,11 +1115,8 @@ impl<T: Config> Pallet<T> {
|
||||
})
|
||||
.encode()
|
||||
};
|
||||
let opposite_party = if origin == channel_id.sender {
|
||||
channel_id.recipient
|
||||
} else {
|
||||
channel_id.sender
|
||||
};
|
||||
let opposite_party =
|
||||
if origin == channel_id.sender { channel_id.recipient } else { channel_id.sender };
|
||||
if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) =
|
||||
<dmp::Pallet<T>>::queue_downward_message(&config, opposite_party, notification_bytes)
|
||||
{
|
||||
@@ -1292,15 +1171,14 @@ impl<T: Config> Pallet<T> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
new_test_ext, Test, Configuration, Paras, ParasShared, Hrmp, System, MockGenesisConfig,
|
||||
Event as MockEvent,
|
||||
new_test_ext, Configuration, Event as MockEvent, Hrmp, MockGenesisConfig, Paras,
|
||||
ParasShared, System, Test,
|
||||
};
|
||||
use frame_support::{assert_noop, assert_ok, traits::Currency as _};
|
||||
use primitives::v1::BlockNumber;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) {
|
||||
|
||||
let config = Configuration::config();
|
||||
while System::block_number() < to {
|
||||
let b = System::block_number();
|
||||
@@ -1500,9 +1378,7 @@ mod tests {
|
||||
// An entry in `HrmpChannels` indicates that the channel is open. Only open channels can
|
||||
// have contents.
|
||||
for (non_empty_channel, contents) in <Hrmp as Store>::HrmpChannelContents::iter() {
|
||||
assert!(<Hrmp as Store>::HrmpChannels::contains_key(
|
||||
&non_empty_channel
|
||||
));
|
||||
assert!(<Hrmp as Store>::HrmpChannels::contains_key(&non_empty_channel));
|
||||
|
||||
// pedantic check: there should be no empty vectors in storage, those should be modeled
|
||||
// by a removed kv pair.
|
||||
@@ -1544,10 +1420,7 @@ mod tests {
|
||||
let channel_set_ground_truth = <Hrmp as Store>::HrmpChannels::iter()
|
||||
.map(|(k, _)| (k.sender, k.recipient))
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
channel_set_derived_from_ingress,
|
||||
channel_set_derived_from_egress
|
||||
);
|
||||
assert_eq!(channel_set_derived_from_ingress, channel_set_derived_from_egress);
|
||||
assert_eq!(channel_set_derived_from_egress, channel_set_ground_truth);
|
||||
|
||||
<Hrmp as Store>::HrmpIngressChannelsIndex::iter()
|
||||
@@ -1583,22 +1456,13 @@ mod tests {
|
||||
|
||||
fn assert_contains_only_onboarded(iter: impl Iterator<Item = ParaId>, cause: &str) {
|
||||
for para in iter {
|
||||
assert!(
|
||||
Paras::is_valid_para(para),
|
||||
"{}: {} para is offboarded",
|
||||
cause,
|
||||
para
|
||||
);
|
||||
assert!(Paras::is_valid_para(para), "{}: {} para is offboarded", cause, para);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_is_sorted<T: Ord>(slice: &[T], id: &str) {
|
||||
assert!(
|
||||
slice.windows(2).all(|xs| xs[0] <= xs[1]),
|
||||
"{} supposed to be sorted",
|
||||
id
|
||||
);
|
||||
assert!(slice.windows(2).all(|xs| xs[0] <= xs[1]), "{} supposed to be sorted", id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1623,15 +1487,13 @@ mod tests {
|
||||
run_to_block(5, Some(vec![4, 5]));
|
||||
Hrmp::hrmp_init_open_channel(para_a_origin.into(), para_b, 2, 8).unwrap();
|
||||
assert_storage_consistency_exhaustive();
|
||||
assert!(System::events().iter().any(|record|
|
||||
record.event == MockEvent::Hrmp(Event::OpenChannelRequested(para_a, para_b, 2, 8))
|
||||
));
|
||||
assert!(System::events().iter().any(|record| record.event ==
|
||||
MockEvent::Hrmp(Event::OpenChannelRequested(para_a, para_b, 2, 8))));
|
||||
|
||||
Hrmp::hrmp_accept_open_channel(para_b_origin.into(), para_a).unwrap();
|
||||
assert_storage_consistency_exhaustive();
|
||||
assert!(System::events().iter().any(|record|
|
||||
record.event == MockEvent::Hrmp(Event::OpenChannelAccepted(para_a, para_b))
|
||||
));
|
||||
assert!(System::events().iter().any(|record| record.event ==
|
||||
MockEvent::Hrmp(Event::OpenChannelAccepted(para_a, para_b))));
|
||||
|
||||
// Advance to a block 6, but without session change. That means that the channel has
|
||||
// not been created yet.
|
||||
@@ -1664,10 +1526,7 @@ mod tests {
|
||||
|
||||
// Close the channel. The effect is not immediate, but rather deferred to the next
|
||||
// session change.
|
||||
let channel_id = HrmpChannelId {
|
||||
sender: para_a,
|
||||
recipient: para_b,
|
||||
};
|
||||
let channel_id = HrmpChannelId { sender: para_a, recipient: para_b };
|
||||
Hrmp::hrmp_close_channel(para_b_origin.into(), channel_id.clone()).unwrap();
|
||||
assert!(channel_exists(para_a, para_b));
|
||||
assert_storage_consistency_exhaustive();
|
||||
@@ -1676,9 +1535,8 @@ mod tests {
|
||||
run_to_block(8, Some(vec![8]));
|
||||
assert!(!channel_exists(para_a, para_b));
|
||||
assert_storage_consistency_exhaustive();
|
||||
assert!(System::events().iter().any(|record|
|
||||
record.event == MockEvent::Hrmp(Event::ChannelClosed(para_b, channel_id.clone()))
|
||||
));
|
||||
assert!(System::events().iter().any(|record| record.event ==
|
||||
MockEvent::Hrmp(Event::ChannelClosed(para_b, channel_id.clone()))));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1732,27 +1590,31 @@ mod tests {
|
||||
register_parachain(para_a);
|
||||
register_parachain(para_b);
|
||||
|
||||
run_to_block(2, Some(vec![1,2]));
|
||||
run_to_block(2, Some(vec![1, 2]));
|
||||
Hrmp::init_open_channel(para_a, para_b, 2, 20).unwrap();
|
||||
Hrmp::accept_open_channel(para_b, para_a).unwrap();
|
||||
|
||||
run_to_block(3, Some(vec![3]));
|
||||
let _ = Hrmp::queue_outbound_hrmp(para_a, vec![OutboundHrmpMessage {
|
||||
recipient: para_b,
|
||||
data: vec![1, 2, 3],
|
||||
}]);
|
||||
let _ = Hrmp::queue_outbound_hrmp(
|
||||
para_a,
|
||||
vec![OutboundHrmpMessage { recipient: para_b, data: vec![1, 2, 3] }],
|
||||
);
|
||||
|
||||
run_to_block(4, None);
|
||||
let _ = Hrmp::queue_outbound_hrmp(para_a, vec![OutboundHrmpMessage {
|
||||
recipient: para_b,
|
||||
data: vec![4, 5, 6],
|
||||
}]);
|
||||
let _ = Hrmp::queue_outbound_hrmp(
|
||||
para_a,
|
||||
vec![OutboundHrmpMessage { recipient: para_b, data: vec![4, 5, 6] }],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Hrmp::hrmp_mqc_heads(para_b),
|
||||
vec![
|
||||
(para_a, hex_literal::hex!["a964fd3b4f3d3ce92a0e25e576b87590d92bb5cb7031909c7f29050e1f04a375"].into()),
|
||||
],
|
||||
vec![(
|
||||
para_a,
|
||||
hex_literal::hex![
|
||||
"a964fd3b4f3d3ce92a0e25e576b87590d92bb5cb7031909c7f29050e1f04a375"
|
||||
]
|
||||
.into()
|
||||
),],
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1803,10 +1665,7 @@ mod tests {
|
||||
run_to_block(6, Some(vec![6]));
|
||||
assert!(Paras::is_valid_para(para_a));
|
||||
|
||||
let msgs = vec![OutboundHrmpMessage {
|
||||
recipient: para_b,
|
||||
data: b"knock".to_vec(),
|
||||
}];
|
||||
let msgs = vec![OutboundHrmpMessage { recipient: para_b, data: b"knock".to_vec() }];
|
||||
let config = Configuration::config();
|
||||
assert!(Hrmp::check_outbound_hrmp(&config, para_a, &msgs).is_ok());
|
||||
let _ = Hrmp::queue_outbound_hrmp(para_a, msgs.clone());
|
||||
@@ -1817,13 +1676,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
contents,
|
||||
vec![
|
||||
(
|
||||
para_a,
|
||||
vec![InboundHrmpMessage {
|
||||
sent_at: 6,
|
||||
data: b"knock".to_vec(),
|
||||
}]
|
||||
),
|
||||
(para_a, vec![InboundHrmpMessage { sent_at: 6, data: b"knock".to_vec() }]),
|
||||
(para_c, vec![])
|
||||
]
|
||||
.into_iter()
|
||||
@@ -1891,29 +1744,19 @@ mod tests {
|
||||
);
|
||||
|
||||
let raw_ingress_index =
|
||||
sp_io::storage::get(
|
||||
&well_known_keys::hrmp_ingress_channel_index(para_b),
|
||||
)
|
||||
.expect("the ingress index must be present for para_b");
|
||||
sp_io::storage::get(&well_known_keys::hrmp_ingress_channel_index(para_b))
|
||||
.expect("the ingress index must be present for para_b");
|
||||
let ingress_index = <Vec<ParaId>>::decode(&mut &raw_ingress_index[..])
|
||||
.expect("ingress indexx should be decodable as a list of para ids");
|
||||
assert_eq!(
|
||||
ingress_index,
|
||||
vec![para_a],
|
||||
);
|
||||
assert_eq!(ingress_index, vec![para_a],);
|
||||
|
||||
// Now, verify that we can access and decode the egress index.
|
||||
let raw_egress_index =
|
||||
sp_io::storage::get(
|
||||
&well_known_keys::hrmp_egress_channel_index(para_a)
|
||||
)
|
||||
.expect("the egress index must be present for para_a");
|
||||
sp_io::storage::get(&well_known_keys::hrmp_egress_channel_index(para_a))
|
||||
.expect("the egress index must be present for para_a");
|
||||
let egress_index = <Vec<ParaId>>::decode(&mut &raw_egress_index[..])
|
||||
.expect("egress index should be decodable as a list of para ids");
|
||||
assert_eq!(
|
||||
egress_index,
|
||||
vec![para_b],
|
||||
);
|
||||
assert_eq!(egress_index, vec![para_b],);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1962,34 +1805,16 @@ mod tests {
|
||||
run_to_block(5, Some(vec![4, 5]));
|
||||
Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap();
|
||||
Hrmp::accept_open_channel(para_b, para_a).unwrap();
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
80
|
||||
);
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_b.into_account()),
|
||||
95
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 80);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_b.into_account()), 95);
|
||||
run_to_block(8, Some(vec![8]));
|
||||
|
||||
// Now, we close the channel and wait until the next session.
|
||||
Hrmp::close_channel(
|
||||
para_b,
|
||||
HrmpChannelId {
|
||||
sender: para_a,
|
||||
recipient: para_b,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
Hrmp::close_channel(para_b, HrmpChannelId { sender: para_a, recipient: para_b })
|
||||
.unwrap();
|
||||
run_to_block(10, Some(vec![10]));
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
100
|
||||
);
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_b.into_account()),
|
||||
110
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 100);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_b.into_account()), 110);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2009,28 +1834,16 @@ mod tests {
|
||||
register_parachain_with_balance(para_b, 110);
|
||||
run_to_block(5, Some(vec![4, 5]));
|
||||
Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap();
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
80
|
||||
);
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_b.into_account()),
|
||||
110
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 80);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_b.into_account()), 110);
|
||||
|
||||
// Request age is 1 out of 2
|
||||
run_to_block(10, Some(vec![10]));
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
80
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 80);
|
||||
|
||||
// Request age is 2 out of 2. The request should expire.
|
||||
run_to_block(20, Some(vec![20]));
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
100
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 100);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2049,14 +1862,8 @@ mod tests {
|
||||
run_to_block(5, Some(vec![4, 5]));
|
||||
Hrmp::init_open_channel(para_a, para_b, 2, 8).unwrap();
|
||||
Hrmp::accept_open_channel(para_b, para_a).unwrap();
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
80
|
||||
);
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_b.into_account()),
|
||||
95
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 80);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_b.into_account()), 95);
|
||||
run_to_block(8, Some(vec![8]));
|
||||
assert!(channel_exists(para_a, para_b));
|
||||
|
||||
@@ -2069,14 +1876,8 @@ mod tests {
|
||||
assert!(!channel_exists(para_a, para_b));
|
||||
assert_storage_consistency_exhaustive();
|
||||
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_a.into_account()),
|
||||
100
|
||||
);
|
||||
assert_eq!(
|
||||
<Test as Config>::Currency::free_balance(¶_b.into_account()),
|
||||
110
|
||||
);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_a.into_account()), 100);
|
||||
assert_eq!(<Test as Config>::Currency::free_balance(¶_b.into_account()), 110);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,15 +19,15 @@
|
||||
//!
|
||||
//! This module can throw fatal errors if session-change notifications are received after initialization.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use primitives::v1::{ValidatorId, SessionIndex, ConsensusLog, BlockNumber};
|
||||
use frame_support::traits::{Randomness, OneSessionHandler};
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use crate::{
|
||||
configuration::{self, HostConfiguration},
|
||||
disputes::DisputesHandler,
|
||||
shared, paras, scheduler, inclusion, session_info, dmp, ump, hrmp,
|
||||
dmp, hrmp, inclusion, paras, scheduler, session_info, shared, ump,
|
||||
};
|
||||
use frame_support::traits::{OneSessionHandler, Randomness};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use primitives::v1::{BlockNumber, ConsensusLog, SessionIndex, ValidatorId};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -70,9 +70,9 @@ struct BufferedSessionChange {
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use super::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
@@ -97,7 +97,6 @@ pub mod pallet {
|
||||
type ForceOrigin: EnsureOrigin<<Self as frame_system::Config>::Origin>;
|
||||
}
|
||||
|
||||
|
||||
/// Whether the parachains modules have been initialized within this block.
|
||||
///
|
||||
/// Semantically a `bool`, but this guarantees it should never hit the trie,
|
||||
@@ -117,7 +116,8 @@ pub mod pallet {
|
||||
/// However this is a `Vec` regardless to handle various edge cases that may occur at runtime
|
||||
/// upgrade boundaries or if governance intervenes.
|
||||
#[pallet::storage]
|
||||
pub(super) type BufferedSessionChanges<T: Config> = StorageValue<_, Vec<BufferedSessionChange>, ValueQuery>;
|
||||
pub(super) type BufferedSessionChanges<T: Config> =
|
||||
StorageValue<_, Vec<BufferedSessionChange>, ValueQuery>;
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
@@ -165,11 +165,8 @@ pub mod pallet {
|
||||
// next block will observe the next session.
|
||||
//
|
||||
// Note that we only apply the last session as all others lasted less than a block (weirdly).
|
||||
if let Some(BufferedSessionChange {
|
||||
session_index,
|
||||
validators,
|
||||
queued,
|
||||
}) = BufferedSessionChanges::<T>::take().pop()
|
||||
if let Some(BufferedSessionChange { session_index, validators, queued }) =
|
||||
BufferedSessionChanges::<T>::take().pop()
|
||||
{
|
||||
Self::apply_new_session(session_index, validators, queued);
|
||||
}
|
||||
@@ -250,8 +247,8 @@ impl<T: Config> Pallet<T> {
|
||||
session_index: SessionIndex,
|
||||
validators: I,
|
||||
queued: Option<I>,
|
||||
)
|
||||
where I: Iterator<Item=(&'a T::AccountId, ValidatorId)>
|
||||
) where
|
||||
I: Iterator<Item = (&'a T::AccountId, ValidatorId)>,
|
||||
{
|
||||
let validators: Vec<_> = validators.map(|(_, v)| v).collect();
|
||||
let queued: Vec<_> = if let Some(queued) = queued {
|
||||
@@ -264,13 +261,10 @@ impl<T: Config> Pallet<T> {
|
||||
// Genesis session should be immediately enacted.
|
||||
Self::apply_new_session(0, validators, queued);
|
||||
} else {
|
||||
BufferedSessionChanges::<T>::mutate(|v| v.push(BufferedSessionChange {
|
||||
validators,
|
||||
queued,
|
||||
session_index,
|
||||
}));
|
||||
BufferedSessionChanges::<T>::mutate(|v| {
|
||||
v.push(BufferedSessionChange { validators, queued, session_index })
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Allow to trigger on_new_session in tests, this is needed as long as pallet_session is not
|
||||
@@ -281,8 +275,8 @@ impl<T: Config> Pallet<T> {
|
||||
session_index: SessionIndex,
|
||||
validators: I,
|
||||
queued: Option<I>,
|
||||
)
|
||||
where I: Iterator<Item=(&'a T::AccountId, ValidatorId)>
|
||||
) where
|
||||
I: Iterator<Item = (&'a T::AccountId, ValidatorId)>,
|
||||
{
|
||||
Self::on_new_session(changed, session_index, validators, queued)
|
||||
}
|
||||
@@ -296,29 +290,31 @@ impl<T: pallet_session::Config + Config> OneSessionHandler<T::AccountId> for Pal
|
||||
type Key = ValidatorId;
|
||||
|
||||
fn on_genesis_session<'a, I: 'a>(validators: I)
|
||||
where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
|
||||
where
|
||||
I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
|
||||
{
|
||||
<Pallet<T>>::on_new_session(false, 0, validators, None);
|
||||
}
|
||||
|
||||
fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued: I)
|
||||
where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
|
||||
where
|
||||
I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
|
||||
{
|
||||
let session_index = <pallet_session::Pallet<T>>::current_index();
|
||||
<Pallet<T>>::on_new_session(changed, session_index, validators, Some(queued));
|
||||
}
|
||||
|
||||
fn on_disabled(_i: usize) { }
|
||||
fn on_disabled(_i: usize) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::v1::{Id as ParaId};
|
||||
use crate::mock::{
|
||||
new_test_ext,
|
||||
Initializer, System, Dmp, Paras, Configuration, SessionInfo, MockGenesisConfig,
|
||||
new_test_ext, Configuration, Dmp, Initializer, MockGenesisConfig, Paras, SessionInfo,
|
||||
System,
|
||||
};
|
||||
use primitives::v1::Id as ParaId;
|
||||
|
||||
use frame_support::{
|
||||
assert_ok,
|
||||
@@ -409,26 +405,24 @@ mod tests {
|
||||
validation_code: Default::default(),
|
||||
};
|
||||
|
||||
new_test_ext(
|
||||
MockGenesisConfig {
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: crate::configuration::HostConfiguration {
|
||||
max_downward_message_size: 1024,
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
paras: crate::paras::GenesisConfig {
|
||||
paras: vec![
|
||||
(a, mock_genesis.clone()),
|
||||
(b, mock_genesis.clone()),
|
||||
(c, mock_genesis.clone()),
|
||||
],
|
||||
new_test_ext(MockGenesisConfig {
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: crate::configuration::HostConfiguration {
|
||||
max_downward_message_size: 1024,
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
paras: crate::paras::GenesisConfig {
|
||||
paras: vec![
|
||||
(a, mock_genesis.clone()),
|
||||
(b, mock_genesis.clone()),
|
||||
(c, mock_genesis.clone()),
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
).execute_with(|| {
|
||||
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.execute_with(|| {
|
||||
// enqueue downward messages to A, B and C.
|
||||
assert_ok!(Dmp::queue_downward_message(&Configuration::config(), a, vec![1, 2, 3]));
|
||||
assert_ok!(Dmp::queue_downward_message(&Configuration::config(), b, vec![4, 5, 6]));
|
||||
|
||||
@@ -24,18 +24,18 @@
|
||||
|
||||
pub mod configuration;
|
||||
pub mod disputes;
|
||||
pub mod shared;
|
||||
pub mod dmp;
|
||||
pub mod hrmp;
|
||||
pub mod inclusion;
|
||||
pub mod initializer;
|
||||
pub mod origin;
|
||||
pub mod paras;
|
||||
pub mod paras_inherent;
|
||||
pub mod reward_points;
|
||||
pub mod scheduler;
|
||||
pub mod session_info;
|
||||
pub mod origin;
|
||||
pub mod dmp;
|
||||
pub mod shared;
|
||||
pub mod ump;
|
||||
pub mod hrmp;
|
||||
pub mod reward_points;
|
||||
|
||||
pub mod runtime_api_impl;
|
||||
|
||||
@@ -44,9 +44,9 @@ mod util;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
pub use origin::{Origin, ensure_parachain};
|
||||
use primitives::v1::Id as ParaId;
|
||||
pub use origin::{ensure_parachain, Origin};
|
||||
pub use paras::ParaLifecycle;
|
||||
use primitives::v1::Id as ParaId;
|
||||
|
||||
/// Schedule a para to be initialized at the start of the next session with the given genesis data.
|
||||
pub fn schedule_para_initialize<T: paras::Config>(
|
||||
|
||||
@@ -16,23 +16,19 @@
|
||||
|
||||
//! Mocks for all the traits.
|
||||
|
||||
use sp_io::TestExternalities;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::traits::{
|
||||
BlakeTwo256, IdentityLookup,
|
||||
};
|
||||
use primitives::v1::{
|
||||
AuthorityDiscoveryId, Balance, BlockNumber, Header, ValidatorIndex, SessionIndex,
|
||||
};
|
||||
use frame_support::parameter_types;
|
||||
use frame_support::traits::GenesisBuild;
|
||||
use frame_support_test::TestRandomness;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use crate::{
|
||||
inclusion, scheduler, dmp, ump, hrmp, session_info, paras, configuration,
|
||||
initializer, shared, disputes,
|
||||
configuration, disputes, dmp, hrmp, inclusion, initializer, paras, scheduler, session_info,
|
||||
shared, ump,
|
||||
};
|
||||
use frame_support::{parameter_types, traits::GenesisBuild};
|
||||
use frame_support_test::TestRandomness;
|
||||
use primitives::v1::{
|
||||
AuthorityDiscoveryId, Balance, BlockNumber, Header, SessionIndex, ValidatorIndex,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_io::TestExternalities;
|
||||
use sp_runtime::traits::{BlakeTwo256, IdentityLookup};
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
@@ -114,16 +110,16 @@ impl crate::initializer::Config for Test {
|
||||
type ForceOrigin = frame_system::EnsureRoot<u64>;
|
||||
}
|
||||
|
||||
impl crate::configuration::Config for Test { }
|
||||
impl crate::configuration::Config for Test {}
|
||||
|
||||
impl crate::shared::Config for Test { }
|
||||
impl crate::shared::Config for Test {}
|
||||
|
||||
impl crate::paras::Config for Test {
|
||||
type Origin = Origin;
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
impl crate::dmp::Config for Test { }
|
||||
impl crate::dmp::Config for Test {}
|
||||
|
||||
parameter_types! {
|
||||
pub const FirstMessageFactorPercent: u64 = 100;
|
||||
@@ -157,7 +153,7 @@ thread_local! {
|
||||
impl crate::disputes::RewardValidators for Test {
|
||||
fn reward_dispute_statement(
|
||||
session: SessionIndex,
|
||||
validators: impl IntoIterator<Item=ValidatorIndex>
|
||||
validators: impl IntoIterator<Item = ValidatorIndex>,
|
||||
) {
|
||||
REWARD_VALIDATORS.with(|r| r.borrow_mut().push((session, validators.into_iter().collect())))
|
||||
}
|
||||
@@ -166,7 +162,7 @@ impl crate::disputes::RewardValidators for Test {
|
||||
impl crate::disputes::PunishValidators for Test {
|
||||
fn punish_for_invalid(
|
||||
session: SessionIndex,
|
||||
validators: impl IntoIterator<Item=ValidatorIndex>,
|
||||
validators: impl IntoIterator<Item = ValidatorIndex>,
|
||||
) {
|
||||
PUNISH_VALIDATORS_FOR
|
||||
.with(|r| r.borrow_mut().push((session, validators.into_iter().collect())))
|
||||
@@ -174,7 +170,7 @@ impl crate::disputes::PunishValidators for Test {
|
||||
|
||||
fn punish_against_valid(
|
||||
session: SessionIndex,
|
||||
validators: impl IntoIterator<Item=ValidatorIndex>,
|
||||
validators: impl IntoIterator<Item = ValidatorIndex>,
|
||||
) {
|
||||
PUNISH_VALIDATORS_AGAINST
|
||||
.with(|r| r.borrow_mut().push((session, validators.into_iter().collect())))
|
||||
@@ -182,14 +178,14 @@ impl crate::disputes::PunishValidators for Test {
|
||||
|
||||
fn punish_inconclusive(
|
||||
session: SessionIndex,
|
||||
validators: impl IntoIterator<Item=ValidatorIndex>,
|
||||
validators: impl IntoIterator<Item = ValidatorIndex>,
|
||||
) {
|
||||
PUNISH_VALIDATORS_INCONCLUSIVE
|
||||
.with(|r| r.borrow_mut().push((session, validators.into_iter().collect())))
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::scheduler::Config for Test { }
|
||||
impl crate::scheduler::Config for Test {}
|
||||
|
||||
impl crate::inclusion::Config for Test {
|
||||
type Event = Event;
|
||||
@@ -197,9 +193,9 @@ impl crate::inclusion::Config for Test {
|
||||
type RewardValidators = TestRewardValidators;
|
||||
}
|
||||
|
||||
impl crate::paras_inherent::Config for Test { }
|
||||
impl crate::paras_inherent::Config for Test {}
|
||||
|
||||
impl crate::session_info::Config for Test { }
|
||||
impl crate::session_info::Config for Test {}
|
||||
|
||||
thread_local! {
|
||||
pub static DISCOVERY_AUTHORITIES: RefCell<Vec<AuthorityDiscoveryId>> = RefCell::new(Vec::new());
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
//! Declaration of the parachain specific origin and a pallet that hosts it.
|
||||
|
||||
use sp_std::result;
|
||||
use sp_runtime::traits::BadOrigin;
|
||||
use primitives::v1::Id as ParaId;
|
||||
use sp_runtime::traits::BadOrigin;
|
||||
use sp_std::result;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
/// Ensure that the origin `o` represents a parachain.
|
||||
/// Returns `Ok` with the parachain ID that effected the extrinsic or an `Err` otherwise.
|
||||
pub fn ensure_parachain<OuterOrigin>(o: OuterOrigin) -> result::Result<ParaId, BadOrigin>
|
||||
where OuterOrigin: Into<result::Result<Origin, OuterOrigin>>
|
||||
where
|
||||
OuterOrigin: Into<result::Result<Origin, OuterOrigin>>,
|
||||
{
|
||||
match o.into() {
|
||||
Ok(Origin::Parachain(id)) => Ok(id),
|
||||
@@ -41,8 +42,8 @@ pub fn ensure_parachain<OuterOrigin>(o: OuterOrigin) -> result::Result<ParaId, B
|
||||
// ideally, though, the `construct_runtime` should support a free-standing origin.
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
|
||||
@@ -23,20 +23,19 @@
|
||||
//! A para is not considered live until it is registered and activated in this pallet. Activation can
|
||||
//! only occur at session boundaries.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::result;
|
||||
use primitives::v1::{
|
||||
Id as ParaId, ValidationCode, ValidationCodeHash, HeadData, SessionIndex, ConsensusLog,
|
||||
};
|
||||
use sp_runtime::{traits::One, DispatchResult, SaturatedConversion};
|
||||
use frame_system::pallet_prelude::*;
|
||||
use crate::{configuration, initializer::SessionChangeNotification, shared};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use crate::{configuration, shared, initializer::SessionChangeNotification};
|
||||
use frame_system::pallet_prelude::*;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use primitives::v1::{
|
||||
ConsensusLog, HeadData, Id as ParaId, SessionIndex, ValidationCode, ValidationCodeHash,
|
||||
};
|
||||
use sp_core::RuntimeDebug;
|
||||
use sp_runtime::{traits::One, DispatchResult, SaturatedConversion};
|
||||
use sp_std::{prelude::*, result};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use crate::Origin as ParachainOrigin;
|
||||
|
||||
@@ -123,10 +122,11 @@ impl ParaLifecycle {
|
||||
/// This also includes transitioning states, so you may want to combine
|
||||
/// this check with `is_stable` if you specifically want `Paralifecycle::Parachain`.
|
||||
pub fn is_parachain(&self) -> bool {
|
||||
matches!(self,
|
||||
matches!(
|
||||
self,
|
||||
ParaLifecycle::Parachain |
|
||||
ParaLifecycle::DowngradingParachain |
|
||||
ParaLifecycle::OffboardingParachain
|
||||
ParaLifecycle::DowngradingParachain |
|
||||
ParaLifecycle::OffboardingParachain
|
||||
)
|
||||
}
|
||||
|
||||
@@ -134,10 +134,11 @@ impl ParaLifecycle {
|
||||
/// This also includes transitioning states, so you may want to combine
|
||||
/// this check with `is_stable` if you specifically want `Paralifecycle::Parathread`.
|
||||
pub fn is_parathread(&self) -> bool {
|
||||
matches!(self,
|
||||
matches!(
|
||||
self,
|
||||
ParaLifecycle::Parathread |
|
||||
ParaLifecycle::UpgradingParathread |
|
||||
ParaLifecycle::OffboardingParathread
|
||||
ParaLifecycle::UpgradingParathread |
|
||||
ParaLifecycle::OffboardingParathread
|
||||
)
|
||||
}
|
||||
|
||||
@@ -196,8 +197,8 @@ impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
|
||||
// The earliest stored code replacement needs to be special-cased, since we need to check
|
||||
// against the pruning state to see if this replacement represents the correct code, or
|
||||
// is simply after a replacement that actually represents the correct code, but has been pruned.
|
||||
let was_pruned = replaced_after_pos == 0
|
||||
&& self.last_pruned.map_or(false, |t| t >= para_at);
|
||||
let was_pruned =
|
||||
replaced_after_pos == 0 && self.last_pruned.map_or(false, |t| t >= para_at);
|
||||
|
||||
if was_pruned {
|
||||
None
|
||||
@@ -210,10 +211,12 @@ impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
|
||||
// we don't know the code necessary anymore. Compare against `last_pruned` to determine.
|
||||
self.last_pruned.as_ref().map_or(
|
||||
Some(UseCodeAt::Current), // nothing pruned, use current
|
||||
|earliest_activation| if ¶_at < earliest_activation {
|
||||
None
|
||||
} else {
|
||||
Some(UseCodeAt::Current)
|
||||
|earliest_activation| {
|
||||
if ¶_at < earliest_activation {
|
||||
None
|
||||
} else {
|
||||
Some(UseCodeAt::Current)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -235,7 +238,7 @@ impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
|
||||
//
|
||||
// returns an iterator of block numbers at which code was replaced, where the replaced
|
||||
// code should be now pruned, in ascending order.
|
||||
fn prune_up_to(&'_ mut self, max: N) -> impl Iterator<Item=N> + '_ {
|
||||
fn prune_up_to(&'_ mut self, max: N) -> impl Iterator<Item = N> + '_ {
|
||||
let to_prune = self.upgrade_times.iter().take_while(|t| t.activated_at <= max).count();
|
||||
let drained = if to_prune == 0 {
|
||||
// no-op prune.
|
||||
@@ -271,11 +274,7 @@ pub mod pallet {
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config:
|
||||
frame_system::Config +
|
||||
configuration::Config +
|
||||
shared::Config
|
||||
{
|
||||
pub trait Config: frame_system::Config + configuration::Config + shared::Config {
|
||||
/// The outer origin type.
|
||||
type Origin: From<Origin>
|
||||
+ From<<Self as frame_system::Config>::Origin>
|
||||
@@ -331,32 +330,24 @@ pub mod pallet {
|
||||
///
|
||||
/// Corresponding code can be retrieved with [`CodeByHash`].
|
||||
#[pallet::storage]
|
||||
pub(super) type CurrentCodeHash<T: Config> = StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
|
||||
pub(super) type CurrentCodeHash<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
|
||||
|
||||
/// Actual past code hash, indicated by the para id as well as the block number at which it
|
||||
/// became outdated.
|
||||
///
|
||||
/// Corresponding code can be retrieved with [`CodeByHash`].
|
||||
#[pallet::storage]
|
||||
pub(super) type PastCodeHash<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
(ParaId, T::BlockNumber),
|
||||
ValidationCodeHash
|
||||
>;
|
||||
pub(super) type PastCodeHash<T: Config> =
|
||||
StorageMap<_, Twox64Concat, (ParaId, T::BlockNumber), ValidationCodeHash>;
|
||||
|
||||
/// Past code of parachains. The parachains themselves may not be registered anymore,
|
||||
/// but we also keep their code on-chain for the same amount of time as outdated code
|
||||
/// to keep it available for secondary checkers.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn past_code_meta)]
|
||||
pub(super) type PastCodeMeta<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
ParaPastCodeMeta<T::BlockNumber>,
|
||||
ValueQuery
|
||||
>;
|
||||
pub(super) type PastCodeMeta<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, ParaPastCodeMeta<T::BlockNumber>, ValueQuery>;
|
||||
|
||||
/// Which paras have past code that needs pruning and the relay-chain block at which the code was replaced.
|
||||
/// Note that this is the actual height of the included block, not the expected height at which the
|
||||
@@ -365,33 +356,39 @@ pub mod pallet {
|
||||
/// from the time at which the parachain perceives a code upgrade as having occurred.
|
||||
/// Multiple entries for a single para are permitted. Ordered ascending by block number.
|
||||
#[pallet::storage]
|
||||
pub(super) type PastCodePruning<T: Config> = StorageValue<_, Vec<(ParaId, T::BlockNumber)>, ValueQuery>;
|
||||
pub(super) type PastCodePruning<T: Config> =
|
||||
StorageValue<_, Vec<(ParaId, T::BlockNumber)>, ValueQuery>;
|
||||
|
||||
/// The block number at which the planned code change is expected for a para.
|
||||
/// The change will be applied after the first parablock for this ID included which executes
|
||||
/// in the context of a relay chain block with a number >= `expected_at`.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn future_code_upgrade_at)]
|
||||
pub(super) type FutureCodeUpgrades<T: Config> = StorageMap<_, Twox64Concat, ParaId, T::BlockNumber>;
|
||||
pub(super) type FutureCodeUpgrades<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, T::BlockNumber>;
|
||||
|
||||
/// The actual future code hash of a para.
|
||||
///
|
||||
/// Corresponding code can be retrieved with [`CodeByHash`].
|
||||
#[pallet::storage]
|
||||
pub(super) type FutureCodeHash<T: Config> = StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
|
||||
pub(super) type FutureCodeHash<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
|
||||
|
||||
/// The actions to perform during the start of a specific session index.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn actions_queue)]
|
||||
pub(super) type ActionsQueue<T: Config> = StorageMap<_, Twox64Concat, SessionIndex, Vec<ParaId>, ValueQuery>;
|
||||
pub(super) type ActionsQueue<T: Config> =
|
||||
StorageMap<_, Twox64Concat, SessionIndex, Vec<ParaId>, ValueQuery>;
|
||||
|
||||
/// Upcoming paras instantiation arguments.
|
||||
#[pallet::storage]
|
||||
pub(super) type UpcomingParasGenesis<T: Config> = StorageMap<_, Twox64Concat, ParaId, ParaGenesisArgs>;
|
||||
pub(super) type UpcomingParasGenesis<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, ParaGenesisArgs>;
|
||||
|
||||
/// The number of reference on the validation code in [`CodeByHash`] storage.
|
||||
#[pallet::storage]
|
||||
pub(super) type CodeByHashRefs<T: Config> = StorageMap<_, Identity, ValidationCodeHash, u32, ValueQuery>;
|
||||
pub(super) type CodeByHashRefs<T: Config> =
|
||||
StorageMap<_, Identity, ValidationCodeHash, u32, ValueQuery>;
|
||||
|
||||
/// Validation code stored by its hash.
|
||||
///
|
||||
@@ -399,7 +396,8 @@ pub mod pallet {
|
||||
/// [`PastCodeHash`].
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn code_by_hash)]
|
||||
pub(super) type CodeByHash<T: Config> = StorageMap<_, Identity, ValidationCodeHash, ValidationCode>;
|
||||
pub(super) type CodeByHash<T: Config> =
|
||||
StorageMap<_, Identity, ValidationCodeHash, ValidationCode>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
pub struct GenesisConfig {
|
||||
@@ -409,16 +407,15 @@ pub mod pallet {
|
||||
#[cfg(feature = "std")]
|
||||
impl Default for GenesisConfig {
|
||||
fn default() -> Self {
|
||||
GenesisConfig {
|
||||
paras: Default::default(),
|
||||
}
|
||||
GenesisConfig { paras: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> GenesisBuild<T> for GenesisConfig {
|
||||
fn build(&self) {
|
||||
let mut parachains: Vec<_> = self.paras
|
||||
let mut parachains: Vec<_> = self
|
||||
.paras
|
||||
.iter()
|
||||
.filter(|(_, args)| args.parachain)
|
||||
.map(|&(ref id, _)| id)
|
||||
@@ -451,7 +448,11 @@ pub mod pallet {
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Set the storage for the parachain validation code immediately.
|
||||
#[pallet::weight(0)]
|
||||
pub fn force_set_current_code(origin: OriginFor<T>, para: ParaId, new_code: ValidationCode) -> DispatchResult {
|
||||
pub fn force_set_current_code(
|
||||
origin: OriginFor<T>,
|
||||
para: ParaId,
|
||||
new_code: ValidationCode,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
let prior_code_hash = <Self as Store>::CurrentCodeHash::get(¶).unwrap_or_default();
|
||||
let new_code_hash = new_code.hash();
|
||||
@@ -466,7 +467,11 @@ pub mod pallet {
|
||||
|
||||
/// Set the storage for the current parachain head data immediately.
|
||||
#[pallet::weight(0)]
|
||||
pub fn force_set_current_head(origin: OriginFor<T>, para: ParaId, new_head: HeadData) -> DispatchResult {
|
||||
pub fn force_set_current_head(
|
||||
origin: OriginFor<T>,
|
||||
para: ParaId,
|
||||
new_head: HeadData,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
<Self as Store>::Heads::insert(¶, new_head);
|
||||
Self::deposit_event(Event::CurrentHeadUpdated(para));
|
||||
@@ -479,7 +484,7 @@ pub mod pallet {
|
||||
origin: OriginFor<T>,
|
||||
para: ParaId,
|
||||
new_code: ValidationCode,
|
||||
expected_at: T::BlockNumber
|
||||
expected_at: T::BlockNumber,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::schedule_code_upgrade(para, new_code, expected_at);
|
||||
@@ -489,7 +494,11 @@ pub mod pallet {
|
||||
|
||||
/// Note a new block head for para within the context of the current block.
|
||||
#[pallet::weight(0)]
|
||||
pub fn force_note_new_head(origin: OriginFor<T>, para: ParaId, new_head: HeadData) -> DispatchResult {
|
||||
pub fn force_note_new_head(
|
||||
origin: OriginFor<T>,
|
||||
para: ParaId,
|
||||
new_head: HeadData,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
let now = frame_system::Pallet::<T>::block_number();
|
||||
Self::note_new_head(para, new_head, now);
|
||||
@@ -522,12 +531,14 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
/// Called by the initializer to finalize the configuration pallet.
|
||||
pub(crate) fn initializer_finalize() { }
|
||||
pub(crate) fn initializer_finalize() {}
|
||||
|
||||
/// Called by the initializer to note that a new session has started.
|
||||
///
|
||||
/// Returns the list of outgoing paras from the actions queue.
|
||||
pub(crate) fn initializer_on_new_session(notification: &SessionChangeNotification<T::BlockNumber>) -> Vec<ParaId> {
|
||||
pub(crate) fn initializer_on_new_session(
|
||||
notification: &SessionChangeNotification<T::BlockNumber>,
|
||||
) -> Vec<ParaId> {
|
||||
let outgoing_paras = Self::apply_actions_queue(notification.session_index);
|
||||
outgoing_paras
|
||||
}
|
||||
@@ -564,7 +575,8 @@ impl<T: Config> Pallet<T> {
|
||||
for para in actions {
|
||||
let lifecycle = ParaLifecycles::<T>::get(¶);
|
||||
match lifecycle {
|
||||
None | Some(ParaLifecycle::Parathread) | Some(ParaLifecycle::Parachain) => { /* Nothing to do... */ },
|
||||
None | Some(ParaLifecycle::Parathread) | Some(ParaLifecycle::Parachain) => { /* Nothing to do... */
|
||||
},
|
||||
// Onboard a new parathread or parachain.
|
||||
Some(ParaLifecycle::Onboarding) => {
|
||||
if let Some(genesis_data) = <Self as Store>::UpcomingParasGenesis::take(¶) {
|
||||
@@ -598,7 +610,8 @@ impl<T: Config> Pallet<T> {
|
||||
ParaLifecycles::<T>::insert(¶, ParaLifecycle::Parathread);
|
||||
},
|
||||
// Offboard a parathread or parachain from the system
|
||||
Some(ParaLifecycle::OffboardingParachain) | Some(ParaLifecycle::OffboardingParathread) => {
|
||||
Some(ParaLifecycle::OffboardingParachain) |
|
||||
Some(ParaLifecycle::OffboardingParathread) => {
|
||||
if let Ok(i) = parachains.binary_search(¶) {
|
||||
parachains.remove(i);
|
||||
}
|
||||
@@ -648,8 +661,8 @@ impl<T: Config> Pallet<T> {
|
||||
// Schedule pruning for this past-code to be removed as soon as it
|
||||
// exits the slashing window.
|
||||
<Self as Store>::PastCodePruning::mutate(|pruning| {
|
||||
let insert_idx = pruning.binary_search_by_key(&at, |&(_, b)| b)
|
||||
.unwrap_or_else(|idx| idx);
|
||||
let insert_idx =
|
||||
pruning.binary_search_by_key(&at, |&(_, b)| b).unwrap_or_else(|idx| idx);
|
||||
pruning.insert(insert_idx, (id, now));
|
||||
});
|
||||
|
||||
@@ -663,19 +676,18 @@ impl<T: Config> Pallet<T> {
|
||||
let code_retention_period = config.code_retention_period;
|
||||
if now <= code_retention_period {
|
||||
let weight = T::DbWeight::get().reads_writes(1, 0);
|
||||
return weight;
|
||||
return weight
|
||||
}
|
||||
|
||||
// The height of any changes we no longer should keep around.
|
||||
let pruning_height = now - (code_retention_period + One::one());
|
||||
|
||||
let pruning_tasks_done =
|
||||
<Self as Store>::PastCodePruning::mutate(|pruning_tasks: &mut Vec<(_, T::BlockNumber)>| {
|
||||
let pruning_tasks_done = <Self as Store>::PastCodePruning::mutate(
|
||||
|pruning_tasks: &mut Vec<(_, T::BlockNumber)>| {
|
||||
let (pruning_tasks_done, pruning_tasks_to_do) = {
|
||||
// find all past code that has just exited the pruning window.
|
||||
let up_to_idx = pruning_tasks.iter()
|
||||
.take_while(|&(_, at)| at <= &pruning_height)
|
||||
.count();
|
||||
let up_to_idx =
|
||||
pruning_tasks.iter().take_while(|&(_, at)| at <= &pruning_height).count();
|
||||
(up_to_idx, pruning_tasks.drain(..up_to_idx))
|
||||
};
|
||||
|
||||
@@ -707,7 +719,8 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
pruning_tasks_done as u64
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// 1 read for the meta for each pruning task, 1 read for the config
|
||||
// 2 writes: updating the meta and pruning the code
|
||||
@@ -751,9 +764,7 @@ impl<T: Config> Pallet<T> {
|
||||
let lifecycle = ParaLifecycles::<T>::get(&id);
|
||||
match lifecycle {
|
||||
// If para is not registered, nothing to do!
|
||||
None => {
|
||||
return Ok(())
|
||||
},
|
||||
None => return Ok(()),
|
||||
Some(ParaLifecycle::Parathread) => {
|
||||
ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParathread);
|
||||
},
|
||||
@@ -864,12 +875,7 @@ impl<T: Config> Pallet<T> {
|
||||
// `now` is only used for registering pruning as part of `fn note_past_code`
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
|
||||
let weight = Self::note_past_code(
|
||||
id,
|
||||
expected_at,
|
||||
now,
|
||||
prior_code_hash,
|
||||
);
|
||||
let weight = Self::note_past_code(id, expected_at, now, prior_code_hash);
|
||||
|
||||
// add 1 to writes due to heads update.
|
||||
weight + T::DbWeight::get().reads_writes(3, 1 + 3)
|
||||
@@ -897,7 +903,7 @@ impl<T: Config> Pallet<T> {
|
||||
assume_intermediate: Option<T::BlockNumber>,
|
||||
) -> Option<ValidationCodeHash> {
|
||||
if assume_intermediate.as_ref().map_or(false, |i| &at <= i) {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
let planned_upgrade = <Self as Store>::FutureCodeUpgrades::get(&id);
|
||||
@@ -912,7 +918,8 @@ impl<T: Config> Pallet<T> {
|
||||
match Self::past_code_meta(&id).code_at(at) {
|
||||
None => None,
|
||||
Some(UseCodeAt::Current) => CurrentCodeHash::<T>::get(&id),
|
||||
Some(UseCodeAt::ReplacedAt(replaced)) => <Self as Store>::PastCodeHash::get(&(id, replaced)),
|
||||
Some(UseCodeAt::ReplacedAt(replaced)) =>
|
||||
<Self as Store>::PastCodeHash::get(&(id, replaced)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -960,7 +967,7 @@ impl<T: Config> Pallet<T> {
|
||||
pub(crate) fn last_code_upgrade(id: ParaId, include_future: bool) -> Option<T::BlockNumber> {
|
||||
if include_future {
|
||||
if let Some(at) = Self::future_code_upgrade_at(id) {
|
||||
return Some(at);
|
||||
return Some(at)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,11 +1020,13 @@ impl<T: Config> Pallet<T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::v1::BlockNumber;
|
||||
use frame_support::assert_ok;
|
||||
use primitives::v1::BlockNumber;
|
||||
|
||||
use crate::mock::{new_test_ext, Paras, ParasShared, System, MockGenesisConfig};
|
||||
use crate::configuration::HostConfiguration;
|
||||
use crate::{
|
||||
configuration::HostConfiguration,
|
||||
mock::{new_test_ext, MockGenesisConfig, Paras, ParasShared, System},
|
||||
};
|
||||
|
||||
fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) {
|
||||
while System::block_number() < to {
|
||||
@@ -1045,7 +1054,10 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn upgrade_at(expected_at: BlockNumber, activated_at: BlockNumber) -> ReplacementTimes<BlockNumber> {
|
||||
fn upgrade_at(
|
||||
expected_at: BlockNumber,
|
||||
activated_at: BlockNumber,
|
||||
) -> ReplacementTimes<BlockNumber> {
|
||||
ReplacementTimes { expected_at, activated_at }
|
||||
}
|
||||
|
||||
@@ -1103,7 +1115,6 @@ mod tests {
|
||||
assert_eq!(past_code.code_at(24), Some(UseCodeAt::ReplacedAt(20)));
|
||||
assert_eq!(past_code.code_at(25), Some(UseCodeAt::ReplacedAt(30)));
|
||||
assert_eq!(past_code.code_at(30), Some(UseCodeAt::Current));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1118,66 +1129,80 @@ mod tests {
|
||||
assert_eq!(old, past_code);
|
||||
|
||||
assert_eq!(past_code.prune_up_to(10).collect::<Vec<_>>(), vec![10]);
|
||||
assert_eq!(past_code, ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(20, 25), upgrade_at(30, 35)],
|
||||
last_pruned: Some(10),
|
||||
});
|
||||
assert_eq!(
|
||||
past_code,
|
||||
ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(20, 25), upgrade_at(30, 35)],
|
||||
last_pruned: Some(10),
|
||||
}
|
||||
);
|
||||
|
||||
assert!(past_code.prune_up_to(21).collect::<Vec<_>>().is_empty());
|
||||
|
||||
assert_eq!(past_code.prune_up_to(26).collect::<Vec<_>>(), vec![20]);
|
||||
assert_eq!(past_code, ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(30, 35)],
|
||||
last_pruned: Some(25),
|
||||
});
|
||||
assert_eq!(
|
||||
past_code,
|
||||
ParaPastCodeMeta { upgrade_times: vec![upgrade_at(30, 35)], last_pruned: Some(25) }
|
||||
);
|
||||
|
||||
past_code.note_replacement(40, 42);
|
||||
past_code.note_replacement(50, 53);
|
||||
past_code.note_replacement(60, 66);
|
||||
|
||||
assert_eq!(past_code, ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(30, 35), upgrade_at(40, 42), upgrade_at(50, 53), upgrade_at(60, 66)],
|
||||
last_pruned: Some(25),
|
||||
});
|
||||
assert_eq!(
|
||||
past_code,
|
||||
ParaPastCodeMeta {
|
||||
upgrade_times: vec![
|
||||
upgrade_at(30, 35),
|
||||
upgrade_at(40, 42),
|
||||
upgrade_at(50, 53),
|
||||
upgrade_at(60, 66)
|
||||
],
|
||||
last_pruned: Some(25),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(past_code.prune_up_to(60).collect::<Vec<_>>(), vec![30, 40, 50]);
|
||||
assert_eq!(past_code, ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(60, 66)],
|
||||
last_pruned: Some(53),
|
||||
});
|
||||
assert_eq!(
|
||||
past_code,
|
||||
ParaPastCodeMeta { upgrade_times: vec![upgrade_at(60, 66)], last_pruned: Some(53) }
|
||||
);
|
||||
|
||||
assert_eq!(past_code.most_recent_change(), Some(60));
|
||||
assert_eq!(past_code.prune_up_to(66).collect::<Vec<_>>(), vec![60]);
|
||||
|
||||
assert_eq!(past_code, ParaPastCodeMeta {
|
||||
upgrade_times: Vec::new(),
|
||||
last_pruned: Some(66),
|
||||
});
|
||||
assert_eq!(
|
||||
past_code,
|
||||
ParaPastCodeMeta { upgrade_times: Vec::new(), last_pruned: Some(66) }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn para_past_code_pruning_in_initialize() {
|
||||
let code_retention_period = 10;
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
}),
|
||||
(1u32.into(), ParaGenesisArgs {
|
||||
parachain: false,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
}),
|
||||
(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
},
|
||||
),
|
||||
(
|
||||
1u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: false,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1200,11 +1225,17 @@ mod tests {
|
||||
}
|
||||
|
||||
let pruned_at: BlockNumber = included_block + code_retention_period + 1;
|
||||
assert_eq!(<Paras as Store>::PastCodeHash::get(&(id, at_block)), Some(validation_code.hash()));
|
||||
assert_eq!(
|
||||
<Paras as Store>::PastCodeHash::get(&(id, at_block)),
|
||||
Some(validation_code.hash())
|
||||
);
|
||||
check_code_is_stored(&validation_code);
|
||||
|
||||
run_to_block(pruned_at - 1, None);
|
||||
assert_eq!(<Paras as Store>::PastCodeHash::get(&(id, at_block)), Some(validation_code.hash()));
|
||||
assert_eq!(
|
||||
<Paras as Store>::PastCodeHash::get(&(id, at_block)),
|
||||
Some(validation_code.hash())
|
||||
);
|
||||
assert_eq!(Paras::past_code_meta(&id).most_recent_change(), Some(at_block));
|
||||
check_code_is_stored(&validation_code);
|
||||
|
||||
@@ -1218,21 +1249,19 @@ mod tests {
|
||||
#[test]
|
||||
fn note_new_head_sets_head() {
|
||||
let code_retention_period = 10;
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1253,25 +1282,28 @@ mod tests {
|
||||
fn note_past_code_sets_up_pruning_correctly() {
|
||||
let code_retention_period = 10;
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
}),
|
||||
(1u32.into(), ParaGenesisArgs {
|
||||
parachain: false,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
}),
|
||||
(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
},
|
||||
),
|
||||
(
|
||||
1u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: false,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1287,17 +1319,11 @@ mod tests {
|
||||
assert_eq!(<Paras as Store>::PastCodePruning::get(), vec![(id_a, 12), (id_b, 23)]);
|
||||
assert_eq!(
|
||||
Paras::past_code_meta(&id_a),
|
||||
ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(10, 12)],
|
||||
last_pruned: None,
|
||||
}
|
||||
ParaPastCodeMeta { upgrade_times: vec![upgrade_at(10, 12)], last_pruned: None }
|
||||
);
|
||||
assert_eq!(
|
||||
Paras::past_code_meta(&id_b),
|
||||
ParaPastCodeMeta {
|
||||
upgrade_times: vec![upgrade_at(20, 23)],
|
||||
last_pruned: None,
|
||||
}
|
||||
ParaPastCodeMeta { upgrade_times: vec![upgrade_at(20, 23)], last_pruned: None }
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1308,13 +1334,14 @@ mod tests {
|
||||
let validation_upgrade_delay = 5;
|
||||
|
||||
let original_code = ValidationCode(vec![1, 2, 3]);
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: original_code.clone(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
@@ -1376,10 +1403,7 @@ mod tests {
|
||||
{
|
||||
Paras::note_new_head(para_id, Default::default(), expected_at);
|
||||
|
||||
assert_eq!(
|
||||
Paras::past_code_meta(¶_id).most_recent_change(),
|
||||
Some(expected_at),
|
||||
);
|
||||
assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at),);
|
||||
assert_eq!(
|
||||
<Paras as Store>::PastCodeHash::get(&(para_id, expected_at)),
|
||||
Some(original_code.hash()),
|
||||
@@ -1399,13 +1423,14 @@ mod tests {
|
||||
let validation_upgrade_delay = 5;
|
||||
|
||||
let original_code = ValidationCode(vec![1, 2, 3]);
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: original_code.clone(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
@@ -1448,10 +1473,7 @@ mod tests {
|
||||
{
|
||||
Paras::note_new_head(para_id, Default::default(), expected_at + 4);
|
||||
|
||||
assert_eq!(
|
||||
Paras::past_code_meta(¶_id).most_recent_change(),
|
||||
Some(expected_at),
|
||||
);
|
||||
assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at),);
|
||||
|
||||
// Some hypothetical block which would have triggered the code change
|
||||
// should still use the old code.
|
||||
@@ -1489,21 +1511,19 @@ mod tests {
|
||||
fn submit_code_change_when_not_allowed_is_err() {
|
||||
let code_retention_period = 10;
|
||||
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: vec![1, 2, 3].into(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1533,21 +1553,19 @@ mod tests {
|
||||
let code_retention_period = 10;
|
||||
|
||||
let original_code = ValidationCode(vec![1, 2, 3]);
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: original_code.clone(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1600,12 +1618,15 @@ mod tests {
|
||||
}
|
||||
|
||||
// run to block #4, with a 2 session changes at the end of the block 2 & 3.
|
||||
run_to_block(4, Some(vec![3,4]));
|
||||
run_to_block(4, Some(vec![3, 4]));
|
||||
|
||||
// cleaning up the parachain should place the current parachain code
|
||||
// into the past code buffer & schedule cleanup.
|
||||
assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(3));
|
||||
assert_eq!(<Paras as Store>::PastCodeHash::get(&(para_id, 3)), Some(original_code.hash()));
|
||||
assert_eq!(
|
||||
<Paras as Store>::PastCodeHash::get(&(para_id, 3)),
|
||||
Some(original_code.hash())
|
||||
);
|
||||
assert_eq!(<Paras as Store>::PastCodePruning::get(), vec![(para_id, 3)]);
|
||||
check_code_is_stored(&original_code);
|
||||
|
||||
@@ -1688,9 +1709,8 @@ mod tests {
|
||||
assert_eq!(<Paras as Store>::ParaLifecycles::get(&b), Some(ParaLifecycle::Onboarding));
|
||||
assert_eq!(<Paras as Store>::ParaLifecycles::get(&c), Some(ParaLifecycle::Onboarding));
|
||||
|
||||
|
||||
// Two sessions pass, so action queue is triggered
|
||||
run_to_block(4, Some(vec![3,4]));
|
||||
run_to_block(4, Some(vec![3, 4]));
|
||||
|
||||
assert_eq!(Paras::parachains(), vec![c, b]);
|
||||
assert_eq!(<Paras as Store>::ActionsQueue::get(Paras::scheduled_session()), Vec::new());
|
||||
@@ -1710,21 +1730,19 @@ mod tests {
|
||||
fn code_hash_at_with_intermediate() {
|
||||
let code_retention_period = 10;
|
||||
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: vec![1, 2, 3].into(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1762,21 +1780,19 @@ mod tests {
|
||||
fn code_hash_at_returns_up_to_end_of_code_retention_period() {
|
||||
let code_retention_period = 10;
|
||||
|
||||
let paras = vec![
|
||||
(0u32.into(), ParaGenesisArgs {
|
||||
let paras = vec![(
|
||||
0u32.into(),
|
||||
ParaGenesisArgs {
|
||||
parachain: true,
|
||||
genesis_head: Default::default(),
|
||||
validation_code: vec![1, 2, 3].into(),
|
||||
}),
|
||||
];
|
||||
},
|
||||
)];
|
||||
|
||||
let genesis_config = MockGenesisConfig {
|
||||
paras: GenesisConfig { paras, ..Default::default() },
|
||||
configuration: crate::configuration::GenesisConfig {
|
||||
config: HostConfiguration {
|
||||
code_retention_period,
|
||||
..Default::default()
|
||||
},
|
||||
config: HostConfiguration { code_retention_period, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1791,10 +1807,7 @@ mod tests {
|
||||
run_to_block(10, None);
|
||||
Paras::note_new_head(para_id, Default::default(), 7);
|
||||
|
||||
assert_eq!(
|
||||
Paras::past_code_meta(¶_id).upgrade_times,
|
||||
vec![upgrade_at(2, 10)],
|
||||
);
|
||||
assert_eq!(Paras::past_code_meta(¶_id).upgrade_times, vec![upgrade_at(2, 10)],);
|
||||
|
||||
assert_eq!(fetch_validation_code_at(para_id, 2, None), Some(old_code.clone()));
|
||||
assert_eq!(fetch_validation_code_at(para_id, 3, None), Some(old_code.clone()));
|
||||
@@ -1814,10 +1827,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
Paras::past_code_meta(¶_id),
|
||||
ParaPastCodeMeta {
|
||||
upgrade_times: Vec::new(),
|
||||
last_pruned: Some(10),
|
||||
},
|
||||
ParaPastCodeMeta { upgrade_times: Vec::new(), last_pruned: Some(10) },
|
||||
);
|
||||
|
||||
assert_eq!(fetch_validation_code_at(para_id, 2, None), None); // pruned :(
|
||||
|
||||
@@ -21,26 +21,26 @@
|
||||
//! as it has no initialization logic and its finalization logic depends only on the details of
|
||||
//! this module.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use primitives::v1::{
|
||||
BackedCandidate, PARACHAINS_INHERENT_IDENTIFIER, InherentData as ParachainsInherentData,
|
||||
};
|
||||
use frame_support::{
|
||||
decl_error, decl_module, decl_storage, ensure,
|
||||
dispatch::DispatchResultWithPostInfo,
|
||||
weights::{DispatchClass, Weight},
|
||||
traits::Get,
|
||||
inherent::{InherentIdentifier, InherentData, MakeFatalError, ProvideInherent},
|
||||
};
|
||||
use frame_system::ensure_none;
|
||||
use crate::{
|
||||
disputes::DisputesHandler,
|
||||
inclusion,
|
||||
scheduler::{self, FreedReason},
|
||||
shared,
|
||||
ump,
|
||||
shared, ump,
|
||||
};
|
||||
use frame_support::{
|
||||
decl_error, decl_module, decl_storage,
|
||||
dispatch::DispatchResultWithPostInfo,
|
||||
ensure,
|
||||
inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent},
|
||||
traits::Get,
|
||||
weights::{DispatchClass, Weight},
|
||||
};
|
||||
use frame_system::ensure_none;
|
||||
use primitives::v1::{
|
||||
BackedCandidate, InherentData as ParachainsInherentData, PARACHAINS_INHERENT_IDENTIFIER,
|
||||
};
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
const LOG_TARGET: &str = "runtime::inclusion-inherent";
|
||||
// In the future, we should benchmark these consts; these are all untested assumptions for now.
|
||||
@@ -249,7 +249,7 @@ fn limit_backed_candidates<T: Config>(
|
||||
return false
|
||||
}
|
||||
|
||||
code_upgrades +=1;
|
||||
code_upgrades += 1;
|
||||
}
|
||||
|
||||
true
|
||||
@@ -258,7 +258,9 @@ fn limit_backed_candidates<T: Config>(
|
||||
|
||||
// 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 {
|
||||
if frame_system::Pallet::<T>::block_weight().total() >
|
||||
<T as frame_system::Config>::BlockWeights::get().max_block
|
||||
{
|
||||
Vec::new()
|
||||
} else {
|
||||
backed_candidates
|
||||
@@ -271,47 +273,41 @@ impl<T: Config> ProvideInherent for Module<T> {
|
||||
const INHERENT_IDENTIFIER: InherentIdentifier = PARACHAINS_INHERENT_IDENTIFIER;
|
||||
|
||||
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
|
||||
let mut inherent_data: ParachainsInherentData<T::Header>
|
||||
= match data.get_data(&Self::INHERENT_IDENTIFIER)
|
||||
{
|
||||
Ok(Some(d)) => d,
|
||||
Ok(None) => return None,
|
||||
Err(_) => {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"ParachainsInherentData failed to decode",
|
||||
);
|
||||
let mut inherent_data: ParachainsInherentData<T::Header> =
|
||||
match data.get_data(&Self::INHERENT_IDENTIFIER) {
|
||||
Ok(Some(d)) => d,
|
||||
Ok(None) => return None,
|
||||
Err(_) => {
|
||||
log::warn!(target: LOG_TARGET, "ParachainsInherentData failed to decode",);
|
||||
|
||||
return None;
|
||||
}
|
||||
};
|
||||
return None
|
||||
},
|
||||
};
|
||||
|
||||
// filter out any unneeded dispute statements
|
||||
T::DisputesHandler::filter_multi_dispute_data(&mut inherent_data.disputes);
|
||||
|
||||
// Sanity check: session changes can invalidate an inherent, and we _really_ don't want that to happen.
|
||||
// See github.com/paritytech/polkadot/issues/1327
|
||||
let inherent_data = match Self::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
inherent_data.clone(),
|
||||
) {
|
||||
Ok(_) => inherent_data,
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"dropping signed_bitfields and backed_candidates because they produced \
|
||||
let inherent_data =
|
||||
match Self::enter(frame_system::RawOrigin::None.into(), inherent_data.clone()) {
|
||||
Ok(_) => inherent_data,
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"dropping signed_bitfields and backed_candidates because they produced \
|
||||
an invalid paras inherent: {:?}",
|
||||
err,
|
||||
);
|
||||
err,
|
||||
);
|
||||
|
||||
ParachainsInherentData {
|
||||
bitfields: Vec::new(),
|
||||
backed_candidates: Vec::new(),
|
||||
disputes: Vec::new(),
|
||||
parent_header: inherent_data.parent_header,
|
||||
}
|
||||
}
|
||||
};
|
||||
ParachainsInherentData {
|
||||
bitfields: Vec::new(),
|
||||
backed_candidates: Vec::new(),
|
||||
disputes: Vec::new(),
|
||||
parent_header: inherent_data.parent_header,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Some(Call::enter(inherent_data))
|
||||
}
|
||||
@@ -325,9 +321,7 @@ impl<T: Config> ProvideInherent for Module<T> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::mock::{
|
||||
new_test_ext, System, MockGenesisConfig, Test
|
||||
};
|
||||
use crate::mock::{new_test_ext, MockGenesisConfig, System, Test};
|
||||
|
||||
mod limit_backed_candidates {
|
||||
use super::*;
|
||||
@@ -345,7 +339,8 @@ mod tests {
|
||||
fn does_not_truncate_on_exactly_full_block() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
let backed_candidates = vec![BackedCandidate::default()];
|
||||
let max_block_weight = <Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let max_block_weight =
|
||||
<Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
// if the consumed resources are precisely equal to the max block weight, we do not truncate.
|
||||
System::set_block_consumed_resources(max_block_weight, 0);
|
||||
assert_eq!(limit_backed_candidates::<Test>(backed_candidates).len(), 1);
|
||||
@@ -356,7 +351,8 @@ mod tests {
|
||||
fn truncates_on_over_full_block() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
let backed_candidates = vec![BackedCandidate::default()];
|
||||
let max_block_weight = <Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let max_block_weight =
|
||||
<Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
// if the consumed resources are precisely equal to the max block weight, we do not truncate.
|
||||
System::set_block_consumed_resources(max_block_weight + 1, 0);
|
||||
assert_eq!(limit_backed_candidates::<Test>(backed_candidates).len(), 0);
|
||||
@@ -367,7 +363,8 @@ mod tests {
|
||||
fn all_backed_candidates_get_truncated() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
let backed_candidates = vec![BackedCandidate::default(); 10];
|
||||
let max_block_weight = <Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let max_block_weight =
|
||||
<Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
// if the consumed resources are precisely equal to the max block weight, we do not truncate.
|
||||
System::set_block_consumed_resources(max_block_weight + 1, 0);
|
||||
assert_eq!(limit_backed_candidates::<Test>(backed_candidates).len(), 0);
|
||||
@@ -388,9 +385,7 @@ mod tests {
|
||||
mod paras_inherent_weight {
|
||||
use super::*;
|
||||
|
||||
use crate::mock::{
|
||||
new_test_ext, System, MockGenesisConfig, Test
|
||||
};
|
||||
use crate::mock::{new_test_ext, MockGenesisConfig, System, Test};
|
||||
use primitives::v1::Header;
|
||||
|
||||
use frame_support::traits::UnfilteredDispatchable;
|
||||
@@ -425,7 +420,8 @@ mod tests {
|
||||
(backed_candidates.len() as Weight * BACKED_CANDIDATE_WEIGHT);
|
||||
|
||||
// we've used half the block weight; there's plenty of margin
|
||||
let max_block_weight = <Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let max_block_weight =
|
||||
<Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let used_block_weight = max_block_weight / 2;
|
||||
System::set_block_consumed_resources(used_block_weight, 0);
|
||||
|
||||
@@ -436,7 +432,9 @@ mod tests {
|
||||
disputes: Vec::new(),
|
||||
parent_header: default_header(),
|
||||
})
|
||||
.dispatch_bypass_filter(None.into()).unwrap_err().post_info;
|
||||
.dispatch_bypass_filter(None.into())
|
||||
.unwrap_err()
|
||||
.post_info;
|
||||
|
||||
// we don't directly check the block's weight post-call. Instead, we check that the
|
||||
// call has returned the appropriate post-dispatch weight for refund, and trust
|
||||
@@ -470,7 +468,8 @@ mod tests {
|
||||
let expected_weight = MINIMAL_INCLUSION_INHERENT_WEIGHT;
|
||||
|
||||
// oops, looks like this mandatory call pushed the block weight over the limit
|
||||
let max_block_weight = <Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let max_block_weight =
|
||||
<Test as frame_system::Config>::BlockWeights::get().max_block;
|
||||
let used_block_weight = max_block_weight + 1;
|
||||
System::set_block_consumed_resources(used_block_weight, 0);
|
||||
|
||||
@@ -481,15 +480,13 @@ mod tests {
|
||||
disputes: Vec::new(),
|
||||
parent_header: header,
|
||||
})
|
||||
.dispatch_bypass_filter(None.into()).unwrap();
|
||||
.dispatch_bypass_filter(None.into())
|
||||
.unwrap();
|
||||
|
||||
// we don't directly check the block's weight post-call. Instead, we check that the
|
||||
// call has returned the appropriate post-dispatch weight for refund, and trust
|
||||
// Substrate to do the right thing with that information.
|
||||
assert_eq!(
|
||||
post_info.actual_weight.unwrap(),
|
||||
expected_weight,
|
||||
);
|
||||
assert_eq!(post_info.actual_weight.unwrap(), expected_weight,);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
//! which doesn't currently mention availability bitfields. As such, we don't reward them
|
||||
//! for the time being, although we will build schemes to do so in the future.
|
||||
|
||||
use primitives::v1::ValidatorIndex;
|
||||
use pallet_staking::SessionInterface;
|
||||
use crate::shared;
|
||||
use pallet_staking::SessionInterface;
|
||||
use primitives::v1::ValidatorIndex;
|
||||
|
||||
/// The amount of era points given by backing a candidate that is included.
|
||||
pub const BACKING_POINTS: u32 = 20;
|
||||
@@ -31,21 +31,27 @@ pub const BACKING_POINTS: u32 = 20;
|
||||
/// Rewards validators for participating in parachains with era points in pallet-staking.
|
||||
pub struct RewardValidatorsWithEraPoints<C>(sp_std::marker::PhantomData<C>);
|
||||
|
||||
fn validators_to_reward<C, T, I>(validators: &'_ [T], indirect_indices: I) -> impl IntoIterator<Item=&'_ T> where
|
||||
fn validators_to_reward<C, T, I>(
|
||||
validators: &'_ [T],
|
||||
indirect_indices: I,
|
||||
) -> impl IntoIterator<Item = &'_ T>
|
||||
where
|
||||
C: shared::Config,
|
||||
I: IntoIterator<Item = ValidatorIndex>
|
||||
I: IntoIterator<Item = ValidatorIndex>,
|
||||
{
|
||||
let validator_indirection = <shared::Pallet<C>>::active_validator_indices();
|
||||
|
||||
indirect_indices.into_iter()
|
||||
indirect_indices
|
||||
.into_iter()
|
||||
.filter_map(move |i| validator_indirection.get(i.0 as usize).map(|v| v.clone()))
|
||||
.filter_map(move |i| validators.get(i.0 as usize))
|
||||
}
|
||||
|
||||
impl<C> crate::inclusion::RewardValidators for RewardValidatorsWithEraPoints<C>
|
||||
where C: pallet_staking::Config + shared::Config,
|
||||
where
|
||||
C: pallet_staking::Config + shared::Config,
|
||||
{
|
||||
fn reward_backing(indirect_indices: impl IntoIterator<Item=ValidatorIndex>) {
|
||||
fn reward_backing(indirect_indices: impl IntoIterator<Item = ValidatorIndex>) {
|
||||
// Fetch the validators from the _session_ because sessions are offset from eras
|
||||
// and we are rewarding for behavior in current session.
|
||||
let validators = C::SessionInterface::validators();
|
||||
@@ -57,16 +63,18 @@ impl<C> crate::inclusion::RewardValidators for RewardValidatorsWithEraPoints<C>
|
||||
<pallet_staking::Pallet<C>>::reward_by_ids(rewards);
|
||||
}
|
||||
|
||||
fn reward_bitfields(_validators: impl IntoIterator<Item=ValidatorIndex>) { }
|
||||
fn reward_bitfields(_validators: impl IntoIterator<Item = ValidatorIndex>) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primitives::v1::ValidatorId;
|
||||
use crate::configuration::HostConfiguration;
|
||||
use crate::mock::{new_test_ext, MockGenesisConfig, ParasShared, Test};
|
||||
use crate::{
|
||||
configuration::HostConfiguration,
|
||||
mock::{new_test_ext, MockGenesisConfig, ParasShared, Test},
|
||||
};
|
||||
use keyring::Sr25519Keyring;
|
||||
use primitives::v1::ValidatorId;
|
||||
|
||||
#[test]
|
||||
fn rewards_based_on_indirection() {
|
||||
@@ -88,12 +96,8 @@ mod tests {
|
||||
|
||||
let pubkeys = validator_pubkeys(&validators);
|
||||
|
||||
let shuffled_pubkeys = ParasShared::initializer_on_new_session(
|
||||
1,
|
||||
[1; 32],
|
||||
&config,
|
||||
pubkeys,
|
||||
);
|
||||
let shuffled_pubkeys =
|
||||
ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys);
|
||||
|
||||
assert_eq!(
|
||||
shuffled_pubkeys,
|
||||
@@ -121,7 +125,10 @@ mod tests {
|
||||
validators_to_reward::<Test, _, _>(
|
||||
&validators,
|
||||
vec![ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(2)],
|
||||
).into_iter().copied().collect::<Vec<_>>(),
|
||||
)
|
||||
.into_iter()
|
||||
.copied()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Sr25519Keyring::Ferdie, Sr25519Keyring::Bob, Sr25519Keyring::Charlie],
|
||||
);
|
||||
})
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
//! Runtimes implementing the v1 runtime API are recommended to forward directly to these
|
||||
//! functions.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::collections::btree_map::BTreeMap;
|
||||
use sp_runtime::traits::One;
|
||||
use crate::{
|
||||
configuration, dmp, hrmp, inclusion, initializer, paras, scheduler, session_info, shared,
|
||||
};
|
||||
use primitives::v1::{
|
||||
AuthorityDiscoveryId, CandidateEvent, CommittedCandidateReceipt, CoreIndex, CoreOccupied,
|
||||
CoreState, GroupIndex, GroupRotationInfo, Id as ParaId, InboundDownwardMessage,
|
||||
@@ -27,8 +27,8 @@ use primitives::v1::{
|
||||
ScheduledCore, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId,
|
||||
ValidatorIndex,
|
||||
};
|
||||
use crate::{initializer, inclusion, scheduler, configuration, paras, session_info, dmp, hrmp, shared};
|
||||
|
||||
use sp_runtime::traits::One;
|
||||
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
|
||||
/// Implementation for the `validators` function of the runtime API.
|
||||
pub fn validators<T: initializer::Config>() -> Vec<ValidatorId> {
|
||||
@@ -36,10 +36,8 @@ pub fn validators<T: initializer::Config>() -> Vec<ValidatorId> {
|
||||
}
|
||||
|
||||
/// Implementation for the `validator_groups` function of the runtime API.
|
||||
pub fn validator_groups<T: initializer::Config>() -> (
|
||||
Vec<Vec<ValidatorIndex>>,
|
||||
GroupRotationInfo<T::BlockNumber>,
|
||||
) {
|
||||
pub fn validator_groups<T: initializer::Config>(
|
||||
) -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<T::BlockNumber>) {
|
||||
let now = <frame_system::Pallet<T>>::block_number() + One::one();
|
||||
|
||||
let groups = <scheduler::Pallet<T>>::validator_groups();
|
||||
@@ -80,10 +78,13 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
|
||||
}
|
||||
};
|
||||
|
||||
let group_responsible_for = |backed_in_number, core_index| {
|
||||
match <scheduler::Pallet<T>>::group_assigned_to_core(core_index, backed_in_number) {
|
||||
let group_responsible_for =
|
||||
|backed_in_number, core_index| match <scheduler::Pallet<T>>::group_assigned_to_core(
|
||||
core_index,
|
||||
backed_in_number,
|
||||
) {
|
||||
Some(g) => g,
|
||||
None => {
|
||||
None => {
|
||||
log::warn!(
|
||||
target: "runtime::polkadot-api::v1",
|
||||
"Could not determine the group responsible for core extracted \
|
||||
@@ -91,23 +92,24 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
|
||||
);
|
||||
|
||||
GroupIndex(0)
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
let mut core_states: Vec<_> = cores.into_iter().enumerate().map(|(i, core)| match core {
|
||||
Some(occupied) => {
|
||||
CoreState::Occupied(match occupied {
|
||||
let mut core_states: Vec<_> = cores
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, core)| match core {
|
||||
Some(occupied) => CoreState::Occupied(match occupied {
|
||||
CoreOccupied::Parachain => {
|
||||
let para_id = parachains[i];
|
||||
let pending_availability = <inclusion::Pallet<T>>
|
||||
::pending_availability(para_id)
|
||||
.expect("Occupied core always has pending availability; qed");
|
||||
let pending_availability =
|
||||
<inclusion::Pallet<T>>::pending_availability(para_id)
|
||||
.expect("Occupied core always has pending availability; qed");
|
||||
|
||||
let backed_in_number = pending_availability.backed_in_number().clone();
|
||||
OccupiedCore {
|
||||
next_up_on_available: <scheduler::Pallet<T>>::next_up_on_available(
|
||||
CoreIndex(i as u32)
|
||||
CoreIndex(i as u32),
|
||||
),
|
||||
occupied_since: backed_in_number,
|
||||
time_out_at: time_out_at(
|
||||
@@ -115,7 +117,7 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
|
||||
config.chain_availability_period,
|
||||
),
|
||||
next_up_on_time_out: <scheduler::Pallet<T>>::next_up_on_time_out(
|
||||
CoreIndex(i as u32)
|
||||
CoreIndex(i as u32),
|
||||
),
|
||||
availability: pending_availability.availability_votes().clone(),
|
||||
group_responsible: group_responsible_for(
|
||||
@@ -125,17 +127,17 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
|
||||
candidate_hash: pending_availability.candidate_hash(),
|
||||
candidate_descriptor: pending_availability.candidate_descriptor().clone(),
|
||||
}
|
||||
}
|
||||
},
|
||||
CoreOccupied::Parathread(p) => {
|
||||
let para_id = p.claim.0;
|
||||
let pending_availability = <inclusion::Pallet<T>>
|
||||
::pending_availability(para_id)
|
||||
.expect("Occupied core always has pending availability; qed");
|
||||
let pending_availability =
|
||||
<inclusion::Pallet<T>>::pending_availability(para_id)
|
||||
.expect("Occupied core always has pending availability; qed");
|
||||
|
||||
let backed_in_number = pending_availability.backed_in_number().clone();
|
||||
OccupiedCore {
|
||||
next_up_on_available: <scheduler::Pallet<T>>::next_up_on_available(
|
||||
CoreIndex(i as u32)
|
||||
CoreIndex(i as u32),
|
||||
),
|
||||
occupied_since: backed_in_number,
|
||||
time_out_at: time_out_at(
|
||||
@@ -143,7 +145,7 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
|
||||
config.thread_availability_period,
|
||||
),
|
||||
next_up_on_time_out: <scheduler::Pallet<T>>::next_up_on_time_out(
|
||||
CoreIndex(i as u32)
|
||||
CoreIndex(i as u32),
|
||||
),
|
||||
availability: pending_availability.availability_votes().clone(),
|
||||
group_responsible: group_responsible_for(
|
||||
@@ -153,11 +155,11 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, T:
|
||||
candidate_hash: pending_availability.candidate_hash(),
|
||||
candidate_descriptor: pending_availability.candidate_descriptor().clone(),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
None => CoreState::Free,
|
||||
}).collect();
|
||||
},
|
||||
}),
|
||||
None => CoreState::Free,
|
||||
})
|
||||
.collect();
|
||||
|
||||
// This will overwrite only `Free` cores if the scheduler module is working as intended.
|
||||
for scheduled in <scheduler::Pallet<T>>::scheduled() {
|
||||
@@ -174,7 +176,8 @@ fn with_assumption<Config, T, F>(
|
||||
para_id: ParaId,
|
||||
assumption: OccupiedCoreAssumption,
|
||||
build: F,
|
||||
) -> Option<T> where
|
||||
) -> Option<T>
|
||||
where
|
||||
Config: inclusion::Config,
|
||||
F: FnOnce() -> Option<T>,
|
||||
{
|
||||
@@ -182,17 +185,15 @@ fn with_assumption<Config, T, F>(
|
||||
OccupiedCoreAssumption::Included => {
|
||||
<inclusion::Pallet<Config>>::force_enact(para_id);
|
||||
build()
|
||||
}
|
||||
OccupiedCoreAssumption::TimedOut => {
|
||||
build()
|
||||
}
|
||||
},
|
||||
OccupiedCoreAssumption::TimedOut => build(),
|
||||
OccupiedCoreAssumption::Free => {
|
||||
if <inclusion::Pallet<Config>>::pending_availability(para_id).is_some() {
|
||||
None
|
||||
} else {
|
||||
build()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +238,8 @@ pub fn session_index_for_child<T: initializer::Config>() -> SessionIndex {
|
||||
/// Implementation for the `AuthorityDiscoveryApi::authorities()` function of the runtime API.
|
||||
/// It is a heavy call, but currently only used for authority discovery, so it is fine.
|
||||
/// Gets next, current and some historical authority ids using `session_info` module.
|
||||
pub fn relevant_authority_ids<T: initializer::Config + pallet_authority_discovery::Config>() -> Vec<AuthorityDiscoveryId> {
|
||||
pub fn relevant_authority_ids<T: initializer::Config + pallet_authority_discovery::Config>(
|
||||
) -> Vec<AuthorityDiscoveryId> {
|
||||
let current_session_index = session_index_for_child::<T>();
|
||||
let earliest_stored_session = <session_info::Pallet<T>>::earliest_stored_session();
|
||||
|
||||
@@ -267,17 +269,13 @@ pub fn validation_code<T: initializer::Config>(
|
||||
para_id: ParaId,
|
||||
assumption: OccupiedCoreAssumption,
|
||||
) -> Option<ValidationCode> {
|
||||
with_assumption::<T, _, _>(
|
||||
para_id,
|
||||
assumption,
|
||||
|| <paras::Pallet<T>>::current_code(¶_id),
|
||||
)
|
||||
with_assumption::<T, _, _>(para_id, assumption, || <paras::Pallet<T>>::current_code(¶_id))
|
||||
}
|
||||
|
||||
/// Implementation for the `candidate_pending_availability` function of the runtime API.
|
||||
pub fn candidate_pending_availability<T: initializer::Config>(para_id: ParaId)
|
||||
-> Option<CommittedCandidateReceipt<T::Hash>>
|
||||
{
|
||||
pub fn candidate_pending_availability<T: initializer::Config>(
|
||||
para_id: ParaId,
|
||||
) -> Option<CommittedCandidateReceipt<T::Hash>> {
|
||||
<inclusion::Pallet<T>>::candidate_pending_availability(para_id)
|
||||
}
|
||||
|
||||
@@ -291,17 +289,17 @@ where
|
||||
{
|
||||
use inclusion::Event as RawEvent;
|
||||
|
||||
<frame_system::Pallet<T>>::events().into_iter()
|
||||
<frame_system::Pallet<T>>::events()
|
||||
.into_iter()
|
||||
.filter_map(|record| extract_event(record.event))
|
||||
.map(|event| match event {
|
||||
RawEvent::<T>::CandidateBacked(c, h, core, group)
|
||||
=> CandidateEvent::CandidateBacked(c, h, core, group),
|
||||
RawEvent::<T>::CandidateIncluded(c, h, core, group)
|
||||
=> CandidateEvent::CandidateIncluded(c, h, core, group),
|
||||
RawEvent::<T>::CandidateTimedOut(c, h, core)
|
||||
=> CandidateEvent::CandidateTimedOut(c, h, core),
|
||||
RawEvent::<T>::__Ignore(_, _)
|
||||
=> unreachable!("__Ignore cannot be used"),
|
||||
RawEvent::<T>::CandidateBacked(c, h, core, group) =>
|
||||
CandidateEvent::CandidateBacked(c, h, core, group),
|
||||
RawEvent::<T>::CandidateIncluded(c, h, core, group) =>
|
||||
CandidateEvent::CandidateIncluded(c, h, core, group),
|
||||
RawEvent::<T>::CandidateTimedOut(c, h, core) =>
|
||||
CandidateEvent::CandidateTimedOut(c, h, core),
|
||||
RawEvent::<T>::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,11 +19,9 @@
|
||||
//!
|
||||
//! See https://w3f.github.io/parachain-implementers-guide/runtime/session_info.html.
|
||||
|
||||
use crate::{configuration, paras, scheduler, shared, util::take_active_subset};
|
||||
use frame_support::{pallet_prelude::*, traits::OneSessionHandler};
|
||||
use primitives::v1::{AssignmentId, AuthorityDiscoveryId, SessionIndex, SessionInfo};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_support::traits::OneSessionHandler;
|
||||
use crate::{configuration, paras, scheduler, shared};
|
||||
use crate::util::take_active_subset;
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
pub use pallet::*;
|
||||
@@ -51,7 +49,8 @@ pub mod pallet {
|
||||
/// Note that this API is private due to it being prone to 'off-by-one' at session boundaries.
|
||||
/// When in doubt, use `Sessions` API instead.
|
||||
#[pallet::storage]
|
||||
pub(super) type AssignmentKeysUnsafe<T: Config> = StorageValue<_, Vec<AssignmentId>, ValueQuery>;
|
||||
pub(super) type AssignmentKeysUnsafe<T: Config> =
|
||||
StorageValue<_, Vec<AssignmentId>, ValueQuery>;
|
||||
|
||||
/// The earliest session for which previous session info is stored.
|
||||
#[pallet::storage]
|
||||
@@ -82,7 +81,7 @@ impl<T: pallet_authority_discovery::Config> AuthorityDiscoveryConfig for T {
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Handle an incoming session change.
|
||||
pub(crate) fn initializer_on_new_session(
|
||||
notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>
|
||||
notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>,
|
||||
) {
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
|
||||
@@ -104,7 +103,8 @@ impl<T: Config> Pallet<T> {
|
||||
let new_session_index = notification.session_index;
|
||||
let old_earliest_stored_session = EarliestStoredSession::<T>::get();
|
||||
let new_earliest_stored_session = new_session_index.saturating_sub(dispute_period);
|
||||
let new_earliest_stored_session = core::cmp::max(new_earliest_stored_session, old_earliest_stored_session);
|
||||
let new_earliest_stored_session =
|
||||
core::cmp::max(new_earliest_stored_session, old_earliest_stored_session);
|
||||
// remove all entries from `Sessions` from the previous value up to the new value
|
||||
// avoid a potentially heavy loop when introduced on a live chain
|
||||
if old_earliest_stored_session != 0 || Sessions::<T>::get(0).is_some() {
|
||||
@@ -150,33 +150,35 @@ impl<T: pallet_session::Config + Config> OneSessionHandler<T::AccountId> for Pal
|
||||
type Key = AssignmentId;
|
||||
|
||||
fn on_genesis_session<'a, I: 'a>(_validators: I)
|
||||
where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
|
||||
where
|
||||
I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, _queued: I)
|
||||
where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
|
||||
where
|
||||
I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
|
||||
{
|
||||
let assignment_keys: Vec<_> = validators.map(|(_, v)| v).collect();
|
||||
AssignmentKeysUnsafe::<T>::set(assignment_keys);
|
||||
}
|
||||
|
||||
fn on_disabled(_i: usize) { }
|
||||
fn on_disabled(_i: usize) {}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
new_test_ext, Configuration, SessionInfo, System, MockGenesisConfig,
|
||||
Origin, ParasShared, Test
|
||||
use crate::{
|
||||
configuration::HostConfiguration,
|
||||
initializer::SessionChangeNotification,
|
||||
mock::{
|
||||
new_test_ext, Configuration, MockGenesisConfig, Origin, ParasShared, SessionInfo,
|
||||
System, Test,
|
||||
},
|
||||
};
|
||||
use crate::initializer::SessionChangeNotification;
|
||||
use crate::configuration::HostConfiguration;
|
||||
use primitives::v1::{BlockNumber, ValidatorId, ValidatorIndex};
|
||||
use keyring::Sr25519Keyring;
|
||||
use primitives::v1::{BlockNumber, ValidatorId, ValidatorIndex};
|
||||
|
||||
fn run_to_block(
|
||||
to: BlockNumber,
|
||||
@@ -190,9 +192,7 @@ mod tests {
|
||||
Configuration::initializer_finalize();
|
||||
|
||||
if let Some(notification) = new_session(b + 1) {
|
||||
Configuration::initializer_on_new_session(
|
||||
¬ification.session_index,
|
||||
);
|
||||
Configuration::initializer_on_new_session(¬ification.session_index);
|
||||
ParasShared::initializer_on_new_session(
|
||||
notification.session_index,
|
||||
notification.random_seed,
|
||||
@@ -234,20 +234,14 @@ mod tests {
|
||||
|
||||
fn session_changes(n: BlockNumber) -> Option<SessionChangeNotification<BlockNumber>> {
|
||||
if n % 10 == 0 {
|
||||
Some(SessionChangeNotification {
|
||||
session_index: n / 10,
|
||||
..Default::default()
|
||||
})
|
||||
Some(SessionChangeNotification { session_index: n / 10, ..Default::default() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn new_session_every_block(n: BlockNumber) -> Option<SessionChangeNotification<BlockNumber>> {
|
||||
Some(SessionChangeNotification{
|
||||
session_index: n,
|
||||
..Default::default()
|
||||
})
|
||||
Some(SessionChangeNotification { session_index: n, ..Default::default() })
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -333,20 +327,17 @@ mod tests {
|
||||
|
||||
let active_set = vec![ValidatorIndex(4), ValidatorIndex(0), ValidatorIndex(2)];
|
||||
|
||||
let unscrambled_validators: Vec<ValidatorId>
|
||||
= unscrambled.iter().map(|v| v.public().into()).collect();
|
||||
let unscrambled_discovery: Vec<AuthorityDiscoveryId>
|
||||
= unscrambled.iter().map(|v| v.public().into()).collect();
|
||||
let unscrambled_assignment: Vec<AssignmentId>
|
||||
= unscrambled.iter().map(|v| v.public().into()).collect();
|
||||
let unscrambled_validators: Vec<ValidatorId> =
|
||||
unscrambled.iter().map(|v| v.public().into()).collect();
|
||||
let unscrambled_discovery: Vec<AuthorityDiscoveryId> =
|
||||
unscrambled.iter().map(|v| v.public().into()).collect();
|
||||
let unscrambled_assignment: Vec<AssignmentId> =
|
||||
unscrambled.iter().map(|v| v.public().into()).collect();
|
||||
|
||||
let validators = take_active_subset(&active_set, &unscrambled_validators);
|
||||
|
||||
new_test_ext(genesis_config()).execute_with(|| {
|
||||
ParasShared::set_active_validators_with_indices(
|
||||
active_set.clone(),
|
||||
validators.clone(),
|
||||
);
|
||||
ParasShared::set_active_validators_with_indices(active_set.clone(), validators.clone());
|
||||
|
||||
assert_eq!(ParasShared::active_validator_indices(), active_set);
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
//! To avoid cyclic dependencies, it is important that this pallet is not
|
||||
//! dependent on any of the other pallets.
|
||||
|
||||
use primitives::v1::{SessionIndex, ValidatorId, ValidatorIndex};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use primitives::v1::{SessionIndex, ValidatorId, ValidatorIndex};
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use rand::{SeedableRng, seq::SliceRandom};
|
||||
use rand::{seq::SliceRandom, SeedableRng};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
|
||||
use crate::configuration::HostConfiguration;
|
||||
@@ -55,7 +55,8 @@ pub mod pallet {
|
||||
/// Indices are into the broader validator set.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn active_validator_indices)]
|
||||
pub(super) type ActiveValidatorIndices<T: Config> = StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
|
||||
pub(super) type ActiveValidatorIndices<T: Config> =
|
||||
StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
|
||||
|
||||
/// The parachain attestation keys of the validators actively participating in parachain consensus.
|
||||
/// This should be the same length as `ActiveValidatorIndices`.
|
||||
@@ -74,7 +75,7 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
/// Called by the initializer to finalize the configuration pallet.
|
||||
pub(crate) fn initializer_finalize() { }
|
||||
pub(crate) fn initializer_finalize() {}
|
||||
|
||||
/// Called by the initializer to note that a new session has started.
|
||||
///
|
||||
@@ -99,10 +100,8 @@ impl<T: Config> Pallet<T> {
|
||||
shuffled_indices.truncate(max as usize);
|
||||
}
|
||||
|
||||
let active_validator_keys = crate::util::take_active_subset(
|
||||
&shuffled_indices,
|
||||
&all_validators,
|
||||
);
|
||||
let active_validator_keys =
|
||||
crate::util::take_active_subset(&shuffled_indices, &all_validators);
|
||||
|
||||
ActiveValidatorIndices::<T>::set(shuffled_indices);
|
||||
ActiveValidatorKeys::<T>::set(active_validator_keys.clone());
|
||||
@@ -124,7 +123,7 @@ impl<T: Config> Pallet<T> {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn set_active_validators_ascending(active: Vec<ValidatorId>) {
|
||||
ActiveValidatorIndices::<T>::set(
|
||||
(0..active.len()).map(|i| ValidatorIndex(i as _)).collect()
|
||||
(0..active.len()).map(|i| ValidatorIndex(i as _)).collect(),
|
||||
);
|
||||
ActiveValidatorKeys::<T>::set(active);
|
||||
}
|
||||
@@ -143,8 +142,10 @@ impl<T: Config> Pallet<T> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::configuration::HostConfiguration;
|
||||
use crate::mock::{new_test_ext, MockGenesisConfig, ParasShared};
|
||||
use crate::{
|
||||
configuration::HostConfiguration,
|
||||
mock::{new_test_ext, MockGenesisConfig, ParasShared},
|
||||
};
|
||||
use keyring::Sr25519Keyring;
|
||||
|
||||
fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> {
|
||||
@@ -167,12 +168,7 @@ mod tests {
|
||||
let pubkeys = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
let validators = ParasShared::initializer_on_new_session(
|
||||
1,
|
||||
[1; 32],
|
||||
&config,
|
||||
pubkeys,
|
||||
);
|
||||
let validators = ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys);
|
||||
|
||||
assert_eq!(
|
||||
validators,
|
||||
@@ -185,10 +181,7 @@ mod tests {
|
||||
])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
ParasShared::active_validator_keys(),
|
||||
validators,
|
||||
);
|
||||
assert_eq!(ParasShared::active_validator_keys(), validators,);
|
||||
|
||||
assert_eq!(
|
||||
ParasShared::active_validator_indices(),
|
||||
@@ -219,32 +212,18 @@ mod tests {
|
||||
let pubkeys = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
let validators = ParasShared::initializer_on_new_session(
|
||||
1,
|
||||
[1; 32],
|
||||
&config,
|
||||
pubkeys,
|
||||
);
|
||||
let validators = ParasShared::initializer_on_new_session(1, [1; 32], &config, pubkeys);
|
||||
|
||||
assert_eq!(
|
||||
validators,
|
||||
validator_pubkeys(&[
|
||||
Sr25519Keyring::Ferdie,
|
||||
Sr25519Keyring::Bob,
|
||||
])
|
||||
validator_pubkeys(&[Sr25519Keyring::Ferdie, Sr25519Keyring::Bob,])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
ParasShared::active_validator_keys(),
|
||||
validators,
|
||||
);
|
||||
assert_eq!(ParasShared::active_validator_keys(), validators,);
|
||||
|
||||
assert_eq!(
|
||||
ParasShared::active_validator_indices(),
|
||||
vec![
|
||||
ValidatorIndex(4),
|
||||
ValidatorIndex(1),
|
||||
]
|
||||
vec![ValidatorIndex(4), ValidatorIndex(1),]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,10 +18,15 @@ use crate::{
|
||||
configuration::{self, HostConfiguration},
|
||||
initializer,
|
||||
};
|
||||
use sp_std::{prelude::*, fmt, marker::PhantomData, convert::TryFrom};
|
||||
use sp_std::collections::{btree_map::BTreeMap, vec_deque::VecDeque};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use primitives::v1::{Id as ParaId, UpwardMessage};
|
||||
use sp_std::{
|
||||
collections::{btree_map::BTreeMap, vec_deque::VecDeque},
|
||||
convert::TryFrom,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
prelude::*,
|
||||
};
|
||||
use xcm::v0::Outcome;
|
||||
|
||||
pub use pallet::*;
|
||||
@@ -46,13 +51,21 @@ pub trait UmpSink {
|
||||
/// it did not begin processing a message since it would otherwise exceed `max_weight`.
|
||||
///
|
||||
/// See the trait docs for more details.
|
||||
fn process_upward_message(origin: ParaId, msg: &[u8], max_weight: Weight) -> Result<Weight, (MessageId, Weight)>;
|
||||
fn process_upward_message(
|
||||
origin: ParaId,
|
||||
msg: &[u8],
|
||||
max_weight: Weight,
|
||||
) -> Result<Weight, (MessageId, Weight)>;
|
||||
}
|
||||
|
||||
/// An implementation of a sink that just swallows the message without consuming any weight. Returns
|
||||
/// `Some(0)` indicating that no messages existed for it to process.
|
||||
impl UmpSink for () {
|
||||
fn process_upward_message(_: ParaId, _: &[u8], _: Weight) -> Result<Weight, (MessageId, Weight)> {
|
||||
fn process_upward_message(
|
||||
_: ParaId,
|
||||
_: &[u8],
|
||||
_: Weight,
|
||||
) -> Result<Weight, (MessageId, Weight)> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
@@ -66,13 +79,19 @@ pub type MessageId = [u8; 32];
|
||||
pub struct XcmSink<XcmExecutor, Config>(PhantomData<(XcmExecutor, Config)>);
|
||||
|
||||
impl<XcmExecutor: xcm::v0::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> {
|
||||
fn process_upward_message(origin: ParaId, data: &[u8], max_weight: Weight) -> Result<Weight, (MessageId, Weight)> {
|
||||
use xcm::VersionedXcm;
|
||||
use xcm::v0::{Xcm, Junction, MultiLocation, Error as XcmError};
|
||||
fn process_upward_message(
|
||||
origin: ParaId,
|
||||
data: &[u8],
|
||||
max_weight: Weight,
|
||||
) -> Result<Weight, (MessageId, Weight)> {
|
||||
use xcm::{
|
||||
v0::{Error as XcmError, Junction, MultiLocation, Xcm},
|
||||
VersionedXcm,
|
||||
};
|
||||
|
||||
let id = sp_io::hashing::blake2_256(&data[..]);
|
||||
let maybe_msg = VersionedXcm::<C::Call>::decode(&mut &data[..])
|
||||
.map(Xcm::<C::Call>::try_from);
|
||||
let maybe_msg =
|
||||
VersionedXcm::<C::Call>::decode(&mut &data[..]).map(Xcm::<C::Call>::try_from);
|
||||
match maybe_msg {
|
||||
Err(_) => {
|
||||
Pallet::<C>::deposit_event(Event::InvalidFormat(id));
|
||||
@@ -92,9 +111,9 @@ impl<XcmExecutor: xcm::v0::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<X
|
||||
let weight_used = outcome.weight_used();
|
||||
Pallet::<C>::deposit_event(Event::ExecutedUpward(id, outcome));
|
||||
Ok(weight_used)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,23 +121,10 @@ impl<XcmExecutor: xcm::v0::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<X
|
||||
/// An error returned by [`check_upward_messages`] that indicates a violation of one of acceptance
|
||||
/// criteria rules.
|
||||
pub enum AcceptanceCheckErr {
|
||||
MoreMessagesThanPermitted {
|
||||
sent: u32,
|
||||
permitted: u32,
|
||||
},
|
||||
MessageSize {
|
||||
idx: u32,
|
||||
msg_size: u32,
|
||||
max_size: u32,
|
||||
},
|
||||
CapacityExceeded {
|
||||
count: u32,
|
||||
limit: u32,
|
||||
},
|
||||
TotalSizeExceeded {
|
||||
total_size: u32,
|
||||
limit: u32,
|
||||
},
|
||||
MoreMessagesThanPermitted { sent: u32, permitted: u32 },
|
||||
MessageSize { idx: u32, msg_size: u32, max_size: u32 },
|
||||
CapacityExceeded { count: u32, limit: u32 },
|
||||
TotalSizeExceeded { total_size: u32, limit: u32 },
|
||||
}
|
||||
|
||||
impl fmt::Debug for AcceptanceCheckErr {
|
||||
@@ -129,11 +135,7 @@ impl fmt::Debug for AcceptanceCheckErr {
|
||||
"more upward messages than permitted by config ({} > {})",
|
||||
sent, permitted,
|
||||
),
|
||||
AcceptanceCheckErr::MessageSize {
|
||||
idx,
|
||||
msg_size,
|
||||
max_size,
|
||||
} => write!(
|
||||
AcceptanceCheckErr::MessageSize { idx, msg_size, max_size } => write!(
|
||||
fmt,
|
||||
"upward message idx {} larger than permitted by config ({} > {})",
|
||||
idx, msg_size, max_size,
|
||||
@@ -204,13 +206,8 @@ pub mod pallet {
|
||||
///
|
||||
/// The messages are processed in FIFO order.
|
||||
#[pallet::storage]
|
||||
pub type RelayDispatchQueues<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
VecDeque<UpwardMessage>,
|
||||
ValueQuery
|
||||
>;
|
||||
pub type RelayDispatchQueues<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, VecDeque<UpwardMessage>, ValueQuery>;
|
||||
|
||||
/// Size of the dispatch queues. Caches sizes of the queues in `RelayDispatchQueue`.
|
||||
///
|
||||
@@ -226,13 +223,8 @@ pub mod pallet {
|
||||
// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
|
||||
// the format will require migration of parachains.
|
||||
#[pallet::storage]
|
||||
pub type RelayDispatchQueueSize<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
(u32, u32),
|
||||
ValueQuery
|
||||
>;
|
||||
pub type RelayDispatchQueueSize<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, (u32, u32), ValueQuery>;
|
||||
|
||||
/// The ordered list of `ParaId`s that have a `RelayDispatchQueue` entry.
|
||||
///
|
||||
@@ -311,7 +303,7 @@ impl<T: Config> Pallet<T> {
|
||||
return Err(AcceptanceCheckErr::MoreMessagesThanPermitted {
|
||||
sent: upward_messages.len() as u32,
|
||||
permitted: config.max_upward_message_num_per_candidate,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
let (mut para_queue_count, mut para_queue_size) =
|
||||
@@ -324,7 +316,7 @@ impl<T: Config> Pallet<T> {
|
||||
idx: idx as u32,
|
||||
msg_size,
|
||||
max_size: config.max_upward_message_size,
|
||||
});
|
||||
})
|
||||
}
|
||||
para_queue_count += 1;
|
||||
para_queue_size += msg_size;
|
||||
@@ -336,13 +328,13 @@ impl<T: Config> Pallet<T> {
|
||||
return Err(AcceptanceCheckErr::CapacityExceeded {
|
||||
count: para_queue_count,
|
||||
limit: config.max_upward_queue_count,
|
||||
});
|
||||
})
|
||||
}
|
||||
if para_queue_size > config.max_upward_queue_size {
|
||||
return Err(AcceptanceCheckErr::TotalSizeExceeded {
|
||||
total_size: para_queue_size,
|
||||
limit: config.max_upward_queue_size,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -364,10 +356,13 @@ impl<T: Config> Pallet<T> {
|
||||
v.extend(upward_messages.into_iter())
|
||||
});
|
||||
|
||||
<Self as Store>::RelayDispatchQueueSize::mutate(¶, |(ref mut cnt, ref mut size)| {
|
||||
*cnt += extra_count;
|
||||
*size += extra_size;
|
||||
});
|
||||
<Self as Store>::RelayDispatchQueueSize::mutate(
|
||||
¶,
|
||||
|(ref mut cnt, ref mut size)| {
|
||||
*cnt += extra_count;
|
||||
*size += extra_size;
|
||||
},
|
||||
);
|
||||
|
||||
<Self as Store>::NeedsDispatch::mutate(|v| {
|
||||
if let Err(i) = v.binary_search(¶) {
|
||||
@@ -398,7 +393,7 @@ impl<T: Config> Pallet<T> {
|
||||
// preferred weight for the dispatching stage.
|
||||
//
|
||||
// if so - bail.
|
||||
break;
|
||||
break
|
||||
}
|
||||
let max_weight = if weight_used == 0 {
|
||||
// we increase the amount of weight that we're allowed to use on the first message to try to prevent
|
||||
@@ -411,7 +406,11 @@ impl<T: Config> Pallet<T> {
|
||||
// dequeue the next message from the queue of the dispatchee
|
||||
let (upward_message, became_empty) = queue_cache.dequeue::<T>(dispatchee);
|
||||
if let Some(upward_message) = upward_message {
|
||||
match T::UmpSink::process_upward_message(dispatchee, &upward_message[..], max_weight) {
|
||||
match T::UmpSink::process_upward_message(
|
||||
dispatchee,
|
||||
&upward_message[..],
|
||||
max_weight,
|
||||
) {
|
||||
Ok(used) => weight_used += used,
|
||||
Err((id, required)) => {
|
||||
// we process messages in order and don't drop them if we run out of weight, so need to break
|
||||
@@ -478,11 +477,7 @@ impl QueueCache {
|
||||
let cache_entry = self.0.entry(para).or_insert_with(|| {
|
||||
let queue = <Pallet<T> as Store>::RelayDispatchQueues::get(¶);
|
||||
let (count, total_size) = <Pallet<T> as Store>::RelayDispatchQueueSize::get(¶);
|
||||
QueueCacheEntry {
|
||||
queue,
|
||||
count,
|
||||
total_size,
|
||||
}
|
||||
QueueCacheEntry { queue, count, total_size }
|
||||
});
|
||||
let upward_message = cache_entry.queue.pop_front();
|
||||
if let Some(ref msg) = upward_message {
|
||||
@@ -499,15 +494,7 @@ impl QueueCache {
|
||||
// NOTE we use an explicit method here instead of Drop impl because it has unwanted semantics
|
||||
// within runtime. It is dangerous to use because of double-panics and flushing on a panic
|
||||
// is not necessary as well.
|
||||
for (
|
||||
para,
|
||||
QueueCacheEntry {
|
||||
queue,
|
||||
count,
|
||||
total_size,
|
||||
},
|
||||
) in self.0
|
||||
{
|
||||
for (para, QueueCacheEntry { queue, count, total_size }) in self.0 {
|
||||
if queue.is_empty() {
|
||||
// remove the entries altogether.
|
||||
<Pallet<T> as Store>::RelayDispatchQueues::remove(¶);
|
||||
@@ -551,15 +538,12 @@ impl NeedsDispatchCursor {
|
||||
// let's select 0 as the starting index as a safe bet.
|
||||
debug_assert!(false);
|
||||
0
|
||||
}
|
||||
},
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
|
||||
Self {
|
||||
needs_dispatch,
|
||||
index: initial_index,
|
||||
}
|
||||
Self { needs_dispatch, index: initial_index }
|
||||
}
|
||||
|
||||
/// Returns the item the cursor points to.
|
||||
@@ -570,7 +554,7 @@ impl NeedsDispatchCursor {
|
||||
/// Moves the cursor to the next item.
|
||||
fn advance(&mut self) {
|
||||
if self.needs_dispatch.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
self.index = (self.index + 1) % self.needs_dispatch.len();
|
||||
}
|
||||
@@ -578,7 +562,7 @@ impl NeedsDispatchCursor {
|
||||
/// Removes the item under the cursor.
|
||||
fn remove(&mut self) {
|
||||
if self.needs_dispatch.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
let _ = self.needs_dispatch.remove(self.index);
|
||||
|
||||
@@ -615,10 +599,9 @@ pub(crate) mod mock_sink {
|
||||
//! 2. All messages expected by the probe must be received by the time of dropping it. Unreceived
|
||||
//! messages will lead to a panic while dropping a probe.
|
||||
|
||||
use super::{UmpSink, UpwardMessage, ParaId, MessageId};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::vec_deque::VecDeque;
|
||||
use super::{MessageId, ParaId, UmpSink, UpwardMessage};
|
||||
use frame_support::weights::Weight;
|
||||
use std::{cell::RefCell, collections::vec_deque::VecDeque};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct UmpExpectation {
|
||||
@@ -634,25 +617,30 @@ pub(crate) mod mock_sink {
|
||||
|
||||
pub struct MockUmpSink;
|
||||
impl UmpSink for MockUmpSink {
|
||||
fn process_upward_message(actual_origin: ParaId, actual_msg: &[u8], _max_weight: Weight) -> Result<Weight, (MessageId, Weight)> {
|
||||
Ok(HOOK.with(|opt_hook| opt_hook.borrow_mut().as_mut().map(|hook| {
|
||||
let UmpExpectation {
|
||||
expected_origin,
|
||||
expected_msg,
|
||||
mock_weight,
|
||||
} = match hook.pop_front() {
|
||||
Some(expectation) => expectation,
|
||||
None => {
|
||||
panic!(
|
||||
fn process_upward_message(
|
||||
actual_origin: ParaId,
|
||||
actual_msg: &[u8],
|
||||
_max_weight: Weight,
|
||||
) -> Result<Weight, (MessageId, Weight)> {
|
||||
Ok(HOOK
|
||||
.with(|opt_hook| {
|
||||
opt_hook.borrow_mut().as_mut().map(|hook| {
|
||||
let UmpExpectation { expected_origin, expected_msg, mock_weight } =
|
||||
match hook.pop_front() {
|
||||
Some(expectation) => expectation,
|
||||
None => {
|
||||
panic!(
|
||||
"The probe is active but didn't expect the message:\n\n\t{:?}.",
|
||||
actual_msg,
|
||||
);
|
||||
}
|
||||
};
|
||||
assert_eq!(expected_origin, actual_origin);
|
||||
assert_eq!(expected_msg, &actual_msg[..]);
|
||||
mock_weight
|
||||
})).unwrap_or(0))
|
||||
},
|
||||
};
|
||||
assert_eq!(expected_origin, actual_origin);
|
||||
assert_eq!(expected_msg, &actual_msg[..]);
|
||||
mock_weight
|
||||
})
|
||||
})
|
||||
.unwrap_or(0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,15 +672,11 @@ pub(crate) mod mock_sink {
|
||||
mock_weight: Weight,
|
||||
) {
|
||||
HOOK.with(|opt_hook| {
|
||||
opt_hook
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.push_back(UmpExpectation {
|
||||
expected_origin,
|
||||
expected_msg,
|
||||
mock_weight,
|
||||
})
|
||||
opt_hook.borrow_mut().as_mut().unwrap().push_back(UmpExpectation {
|
||||
expected_origin,
|
||||
expected_msg,
|
||||
mock_weight,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -727,9 +711,8 @@ pub(crate) mod mock_sink {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::mock_sink::Probe;
|
||||
use crate::mock::{Configuration, Ump, new_test_ext, MockGenesisConfig};
|
||||
use super::{mock_sink::Probe, *};
|
||||
use crate::mock::{new_test_ext, Configuration, MockGenesisConfig, Ump};
|
||||
use std::collections::HashSet;
|
||||
|
||||
struct GenesisConfigBuilder {
|
||||
@@ -761,8 +744,7 @@ mod tests {
|
||||
config.max_upward_message_num_per_candidate = self.max_upward_message_num_per_candidate;
|
||||
config.max_upward_queue_count = self.max_upward_queue_count;
|
||||
config.max_upward_queue_size = self.max_upward_queue_size;
|
||||
config.ump_service_total_weight =
|
||||
self.ump_service_total_weight;
|
||||
config.ump_service_total_weight = self.ump_service_total_weight;
|
||||
genesis
|
||||
}
|
||||
}
|
||||
@@ -811,9 +793,8 @@ mod tests {
|
||||
let queue_sizes_set = <Ump as Store>::RelayDispatchQueueSize::iter()
|
||||
.map(|(k, _)| k)
|
||||
.collect::<HashSet<ParaId>>();
|
||||
let needs_dispatch_set = <Ump as Store>::NeedsDispatch::get()
|
||||
.into_iter()
|
||||
.collect::<HashSet<ParaId>>();
|
||||
let needs_dispatch_set =
|
||||
<Ump as Store>::NeedsDispatch::get().into_iter().collect::<HashSet<ParaId>>();
|
||||
assert_eq!(queue_contents_set, queue_sizes_set);
|
||||
assert_eq!(queue_contents_set, needs_dispatch_set);
|
||||
|
||||
@@ -823,11 +804,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// `NeedsDispatch` is always sorted.
|
||||
assert!(
|
||||
<Ump as Store>::NeedsDispatch::get()
|
||||
.windows(2)
|
||||
.all(|xs| xs[0] <= xs[1])
|
||||
);
|
||||
assert!(<Ump as Store>::NeedsDispatch::get().windows(2).all(|xs| xs[0] <= xs[1]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -872,11 +849,7 @@ mod tests {
|
||||
let q_msg = b"we are Q".to_vec();
|
||||
|
||||
new_test_ext(
|
||||
GenesisConfigBuilder {
|
||||
ump_service_total_weight: 500,
|
||||
..Default::default()
|
||||
}
|
||||
.build(),
|
||||
GenesisConfigBuilder { ump_service_total_weight: 500, ..Default::default() }.build(),
|
||||
)
|
||||
.execute_with(|| {
|
||||
queue_upward_msg(q, q_msg.clone());
|
||||
@@ -946,11 +919,7 @@ mod tests {
|
||||
let b_msg_1 = vec![4, 5, 6];
|
||||
|
||||
new_test_ext(
|
||||
GenesisConfigBuilder {
|
||||
ump_service_total_weight: 900,
|
||||
..Default::default()
|
||||
}
|
||||
.build(),
|
||||
GenesisConfigBuilder { ump_service_total_weight: 900, ..Default::default() }.build(),
|
||||
)
|
||||
.execute_with(|| {
|
||||
// We want to test here an edge case, where we remove the queue with the highest
|
||||
@@ -982,8 +951,8 @@ mod tests {
|
||||
// Make sure that the relay dispatch queue size storage entry is accessible via well known
|
||||
// keys and is decodable into a (u32, u32).
|
||||
|
||||
use primitives::v1::well_known_keys;
|
||||
use parity_scale_codec::Decode as _;
|
||||
use primitives::v1::well_known_keys;
|
||||
|
||||
let a = ParaId::from(228);
|
||||
let msg = vec![1, 2, 3];
|
||||
@@ -991,9 +960,11 @@ mod tests {
|
||||
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
|
||||
queue_upward_msg(a, msg);
|
||||
|
||||
let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(a))
|
||||
.expect("enqueing a message should create the dispatch queue\
|
||||
and it should be accessible via the well known keys");
|
||||
let raw_queue_size =
|
||||
sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(a)).expect(
|
||||
"enqueing a message should create the dispatch queue\
|
||||
and it should be accessible via the well known keys",
|
||||
);
|
||||
let (cnt, size) = <(u32, u32)>::decode(&mut &raw_queue_size[..])
|
||||
.expect("the dispatch queue size should be decodable into (u32, u32)");
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
use primitives::v1::{Id as ParaId, PersistedValidationData, ValidatorIndex};
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use crate::{configuration, paras, hrmp};
|
||||
use crate::{configuration, hrmp, paras};
|
||||
|
||||
/// Make the persisted validation data for a particular parachain, a specified relay-parent and it's
|
||||
/// storage root.
|
||||
@@ -43,7 +43,8 @@ pub fn make_persisted_validation_data<T: paras::Config + hrmp::Config>(
|
||||
|
||||
/// Take the active subset of a set containing all validators.
|
||||
pub fn take_active_subset<T: Clone>(active_validators: &[ValidatorIndex], set: &[T]) -> Vec<T> {
|
||||
let subset: Vec<_> = active_validators.iter()
|
||||
let subset: Vec<_> = active_validators
|
||||
.iter()
|
||||
.filter_map(|i| set.get(i.0 as usize))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
Reference in New Issue
Block a user