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:
Sergei Shulepov
2020-11-06 16:35:36 +01:00
committed by GitHub
parent 8a2911b85d
commit c96f8cfcca
33 changed files with 2024 additions and 72 deletions
+1
View File
@@ -5478,6 +5478,7 @@ dependencies = [
"sp-std",
"sp-trie",
"sp-version",
"xcm",
]
[[package]]
+20
View File
@@ -102,6 +102,26 @@ pub struct InboundDownwardMessage<BlockNumber = crate::BlockNumber> {
pub msg: DownwardMessage,
}
/// An HRMP message seen from the perspective of a recipient.
#[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq)]
pub struct InboundHrmpMessage<BlockNumber = crate::BlockNumber> {
/// The block number at which this message was sent.
/// Specifically, it is the block number at which the candidate that sends this message was
/// enacted.
pub sent_at: BlockNumber,
/// The message payload.
pub data: sp_std::vec::Vec<u8>,
}
/// An HRMP message seen from the perspective of a sender.
#[derive(codec::Encode, codec::Decode, Clone, sp_runtime::RuntimeDebug, PartialEq, Eq, Hash)]
pub struct OutboundHrmpMessage<Id> {
/// The para that will get this message in its downward message queue.
pub recipient: Id,
/// The message payload.
pub data: sp_std::vec::Vec<u8>,
}
/// V1 primitives.
pub mod v1 {
pub use super::*;
@@ -274,10 +274,12 @@ async fn handle_new_activations<Context: SubsystemContext>(
let commitments = CandidateCommitments {
upward_messages: collation.upward_messages,
horizontal_messages: collation.horizontal_messages,
new_validation_code: collation.new_validation_code,
head_data: collation.head_data,
erasure_root,
processed_downward_messages: collation.processed_downward_messages,
hrmp_watermark: collation.hrmp_watermark,
};
let ccr = CandidateReceipt {
@@ -382,12 +384,14 @@ mod tests {
fn test_collation() -> Collation {
Collation {
upward_messages: Default::default(),
horizontal_messages: Default::default(),
new_validation_code: Default::default(),
head_data: Default::default(),
proof_of_validity: PoV {
block_data: BlockData(Vec::new()),
},
processed_downward_messages: Default::default(),
hrmp_watermark: Default::default(),
}
}
+10
View File
@@ -726,10 +726,12 @@ impl CandidateBackingJob {
let commitments = CandidateCommitments {
upward_messages: outputs.upward_messages,
horizontal_messages: outputs.horizontal_messages,
erasure_root,
new_validation_code: outputs.new_validation_code,
head_data: outputs.head_data,
processed_downward_messages: outputs.processed_downward_messages,
hrmp_watermark: outputs.hrmp_watermark,
};
let res = match with_commitments(commitments) {
@@ -1209,9 +1211,11 @@ mod tests {
tx.send(Ok(
ValidationResult::Valid(ValidationOutputs {
head_data: expected_head_data.clone(),
horizontal_messages: Vec::new(),
upward_messages: Vec::new(),
new_validation_code: None,
processed_downward_messages: 0,
hrmp_watermark: 0,
}, test_state.validation_data.persisted),
)).unwrap();
}
@@ -1346,8 +1350,10 @@ mod tests {
ValidationResult::Valid(ValidationOutputs {
head_data: expected_head_data.clone(),
upward_messages: Vec::new(),
horizontal_messages: Vec::new(),
new_validation_code: None,
processed_downward_messages: 0,
hrmp_watermark: 0,
}, test_state.validation_data.persisted),
)).unwrap();
}
@@ -1495,8 +1501,10 @@ mod tests {
ValidationResult::Valid(ValidationOutputs {
head_data: expected_head_data.clone(),
upward_messages: Vec::new(),
horizontal_messages: Vec::new(),
new_validation_code: None,
processed_downward_messages: 0,
hrmp_watermark: 0,
}, test_state.validation_data.persisted),
)).unwrap();
}
@@ -1678,8 +1686,10 @@ mod tests {
ValidationResult::Valid(ValidationOutputs {
head_data: expected_head_data.clone(),
upward_messages: Vec::new(),
horizontal_messages: Vec::new(),
new_validation_code: None,
processed_downward_messages: 0,
hrmp_watermark: 0,
}, test_state.validation_data.persisted),
)).unwrap();
}
@@ -489,8 +489,10 @@ fn validate_candidate_exhaustive<B: ValidationBackend, S: SpawnNamed + 'static>(
let outputs = ValidationOutputs {
head_data: res.head_data,
upward_messages: res.upward_messages,
horizontal_messages: res.horizontal_messages,
new_validation_code: res.new_validation_code,
processed_downward_messages: res.processed_downward_messages,
hrmp_watermark: res.hrmp_watermark,
};
Ok(ValidationResult::Valid(outputs, persisted_validation_data))
}
@@ -833,7 +835,9 @@ mod tests {
head_data: HeadData(vec![1, 1, 1]),
new_validation_code: Some(vec![2, 2, 2].into()),
upward_messages: Vec::new(),
horizontal_messages: Vec::new(),
processed_downward_messages: 0,
hrmp_watermark: 0,
};
let v = validate_candidate_exhaustive::<MockValidationBackend, _>(
@@ -848,7 +852,9 @@ mod tests {
assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => {
assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1]));
assert_eq!(outputs.upward_messages, Vec::<UpwardMessage>::new());
assert_eq!(outputs.horizontal_messages, Vec::new());
assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into()));
assert_eq!(outputs.hrmp_watermark, 0);
assert_eq!(used_validation_data, validation_data);
});
}
+78 -4
View File
@@ -130,6 +130,7 @@ fn make_runtime_api_request<Client>(
Request::CandidateEvents(sender) => query!(candidate_events(), sender),
Request::ValidatorDiscovery(ids, sender) => query!(validator_discovery(ids), sender),
Request::DmqContents(id, sender) => query!(dmq_contents(id), sender),
Request::InboundHrmpChannelsContents(id, sender) => query!(inbound_hrmp_channels_contents(id), sender),
}
}
@@ -180,12 +181,11 @@ mod tests {
ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, PersistedValidationData,
Id as ParaId, OccupiedCoreAssumption, ValidationData, SessionIndex, ValidationCode,
CommittedCandidateReceipt, CandidateEvent, AuthorityDiscoveryId, InboundDownwardMessage,
BlockNumber,
BlockNumber, InboundHrmpMessage,
};
use polkadot_node_subsystem_test_helpers as test_helpers;
use sp_core::testing::TaskExecutor;
use std::collections::HashMap;
use std::collections::{HashMap, BTreeMap};
use futures::channel::oneshot;
#[derive(Default, Clone)]
@@ -201,6 +201,7 @@ mod tests {
candidate_pending_availability: HashMap<ParaId, CommittedCandidateReceipt>,
candidate_events: Vec<CandidateEvent>,
dmq_contents: HashMap<ParaId, Vec<InboundDownwardMessage>>,
hrmp_channels: HashMap<ParaId, BTreeMap<ParaId, Vec<InboundHrmpMessage>>>,
}
impl ProvideRuntimeApi<Block> for MockRuntimeApi {
@@ -306,9 +307,16 @@ mod tests {
fn dmq_contents(
&self,
recipient: ParaId,
) -> Vec<polkadot_primitives::v1::InboundDownwardMessage> {
) -> Vec<InboundDownwardMessage> {
self.dmq_contents.get(&recipient).map(|q| q.clone()).unwrap_or_default()
}
fn inbound_hrmp_channels_contents(
&self,
recipient: ParaId
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage>> {
self.hrmp_channels.get(&recipient).map(|q| q.clone()).unwrap_or_default()
}
}
}
@@ -701,6 +709,72 @@ mod tests {
futures::executor::block_on(future::join(subsystem_task, test_task));
}
#[test]
fn requests_inbound_hrmp_channels_contents() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
let relay_parent = [1; 32].into();
let para_a = 99.into();
let para_b = 66.into();
let para_c = 33.into();
let para_b_inbound_channels = [
(para_a, vec![]),
(
para_c,
vec![InboundHrmpMessage {
sent_at: 1,
data: "𝙀=𝙈𝘾²".as_bytes().to_owned(),
}],
),
]
.iter()
.cloned()
.collect::<BTreeMap<_, _>>();
let runtime_api = Arc::new({
let mut runtime_api = MockRuntimeApi::default();
runtime_api.hrmp_channels.insert(para_a, BTreeMap::new());
runtime_api
.hrmp_channels
.insert(para_b, para_b_inbound_channels.clone());
runtime_api
});
let subsystem = RuntimeApiSubsystem::new(runtime_api.clone(), Metrics(None));
let subsystem_task = run(ctx, subsystem).map(|x| x.unwrap());
let test_task = async move {
let (tx, rx) = oneshot::channel();
ctx_handle
.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(
relay_parent,
Request::InboundHrmpChannelsContents(para_a, tx),
),
})
.await;
assert_eq!(rx.await.unwrap().unwrap(), BTreeMap::new());
let (tx, rx) = oneshot::channel();
ctx_handle
.send(FromOverseer::Communication {
msg: RuntimeApiMessage::Request(
relay_parent,
Request::InboundHrmpChannelsContents(para_b, tx),
),
})
.await;
assert_eq!(rx.await.unwrap().unwrap(), para_b_inbound_channels,);
ctx_handle
.send(FromOverseer::Signal(OverseerSignal::Conclude))
.await;
};
futures::executor::block_on(future::join(subsystem_task, test_task));
}
#[test]
fn requests_historical_code() {
let (ctx, mut ctx_handle) = test_helpers::make_subsystem_context(TaskExecutor::new());
+6 -2
View File
@@ -28,7 +28,7 @@ use polkadot_primitives::v1::{
Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement,
EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
UpwardMessage, ValidationCode, PersistedValidationData, ValidationData,
HeadData, PoV, CollatorPair, Id as ParaId, ValidationOutputs, CandidateHash,
HeadData, PoV, CollatorPair, Id as ParaId, OutboundHrmpMessage, ValidationOutputs, CandidateHash,
};
use polkadot_statement_table::{
generic::{
@@ -252,9 +252,11 @@ impl std::convert::TryFrom<FromTableMisbehavior> for MisbehaviorReport {
/// - does not contain the erasure root; that's computed at the Polkadot level, not at Cumulus
/// - contains a proof of validity.
#[derive(Clone, Encode, Decode)]
pub struct Collation {
pub struct Collation<BlockNumber = polkadot_primitives::v1::BlockNumber> {
/// Messages destined to be interpreted by the Relay chain itself.
pub upward_messages: Vec<UpwardMessage>,
/// The horizontal messages sent by the parachain.
pub horizontal_messages: Vec<OutboundHrmpMessage<ParaId>>,
/// New validation code.
pub new_validation_code: Option<ValidationCode>,
/// The head-data produced as a result of execution.
@@ -263,6 +265,8 @@ pub struct Collation {
pub proof_of_validity: PoV,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
pub hrmp_watermark: BlockNumber,
}
/// Configuration for the collation generator
+8 -1
View File
@@ -37,9 +37,10 @@ use polkadot_primitives::v1::{
GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption,
PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield,
ValidationCode, ValidatorId, ValidationData, CandidateHash,
ValidatorIndex, ValidatorSignature, InboundDownwardMessage,
ValidatorIndex, ValidatorSignature, InboundDownwardMessage, InboundHrmpMessage,
};
use std::sync::Arc;
use std::collections::btree_map::BTreeMap;
/// A notification of a new backed candidate.
#[derive(Debug)]
@@ -452,6 +453,12 @@ pub enum RuntimeApiRequest {
ParaId,
RuntimeApiSender<Vec<InboundDownwardMessage<BlockNumber>>>,
),
/// Get the contents of all channels addressed to the given recipient. Channels that have no
/// messages in them are also included.
InboundHrmpChannelsContents(
ParaId,
RuntimeApiSender<BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>>>,
),
}
/// A message to the Runtime API subsystem.
+21 -2
View File
@@ -28,7 +28,7 @@ use serde::{Serialize, Deserialize};
#[cfg(feature = "std")]
use sp_core::bytes;
use polkadot_core_primitives::Hash;
use polkadot_core_primitives::{Hash, OutboundHrmpMessage};
/// Block number type used by the relay chain.
pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;
@@ -186,6 +186,21 @@ impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
}
}
/// A type that uniquely identifies an HRMP channel. An HRMP channel is established between two paras.
/// In text, we use the notation `(A, B)` to specify a channel between A and B. The channels are
/// unidirectional, meaning that `(A, B)` and `(B, A)` refer to different channels. The convention is
/// that we use the first item tuple for the sender and the second for the recipient. Only one channel
/// is allowed between two participants in one direction, i.e. there cannot be 2 different channels
/// identified by `(A, B)`.
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Hash))]
pub struct HrmpChannelId {
/// The para that acts as the sender in this channel.
pub sender: Id,
/// The para that acts as the recipient in this channel.
pub recipient: Id,
}
/// A message from a parachain to its Relay Chain.
pub type UpwardMessage = Vec<u8>;
@@ -212,7 +227,7 @@ pub struct ValidationParams {
}
/// The result of parachain validation.
// TODO: egress and balance uploads (https://github.com/paritytech/polkadot/issues/220)
// TODO: balance uploads (https://github.com/paritytech/polkadot/issues/220)
#[derive(PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Debug, Decode))]
pub struct ValidationResult {
@@ -222,8 +237,12 @@ pub struct ValidationResult {
pub new_validation_code: Option<ValidationCode>,
/// Upward messages send by the Parachain.
pub upward_messages: Vec<UpwardMessage>,
/// Outbound horizontal messages sent by the parachain.
pub horizontal_messages: Vec<OutboundHrmpMessage<Id>>,
/// Number of downward messages that were processed by the Parachain.
///
/// It is expected that the Parachain processes them from first to last.
pub processed_downward_messages: u32,
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
pub hrmp_watermark: RelayChainBlockNumber,
}
@@ -114,10 +114,12 @@ impl Collator {
let collation = Collation {
upward_messages: Vec::new(),
horizontal_messages: Vec::new(),
new_validation_code: None,
head_data: head_data.encode().into(),
proof_of_validity: PoV { block_data: block_data.encode().into() },
processed_downward_messages: 0,
hrmp_watermark: validation_data.persisted.block_number,
};
async move { Some(collation) }.boxed()
@@ -17,12 +17,13 @@
//! WASM validation for adder parachain.
use crate::{HeadData, BlockData};
use core::{intrinsics, panic};
use core::panic;
use sp_std::vec::Vec;
use parachain::primitives::{ValidationResult, HeadData as GenericHeadData};
use codec::{Encode, Decode};
#[no_mangle]
pub extern fn validate_block(params: *const u8, len: usize) -> u64 {
pub extern "C" fn validate_block(params: *const u8, len: usize) -> u64 {
let params = unsafe { parachain::load_params(params, len) };
let parent_head = HeadData::decode(&mut &params.parent_head.0[..])
.expect("invalid parent head format.");
@@ -38,7 +39,9 @@ pub extern fn validate_block(params: *const u8, len: usize) -> u64 {
head_data: GenericHeadData(new_head.encode()),
new_validation_code: None,
upward_messages: sp_std::vec::Vec::new(),
horizontal_messages: sp_std::vec::Vec::new(),
processed_downward_messages: 0,
hrmp_watermark: params.relay_chain_height,
}
)
}
+18 -5
View File
@@ -17,6 +17,7 @@
//! V1 Primitives.
use sp_std::prelude::*;
use sp_std::collections::btree_map::BTreeMap;
use parity_scale_codec::{Encode, Decode};
use bitvec::vec::BitVec;
@@ -29,14 +30,14 @@ pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT};
// Export some core primitives.
pub use polkadot_core_primitives::v1::{
BlockNumber, Moment, Signature, AccountPublic, AccountId, AccountIndex,
ChainId, Hash, Nonce, Balance, Header, Block, BlockId, UncheckedExtrinsic,
Remark, DownwardMessage, InboundDownwardMessage, CandidateHash,
BlockNumber, Moment, Signature, AccountPublic, AccountId, AccountIndex, ChainId, Hash, Nonce,
Balance, Header, Block, BlockId, UncheckedExtrinsic, Remark, DownwardMessage,
InboundDownwardMessage, CandidateHash, InboundHrmpMessage, OutboundHrmpMessage,
};
// Export some polkadot-parachain primitives
pub use polkadot_parachain::primitives::{
Id, LOWEST_USER_ID, UpwardMessage, HeadData, BlockData, ValidationCode,
Id, LOWEST_USER_ID, HrmpChannelId, UpwardMessage, HeadData, BlockData, ValidationCode,
};
// Export some basic parachain primitives from v0.
@@ -317,18 +318,24 @@ pub struct ValidationOutputs {
pub head_data: HeadData,
/// Upward messages to the relay chain.
pub upward_messages: Vec<UpwardMessage>,
/// The horizontal messages sent by the parachain.
pub horizontal_messages: Vec<OutboundHrmpMessage<Id>>,
/// The new validation code submitted by the execution, if any.
pub new_validation_code: Option<ValidationCode>,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
pub hrmp_watermark: BlockNumber,
}
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default, Hash))]
pub struct CandidateCommitments {
pub struct CandidateCommitments<N = BlockNumber> {
/// Messages destined to be interpreted by the Relay chain itself.
pub upward_messages: Vec<UpwardMessage>,
/// Horizontal messages sent by the parachain.
pub horizontal_messages: Vec<OutboundHrmpMessage<Id>>,
/// The root of a block's erasure encoding Merkle tree.
pub erasure_root: Hash,
/// New validation code.
@@ -337,6 +344,8 @@ pub struct CandidateCommitments {
pub head_data: HeadData,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
/// The mark which specifies the block number up to which all inbound HRMP messages are processed.
pub hrmp_watermark: N,
}
impl CandidateCommitments {
@@ -735,6 +744,10 @@ sp_api::decl_runtime_apis! {
fn dmq_contents(
recipient: Id,
) -> Vec<InboundDownwardMessage<N>>;
/// Get the contents of all channels addressed to the given recipient. Channels that have no
/// messages in them are also included.
fn inbound_hrmp_channels_contents(recipient: Id) -> BTreeMap<Id, Vec<InboundHrmpMessage<N>>>;
}
}
@@ -70,8 +70,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
1. call `Router::check_upward_messages(para, commitments.upward_messages)` to check that the upward messages are valid.
1. call `Router::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained.
1. call `Router::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark.
1. check that in the commitments of each candidate the horizontal messages are sorted by ascending recipient ParaId and there is no two horizontal messages have the same recipient.
1. using `Router::verify_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate send a valid set of horizontal messages
1. using `Router::check_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate sent a valid set of horizontal messages
1. create an entry in the `PendingAvailability` map for each backed candidate with a blank `availability_votes` bitfield.
1. create a corresponding entry in the `PendingAvailabilityCommitments` with the commitments.
1. Return a `Vec<CoreIndex>` of all scheduled cores of the list of passed assignments that a candidate was successfully backed for, sorted ascending by CoreIndex.
@@ -79,9 +78,9 @@ All failed checks should lead to an unrecoverable error making the block invalid
1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number + config.validationl_upgrade_delay)`.
> TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it.
1. call `Router::enact_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments).
1. call `Router::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment,
1. call `Router::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`.
1. call `Router::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`.
1. call `Router::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`.
1. call `Router::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment,
1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`.
* `collect_pending`:
@@ -111,6 +111,7 @@ OutgoingParas: Vec<ParaId>;
* `note_new_head(ParaId, HeadData, BlockNumber)`: note that a para has progressed to a new head, where the new head was executed in the context of a relay-chain block with given number. This will apply pending code upgrades based on the block number provided.
* `validation_code_at(ParaId, at: BlockNumber, assume_intermediate: Option<BlockNumber>)`: Fetches the validation code to be used when validating a block in the context of the given relay-chain height. A second block number parameter may be used to tell the lookup to proceed as if an intermediate parablock has been included at the given relay-chain height. This may return past, current, or (with certain choices of `assume_intermediate`) future code. `assume_intermediate`, if provided, must be before `at`. If the validation code has been pruned, this will return `None`.
* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread.
* `is_valid_para(ParaId) -> bool`: Returns true if the para ID references either a live parathread or live parachain.
* `last_code_upgrade(id: ParaId, include_future: bool) -> Option<BlockNumber>`: The block number of the last scheduled upgrade of the requested para. Includes future upgrades if the flag is set. This is the `expected_at` number, not the `activated_at` number.
* `persisted_validation_data(id: ParaId) -> Option<PersistedValidationData>`: Get the PersistedValidationData of the given para, assuming the context is the parent block. Returns `None` if the para is not known.
@@ -78,10 +78,12 @@ struct HrmpOpenChannelRequest {
age: SessionIndex,
/// The amount that the sender supplied at the time of creation of this request.
sender_deposit: Balance,
/// The maximum message size that could be put into the channel.
max_message_size: u32,
/// The maximum number of messages that can be pending in the channel at once.
limit_used_places: u32,
max_capacity: u32,
/// The maximum total size of the messages that can be pending in the channel at once.
limit_used_bytes: u32,
max_total_size: u32,
}
/// A metadata of an HRMP channel.
@@ -91,25 +93,25 @@ struct HrmpChannel {
/// The amount that the recipient supplied as a deposit when accepting opening this channel.
recipient_deposit: Balance,
/// The maximum number of messages that can be pending in the channel at once.
limit_used_places: u32,
max_capacity: u32,
/// The maximum total size of the messages that can be pending in the channel at once.
limit_used_bytes: u32,
max_total_size: u32,
/// The maximum message size that could be put into the channel.
limit_message_size: u32,
max_message_size: u32,
/// The current number of messages pending in the channel.
/// Invariant: should be less or equal to `limit_used_places`.
used_places: u32,
/// Invariant: should be less or equal to `max_capacity`.
msg_count: u32,
/// The total size in bytes of all message payloads in the channel.
/// Invariant: should be less or equal to `limit_used_bytes`.
used_bytes: u32,
/// Invariant: should be less or equal to `max_total_size`.
total_size: u32,
/// A head of the Message Queue Chain for this channel. Each link in this chain has a form:
/// `(prev_head, B, H(M))`, where
/// - `prev_head`: is the previous value of `mqc_head`.
/// - `prev_head`: is the previous value of `mqc_head` or zero if none.
/// - `B`: is the [relay-chain] block number in which a message was appended
/// - `H(M)`: is the hash of the message being appended.
/// This value is initialized to a special value that consists of all zeroes which indicates
/// that no messages were previously added.
mqc_head: Hash,
mqc_head: Option<Hash>,
}
```
HRMP related storage layout
@@ -144,14 +146,26 @@ HrmpCloseChannelRequests: map 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 ParaId => Option<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 HrmpChannelId => Option<HrmpChannel>;
/// The indexes that map all senders to their recievers and vise versa.
/// 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)`.
/// - 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 ParaId => Vec<ParaId>;
HrmpEgressChannelsIndex: map ParaId => Vec<ParaId>;
/// Storage for the messages for each channel.
@@ -159,7 +173,11 @@ HrmpEgressChannelsIndex: map ParaId => Vec<ParaId>;
HrmpChannelContents: map HrmpChannelId => Vec<InboundHrmpMessage>;
/// 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.
/// Invariant: The para ids vector is never empty.
/// 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 ParaId => Vec<(BlockNumber, Vec<ParaId>)>;
```
@@ -184,12 +202,14 @@ Candidate Acceptance Function:
1. `new_hrmp_watermark` should be either
1. equal to the context's block number
1. or in `HrmpChannelDigests` for `P` an entry with the block number should exist
* `verify_outbound_hrmp(sender: ParaId, Vec<OutboundHrmpMessage>)`:
* `check_outbound_hrmp(sender: ParaId, Vec<OutboundHrmpMessage>)`:
1. Checks that there are at most `config.hrmp_max_message_num_per_candidate` messages.
1. Checks that horizontal messages are sorted by ascending recipient ParaId and there is no two horizontal messages have the same recipient.
1. For each horizontal message `M` with the channel `C` identified by `(sender, M.recipient)` check:
1. exists
1. `M`'s payload size doesn't exceed a preconfigured limit `C.limit_message_size`
1. `M`'s payload size summed with the `C.used_bytes` doesn't exceed a preconfigured limit `C.limit_used_bytes`.
1. `C.used_places + 1` doesn't exceed a preconfigured limit `C.limit_used_places`.
1. `M`'s payload size doesn't exceed a preconfigured limit `C.max_message_size`
1. `M`'s payload size summed with the `C.total_size` doesn't exceed a preconfigured limit `C.max_total_size`.
1. `C.msg_count + 1` doesn't exceed a preconfigured limit `C.max_capacity`.
Candidate Enactment:
@@ -197,17 +217,21 @@ Candidate Enactment:
1. For each horizontal message `HM` with the channel `C` identified by `(sender, HM.recipient)`:
1. Append `HM` into `HrmpChannelContents` that corresponds to `C` with `sent_at` equals to the current block number.
1. Locate or create an entry in `HrmpChannelDigests` for `HM.recipient` and append `sender` into the entry's list.
1. Increment `C.used_places`
1. Increment `C.used_bytes` by `HM`'s payload size
1. Increment `C.msg_count`
1. Increment `C.total_size` by `HM`'s payload size
1. Append a new link to the MQC and save the new head in `C.mqc_head`. Note that the current block number as of enactment is used for the link.
* `prune_hrmp(recipient, new_hrmp_watermark)`:
1. From `HrmpChannelDigests` for `recipient` remove all entries up to an entry with block number equal to `new_hrmp_watermark`.
1. From the removed digests construct a set of paras that sent new messages within the interval between the old and new watermarks.
1. For each channel `C` identified by `(sender, recipient)` for each `sender` coming from the set, prune messages up to the `new_hrmp_watermark`.
1. For each pruned message `M` from channel `C`:
1. Decrement `C.used_places`
1. Decrement `C.used_bytes` by `M`'s payload size.
1. Decrement `C.msg_count`
1. Decrement `C.total_size` by `M`'s payload size.
1. Set `HrmpWatermarks` for `P` to be equal to `new_hrmp_watermark`
> NOTE: That collecting digests can be inefficient and the time it takes grows very fast. Thanks to the aggresive
> parametrization this shouldn't be a big of a deal.
> If that becomes a problem consider introducing an extra dictionary which says at what block the given sender
> sent a message to the recipient.
* `prune_dmq(P: ParaId, processed_downward_messages)`:
1. Remove the first `processed_downward_messages` from the `DownwardMessageQueues` of `P`.
* `enact_upward_messages(P: ParaId, Vec<UpwardMessage>)`:
@@ -251,10 +275,10 @@ The following entry-points are meant to be used for HRMP channel management.
Those entry-points are meant to be called from a parachain. `origin` is defined as the `ParaId` of
the parachain executed the message.
* `hrmp_init_open_channel(recipient, max_places, max_message_size)`:
* `hrmp_init_open_channel(recipient, proposed_max_capacity, proposed_max_message_size)`:
1. Check that the `origin` is not `recipient`.
1. Check that `max_places` is less or equal to `config.hrmp_channel_max_places` and greater than zero.
1. Check that `max_message_size` is less or equal to `config.hrmp_channel_max_message_size` and greater than zero.
1. Check that `proposed_max_capacity` is less or equal to `config.hrmp_channel_max_capacity` and greater than zero.
1. Check that `proposed_max_message_size` is less or equal to `config.hrmp_channel_max_message_size` and greater than zero.
1. Check that `recipient` is a valid para.
1. Check that there is no existing channel for `(origin, recipient)` in `HrmpChannels`.
1. Check that there is no existing open channel request (`origin`, `recipient`) in `HrmpOpenChannelRequests`.
@@ -268,9 +292,15 @@ the parachain executed the message.
1. Append `(origin, recipient)` to `HrmpOpenChannelRequestsList`.
1. Add a new entry to `HrmpOpenChannelRequests` for `(origin, recipient)`
1. Set `sender_deposit` to `config.hrmp_sender_deposit`
1. Set `limit_used_places` to `max_places`
1. Set `limit_message_size` to `max_message_size`
1. Set `limit_used_bytes` to `config.hrmp_channel_max_size`
1. Set `max_capacity` to `proposed_max_capacity`
1. Set `max_message_size` to `proposed_max_message_size`
1. Set `max_total_size` to `config.hrmp_channel_max_total_size`
1. Send a downward message to `recipient` notifying about an inbound HRMP channel request.
- The DM is sent using `queue_downward_message`.
- The DM is represented by the `HrmpNewChannelOpenRequest` XCM message.
- `sender` is set to `origin`,
- `max_message_size` is set to `proposed_max_message_size`,
- `max_capacity` is set to `proposed_max_capacity`.
* `hrmp_accept_open_channel(sender)`:
1. Check that there is an existing request between (`sender`, `origin`) in `HrmpOpenChannelRequests`
1. Check that it is not confirmed.
@@ -283,12 +313,23 @@ the parachain executed the message.
1. Reserve the deposit for the `origin` according to `config.hrmp_recipient_deposit`
1. For the request in `HrmpOpenChannelRequests` identified by `(sender, P)`, set `confirmed` flag to `true`.
1. Increase `HrmpAcceptedChannelRequestCount` by 1 for `origin`.
1. Send a downward message to `sender` notifying that the channel request was accepted.
- The DM is sent using `queue_downward_message`.
- The DM is represented by the `HrmpChannelAccepted` XCM message.
- `recipient` is set to `origin`.
* `hrmp_close_channel(ch)`:
1. Check that `origin` is either `ch.sender` or `ch.recipient`
1. Check that `HrmpChannels` for `ch` exists.
1. Check that `ch` is not in the `HrmpCloseChannelRequests` set.
1. If not already there, insert a new entry `Some(())` to `HrmpCloseChannelRequests` for `ch`
and append `ch` to `HrmpCloseChannelRequestsList`.
1. Send a downward message to the opposite party notifying about the channel closing.
- The DM is sent using `queue_downward_message`.
- The DM is represented by the `HrmpChannelClosing` XCM message with:
- `initator` is set to `origin`,
- `sender` is set to `ch.sender`,
- `recipient` is set to `ch.recipient`.
- The opposite party is `ch.sender` if `origin` is `ch.recipient` and `ch.recipient` if `origin` is `ch.sender`.
## Session Change
@@ -42,8 +42,6 @@ that we use the first item tuple for the sender and the second for the recipient
is allowed between two participants in one direction, i.e. there cannot be 2 different channels
identified by `(A, B)`.
`HrmpChannelId` has a defined ordering: first `sender` and tie is resolved by `recipient`.
```rust,ignore
struct HrmpChannelId {
sender: ParaId,
@@ -77,18 +77,24 @@ struct HostConfiguration {
/// The deposit that the recipient should provide for accepting opening an HRMP channel.
pub hrmp_recipient_deposit: u32,
/// The maximum number of messages allowed in an HRMP channel at once.
pub hrmp_channel_max_places: u32,
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_size: u32,
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,
}
```
@@ -427,6 +427,7 @@ mod tests {
impl router::Trait for Test {
type UmpSink = ();
type Origin = Origin;
}
impl pallet_session::historical::Trait for Test {
+9 -1
View File
@@ -22,12 +22,14 @@
use pallet_transaction_payment::CurrencyAdapter;
use sp_std::prelude::*;
use sp_std::collections::btree_map::BTreeMap;
use sp_core::u32_trait::{_1, _2, _3, _5};
use codec::{Encode, Decode};
use primitives::v1::{
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
InboundDownwardMessage, InboundHrmpMessage,
};
use runtime_common::{
claims, SlowAdjustingFeeUpdate, CurrencyToVote,
@@ -1112,9 +1114,15 @@ sp_api::impl_runtime_apis! {
fn dmq_contents(
_recipient: Id,
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
) -> Vec<InboundDownwardMessage<BlockNumber>> {
Vec::new()
}
fn inbound_hrmp_channels_contents(
_recipient: Id
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
BTreeMap::new()
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
+2
View File
@@ -33,6 +33,7 @@ pallet-vesting = { git = "https://github.com/paritytech/substrate", branch = "ma
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
xcm = { package = "xcm", path = "../../xcm", default-features = false }
primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false }
libsecp256k1 = { version = "0.3.2", default-features = false, optional = true }
@@ -81,6 +82,7 @@ std = [
"frame-system/std",
"pallet-timestamp/std",
"pallet-vesting/std",
"xcm/std",
]
runtime-benchmarks = [
"libsecp256k1/hmac",
@@ -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(
+1
View File
@@ -109,6 +109,7 @@ impl crate::paras::Trait for Test {
}
impl crate::router::Trait for Test {
type Origin = Origin;
type UmpSink = crate::router::MockUmpSink;
}
+6
View File
@@ -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()
+154 -9
View File
@@ -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(&notification.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)
}
+1 -2
View File
@@ -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(&para_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),
})
}
+10 -1
View File
@@ -30,12 +30,14 @@ use runtime_common::{
};
use sp_std::prelude::*;
use sp_std::collections::btree_map::BTreeMap;
use sp_core::u32_trait::{_1, _2, _3, _4, _5};
use codec::{Encode, Decode};
use primitives::v1::{
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
InboundDownwardMessage, InboundHrmpMessage,
};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys, ModuleId, ApplyExtrinsicResult,
@@ -1106,9 +1108,16 @@ sp_api::impl_runtime_apis! {
fn dmq_contents(
_recipient: Id,
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
) -> Vec<InboundDownwardMessage<BlockNumber>> {
Vec::new()
}
fn inbound_hrmp_channels_contents(
_recipient: Id
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
BTreeMap::new()
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
+10 -2
View File
@@ -22,12 +22,13 @@
use pallet_transaction_payment::CurrencyAdapter;
use sp_std::prelude::*;
use sp_std::collections::btree_map::BTreeMap;
use codec::Encode;
use primitives::v1::{
AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
GroupRotationInfo, CoreState, Id, ValidationData, ValidationCode, CandidateEvent,
ValidatorId, ValidatorIndex, CommittedCandidateReceipt, OccupiedCoreAssumption,
PersistedValidationData,
PersistedValidationData, InboundDownwardMessage, InboundHrmpMessage,
};
use runtime_common::{
SlowAdjustingFeeUpdate,
@@ -532,6 +533,7 @@ impl parachains_paras::Trait for Runtime {
}
impl parachains_router::Trait for Runtime {
type Origin = Origin;
type UmpSink = (); // TODO: #1873 To be handled by the XCM receiver.
}
@@ -681,9 +683,15 @@ sp_api::impl_runtime_apis! {
runtime_api_impl::validator_discovery::<Runtime>(validators)
}
fn dmq_contents(recipient: Id) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
fn dmq_contents(recipient: Id) -> Vec<InboundDownwardMessage<BlockNumber>> {
runtime_api_impl::dmq_contents::<Runtime>(recipient)
}
fn inbound_hrmp_channels_contents(
recipient: Id
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
runtime_api_impl::inbound_hrmp_channels_contents::<Runtime>(recipient)
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
+10 -1
View File
@@ -22,6 +22,7 @@
use pallet_transaction_payment::CurrencyAdapter;
use sp_std::prelude::*;
use sp_std::collections::btree_map::BTreeMap;
use codec::Encode;
use polkadot_runtime_parachains::{
configuration,
@@ -36,6 +37,7 @@ use primitives::v1::{
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
CoreState, GroupRotationInfo, Hash as HashT, Id as ParaId, Moment, Nonce, OccupiedCoreAssumption,
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
InboundDownwardMessage, InboundHrmpMessage,
};
use runtime_common::{
claims, SlowAdjustingFeeUpdate, paras_sudo_wrapper,
@@ -453,6 +455,7 @@ impl paras::Trait for Runtime {
}
impl router::Trait for Runtime {
type Origin = Origin;
type UmpSink = ();
}
@@ -668,9 +671,15 @@ sp_api::impl_runtime_apis! {
fn dmq_contents(
recipient: ParaId,
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
) -> Vec<InboundDownwardMessage<BlockNumber>> {
runtime_impl::dmq_contents::<Runtime>(recipient)
}
fn inbound_hrmp_channels_contents(
recipient: ParaId,
) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>> {
runtime_impl::inbound_hrmp_channels_contents::<Runtime>(recipient)
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
+9 -1
View File
@@ -22,11 +22,13 @@
use pallet_transaction_payment::CurrencyAdapter;
use sp_std::prelude::*;
use sp_std::collections::btree_map::BTreeMap;
use codec::{Encode, Decode};
use primitives::v1::{
AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
CoreState, GroupRotationInfo, Hash, Id, Moment, Nonce, OccupiedCoreAssumption,
PersistedValidationData, Signature, ValidationCode, ValidationData, ValidatorId, ValidatorIndex,
InboundDownwardMessage, InboundHrmpMessage,
};
use runtime_common::{
SlowAdjustingFeeUpdate, CurrencyToVote,
@@ -856,9 +858,15 @@ sp_api::impl_runtime_apis! {
fn dmq_contents(
_recipient: Id,
) -> Vec<primitives::v1::InboundDownwardMessage<BlockNumber>> {
) -> Vec<InboundDownwardMessage<BlockNumber>> {
Vec::new()
}
fn inbound_hrmp_channels_contents(
_recipient: Id
) -> BTreeMap<Id, Vec<InboundHrmpMessage<BlockNumber>>> {
BTreeMap::new()
}
}
impl fg_primitives::GrandpaApi<Block> for Runtime {
+45
View File
@@ -158,6 +158,51 @@ pub enum Xcm {
///
/// Errors:
RelayedFrom { superorigin: MultiLocation, inner: Box<VersionedXcm> },
/// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the
/// relay-chain to a para.
///
/// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening.
/// - `max_message_size`: The maximum size of a message proposed by the sender.
/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
///
/// Safety: The message should originate directly from the relay-chain.
///
/// Kind: *System Notification*
HrmpNewChannelOpenRequest {
#[codec(compact)] sender: u32,
#[codec(compact)] max_message_size: u32,
#[codec(compact)] max_capacity: u32,
},
/// A message to notify about that a previously sent open channel request has been accepted by
/// the recipient. That means that the channel will be opened during the next relay-chain session
/// change. This message is meant to be sent by the relay-chain to a para.
///
/// Safety: The message should originate directly from the relay-chain.
///
/// Kind: *System Notification*
///
/// Errors:
HrmpChannelAccepted {
#[codec(compact)] recipient: u32,
},
/// A message to notify that the other party in an open channel decided to close it. In particular,
/// `inititator` is going to close the channel opened from `sender` to the `recipient`. The close
/// will be enacted at the next relay-chain session change. This message is meant to be sent by
/// the relay-chain to a para.
///
/// Safety: The message should originate directly from the relay-chain.
///
/// Kind: *System Notification*
///
/// Errors:
HrmpChannelClosing {
#[codec(compact)] initiator: u32,
#[codec(compact)] sender: u32,
#[codec(compact)] recipient: u32,
},
}
impl From<Xcm> for VersionedXcm {