From 3bce443ca0746efaa0dfba7048326813193fc0f8 Mon Sep 17 00:00:00 2001 From: Sergei Shulepov Date: Mon, 24 Aug 2020 12:47:15 +0200 Subject: [PATCH 1/4] Integrate `DMP` into `PersistentValidationData` --- .../src/runtime/inclusion.md | 4 +- .../implementers-guide/src/runtime/router.md | 54 +++++++++++++++---- .../implementers-guide/src/types/candidate.md | 25 ++++++--- .../implementers-guide/src/types/messages.md | 12 +++++ 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/roadmap/implementers-guide/src/runtime/inclusion.md b/roadmap/implementers-guide/src/runtime/inclusion.md index 17dbdc94cc02..58bc912a4e6e 100644 --- a/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/roadmap/implementers-guide/src/runtime/inclusion.md @@ -69,7 +69,7 @@ All failed checks should lead to an unrecoverable error making the block invalid 1. Check the collator's signature on the candidate data. 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup. 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_dmq_watermark(para, commitments.dmq_watermark)` for each canddiate to check rules of processing the DMQ watermark. 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 @@ -82,7 +82,7 @@ All failed checks should lead to an unrecoverable error making the block invalid 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_dmq` with the para id of the candidate and the candidate's `dmq_watermark`. 1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`. * `collect_pending`: diff --git a/roadmap/implementers-guide/src/runtime/router.md b/roadmap/implementers-guide/src/runtime/router.md index 4253453fe924..1c4eab8ad48d 100644 --- a/roadmap/implementers-guide/src/runtime/router.md +++ b/roadmap/implementers-guide/src/runtime/router.md @@ -23,8 +23,28 @@ NeedsDispatch: Vec; /// This is the para that gets will get dispatched first during the next upward dispatchable queue /// execution round. NextDispatchRoundStartWith: Option; +``` + +### DMP + +Storage layout required for implementation of DMP. + +``` /// The downward messages addressed for a certain para. -DownwardMessageQueues: map ParaId => Vec; +DownwardMessageQueues: map ParaId => Vec; +/// A mapping that stores the downward message queue MQC head for each para. +/// +/// Each link in this chain has a form: +/// `(prev_head, B, H(M))`, where +/// - `prev_head`: is the previous head hash. +/// - `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. +DownwardMessageQueueHeads: map ParaId => Option; +DownwardMessageQueueWatermarks: map ParaId => Option; +/// A set of numbers of blocks in which at least one downward message were enqueued for a given para. +DownwardMessagesDigest: map ParaId => Vec; ``` ### HRMP @@ -115,7 +135,7 @@ HrmpEgressChannelsIndex: map ParaId => Vec; HrmpChannelContents: map HrmpChannelId => Vec; /// 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 vector is never empty. +/// Invariant: The para ids vector is never empty. HrmpChannelDigests: map ParaId => Vec<(BlockNumber, Vec)>; ``` @@ -151,9 +171,10 @@ Candidate Acceptance Function: 1. Check that `P` is either `ch.sender` or `ch.recipient` 1. Check that `HrmpChannels` for `ch` exists. 1. Check that `ch` is not in the `HrmpCloseChannelRequests` set. -* `check_processed_downward_messages(P: ParaId, processed_downward_messages)`: - 1. Checks that `DownwardMessageQueues` for `P` is at least `processed_downward_messages` long. - 1. Checks that `processed_downward_messages` is at least 1 if `DownwardMessageQueues` for `P` is not empty. +* `check_dmq_watermark(P: ParaId, new_dmq_watermark)`: + 1. `new_dmq_watermark` should be strictly greater than the value of `DownwardMessageQueueWatermarks` for `P` (if any). + 1. `new_dmq_watermark` must be not greater than the context's block number. + 1. in `DownwardMessagesDigest` for `P` an entry with the block number equal to `new_dmq_watermark` should exist. * `check_hrmp_watermark(P: ParaId, new_hrmp_watermark)`: 1. `new_hrmp_watermark` should be strictly greater than the value of `HrmpWatermarks` for `P` (if any). 1. `new_hrmp_watermark` must not be greater than the context's block number. @@ -168,7 +189,7 @@ Candidate Enactment: * `queue_outbound_hrmp(sender: ParaId, Vec)`: 1. For each horizontal message `HM` with the channel `C` identified by `(sender, HM.recipient)`: - 1. Append `HM` into `HrmpChannelContents` that corresponds to `C`. + 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 @@ -181,8 +202,8 @@ Candidate Enactment: 1. Decrement `C.used_places` 1. Decrement `C.used_bytes` by `M`'s payload size. 1. Set `HrmpWatermarks` for `P` to be equal to `new_hrmp_watermark` -* `prune_dmq(P: ParaId, processed_downward_messages)`: - 1. Remove the first `processed_downward_messages` from the `DownwardMessageQueues` of `P`. +* `prune_dmq(P: ParaId, new_dmq_watermark)`: + 1. Remove all messages in `DownwardMessageQueues` for `P` up to (including) a message with `sent_at` equal to `new_dmq_watermark`. * `enact_upward_messages(P: ParaId, Vec)`: 1. Process all upward messages in order depending on their kinds: 1. If the message kind is `Dispatchable`: @@ -228,7 +249,15 @@ any of dispatchables return an error. 1. If `NeedsDispatch` became empty then finish processing and set `NextDispatchRoundStartWith` to `None`. 1. Then, for each `P` and the vector of `DispatchResult` in `R`: 1. Obtain a message by wrapping the vector into `DownwardMessage::DispatchResult` - 1. Append the resulting message to `DownwardMessageQueues` for `P`. + 1. Call `enqueue_downward_message` with `P` and the resulting message. + +Utility routines. + +`queue_downward_message(P: ParaId, M: DownwardMessage)`: + 1. Wrap `M` into `InboundDownwardMessage` using the current block number for `sent_at`. + 1. Obtain a new MQC link for the resulting `InboundDownwardMessage` and replace `DownwardMessageQueueHeads` for `P` with the resulting hash. + 1. Adds the current block number to the set `DownwardMessagesDigest` for `P`. + 1. Add the resulting `InboundDownwardMessage` into `DownwardMessageQueues` for `P`. ## Session Change @@ -236,6 +265,9 @@ any of dispatchables return an error. 1. Remove all inbound channels of `P`, i.e. `(_, P)`, 1. Remove all outbound channels of `P`, i.e. `(P, _)`, 1. Remove all `DownwardMessageQueues` of `P`. + 1. Remove `DownwardMessageQueueWatermarks` for `P`. + 1. Remove `DownwardMessageQueueHeads` for `P`. + 1. Remove `DownwardMessagesDigest` for `P`. 1. Remove `RelayDispatchQueueSize` of `P`. 1. Remove `RelayDispatchQueues` of `P`. 1. Remove `P` if it exists in `NeedsDispatch`. @@ -259,12 +291,12 @@ any of dispatchables return an error. 1. decrement `HrmpOpenChannelRequestCount` for `D.sender` by 1. 1. remove `R` 1. remove `D` -1. For each channel designator `D` in `HrmpCloseChannelRequestsList` +1. For each HRMP channel designator `D` in `HrmpCloseChannelRequestsList` 1. remove the channel identified by `D`, if exists. 1. remove `D` from `HrmpCloseChannelRequests`. 1. remove `D` from `HrmpCloseChannelRequestsList` -To remove a channel `C` identified with a tuple `(sender, recipient)`: +To remove a HRMP channel `C` identified with a tuple `(sender, recipient)`: 1. Return `C.sender_deposit` to the `sender`. 1. Return `C.recipient_deposit` to the `recipient`. diff --git a/roadmap/implementers-guide/src/types/candidate.md b/roadmap/implementers-guide/src/types/candidate.md index 6732d11ad8dd..baf9ed21bafd 100644 --- a/roadmap/implementers-guide/src/types/candidate.md +++ b/roadmap/implementers-guide/src/types/candidate.md @@ -129,9 +129,14 @@ struct PersistedValidationData { /// vector is sorted ascending by the para id and doesn't contain multiple entries with the same /// sender. /// - /// The MQC heads will be used by the validation function to authorize the input messages passed + /// The HRMP MQC heads will be used by the validation function to authorize the input messages passed /// by the collator. hrmp_mqc_heads: Vec<(ParaId, Hash)>, + /// The MQC head for the DMQ. + /// + /// The DMQ MQC head will be used by the validation fnction to authorize the downward messages + /// passed by the collator. + dmq_mqc_head: Hash, } ``` @@ -170,9 +175,13 @@ struct TransientValidationData { /// A copy of `config.max_upward_message_num_per_candidate` for checking that a candidate doesn't /// send more messages that permitted. config_max_upward_message_num_per_candidate: u32, - /// The number of messages pending of the downward message queue. - dmq_length: u32, - /// A part of transient validation data related to HRMP. + /// A vector that enumerates the list of blocks in which there was at least one DMQ messages + /// enqueued. + /// + /// The first number in the vector, if any, is always greater than the DMQ watermark. The + /// elements are ordered by ascending the block number. The vector doesn't contain duplicates. + dmq_digest: Vec, + /// A part of transient validaiton data related to HRMP. hrmp: HrmpTransientValidationData, } @@ -246,8 +255,8 @@ struct CandidateCommitments { new_validation_code: Option, /// The head-data produced as a result of execution. head_data: HeadData, - /// The number of messages processed from the DMQ. - processed_downward_messages: u32, + /// The mark which specifies the block number up to which all inbound DMP messages are processed. + dmq_watermark: BlockNumber, /// The mark which specifies the block number up to which all inbound HRMP messages are processed. hrmp_watermark: BlockNumber, } @@ -284,8 +293,8 @@ struct ValidationOutputs { fees: Balance, /// The new validation code submitted by the execution, if any. new_validation_code: Option, - /// The number of messages processed from the DMQ. - processed_downward_messages: u32, + /// The mark which specifies the block number up to which all inbound DMP messages are processed. + dmq_watermark: BlockNumber, /// The mark which specifies the block number up to which all inbound HRMP messages are processed. hrmp_watermark: BlockNumber, } diff --git a/roadmap/implementers-guide/src/types/messages.md b/roadmap/implementers-guide/src/types/messages.md index ba77a9ecbc10..6a5005ae0dc1 100644 --- a/roadmap/implementers-guide/src/types/messages.md +++ b/roadmap/implementers-guide/src/types/messages.md @@ -90,6 +90,9 @@ struct OutboundHrmpMessage { } struct InboundHrmpMessage { + /// 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: Vec, @@ -125,4 +128,13 @@ enum DownwardMessage { /// paras. ParachainSpecific(Vec), } + +/// A wrapped version of `DownwardMessage`. The difference is that it has attached the block number when +/// the message was sent. +struct InboundDownwardMessage { + /// The block number at which this messages was put into the downward message queue. + pub sent_at: BlockNumber, + /// The actual downward message to processes. + pub msg: DownwardMessage, +} ``` From 9fab10eeb99cb4f41328b2c783c92f98a5ebe95a Mon Sep 17 00:00:00 2001 From: Sergei Shulepov Date: Mon, 24 Aug 2020 14:22:12 +0200 Subject: [PATCH 2/4] Prune DMP digests according to the watermark --- roadmap/implementers-guide/src/runtime/router.md | 1 + 1 file changed, 1 insertion(+) diff --git a/roadmap/implementers-guide/src/runtime/router.md b/roadmap/implementers-guide/src/runtime/router.md index 1c4eab8ad48d..2563a31a06fa 100644 --- a/roadmap/implementers-guide/src/runtime/router.md +++ b/roadmap/implementers-guide/src/runtime/router.md @@ -204,6 +204,7 @@ Candidate Enactment: 1. Set `HrmpWatermarks` for `P` to be equal to `new_hrmp_watermark` * `prune_dmq(P: ParaId, new_dmq_watermark)`: 1. Remove all messages in `DownwardMessageQueues` for `P` up to (including) a message with `sent_at` equal to `new_dmq_watermark`. + 1. Remove all block numbers up to (including) `new_dmq_watermark` in `DownwardMessagesDigest` for `P` * `enact_upward_messages(P: ParaId, Vec)`: 1. Process all upward messages in order depending on their kinds: 1. If the message kind is `Dispatchable`: From 6815951545d3934ab9c1d66f33818fb6be524cf0 Mon Sep 17 00:00:00 2001 From: Sergei Shulepov Date: Mon, 31 Aug 2020 12:44:10 +0200 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Bernhard Schuster --- roadmap/implementers-guide/src/runtime/inclusion.md | 2 +- roadmap/implementers-guide/src/runtime/router.md | 2 +- roadmap/implementers-guide/src/types/candidate.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roadmap/implementers-guide/src/runtime/inclusion.md b/roadmap/implementers-guide/src/runtime/inclusion.md index 58bc912a4e6e..45bff7935a2e 100644 --- a/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/roadmap/implementers-guide/src/runtime/inclusion.md @@ -69,7 +69,7 @@ All failed checks should lead to an unrecoverable error making the block invalid 1. Check the collator's signature on the candidate data. 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup. 1. call `Router::check_upward_messages(para, commitments.upward_messages)` to check that the upward messages are valid. - 1. call `Router::check_dmq_watermark(para, commitments.dmq_watermark)` for each canddiate to check rules of processing the DMQ watermark. + 1. call `Router::check_dmq_watermark(para, commitments.dmq_watermark)` for each candidate to check rules of processing the DMQ watermark. 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 diff --git a/roadmap/implementers-guide/src/runtime/router.md b/roadmap/implementers-guide/src/runtime/router.md index 2563a31a06fa..88ca457cc01f 100644 --- a/roadmap/implementers-guide/src/runtime/router.md +++ b/roadmap/implementers-guide/src/runtime/router.md @@ -25,7 +25,7 @@ NeedsDispatch: Vec; NextDispatchRoundStartWith: Option; ``` -### DMP +### Downward Message Passing (DMP) Storage layout required for implementation of DMP. diff --git a/roadmap/implementers-guide/src/types/candidate.md b/roadmap/implementers-guide/src/types/candidate.md index baf9ed21bafd..6624ec6e712c 100644 --- a/roadmap/implementers-guide/src/types/candidate.md +++ b/roadmap/implementers-guide/src/types/candidate.md @@ -173,7 +173,7 @@ struct TransientValidationData { /// This informs a relay-chain backing check and the parachain logic. code_upgrade_allowed: Option, /// A copy of `config.max_upward_message_num_per_candidate` for checking that a candidate doesn't - /// send more messages that permitted. + /// send more messages than permitted. config_max_upward_message_num_per_candidate: u32, /// A vector that enumerates the list of blocks in which there was at least one DMQ messages /// enqueued. From 398cf4a419f002a1382288a3c1083c0a58c07caa Mon Sep 17 00:00:00 2001 From: Sergei Shulepov Date: Mon, 31 Aug 2020 12:44:21 +0200 Subject: [PATCH 4/4] Update roadmap/implementers-guide/src/types/candidate.md Co-authored-by: Bernhard Schuster --- roadmap/implementers-guide/src/types/candidate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roadmap/implementers-guide/src/types/candidate.md b/roadmap/implementers-guide/src/types/candidate.md index 6624ec6e712c..d479edc668f1 100644 --- a/roadmap/implementers-guide/src/types/candidate.md +++ b/roadmap/implementers-guide/src/types/candidate.md @@ -181,7 +181,7 @@ struct TransientValidationData { /// The first number in the vector, if any, is always greater than the DMQ watermark. The /// elements are ordered by ascending the block number. The vector doesn't contain duplicates. dmq_digest: Vec, - /// A part of transient validaiton data related to HRMP. + /// A part of transient validation data related to HRMP. hrmp: HrmpTransientValidationData, }