mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 08:11:03 +00:00
Implement HRMP (#1900)
* HRMP: Update the impl guide * HRMP: Incorporate the channel notifications into the guide * HRMP: Renaming in the impl guide * HRMP: Constrain the maximum number of HRMP messages per candidate This commit addresses the HRMP part of https://github.com/paritytech/polkadot/issues/1869 * XCM: Introduce HRMP related message types * HRMP: Data structures and plumbing * HRMP: Configuration * HRMP: Data layout * HRMP: Acceptance & Enactment * HRMP: Test base logic * Update adder collator * HRMP: Runtime API for accessing inbound messages Also, removing some redundant fully-qualified names. * HRMP: Add diagnostic logging in acceptance criteria * HRMP: Additional tests * Self-review fixes * save test refactorings for the next time * Missed a return statement. * a formatting blip * Add missing logic for appending HRMP digests * Remove the channel contents vectors which became empty * Tighten HRMP channel digests invariants. * Apply suggestions from code review Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * Remove a note about sorting for channel id * Add missing rustdocs to the configuration * Clarify and update the invariant for HrmpChannelDigests * Make the onboarding invariant less sloppy Namely, introduce `Paras::is_valid_para` (in fact, it already is present in the implementation) and hook up the invariant to that. Note that this says "within a session" because I don't want to make it super strict on the session boundary. The logic on the session boundary should be extremely careful. * Make `CandidateCheckContext` use T::BlockNumber for hrmp_watermark Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
//! Configuration can change only at session boundaries and is buffered until then.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use primitives::v1::ValidatorId;
|
||||
use primitives::v1::{Balance, ValidatorId};
|
||||
use frame_support::{
|
||||
decl_storage, decl_module, decl_error,
|
||||
dispatch::DispatchResult,
|
||||
@@ -84,6 +84,32 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
///
|
||||
/// This parameter affects the size upper bound of the `CandidateCommitments`.
|
||||
pub max_upward_message_num_per_candidate: u32,
|
||||
/// Number of sessions after which an HRMP open channel request expires.
|
||||
pub hrmp_open_request_ttl: u32,
|
||||
/// The deposit that the sender should provide for opening an HRMP channel.
|
||||
pub hrmp_sender_deposit: Balance,
|
||||
/// The deposit that the recipient should provide for accepting opening an HRMP channel.
|
||||
pub hrmp_recipient_deposit: Balance,
|
||||
/// The maximum number of messages allowed in an HRMP channel at once.
|
||||
pub hrmp_channel_max_capacity: u32,
|
||||
/// The maximum total size of messages in bytes allowed in an HRMP channel at once.
|
||||
pub hrmp_channel_max_total_size: u32,
|
||||
/// The maximum number of inbound HRMP channels a parachain is allowed to accept.
|
||||
pub hrmp_max_parachain_inbound_channels: u32,
|
||||
/// The maximum number of inbound HRMP channels a parathread is allowed to accept.
|
||||
pub hrmp_max_parathread_inbound_channels: u32,
|
||||
/// The maximum size of a message that could ever be put into an HRMP channel.
|
||||
///
|
||||
/// This parameter affects the upper bound of size of `CandidateCommitments`.
|
||||
pub hrmp_channel_max_message_size: u32,
|
||||
/// The maximum number of outbound HRMP channels a parachain is allowed to open.
|
||||
pub hrmp_max_parachain_outbound_channels: u32,
|
||||
/// The maximum number of outbound HRMP channels a parathread is allowed to open.
|
||||
pub hrmp_max_parathread_outbound_channels: u32,
|
||||
/// The maximum number of outbound HRMP messages can be sent by a candidate.
|
||||
///
|
||||
/// This parameter affects the upper bound of size of `CandidateCommitments`.
|
||||
pub hrmp_max_message_num_per_candidate: u32,
|
||||
}
|
||||
|
||||
pub trait Trait: frame_system::Trait { }
|
||||
@@ -276,6 +302,117 @@ decl_module! {
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the number of sessions after which an HRMP open channel request expires.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_open_request_ttl(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_open_request_ttl, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the amount of funds that the sender should provide for opening an HRMP channel.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_sender_deposit(origin, new: Balance) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_sender_deposit, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the amount of funds that the recipient should provide for accepting opening an HRMP
|
||||
/// channel.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_recipient_deposit(origin, new: Balance) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_recipient_deposit, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum number of messages allowed in an HRMP channel at once.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_channel_max_capacity(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_channel_max_capacity, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum total size of messages in bytes allowed in an HRMP channel at once.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_channel_max_total_size(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_channel_max_total_size, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum number of inbound HRMP channels a parachain is allowed to accept.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_max_parachain_inbound_channels(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parachain_inbound_channels, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum number of inbound HRMP channels a parathread is allowed to accept.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_max_parathread_inbound_channels(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parathread_inbound_channels, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum size of a message that could ever be put into an HRMP channel.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_channel_max_message_size(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_channel_max_message_size, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum number of outbound HRMP channels a parachain is allowed to open.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_max_parachain_outbound_channels(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parachain_outbound_channels, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum number of outbound HRMP channels a parathread is allowed to open.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_max_parathread_outbound_channels(origin, new: u32) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
Self::update_config_member(|config| {
|
||||
sp_std::mem::replace(&mut config.hrmp_max_parathread_outbound_channels, new) != new
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the maximum number of outbound HRMP messages can be sent by a candidate.
|
||||
#[weight = (1_000, DispatchClass::Operational)]
|
||||
pub fn set_hrmp_max_message_num_per_candidate(origin, 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
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,6 +497,17 @@ mod tests {
|
||||
preferred_dispatchable_upward_messages_step_weight: 20000,
|
||||
max_upward_message_size: 448,
|
||||
max_upward_message_num_per_candidate: 5,
|
||||
hrmp_open_request_ttl: 1312,
|
||||
hrmp_sender_deposit: 22,
|
||||
hrmp_recipient_deposit: 4905,
|
||||
hrmp_channel_max_capacity: 3921,
|
||||
hrmp_channel_max_total_size: 7687,
|
||||
hrmp_max_parachain_inbound_channels: 3722,
|
||||
hrmp_max_parathread_inbound_channels: 1967,
|
||||
hrmp_channel_max_message_size: 8192,
|
||||
hrmp_max_parachain_outbound_channels: 100,
|
||||
hrmp_max_parathread_outbound_channels: 200,
|
||||
hrmp_max_message_num_per_candidate: 20,
|
||||
};
|
||||
|
||||
assert!(<Configuration as Store>::PendingConfig::get().is_none());
|
||||
@@ -415,6 +563,50 @@ mod tests {
|
||||
Configuration::set_max_upward_message_num_per_candidate(
|
||||
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();
|
||||
Configuration::set_hrmp_recipient_deposit(
|
||||
Origin::root(),
|
||||
new_config.hrmp_recipient_deposit,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_channel_max_capacity(
|
||||
Origin::root(),
|
||||
new_config.hrmp_channel_max_capacity,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_channel_max_total_size(
|
||||
Origin::root(),
|
||||
new_config.hrmp_channel_max_total_size,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_max_parachain_inbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parachain_inbound_channels,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_max_parathread_inbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parathread_inbound_channels,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_channel_max_message_size(
|
||||
Origin::root(),
|
||||
new_config.hrmp_channel_max_message_size,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_max_parachain_outbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parachain_outbound_channels,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_max_parathread_outbound_channels(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_parathread_outbound_channels,
|
||||
).unwrap();
|
||||
Configuration::set_hrmp_max_message_num_per_candidate(
|
||||
Origin::root(),
|
||||
new_config.hrmp_max_message_num_per_candidate,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(<Configuration as Store>::PendingConfig::get(), Some(new_config));
|
||||
})
|
||||
|
||||
@@ -157,6 +157,10 @@ decl_error! {
|
||||
IncorrectDownwardMessageHandling,
|
||||
/// At least one upward message sent does not pass the acceptance criteria.
|
||||
InvalidUpwardMessages,
|
||||
/// The candidate didn't follow the rules of HRMP watermark advancement.
|
||||
HrmpWatermarkMishandling,
|
||||
/// The HRMP messages sent by the candidate is not valid.
|
||||
InvalidOutboundHrmp,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,6 +419,8 @@ impl<T: Trait> Module<T> {
|
||||
&candidate.candidate.commitments.new_validation_code,
|
||||
candidate.candidate.commitments.processed_downward_messages,
|
||||
&candidate.candidate.commitments.upward_messages,
|
||||
T::BlockNumber::from(candidate.candidate.commitments.hrmp_watermark),
|
||||
&candidate.candidate.commitments.horizontal_messages,
|
||||
)?;
|
||||
|
||||
for (i, assignment) in scheduled[skip..].iter().enumerate() {
|
||||
@@ -548,6 +554,8 @@ impl<T: Trait> Module<T> {
|
||||
&validation_outputs.new_validation_code,
|
||||
validation_outputs.processed_downward_messages,
|
||||
&validation_outputs.upward_messages,
|
||||
T::BlockNumber::from(validation_outputs.hrmp_watermark),
|
||||
&validation_outputs.horizontal_messages,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -578,6 +586,14 @@ impl<T: Trait> Module<T> {
|
||||
receipt.descriptor.para_id,
|
||||
commitments.upward_messages,
|
||||
);
|
||||
weight += <router::Module<T>>::prune_hrmp(
|
||||
receipt.descriptor.para_id,
|
||||
T::BlockNumber::from(commitments.hrmp_watermark),
|
||||
);
|
||||
weight += <router::Module<T>>::queue_outbound_hrmp(
|
||||
receipt.descriptor.para_id,
|
||||
commitments.horizontal_messages,
|
||||
);
|
||||
|
||||
Self::deposit_event(
|
||||
Event::<T>::CandidateIncluded(plain, commitments.head_data.clone())
|
||||
@@ -702,6 +718,8 @@ impl<T: Trait> CandidateCheckContext<T> {
|
||||
new_validation_code: &Option<primitives::v1::ValidationCode>,
|
||||
processed_downward_messages: u32,
|
||||
upward_messages: &[primitives::v1::UpwardMessage],
|
||||
hrmp_watermark: T::BlockNumber,
|
||||
horizontal_messages: &[primitives::v1::OutboundHrmpMessage<ParaId>],
|
||||
) -> Result<(), DispatchError> {
|
||||
ensure!(
|
||||
head_data.0.len() <= self.config.max_head_data_size as _,
|
||||
@@ -739,6 +757,22 @@ impl<T: Trait> CandidateCheckContext<T> {
|
||||
),
|
||||
Error::<T>::InvalidUpwardMessages,
|
||||
);
|
||||
ensure!(
|
||||
<router::Module<T>>::check_hrmp_watermark(
|
||||
para_id,
|
||||
self.relay_parent_number,
|
||||
hrmp_watermark,
|
||||
),
|
||||
Error::<T>::HrmpWatermarkMishandling,
|
||||
);
|
||||
ensure!(
|
||||
<router::Module<T>>::check_outbound_hrmp(
|
||||
&self.config,
|
||||
para_id,
|
||||
horizontal_messages,
|
||||
),
|
||||
Error::<T>::InvalidOutboundHrmp,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -946,6 +980,7 @@ mod tests {
|
||||
relay_parent: Hash,
|
||||
persisted_validation_data_hash: Hash,
|
||||
new_validation_code: Option<ValidationCode>,
|
||||
hrmp_watermark: BlockNumber,
|
||||
}
|
||||
|
||||
impl TestCandidateBuilder {
|
||||
@@ -961,6 +996,7 @@ mod tests {
|
||||
commitments: CandidateCommitments {
|
||||
head_data: self.head_data,
|
||||
new_validation_code: self.new_validation_code,
|
||||
hrmp_watermark: self.hrmp_watermark,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
@@ -1359,6 +1395,9 @@ mod tests {
|
||||
let chain_b = ParaId::from(2);
|
||||
let thread_a = ParaId::from(3);
|
||||
|
||||
// The block number of the relay-parent for testing.
|
||||
const RELAY_PARENT_NUM: BlockNumber = 4;
|
||||
|
||||
let paras = vec![(chain_a, true), (chain_b, true), (thread_a, false)];
|
||||
let validators = vec![
|
||||
Sr25519Keyring::Alice,
|
||||
@@ -1421,6 +1460,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
collator_sign_candidate(
|
||||
@@ -1454,6 +1494,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
let mut candidate_b = TestCandidateBuilder {
|
||||
@@ -1461,6 +1502,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([2; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1510,6 +1552,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
collator_sign_candidate(
|
||||
@@ -1579,6 +1622,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1618,6 +1662,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1656,6 +1701,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1703,6 +1749,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1743,6 +1790,7 @@ mod tests {
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
new_validation_code: Some(vec![5, 6, 7, 8].into()),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1785,6 +1833,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: [42u8; 32].into(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
|
||||
@@ -1820,6 +1869,9 @@ mod tests {
|
||||
let chain_b = ParaId::from(2);
|
||||
let thread_a = ParaId::from(3);
|
||||
|
||||
// The block number of the relay-parent for testing.
|
||||
const RELAY_PARENT_NUM: BlockNumber = 4;
|
||||
|
||||
let paras = vec![(chain_a, true), (chain_b, true), (thread_a, false)];
|
||||
let validators = vec![
|
||||
Sr25519Keyring::Alice,
|
||||
@@ -1880,6 +1932,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
collator_sign_candidate(
|
||||
@@ -1892,6 +1945,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([2; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_b).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
collator_sign_candidate(
|
||||
@@ -1904,6 +1958,7 @@ mod tests {
|
||||
relay_parent: System::parent_hash(),
|
||||
pov_hash: Hash::from([3; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(thread_a).unwrap(),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
collator_sign_candidate(
|
||||
@@ -2001,6 +2056,9 @@ mod tests {
|
||||
fn can_include_candidate_with_ok_code_upgrade() {
|
||||
let chain_a = ParaId::from(1);
|
||||
|
||||
// The block number of the relay-parent for testing.
|
||||
const RELAY_PARENT_NUM: BlockNumber = 4;
|
||||
|
||||
let paras = vec![(chain_a, true)];
|
||||
let validators = vec![
|
||||
Sr25519Keyring::Alice,
|
||||
@@ -2044,6 +2102,7 @@ mod tests {
|
||||
pov_hash: Hash::from([1; 32]),
|
||||
persisted_validation_data_hash: make_vdata_hash(chain_a).unwrap(),
|
||||
new_validation_code: Some(vec![1, 2, 3].into()),
|
||||
hrmp_watermark: RELAY_PARENT_NUM,
|
||||
..Default::default()
|
||||
}.build();
|
||||
collator_sign_candidate(
|
||||
|
||||
@@ -109,6 +109,7 @@ impl crate::paras::Trait for Test {
|
||||
}
|
||||
|
||||
impl crate::router::Trait for Test {
|
||||
type Origin = Origin;
|
||||
type UmpSink = crate::router::MockUmpSink;
|
||||
}
|
||||
|
||||
|
||||
@@ -541,6 +541,12 @@ impl<T: Trait> Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the given ID refers to a valid para.
|
||||
pub(crate) fn is_valid_para(id: ParaId) -> bool {
|
||||
Self::parachains().binary_search(&id).is_ok()
|
||||
|| Self::is_parathread(id)
|
||||
}
|
||||
|
||||
/// Whether a para ID corresponds to any live parathread.
|
||||
pub(crate) fn is_parathread(id: ParaId) -> bool {
|
||||
Parathreads::get(&id).is_some()
|
||||
|
||||
@@ -20,25 +20,30 @@
|
||||
//! routing the messages at their destinations and informing the parachains about the incoming
|
||||
//! messages.
|
||||
|
||||
use crate::{
|
||||
configuration,
|
||||
initializer,
|
||||
};
|
||||
use crate::{configuration, paras, initializer, ensure_parachain};
|
||||
use sp_std::prelude::*;
|
||||
use frame_support::{decl_error, decl_module, decl_storage, weights::Weight};
|
||||
use frame_support::{decl_error, decl_module, decl_storage, dispatch::DispatchResult, weights::Weight};
|
||||
use sp_std::collections::vec_deque::VecDeque;
|
||||
use primitives::v1::{Id as ParaId, InboundDownwardMessage, Hash, UpwardMessage};
|
||||
use primitives::v1::{
|
||||
Id as ParaId, InboundDownwardMessage, Hash, UpwardMessage, HrmpChannelId, InboundHrmpMessage,
|
||||
};
|
||||
|
||||
mod dmp;
|
||||
mod hrmp;
|
||||
mod ump;
|
||||
|
||||
use hrmp::{HrmpOpenChannelRequest, HrmpChannel};
|
||||
pub use dmp::QueueDownwardMessageError;
|
||||
pub use ump::UmpSink;
|
||||
|
||||
#[cfg(test)]
|
||||
pub use ump::mock_sink::MockUmpSink;
|
||||
|
||||
pub trait Trait: frame_system::Trait + configuration::Trait {
|
||||
pub trait Trait: frame_system::Trait + configuration::Trait + paras::Trait {
|
||||
type Origin: From<crate::Origin>
|
||||
+ From<<Self as frame_system::Trait>::Origin>
|
||||
+ Into<Result<crate::Origin, <Self as Trait>::Origin>>;
|
||||
|
||||
/// A place where all received upward messages are funneled.
|
||||
type UmpSink: UmpSink;
|
||||
}
|
||||
@@ -103,17 +108,148 @@ decl_storage! {
|
||||
/// Invariant:
|
||||
/// - If `Some(para)`, then `para` must be present in `NeedsDispatch`.
|
||||
NextDispatchRoundStartWith: Option<ParaId>;
|
||||
|
||||
/*
|
||||
* Horizontally Relay-routed Message Passing (HRMP)
|
||||
*
|
||||
* HRMP related storage layout
|
||||
*/
|
||||
|
||||
/// The set of pending HRMP open channel requests.
|
||||
///
|
||||
/// The set is accompanied by a list for iteration.
|
||||
///
|
||||
/// Invariant:
|
||||
/// - There are no channels that exists in list but not in the set and vice versa.
|
||||
HrmpOpenChannelRequests: map hasher(twox_64_concat) HrmpChannelId => Option<HrmpOpenChannelRequest>;
|
||||
HrmpOpenChannelRequestsList: Vec<HrmpChannelId>;
|
||||
|
||||
/// This mapping tracks how many open channel requests are inititated by a given sender para.
|
||||
/// Invariant: `HrmpOpenChannelRequests` should contain the same number of items that has `(X, _)`
|
||||
/// as the number of `HrmpOpenChannelRequestCount` for `X`.
|
||||
HrmpOpenChannelRequestCount: map hasher(twox_64_concat) ParaId => u32;
|
||||
/// 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`.
|
||||
HrmpAcceptedChannelRequestCount: map hasher(twox_64_concat) ParaId => u32;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// The set is accompanied by a list for iteration.
|
||||
///
|
||||
/// Invariant:
|
||||
/// - There are no channels that exists in list but not in the set and vice versa.
|
||||
HrmpCloseChannelRequests: map hasher(twox_64_concat) HrmpChannelId => Option<()>;
|
||||
HrmpCloseChannelRequestsList: Vec<HrmpChannelId>;
|
||||
|
||||
/// The HRMP watermark associated with each para.
|
||||
/// Invariant:
|
||||
/// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a session.
|
||||
HrmpWatermarks: map hasher(twox_64_concat) ParaId => Option<T::BlockNumber>;
|
||||
/// HRMP channel data associated with each para.
|
||||
/// Invariant:
|
||||
/// - each participant in the channel should satisfy `Paras::is_valid_para(P)` within a session.
|
||||
HrmpChannels: map hasher(twox_64_concat) HrmpChannelId => Option<HrmpChannel>;
|
||||
/// Ingress/egress indexes allow to find all the senders and receivers given the opposite
|
||||
/// side. I.e.
|
||||
///
|
||||
/// (a) ingress index allows to find all the senders for a given recipient.
|
||||
/// (b) egress index allows to find all the recipients for a given sender.
|
||||
///
|
||||
/// Invariants:
|
||||
/// - for each ingress index entry for `P` each item `I` in the index should present in `HrmpChannels`
|
||||
/// as `(I, P)`.
|
||||
/// - for each egress index entry for `P` each item `E` in the index should present in `HrmpChannels`
|
||||
/// as `(P, E)`.
|
||||
/// - there should be no other dangling channels in `HrmpChannels`.
|
||||
/// - the vectors are sorted.
|
||||
HrmpIngressChannelsIndex: map hasher(twox_64_concat) ParaId => Vec<ParaId>;
|
||||
HrmpEgressChannelsIndex: map hasher(twox_64_concat) ParaId => Vec<ParaId>;
|
||||
/// Storage for the messages for each channel.
|
||||
/// Invariant: cannot be non-empty if the corresponding channel in `HrmpChannels` is `None`.
|
||||
HrmpChannelContents: map hasher(twox_64_concat) HrmpChannelId => Vec<InboundHrmpMessage<T::BlockNumber>>;
|
||||
/// Maintains a mapping that can be used to answer the question:
|
||||
/// What paras sent a message at the given block number for a given reciever.
|
||||
/// Invariants:
|
||||
/// - The inner `Vec<ParaId>` is never empty.
|
||||
/// - The inner `Vec<ParaId>` cannot store two same `ParaId`.
|
||||
/// - The outer vector is sorted ascending by block number and cannot store two items with the same
|
||||
/// block number.
|
||||
HrmpChannelDigests: map hasher(twox_64_concat) ParaId => Vec<(T::BlockNumber, Vec<ParaId>)>;
|
||||
}
|
||||
}
|
||||
|
||||
decl_error! {
|
||||
pub enum Error for Module<T: Trait> { }
|
||||
pub enum Error for Module<T: Trait> {
|
||||
/// The sender tried to open a channel to themselves.
|
||||
OpenHrmpChannelToSelf,
|
||||
/// The recipient is not a valid para.
|
||||
OpenHrmpChannelInvalidRecipient,
|
||||
/// The requested capacity is zero.
|
||||
OpenHrmpChannelZeroCapacity,
|
||||
/// The requested capacity exceeds the global limit.
|
||||
OpenHrmpChannelCapacityExceedsLimit,
|
||||
/// The requested maximum message size is 0.
|
||||
OpenHrmpChannelZeroMessageSize,
|
||||
/// The open request requested the message size that exceeds the global limit.
|
||||
OpenHrmpChannelMessageSizeExceedsLimit,
|
||||
/// The channel already exists
|
||||
OpenHrmpChannelAlreadyExists,
|
||||
/// There is already a request to open the same channel.
|
||||
OpenHrmpChannelAlreadyRequested,
|
||||
/// The sender already has the maximum number of allowed outbound channels.
|
||||
OpenHrmpChannelLimitExceeded,
|
||||
/// The channel from the sender to the origin doesn't exist.
|
||||
AcceptHrmpChannelDoesntExist,
|
||||
/// The channel is already confirmed.
|
||||
AcceptHrmpChannelAlreadyConfirmed,
|
||||
/// The recipient already has the maximum number of allowed inbound channels.
|
||||
AcceptHrmpChannelLimitExceeded,
|
||||
/// The origin tries to close a channel where it is neither the sender nor the recipient.
|
||||
CloseHrmpChannelUnauthorized,
|
||||
/// The channel to be closed doesn't exist.
|
||||
CloseHrmpChannelDoesntExist,
|
||||
/// The channel close request is already requested.
|
||||
CloseHrmpChannelAlreadyUnderway,
|
||||
}
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
/// The router module.
|
||||
pub struct Module<T: Trait> for enum Call where origin: <T as frame_system::Trait>::Origin {
|
||||
type Error = Error<T>;
|
||||
|
||||
#[weight = 0]
|
||||
fn hrmp_init_open_channel(
|
||||
origin,
|
||||
recipient: ParaId,
|
||||
proposed_max_capacity: u32,
|
||||
proposed_max_message_size: u32,
|
||||
) -> DispatchResult {
|
||||
let origin = ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||
Self::init_open_channel(
|
||||
origin,
|
||||
recipient,
|
||||
proposed_max_capacity,
|
||||
proposed_max_message_size
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[weight = 0]
|
||||
fn hrmp_accept_open_channel(origin, sender: ParaId) -> DispatchResult {
|
||||
let origin = ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||
Self::accept_open_channel(origin, sender)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[weight = 0]
|
||||
fn hrmp_close_channel(origin, channel_id: HrmpChannelId) -> DispatchResult {
|
||||
let origin = ensure_parachain(<T as Trait>::Origin::from(origin))?;
|
||||
Self::close_channel(origin, channel_id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +264,21 @@ impl<T: Trait> Module<T> {
|
||||
|
||||
/// Called by the initializer to note that a new session has started.
|
||||
pub(crate) fn initializer_on_new_session(
|
||||
_notification: &initializer::SessionChangeNotification<T::BlockNumber>,
|
||||
notification: &initializer::SessionChangeNotification<T::BlockNumber>,
|
||||
) {
|
||||
Self::perform_outgoing_para_cleanup();
|
||||
Self::process_hrmp_open_channel_requests(¬ification.prev_config);
|
||||
Self::process_hrmp_close_channel_requests();
|
||||
}
|
||||
|
||||
/// Iterate over all paras that were registered for offboarding and remove all the data
|
||||
/// associated with them.
|
||||
fn perform_outgoing_para_cleanup() {
|
||||
let outgoing = OutgoingParas::take();
|
||||
for outgoing_para in outgoing {
|
||||
Self::clean_dmp_after_outgoing(outgoing_para);
|
||||
Self::clean_ump_after_outgoing(outgoing_para);
|
||||
Self::clean_hrmp_after_outgoing(outgoing_para);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,12 +18,13 @@
|
||||
//! functions.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::collections::btree_map::BTreeMap;
|
||||
use primitives::v1::{
|
||||
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, ValidationData,
|
||||
Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode,
|
||||
CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex,
|
||||
GroupIndex, CandidateEvent, PersistedValidationData, AuthorityDiscoveryId,
|
||||
InboundDownwardMessage,
|
||||
InboundDownwardMessage, InboundHrmpMessage,
|
||||
};
|
||||
use sp_runtime::traits::Zero;
|
||||
use frame_support::debug;
|
||||
@@ -328,3 +329,10 @@ pub fn dmq_contents<T: router::Trait>(
|
||||
) -> Vec<InboundDownwardMessage<T::BlockNumber>> {
|
||||
<router::Module<T>>::dmq_contents(recipient)
|
||||
}
|
||||
|
||||
/// Implementation for the `inbound_hrmp_channels_contents` function of the runtime API.
|
||||
pub fn inbound_hrmp_channels_contents<T: router::Trait>(
|
||||
recipient: ParaId,
|
||||
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<T::BlockNumber>>> {
|
||||
<router::Module<T>>::inbound_hrmp_channels_contents(recipient)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
use sp_runtime::traits::{One, Saturating};
|
||||
use primitives::v1::{Id as ParaId, PersistedValidationData, TransientValidationData};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use crate::{configuration, paras, router};
|
||||
|
||||
@@ -34,7 +33,7 @@ pub fn make_persisted_validation_data<T: paras::Trait + router::Trait>(
|
||||
Some(PersistedValidationData {
|
||||
parent_head: <paras::Module<T>>::para_head(¶_id)?,
|
||||
block_number: relay_parent_number,
|
||||
hrmp_mqc_heads: Vec::new(),
|
||||
hrmp_mqc_heads: <router::Module<T>>::hrmp_mqc_heads(para_id),
|
||||
dmq_mqc_head: <router::Module<T>>::dmq_mqc_head(para_id),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user