mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 12:11:02 +00:00
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: Bernhard Schuster <bernhard@ahoi.io> * Update roadmap/implementers-guide/src/runtime/router.md Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> * Update router.md * Update roadmap/implementers-guide/src/runtime/router.md Co-authored-by: Robert Habermeier <rphmeier@gmail.com> Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> Co-authored-by: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
@@ -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
|
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.
|
in a round robin fashion.
|
||||||
|
|
||||||
Other kinds of upward messages can be introduced in the future as well. Potential candidates are channel management for
|
Upward messages are also used by a parachain to request opening and closing HRMP channels (HRMP will be described below).
|
||||||
horizontal message passing (XCMP and HRMP, both are to be described below), new validation code signalling, or other
|
|
||||||
requests to the relay chain.
|
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
|
## Horizontal Message Passing
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ HRMP related structs:
|
|||||||
```rust,ignore
|
```rust,ignore
|
||||||
/// A description of a request to open an HRMP channel.
|
/// A description of a request to open an HRMP channel.
|
||||||
struct HrmpOpenChannelRequest {
|
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.
|
/// Indicates if this request was confirmed by the recipient.
|
||||||
confirmed: bool,
|
confirmed: bool,
|
||||||
/// How many session boundaries ago this request was seen.
|
/// How many session boundaries ago this request was seen.
|
||||||
@@ -50,19 +46,6 @@ struct HrmpOpenChannelRequest {
|
|||||||
limit_used_bytes: u32,
|
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.
|
/// A metadata of an HRMP channel.
|
||||||
struct HrmpChannel {
|
struct HrmpChannel {
|
||||||
/// The amount that the sender supplied as a deposit when opening this channel.
|
/// The amount that the sender supplied as a deposit when opening this channel.
|
||||||
@@ -92,14 +75,30 @@ struct HrmpChannel {
|
|||||||
HRMP related storage layout
|
HRMP related storage layout
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
/// Pending HRMP open channel requests.
|
/// The set of pending HRMP open channel requests.
|
||||||
HrmpOpenChannelRequests: Vec<HrmpOpenChannelRequest>;
|
///
|
||||||
|
/// 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.
|
/// 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`.
|
/// as the number of `HrmpOpenChannelRequestCount` for `X`.
|
||||||
HrmpOpenChannelRequestCount: map ParaId => u32;
|
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.
|
/// The HRMP watermark associated with each para.
|
||||||
HrmpWatermarks: map ParaId => Option<BlockNumber>;
|
HrmpWatermarks: map ParaId => Option<BlockNumber>;
|
||||||
/// HRMP channel data associated with each para.
|
/// 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.
|
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
|
## Routines
|
||||||
|
|
||||||
Candidate Acceptance Function:
|
Candidate Acceptance Function:
|
||||||
|
|
||||||
* `check_upward_messages(P: ParaId, Vec<UpwardMessage>`:
|
* `check_upward_messages(P: ParaId, Vec<UpwardMessage>`:
|
||||||
1. Checks that there are at most `config.max_upward_message_num_per_candidate` messages.
|
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. If the message kind is `Dispatchable`:
|
||||||
1. Verify that `RelayDispatchQueueSize` for `P` has enough capacity for the message (NOTE that should include all processed
|
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!)
|
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)`:
|
* `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 `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.
|
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. Append the message to `RelayDispatchQueues` for `P`
|
||||||
1. Increment the size and the count in `RelayDispatchQueueSize` for `P`.
|
1. Increment the size and the count in `RelayDispatchQueueSize` for `P`.
|
||||||
1. Ensure that `P` is present in `NeedsDispatch`.
|
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.
|
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 `RelayDispatchQueues` of `P`.
|
||||||
1. Remove `P` if it exists in `NeedsDispatch`.
|
1. Remove `P` if it exists in `NeedsDispatch`.
|
||||||
1. If `P` is in `NextDispatchRoundStartWith`, then reset it to `None`
|
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.
|
- 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 request `R` in `HrmpOpenChannelRequests`:
|
1. For each channel designator `D` in `HrmpOpenChannelRequestsList` we query the request `R` from `HrmpOpenChannelRequests`:
|
||||||
1. if `R.confirmed = false`:
|
1. if `R.confirmed = false`:
|
||||||
1. increment `R.age` by 1.
|
1. increment `R.age` by 1.
|
||||||
1. if `R.age` reached a preconfigured time-to-live limit `config.hrmp_open_request_ttl`, then:
|
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. 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 `R`
|
||||||
|
1. remove `D`
|
||||||
2. if `R.confirmed = true`,
|
2. if `R.confirmed = true`,
|
||||||
1. check that `R.sender` and `R.recipient` are not offboarded.
|
1. if both `D.sender` and `D.recipient` are not offboarded.
|
||||||
1. create a new channel `C` between `(R.sender, R.recipient)`.
|
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. 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 `sender` into the set `HrmpIngressChannelsIndex` for the `recipient`.
|
||||||
1. Insert `recipient` into the set `HrmpEgressChannelsIndex` for the `sender`.
|
1. Insert `recipient` into the set `HrmpEgressChannelsIndex` for the `sender`.
|
||||||
1. decrement `HrmpOpenChannelRequestCount` for `R.sender` by 1.
|
1. decrement `HrmpOpenChannelRequestCount` for `D.sender` by 1.
|
||||||
1. remove `R`
|
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)`:
|
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.
|
/// The dispatchable to be executed in its raw form.
|
||||||
dispatchable: RawDispatchable,
|
dispatchable: RawDispatchable,
|
||||||
},
|
},
|
||||||
// Examples:
|
/// A message for initiation of opening a new HRMP channel between the origin para and the
|
||||||
// HrmpOpenChannel { .. },
|
/// given `recipient`.
|
||||||
// HrmpCloseChannel { .. },
|
///
|
||||||
|
/// 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),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user