mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Squashed 'bridges/' content from commit 062554430
git-subtree-dir: bridges git-subtree-split: 0625544309ff299307f7e110f252f04eac383102
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# High-Level Bridge Documentation
|
||||
|
||||
## Purpose
|
||||
|
||||
Trustless connecting between two Substrate-based chains using GRANDPA finality.
|
||||
|
||||
## Overview
|
||||
|
||||
Even though we support two-way bridging, the documentation will generally talk about a one-sided
|
||||
interaction. That's to say, we will only talk about syncing headers and messages from a _source_
|
||||
chain to a _target_ chain. This is because the two-sided interaction is really just the one-sided
|
||||
interaction with the source and target chains switched.
|
||||
|
||||
To understand the full interaction with the bridge, take a look at the
|
||||
[testing scenarios](./testing-scenarios.md) document. It describes potential use cases and describes
|
||||
how each of the layers outlined below is involved.
|
||||
|
||||
The bridge is built from various components. Here is a quick overview of the important ones.
|
||||
|
||||
### Header Sync
|
||||
|
||||
A light client of the source chain built into the target chain's runtime. It is a single FRAME
|
||||
pallet. It provides a "source of truth" about the source chain headers which have been finalized.
|
||||
This is useful for higher level applications.
|
||||
|
||||
### Headers Relayer
|
||||
|
||||
A standalone application connected to both chains. It submits every source chain header it sees to
|
||||
the target chain through RPC.
|
||||
|
||||
### Message Delivery
|
||||
|
||||
A FRAME pallet built on top of the header sync pallet. It allows users to submit messages to the
|
||||
source chain, which are to be delivered to the target chain. The delivery protocol doesn't care
|
||||
about the payload more than it has to. Handles replay protection and message ordering.
|
||||
|
||||
### Message Dispatch
|
||||
|
||||
A FRAME pallet responsible for interpreting the payload of delivered messages.
|
||||
|
||||
### Message Relayer
|
||||
|
||||
A standalone application handling delivery of the messages from source chain to the target chain.
|
||||
|
||||
## Processes
|
||||
|
||||
High level sequence charts of the process can be found in [a separate document](./high-level.html).
|
||||
|
||||
### Substrate (GRANDPA) Header Sync
|
||||
|
||||
The header sync pallet (`pallet-bridge-grandpa`) is an on-chain light client for chains which use
|
||||
GRANDPA finality. It is part of the target chain's runtime, and accepts finality proofs from the source
|
||||
chain. Verify GRANDPA finality proofs (a.k.a justifications) and track GRANDPA finality set changes.
|
||||
|
||||
The pallet does not care about what block production mechanism is used for the source chain
|
||||
(e.g Aura or BABE) as long as it uses the GRANDPA finality gadget. In fact the pallet does not
|
||||
necessarily store all produced headers, we only import headers with valid GRANDPA justifications.
|
||||
|
||||
Referer to the [pallet documentation](../modules/grandpa/src/lib.rs) for more details.
|
||||
|
||||
#### Header Relayer strategy
|
||||
|
||||
There is currently no reward strategy for the relayers at all. They also are not required to be
|
||||
staked or registered on-chain, unlike in other bridge designs. We consider the header sync to be
|
||||
an essential part of the bridge and the incentivization should be happening on the higher layers.
|
||||
|
||||
At the moment, signed transactions are the only way to submit headers to the header sync pallet.
|
||||
However, in the future we would like to use unsigned transactions for headers delivery. This will
|
||||
allow transaction de-duplication to be done at the transaction pool level and also remove the cost
|
||||
for message relayers to run header relayers.
|
||||
|
||||
### Message Passing
|
||||
|
||||
Once header sync is maintained, the target side of the bridge can receive and verify proofs about
|
||||
events happening on the source chain, or its internal state. On top of this, we built a message
|
||||
passing protocol which consists of two parts described in following sections: message delivery and
|
||||
message dispatch.
|
||||
|
||||
#### Message Lanes Delivery
|
||||
|
||||
The [Message delivery pallet](../modules/messages/src/lib.rs) is responsible for queueing up
|
||||
messages and delivering them in order on the target chain. It also dispatches messages, but we will
|
||||
cover that in the next section.
|
||||
|
||||
The pallet supports multiple lanes (channels) where messages can be added. Every lane can be
|
||||
considered completely independent from others, which allows them to make progress in parallel.
|
||||
Different lanes can be configured to validated messages differently (e.g higher rewards, specific
|
||||
types of payload, etc.) and may be associated with a particular "user application" built on top of
|
||||
the bridge. Note that messages in the same lane MUST be delivered _in the same order_ they were
|
||||
queued up.
|
||||
|
||||
The message delivery protocol does not care about the payload it transports and can be coupled
|
||||
with an arbitrary message dispatch mechanism that will interpret and execute the payload if delivery
|
||||
conditions are met. Each delivery on the target chain is confirmed back to the source chain by the
|
||||
relayer. This is so that she can collect the reward for delivering these messages.
|
||||
|
||||
Users of the pallet add their messages to an "outbound lane" on the source chain. When a block is
|
||||
finalized message relayers are responsible for reading the current queue of messages and submitting
|
||||
some (or all) of them to the "inbound lane" of the target chain. Each message has a `nonce`
|
||||
associated with it, which serves as the ordering of messages. The inbound lane stores the last
|
||||
delivered nonce to prevent replaying messages. To successfully deliver the message to the inbound lane
|
||||
on target chain the relayer has to present present a storage proof which shows that the message was
|
||||
part of the outbound lane on the source chain.
|
||||
|
||||
During delivery of messages they are immediately dispatched on the target chain and the relayer is
|
||||
required to declare the correct `weight` to cater for all messages dispatch and pay all required
|
||||
fees of the target chain. To make sure the relayer is incentivised to do so, on the source chain:
|
||||
- the user provides a declared dispatch weight of the payload
|
||||
- the pallet calculates the expected fee on the target chain based on the declared weight
|
||||
- the pallet converts the target fee into source tokens (based on a price oracle) and reserves
|
||||
enough tokens to cover for the delivery, dispatch, confirmation and additional relayers reward.
|
||||
|
||||
If the declared weight turns out to be too low on the target chain the message is delivered but
|
||||
it immediately fails to dispatch. The fee and reward is collected by the relayer upon confirmation
|
||||
of delivery.
|
||||
|
||||
Due to the fact that message lanes require delivery confirmation transactions, they also strictly
|
||||
require bi-directional header sync (i.e. you can't use message delivery with one-way header sync).
|
||||
|
||||
#### Dispatching Messages
|
||||
|
||||
The [Message dispatch pallet](../modules/dispatch/src/lib.rs) is used to perform the actions
|
||||
specified by messages which have come over the bridge. For Substrate-based chains this means
|
||||
interpreting the source chain's message as a `Call` on the target chain.
|
||||
|
||||
An example `Call` of the target chain would look something like this:
|
||||
|
||||
```rust
|
||||
target_runtime::Call::Balances(target_runtime::pallet_balances::Call::transfer(recipient, amount))
|
||||
```
|
||||
|
||||
When sending a `Call` it must first be SCALE encoded and then sent to the source chain. The `Call`
|
||||
is then delivered by the message lane delivery mechanism from the source chain to the target chain.
|
||||
When a message is received the inbound message lane on the target chain will try and decode the
|
||||
message payload into a `Call` enum. If it's successful it will be dispatched after we check that the
|
||||
weight of the call does not exceed the weight declared by the sender. The relayer pays fees for
|
||||
executing the transaction on the target chain, but her costs should be covered by the sender on the
|
||||
source chain.
|
||||
|
||||
When dispatching messages there are three Origins which can be used by the target chain:
|
||||
1. Root Origin
|
||||
2. Source Origin
|
||||
3. Target Origin
|
||||
|
||||
Senders of a message can indicate which one of the three origins they would like to dispatch their
|
||||
message with. However, there are restrictions on who/what is allowed to dispatch messages with a
|
||||
particular origin.
|
||||
|
||||
The Root origin represents the source chain's Root account on the target chain. This origin can can
|
||||
only be dispatched on the target chain if the "send message" request was made by the Root origin of
|
||||
the source chain - otherwise the message will fail to be dispatched.
|
||||
|
||||
The Source origin represents an account without a private key on the target chain. This account will
|
||||
be generated/derived using the account ID of the sender on the source chain. We don't necessarily
|
||||
require the source account id to be associated with a private key on the source chain either. This
|
||||
is useful for representing things such as source chain proxies or pallets.
|
||||
|
||||
The Target origin represents an account with a private key on the target chain. The sender on the
|
||||
source chain needs to prove ownership of this account by using their target chain private key to
|
||||
sign: `(Call, SourceChainAccountId).encode()`. This will be included in the message payload and
|
||||
verified by the target chain before dispatch.
|
||||
|
||||
See [`CallOrigin` documentation](../primitives/message-dispatch/src/lib.rs) for more details.
|
||||
|
||||
#### Message Relayers Strategy
|
||||
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>High Level Bridge Components</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Header Sync</h1>
|
||||
<p>Header pallet on the target chain, keeps track of the forks, but requires finality for blocks that perform authority set changes. That means, it won't sync a fork with authority set change unless that change finalized.</p>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
participant Source Chain
|
||||
participant Relayer
|
||||
participant Target Chain
|
||||
Note right of Target Chain: Best: 0, Finalized: 0
|
||||
Source Chain ->> Source Chain: Import Block 1
|
||||
Source Chain ->> Source Chain: Import Block 2
|
||||
Relayer ->> Target Chain: Submit Block 1
|
||||
Note right of Target Chain: Best: 1, Finalized: 0
|
||||
Relayer ->> Target Chain: Submit Block 2
|
||||
Note right of Target Chain: Best: 2, Finalized: 0
|
||||
Source Chain ->> Source Chain: Import Block 2'
|
||||
Relayer ->> Target Chain: Submit Block 2'
|
||||
Note right of Target Chain: Best: 2 or 2', Finalized: 0
|
||||
Source Chain ->> Source Chain: Finalize Block 2'
|
||||
Relayer ->> Target Chain: Submit Finality of Block 2'
|
||||
Note right of Target Chain: Best: 2', Finalized: 2'
|
||||
</div>
|
||||
<h1>Message Delivery (single lane)</h1>
|
||||
<p>Pending messages are stored on-chain (source) so the relayer code is completely stateless - it can read all the details from the chain.</p>
|
||||
<p>Delivering pending messages requires finality first.</p>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
participant Source Chain
|
||||
participant Relayer
|
||||
participant Target Chain
|
||||
Source Chain ->> Source Chain: Queue Message 1
|
||||
Source Chain ->> Source Chain: Queue Message 2
|
||||
Source Chain ->> Source Chain: Queue Message 3
|
||||
Note left of Source Chain: Queued Messages: [1, 2, 3, ]
|
||||
Note left of Source Chain: Reward for [1, 2, 3, ] reserved
|
||||
Relayer ->> Target Chain: Deliver Messages 1..2
|
||||
Note right of Target Chain: Target chain dispatches the messages.<br> To Confirm: {1..2 => relayer_1}
|
||||
Relayer ->> Source Chain: Delivery Confirmation of 1..2
|
||||
Note left of Source Chain: Queued Messages: [3, ]
|
||||
Note left of Source Chain: Reward payout for [1, 2, ]
|
||||
Relayer -->> Target Chain: Confirmed Messages 1..2
|
||||
Note right of Target Chain: To Confirm: {}
|
||||
Note over Relayer, Target Chain: (this is not a separate transaction, <br >it's bundled with the "Deliver Messages" proof)
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@8.8.4/dist/mermaid.min.js"></script>
|
||||
<script>mermaid.initialize({startOnLoad: true})</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
Plan for the Internal Audit:
|
||||
1. High-level overview (describing layers, maybe with pictures)
|
||||
- what have we done already.
|
||||
[Tomek to present]
|
||||
[Hernando to help with diagrams today]
|
||||
|
||||
2. Demo? How to play with the network.
|
||||
[Hernando]
|
||||
|
||||
3. Demo of token transfer on Millau.
|
||||
[Hernando]
|
||||
|
||||
4. Go through the scenario description and let people ask questions in the meantime.
|
||||
Jump to the code on demand.
|
||||
[Tomek, Hernando, Slava]
|
||||
|
||||
...
|
||||
|
||||
5. The roadmap
|
||||
- outstanding issues.
|
||||
[Tomek]
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Flow Chart of Millau to Rialto Transfer</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Scenario: <code>mDave</code> sending RLT to <code>rEve</code></h1>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
participant mDave
|
||||
participant Millau
|
||||
participant Bridge Relayer
|
||||
participant Rialto
|
||||
participant rEve
|
||||
Rialto->>Rialto: Endow r(mDave) with RLT.
|
||||
mDave->>Millau: send_message(transfer, 5 RLT, rEve)
|
||||
Millau->>Millau: Locks fee & reward for the relayer and queues the message.
|
||||
rect rgb(205, 226, 244)
|
||||
Bridge Relayer->>+Millau: What's your best header?
|
||||
Millau-->>-Bridge Relayer: It's header 5.
|
||||
Bridge Relayer->>+Rialto: What's the best Millau header you know about?
|
||||
Rialto-->>-Bridge Relayer: I only know about 4.
|
||||
Bridge Relayer->>Rialto: Cool, here is Millau header 5 [`submit_signed_header()`].
|
||||
Bridge Relayer->>+Rialto: What's the best finalized Millau header you know about?
|
||||
Rialto-->>-Bridge Relayer: I only know about 3.
|
||||
Bridge Relayer->>+Millau: Do you have a finality proof for 4..5?
|
||||
Millau-->>-Bridge Relayer: Yes I do, here it is.
|
||||
Bridge Relayer->>Rialto: Here is the finality proof for 5 [`finalize_header()`].
|
||||
end
|
||||
rect rgb(218, 195, 244)
|
||||
Bridge Relayer->>+Millau: Do you have any messages for me to deliver (at 5)?
|
||||
Millau-->>-Bridge Relayer: Yes, here they are.
|
||||
Bridge Relayer->>+Rialto: I have some new messages for you [`receive_messages_proof()`].
|
||||
Rialto->>Rialto: Validate and Dispatch Message.
|
||||
Rialto->>rEve: Transfer(5 RLT) from r(mDave).
|
||||
Rialto-->>-Bridge Relayer: Event(Message Succesfully Dispatched).
|
||||
Bridge Relayer->>Millau: I sent your message, can I get paid now [`receive_messages_delivery_proof`]?
|
||||
Millau-->>Bridge Relayer: Yes, here you go $$$.
|
||||
Bridge Relayer ->>Rialto: These messages are confirmed now, feel free to clean up.
|
||||
end
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@8.8.4/dist/mermaid.min.js"></script>
|
||||
<script>mermaid.initialize({startOnLoad: true})</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,131 @@
|
||||
# How to send messages
|
||||
|
||||
The Substrate-to-Substrate relay comes with a command line interface (CLI) which is implemented
|
||||
by the `substrate-relay` binary.
|
||||
|
||||
```
|
||||
Substrate-to-Substrate relay
|
||||
|
||||
USAGE:
|
||||
substrate-relay <SUBCOMMAND>
|
||||
|
||||
FLAGS:
|
||||
-h, --help
|
||||
Prints help information
|
||||
|
||||
-V, --version
|
||||
Prints version information
|
||||
|
||||
|
||||
SUBCOMMANDS:
|
||||
help Prints this message or the help of the given subcommand(s)
|
||||
init-bridge Initialize on-chain bridge pallet with current header data
|
||||
relay-headers Start headers relay between two chains
|
||||
relay-messages Start messages relay between two chains
|
||||
send-message Send custom message over the bridge
|
||||
```
|
||||
The relay related commands `relay-headers` and `relay-messages` are basically continously running a
|
||||
sync loop between the `Millau` and `Rialto` chains. The `init-bridge` command submitts initialization
|
||||
transactions. An initialization transaction brings an initial header and authorities set from a source
|
||||
chain to a target chain. The header synchronization then starts from that header.
|
||||
|
||||
For sending custom messages over an avialable bridge, the `send-message` command is used.
|
||||
|
||||
```
|
||||
Send custom message over the bridge.
|
||||
|
||||
Allows interacting with the bridge by sending messages over `Messages` component. The message is being sent to the
|
||||
source chain, delivered to the target chain and dispatched there.
|
||||
|
||||
USAGE:
|
||||
substrate-relay send-message <SUBCOMMAND>
|
||||
|
||||
FLAGS:
|
||||
-h, --help Prints help information
|
||||
-V, --version Prints version information
|
||||
|
||||
SUBCOMMANDS:
|
||||
help Prints this message or the help of the given subcommand(s)
|
||||
millau-to-rialto Submit message to given Millau -> Rialto lane
|
||||
rialto-to-millau Submit message to given Rialto -> Millau lane
|
||||
|
||||
```
|
||||
Messages are send from a source chain to a target chain using a so called `message lane`. Message lanes handle
|
||||
both, message transport and message dispatch. There is one command for submitting a message to each of the two
|
||||
available bridges, namely `millau-to-rialto` and `rialto-to-millau`.
|
||||
|
||||
Submitting a message requires a number of arguments to be provided. Those arguments are essentially the same
|
||||
for both submit message commands, hence only the output for `millau-to-rialto` is shown below.
|
||||
|
||||
```
|
||||
Submit message to given Millau -> Rialto lane
|
||||
|
||||
USAGE:
|
||||
substrate-relay send-message millau-to-rialto [OPTIONS] --lane <lane> --source-host <source-host> --source-port <source-port> --source-signer <source-signer> --origin <origin> --target-signer <target-signer> <SUBCOMMAND>
|
||||
|
||||
FLAGS:
|
||||
-h, --help Prints help information
|
||||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
--fee <fee>
|
||||
Delivery and dispatch fee. If not passed, determined automatically
|
||||
|
||||
--lane <lane> Hex-encoded lane id
|
||||
--source-host <source-host> Connect to Source node at given host
|
||||
--source-port <source-port> Connect to Source node websocket server at given port
|
||||
--source-signer <source-signer>
|
||||
The SURI of secret key to use when transactions are submitted to the Source node
|
||||
|
||||
--source-signer-password <source-signer-password>
|
||||
The password for the SURI of secret key to use when transactions are submitted to the Source node
|
||||
|
||||
--origin <origin>
|
||||
The origin to use when dispatching the message on the target chain [possible values: Target, Source]
|
||||
|
||||
--target-signer <target-signer>
|
||||
The SURI of secret key to use when transactions are submitted to the Target node
|
||||
|
||||
--target-signer-password <target-signer-password>
|
||||
The password for the SURI of secret key to use when transactions are submitted to the Target node
|
||||
|
||||
|
||||
SUBCOMMANDS:
|
||||
help Prints this message or the help of the given subcommand(s)
|
||||
remark Make an on-chain remark (comment)
|
||||
transfer Transfer the specified `amount` of native tokens to a particular `recipient`
|
||||
|
||||
```
|
||||
As can be seen from the output, there are two types of messages available: `remark` and `transfer`.
|
||||
A remark is some opaque message which will be placed on-chain. For basic testing, a remark is
|
||||
the easiest to go with.
|
||||
|
||||
Usage of the arguments is best explained with an example. Below you can see, how a remark
|
||||
would look like:
|
||||
|
||||
```
|
||||
substrate-relay send-message millau-to-rialto \
|
||||
--source-host=127.0.0.1 \
|
||||
--source-port=10946 \
|
||||
--source-signer=//Dave \
|
||||
--target-signer=//Dave \
|
||||
--lane=00000000 \
|
||||
--origin Target \
|
||||
remark
|
||||
```
|
||||
Messages are basically regular transactions. That means, they have to be signed. In order
|
||||
to send a message, you have to control an account private key on both, the source and
|
||||
the target chain. Those accounts are specified using the `--source-signer` and `--target-signer`
|
||||
arguments in the example above.
|
||||
|
||||
Message delivery and dispatch requires a fee to be paid. In the example above, we have not
|
||||
specified the `--fee` argument. Hence, the fee will be estimated automatically. Note that
|
||||
in order to pay the fee, the message sender account has to have sufficient funds available.
|
||||
|
||||
The `--origin` argument allows to denote under which authority the message will be dispatched
|
||||
on the target chain. Accepted values are `Target` and `Source`.
|
||||
|
||||
Although not strictly necessary, it is recommended, to use one of the well-known development
|
||||
accounts (`Alice`, `Bob`, `Charlie`, `Dave`, `Eve`) for message sending. Those accounts are
|
||||
endowed with funds for fee payment. In addtion, the development `Seed URI` syntax
|
||||
(like `//Dave`) for the signer can be used, which will remove the need for a password.
|
||||
@@ -0,0 +1,221 @@
|
||||
# Testing Scenarios
|
||||
|
||||
In the scenarios, for simplicity, we call the chains Kusama (KSM token) and Polkadot (DOT token),
|
||||
but they should be applicable to any other chains. The first scenario has detailed description about
|
||||
the entire process (also see the [sequence diagram](./scenario1.html)). Other scenarios only contain
|
||||
a simplified interaction focusing on things that are unique for that particular scenario.
|
||||
|
||||
Notation:
|
||||
- kX - user X interacting with Kusama chain.
|
||||
- `k(kX)` - Kusama account id of user kX (native account id; usable on Kusama)
|
||||
- `p(kX)` - Polkadot account id of user kX (account id derived from `k(kX)` usable on Polkadot)
|
||||
- [Kusama] ... - Interaction happens on Kusama (e.g. the user interacts with Kusama chain)
|
||||
- [Polkadot] ... - Interaction happens on Polkadot
|
||||
|
||||
Basic Scenarios
|
||||
===========================
|
||||
|
||||
Scenario 1: Kusama's Alice receiving & spending DOTs
|
||||
---------------------------
|
||||
|
||||
Kusama's Alice (kAlice) receives 5 DOTs from Polkadot's Bob (pBob) and sends half of them to
|
||||
kCharlie.
|
||||
|
||||
1. Generate kAlice's DOT address (`p(kAlice)`).
|
||||
See function:
|
||||
|
||||
```rust
|
||||
bp_runtime::derive_account_id(b"pdot", kAlice)
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```rust
|
||||
let hash = bp_polkadot::derive_kusama_account_id(kAlice);
|
||||
let p_kAlice = bp_polkadot::AccountIdConverter::convert(hash);
|
||||
```
|
||||
|
||||
2. [Polkadot] pBob transfers 5 DOTs to `p(kAlice)`
|
||||
1. Creates & Signs a transaction with `Call::Transfer(..)`
|
||||
1. It is included in block.
|
||||
1. kAlice observers Polkadot chain to see her balance at `p(kAlice)` updated.
|
||||
|
||||
3. [Kusama] kAlice sends 2.5 DOTs to `p(kCharlie)`
|
||||
1. kAlice prepares:
|
||||
```rust
|
||||
let call = polkadot::Call::Balances(polkadot::Balances::Transfer(p(kCharlie), 2.5DOT)).encode();
|
||||
let weight = call.get_dispatch_info().weight;
|
||||
```
|
||||
|
||||
1. kAlice prepares Kusama transaction:
|
||||
```rust
|
||||
kusama::Call::Messages::<Instance=Polkadot>::send_message(
|
||||
// dot-transfer-lane (truncated to 4bytes)
|
||||
lane_id,
|
||||
payload: MessagePayload {
|
||||
// Get from current polkadot runtime (kind of hardcoded)
|
||||
spec_version: 1,
|
||||
// kAlice should know the exact dispatch weight of the call on the target
|
||||
// source verifies: at least to cover call.length() and below max weight
|
||||
weight,
|
||||
// simply bytes, we don't know anything about that on the source chain
|
||||
call,
|
||||
// origin that should be used during dispatch on the target chain
|
||||
origin: CallOrigin::SourceAccount(kAlice),
|
||||
},
|
||||
delivery_and_dispatch_fee: {
|
||||
(single_message_delivery_weight
|
||||
// source weight = X * target weight
|
||||
+ convert_target_weight_to_source_weight(weight)
|
||||
+ confirmation_transaction_weight
|
||||
)
|
||||
// This uses an on-chain oracle to convert weights of the target chain to source fee
|
||||
* weight_to_fee
|
||||
// additional reward for the relayer (pallet parameter)
|
||||
+ relayers_fee
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
1. [Kusama] kAlice sends Kusama transaction with the above `Call` and pays regular fees. The
|
||||
dispatch additionally reservers target-chain delivery and dispatch fees (including relayer's
|
||||
reward).
|
||||
|
||||
4. [Kusama] kAlice's transaction is included in block `B1`
|
||||
|
||||
### Syncing headers loop
|
||||
|
||||
5. Relayer sees that `B1` has not yet been delivered to the target chain.
|
||||
[Sync loop code](https://github.com/paritytech/parity-bridges-common/blob/8b327a94595c4a6fae6d7866e24ecf2390501e32/relays/headers-relay/src/sync_loop.rs#L199).
|
||||
|
||||
1. Relayer prepares transaction which delivers `B1` and with all of the missing
|
||||
ancestors to the target chain (one header per transaction).
|
||||
|
||||
1. After the transaction is succesfully dispatched the Polkadot on-chain light client of the Kusama
|
||||
chain learns about block `B1` - it is stored in the on-chain storage.
|
||||
|
||||
### Syncing finality loop
|
||||
|
||||
8. Relayer is subscribed to finality events on Kusama. Relayer gets a finality notification for
|
||||
block `B3`.
|
||||
|
||||
1. The header sync informs the target chain about `B1..B3` blocks (see point 6).
|
||||
|
||||
1. Relayer learns about missing finalization of `B1..B3` on the target chain, see
|
||||
[finality maintenance code](https://github.com/paritytech/parity-bridges-common/blob/8b327a94595c4a6fae6d7866e24ecf2390501e32/relays/substrate/src/headers_maintain.rs#L107).
|
||||
|
||||
1. Relayer submits justification for `B3` to the target chain (`finalize_header`).
|
||||
See [#421](https://github.com/paritytech/parity-bridges-common/issues/421) for multiple
|
||||
authority set changes support in Relayer (i.e. what block the target chain expects, not only
|
||||
what I have).
|
||||
|
||||
Relayer is doing two things:
|
||||
- syncing on demand (what blocks miss finality)
|
||||
- and syncing as notifications are received (recently finalized on-chain)
|
||||
|
||||
1. Eventually Polkadot on-chain light client of Kusama learns about finality of `B1`.
|
||||
|
||||
### Syncing messages loop
|
||||
|
||||
13. The relayer checks the on-chain storage (last finalized header on the source, best header on the
|
||||
target):
|
||||
- Kusama outbound lane
|
||||
- Polkadot inbound lane
|
||||
Lanes contains `latest_generated_nonce` and `latest_received_nonce` respectively. The relayer
|
||||
syncs messages between that range.
|
||||
|
||||
1. The relayer gets a proof for every message in that range (using the RPC of messages module)
|
||||
|
||||
1. The relayer creates a message delivery transaction (but it has weight, size, and count limits).
|
||||
The count limit is there to make the loop of delivery code bounded.
|
||||
```rust
|
||||
receive_message_proof(
|
||||
relayer_id, // account id of the source chain
|
||||
proof, // messages + proofs (hash of source block `B1`, nonces, lane_id + storage proof)
|
||||
dispatch_weight // relayer declares how much it will take to dispatch all messages in that transaction,
|
||||
)
|
||||
```
|
||||
The `proof` can also contain an update of outbound lane state of source chain, which indicates
|
||||
the delivery confirmation of these messages and reward payment, so that the target chain can
|
||||
truncate its unpayed rewards vector.
|
||||
|
||||
The target chain stores `relayer_ids` that delivered messages because the relayer can generate
|
||||
a storage proof to show that they did indeed deliver those messages. The reward is paid on the
|
||||
source chain and we inform the target chain about that fact so it can prune these `relayer_ids`.
|
||||
|
||||
It's totally fine if there are no messages, and we only include the reward payment proof
|
||||
when calling that function.
|
||||
|
||||
1. 🥳 the message is now delivered and dispatched on the target chain!
|
||||
|
||||
1. The relayer now needs to confirm the delivery to claim her payment and reward on the source
|
||||
chain.
|
||||
|
||||
1. The relayer creates a transaction on the source chain with call:
|
||||
|
||||
```rust
|
||||
receive_messages_delivery_proof(
|
||||
proof, // hash of the finalized target chain block, lane_id, storage proof
|
||||
)
|
||||
```
|
||||
|
||||
### UI challenges
|
||||
|
||||
- The UI should warn before (or prevent) sending to `k(kCharlie)`!
|
||||
|
||||
|
||||
Scenario 2: Kusama's Alice nominating validators with her DOTs
|
||||
---------------------------
|
||||
|
||||
kAlice receives 10 DOTs from pBob and nominates `p(pCharlie)` and `p(pDave)`.
|
||||
|
||||
1. Generate kAlice's DOT address (`p(kAlice)`)
|
||||
2. [Polkadot] pBob transfers 5 DOTs to `p(kAlice)`
|
||||
3. [Kusama] kAlice sends a batch transaction:
|
||||
- `staking::Bond` transaction to create stash account choosing `p(kAlice)` as the controller account.
|
||||
- `staking::Nominate(vec![p(pCharlie)])` to nominate pCharlie using the controller account.
|
||||
|
||||
|
||||
Scenario 3: Kusama Treasury receiving & spending DOTs
|
||||
---------------------------
|
||||
|
||||
pBob sends 15 DOTs to Kusama Treasury which Kusama Governance decides to transfer to kCharlie.
|
||||
|
||||
1. Generate source account for the treasury (`kTreasury`).
|
||||
2. [Polkadot] pBob tarnsfers 15 DOTs to `p(kTreasury)`.
|
||||
2. [Kusama] Send a governance proposal to send a bridge message which transfers funds to `p(kCharlie)`.
|
||||
3. [Kusama] Dispatch the governance proposal using `kTreasury` account id.
|
||||
|
||||
Extra scenarios
|
||||
===========================
|
||||
|
||||
Scenario 4: Kusama's Alice setting up 1-of-2 multi-sig to spend from either Kusama or Polkadot
|
||||
---------------------------
|
||||
|
||||
Assuming `p(pAlice)` has at least 7 DOTs already.
|
||||
|
||||
1. Generate multisig account id: `pMultiSig = multi_account_id(&[p(kAlice), p(pAlice)], 1)`.
|
||||
2. [Kusama] Transfer 7 DOTs to `pMultiSig` using `TargetAccount` origin of `pAlice`.
|
||||
3. [Kusama] Transfer 2 DOTs to `p(kAlice)` from the multisig:
|
||||
- Send `multisig::as_multi_threshold_1(vec![p(pAlice)], balances::Transfer(p(kAlice), 2))`
|
||||
|
||||
Scenario 5: Kusama Treasury staking & nominating validators with DOTs
|
||||
---------------------------
|
||||
|
||||
Scenario 6: Kusama Treasury voting in Polkadot's democracy proposal
|
||||
---------------------------
|
||||
|
||||
Potentially interesting scenarios
|
||||
===========================
|
||||
|
||||
Scenario 7: Polkadot's Bob spending his DOTs by using Kusama chain
|
||||
---------------------------
|
||||
|
||||
We can assume he holds KSM. Problem: he can pay fees, but can't really send (sign) a transaction?
|
||||
Shall we support some kind of dispatcher?
|
||||
|
||||
Scenario 8: Kusama Governance taking over Kusama's Alice DOT holdings
|
||||
---------------------------
|
||||
|
||||
We use `SourceRoot` call to transfer her's DOTs to Kusama treasury. Source chain root
|
||||
should also be able to send messages as `CallOrigin::SourceAccount(Alice)` though.
|
||||
Reference in New Issue
Block a user