Unverified Commit 31f7ef9b authored by Sergey Pepyakin's avatar Sergey Pepyakin Committed by GitHub
Browse files

Implementer's Guide: Make HRMP use upward message kinds (#1591)



* Draft HRMP related message types

* Make HRMP use upward message kinds

* Incorporate changes into messaging.md

* Make docs a bit more clear

* Clarify remove "D"

* Update roadmap/implementers-guide/src/messaging.md
Co-authored-by: default avatarBernhard Schuster <bernhard@ahoi.io>

* Update roadmap/implementers-guide/src/runtime/router.md
Co-authored-by: default avatarBernhard Schuster <bernhard@ahoi.io>

* Update router.md

* Update roadmap/implementers-guide/src/runtime/router.md
Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>
Co-authored-by: default avatarBernhard Schuster <bernhard@ahoi.io>
Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>
parent 804958ab
Pipeline #104138 passed with stages
in 26 minutes and 20 seconds
......@@ -36,9 +36,10 @@ The weight that processing of the dispatchables can consume is limited by a prec
that some dispatchables will be left for later blocks. To make the dispatching more fair, the queues are processed turn-by-turn
in a round robin fashion.
Other kinds of upward messages can be introduced in the future as well. Potential candidates are channel management for
horizontal message passing (XCMP and HRMP, both are to be described below), new validation code signalling, or other
requests to the relay chain.
Upward messages are also used by a parachain to request opening and closing HRMP channels (HRMP will be described below).
Other kinds of upward messages can be introduced in the future as well. Potential candidates are
new validation code signalling, or other requests to the relay chain.
## Horizontal Message Passing
......
......@@ -34,10 +34,6 @@ HRMP related structs:
```rust,ignore
/// A description of a request to open an HRMP channel.
struct HrmpOpenChannelRequest {
/// The sender and the initiator of this request.
sender: ParaId,
/// The recipient of the opened request.
recipient: ParaId,
/// Indicates if this request was confirmed by the recipient.
confirmed: bool,
/// How many session boundaries ago this request was seen.
......@@ -50,19 +46,6 @@ struct HrmpOpenChannelRequest {
limit_used_bytes: u32,
}
/// A description of a request to close an opened HRMP channel.
struct HrmpCloseChannelRequest {
/// The para which initiated closing an existing channel.
///
/// Invariant: it should be equal to one of the following
/// - `Some(sender)`
/// - `Some(recipient)`
/// - `None` in case the request initiated by the runtime (including governance, migration, etc)
initiator: Option<ParaId>,
/// The identifier of an HRMP channel to be closed.
id: HrmpChannelId,
}
/// A metadata of an HRMP channel.
struct HrmpChannel {
/// The amount that the sender supplied as a deposit when opening this channel.
......@@ -92,14 +75,30 @@ struct HrmpChannel {
HRMP related storage layout
```rust,ignore
/// Pending HRMP open channel requests.
HrmpOpenChannelRequests: Vec<HrmpOpenChannelRequest>;
/// 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 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 `_.sender == X`
/// Invariant: `HrmpOpenChannelRequestsList` should contain the same number of items that has `(X, _)`
/// as the number of `HrmpOpenChannelRequestCount` for `X`.
HrmpOpenChannelRequestCount: map ParaId => u32;
/// Pending HRMP close channel requests.
HrmpCloseChannelRequests: Vec<HrmpCloseChannelRequest>;
/// 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 HrmpChannelId => Option<()>;
HrmpCloseChannelRequestsList: Vec<HrmpChannelId>;
/// The HRMP watermark associated with each para.
HrmpWatermarks: map ParaId => Option<BlockNumber>;
/// HRMP channel data associated with each para.
......@@ -123,44 +122,32 @@ HrmpChannelDigests: map ParaId => Vec<(BlockNumber, Vec<ParaId>)>;
No initialization routine runs for this module.
## Entry points
The following routines are intended to be invoked by paras' upward messages.
* `hrmp_init_open_channel(recipient)`:
1. Check that the origin of this message is a para. We say that the origin of this message is the `sender`.
1. Check that the `sender` is not `recipient`.
1. Check that the `recipient` para exists.
1. Check that there is no existing open channel request from sender to recipient.
1. Check that the sum of the number of already opened HRMP channels by the `sender` (the size of the set found `HrmpEgressChannelsIndex` for `sender`) and the number of open requests by the `sender` (the value from `HrmpOpenChannelRequestCount` for `sender`) doesn't exceed the limit of channels (`config.hrmp_max_parachain_outbound_channels` or `config.hrmp_max_parathread_outbound_channels`) minus 1.
1. Reserve the deposit for the `sender` according to `config.hrmp_sender_deposit`
1. Add a new entry to `HrmpOpenChannelRequests` and increase `HrmpOpenChannelRequestCount` by 1 for the `sender`.
1. Set `sender_deposit` to `config.hrmp_sender_deposit`
1. Set `limit_used_places` to `config.hrmp_channel_max_places`
1. Set `limit_limit_used_bytes` to `config.hrmp_channel_max_size`
* `hrmp_accept_open_channel(i)`, `i` - is the index of open channel request:
1. Check that the designated open channel request exists
1. Check that the request's `recipient` corresponds to the origin of this message.
1. Reserve the deposit for the `recipient` according to `config.hrmp_recipient_deposit`
1. Set the request's `confirmed` flag to `true`.
* `hrmp_close_channel(sender, recipient)`:
1. Check that the channel between `sender` and `recipient` exists
1. Check that the origin of the message is either `sender` or `recipient`
1. Check that there is no existing intention to close the channel between `sender` and `recipient`.
1. Add a new entry to `HrmpCloseChannelRequests` with initiator set to the `Some` variant with the origin of this message.
## Routines
Candidate Acceptance Function:
* `check_upward_messages(P: ParaId, Vec<UpwardMessage>`:
1. Checks that there are at most `config.max_upward_message_num_per_candidate` messages.
1. Checks each upward message individually depending on its kind:
1. Checks each upward message `M` individually depending on its kind:
1. If the message kind is `Dispatchable`:
1. Verify that `RelayDispatchQueueSize` for `P` has enough capacity for the message (NOTE that should include all processed
upward messages of the `Dispatchable` kind up to this point!)
1. If the message kind is `HrmpInitOpenChannel(recipient)`:
1. Check that the `P` is not `recipient`.
1. Check that `recipient` is a valid para.
1. Check that there is no existing open channel request (`P`, `recipient`) in `HrmpOpenChannelRequests`.
1. Check that the sum of the number of already opened HRMP channels by the `sender` (the size
of the set found `HrmpEgressChannelsIndex` for `sender`) and the number of open requests by the
`sender` (the value from `HrmpOpenChannelRequestCount` for `sender`) doesn't exceed the limit of
channels (`config.hrmp_max_parachain_outbound_channels` or `config.hrmp_max_parathread_outbound_channels`) minus 1.
1. Check that `P`'s balance is more or equal to `config.hrmp_sender_deposit`
1. If the message kind is `HrmpAcceptOpenChannel(sender)`:
1. Check that there is existing request between (`sender`, `P`) in `HrmpOpenChannelRequests`
1. Check that `P`'s balance is more or equal to `config.hrmp_recipient_deposit`.
1. If the message kind is `HrmpCloseChannel(ch)`:
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.
......@@ -199,6 +186,20 @@ Candidate Enactment:
1. Append the message to `RelayDispatchQueues` for `P`
1. Increment the size and the count in `RelayDispatchQueueSize` for `P`.
1. Ensure that `P` is present in `NeedsDispatch`.
1. If the message kind is `HrmpInitOpenChannel(recipient)`:
1. Increase `HrmpOpenChannelRequestCount` by 1 for the `P`.
1. Append `(P, recipient)` to `HrmpOpenChannelRequestsList`.
1. Add a new entry to `HrmpOpenChannelRequests` for `(sender, recipient)`
1. Set `sender_deposit` to `config.hrmp_sender_deposit`
1. Set `limit_used_places` to `config.hrmp_channel_max_places`
1. Set `limit_limit_used_bytes` to `config.hrmp_channel_max_size`
1. Reserve the deposit for the `P` according to `config.hrmp_sender_deposit`
1. If the message kind is `HrmpAcceptOpenChannel(sender)`:
1. Reserve the deposit for the `P` according to `config.hrmp_recipient_deposit`
1. For the request in `HrmpOpenChannelRequests` identified by `(sender, P)`, set `confirmed` flag to `true`.
1. If the message kind is `HrmpCloseChannel(ch)`:
1. Insert a new entry `Some(())` to `HrmpCloseChannelRequests` for `ch`.
1. Append `ch` to `HrmpCloseChannelRequestsList`.
The following routine is intended to be called in the same time when `Paras::schedule_para_cleanup` is called.
......@@ -236,23 +237,29 @@ any of dispatchables return an error.
1. Remove `RelayDispatchQueues` of `P`.
1. Remove `P` if it exists in `NeedsDispatch`.
1. If `P` is in `NextDispatchRoundStartWith`, then reset it to `None`
- Note that we don't remove the open/close requests since they are gon die out naturally.
1. For each request `R` in `HrmpOpenChannelRequests`:
- Note that if we don't remove the open/close requests since they are going to die out naturally at the end of the session.
1. For each channel designator `D` in `HrmpOpenChannelRequestsList` we query the request `R` from `HrmpOpenChannelRequests`:
1. if `R.confirmed = false`:
1. increment `R.age` by 1.
1. if `R.age` reached a preconfigured time-to-live limit `config.hrmp_open_request_ttl`, then:
1. refund `R.sender_deposit` to the sender
1. decrement `HrmpOpenChannelRequestCount` for `R.sender` by 1.
1. decrement `HrmpOpenChannelRequestCount` for `D.sender` by 1.
1. remove `R`
1. remove `D`
2. if `R.confirmed = true`,
1. check that `R.sender` and `R.recipient` are not offboarded.
1. create a new channel `C` between `(R.sender, R.recipient)`.
1. Initialize the `C.sender_deposit` with `R.sender_deposit` and `C.recipient_deposit` with the value found in the configuration `config.hrmp_recipient_deposit`.
1. Insert `sender` into the set `HrmpIngressChannelsIndex` for the `recipient`.
1. Insert `recipient` into the set `HrmpEgressChannelsIndex` for the `sender`.
1. decrement `HrmpOpenChannelRequestCount` for `R.sender` by 1.
1. if both `D.sender` and `D.recipient` are not offboarded.
1. create a new channel `C` between `(D.sender, D.recipient)`.
1. Initialize the `C.sender_deposit` with `R.sender_deposit` and `C.recipient_deposit`
with the value found in the configuration `config.hrmp_recipient_deposit`.
1. Insert `sender` into the set `HrmpIngressChannelsIndex` for the `recipient`.
1. Insert `recipient` into the set `HrmpEgressChannelsIndex` for the `sender`.
1. decrement `HrmpOpenChannelRequestCount` for `D.sender` by 1.
1. remove `R`
1. For each request `R` in `HrmpCloseChannelRequests` remove the channel identified by `R.id`, if exists.
1. remove `D`
1. For each 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)`:
......
......@@ -53,9 +53,23 @@ enum UpwardMessage {
/// The dispatchable to be executed in its raw form.
dispatchable: RawDispatchable,
},
// Examples:
// HrmpOpenChannel { .. },
// HrmpCloseChannel { .. },
/// A message for initiation of opening a new HRMP channel between the origin para and the
/// given `recipient`.
///
/// Let `origin` be the parachain that sent this upward message. In that case the channel
/// to be opened is (`origin` -> `recipient`).
HrmpInitOpenChannel(ParaId),
/// A message that is meant to confirm the HRMP open channel request initiated earlier by the
/// `HrmpInitOpenChannel` by the given `sender`.
///
/// Let `origin` be the parachain that sent this upward message. In that case the channel
/// (`origin` -> `sender`) will be opened during the session change.
HrmpAcceptOpenChannel(ParaId),
/// A message for closing the specified existing channel `ch`.
///
/// The channel to be closed is `(ch.sender -> ch.recipient)`. The parachain that sent this
/// upward message must be either `ch.sender` or `ch.recipient`.
HrmpCloseChannel(HrmpChannelId),
}
```
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment