Update project level docs (#1734)

* updated project level document

* updated high level overview document

* GRANDPA finality relay sequence diagram

* Parachains Finality Relay Sequence Diagram

* Messages Relay Sequence Diagram

* Complex Relayer Sequence Diagram

* small fix

* Polkadot <> Kusama bridge flowchart

* remove obsolete files

* started polkadot-kusama-bridge-overview.md

* continue polkadot-kusama-bridge-overview.md

* couple more sections in polkadot-kusama-bridge-overview.md

* continue polkadot-kusama-bridge-overview.md

* renew deployments readme

* fixed review suggestions

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* removed obsolete section

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* typo

* Update docs/polkadot-kusama-bridge-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/high-level-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/polkadot-kusama-bridge-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/polkadot-kusama-bridge-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/polkadot-kusama-bridge-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

* Update docs/polkadot-kusama-bridge-overview.md

Co-authored-by: Adrian Catangiu <adrian@parity.io>

Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
Svyatoslav Nikolsky
2023-01-09 08:44:47 +03:00
committed by Bastian Köcher
parent 64f03aaa0b
commit 7821e66bcd
8 changed files with 633 additions and 147 deletions
+132 -116
View File
@@ -1,165 +1,181 @@
# High-Level Bridge Documentation
This document gives a brief, abstract description of main components that may be found in this repository.
If you want to see how we're using them to build Rococo <> Wococo (Kusama <> Polkadot) bridge, please
refer to the [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md).
## Purpose
Trustless connecting between two Substrate-based chains using GRANDPA finality.
This repo contains all components required to build a trustless connection between standalone Substrate chains,
that are using GRANDPA finality, their parachains or any combination of those. On top of this connection, we
offer a messaging pallet that provides means to organize messages exchange.
## Overview
On top of that layered infrastructure, anyone may build their own bridge applications - e.g. [XCM messaging](./polkadot-kusama-bridge-overview.md),
[encoded calls messaging](https://github.com/paritytech/parity-bridges-common/releases/tag/encoded-calls-messaging) and so on.
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.
## Terminology
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.
Even though we support (and require) two-way bridging, the documentation will generally talk about
a one-sided interaction. That's to say, we will only talk about syncing finality proofs 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.
The bridge is built from various components. Here is a quick overview of the important ones.
The bridge has both on-chain (pallets) and offchain (relayers) components.
### Header Sync
## On-chain components
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.
On-chain bridge components are pallets that are deployed at the chain runtime. Finality pallets require
deployment at the target chain, while messages pallet needs to be deployed at both, source
and target chains.
### Headers Relayer
### Bridge GRANDPA Finality Pallet
A standalone application connected to both chains. It submits every source chain header it sees to
the target chain through RPC.
A GRANDPA light client of the source chain built into the target chain's runtime. It provides a "source of truth"
about the source chain headers which have been finalized. This is useful for higher level applications.
### Message Delivery
The pallet tracks current GRANDPA authorities set and only accepts finality proofs (GRANDPA justifications),
generated by the current authorities set. The GRANDPA protocol itself requires current authorities set to
generate explicit justificaion for the header that enacts next authorities set. Such headers and their finality
proofs are called mandatory in the pallet and relayer pays no fee for such headers submission.
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.
The pallet does not require all headers to be imported or provided. The relayer itself chooses which headers
he wants to submit (with the exception of mandatory headers).
### Message Dispatch
More: [code](../modules/grandpa/).
A FRAME pallet responsible for interpreting the payload of delivered messages.
### Bridge Parachains Finality Pallet
### Message Relayer
Parachains are not supposed to have their own finality, so we can't use bridge GRANDPA pallet to verify their
finality proofs. Instead, they rely on their relay chain finality. The parachain header is considered final,
when it is accepted by the [`paras` pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras)
at its relay chain. Obviously, the relay chain block, where it is accepted, must also be finalized by the relay
chain GRANDPA gadget.
A standalone application handling delivery of the messages from source chain to the target chain.
That said, the bridge parachains pallet accepts storage proof of one or several parachain heads, inserted to the
[`Heads`](https://github.com/paritytech/polkadot/blob/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras/mod.rs#L642)
map of the [`paras` pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras).
To verify this storage proof, the pallet uses relay chain header, imported earlier by the bridge GRANDPA pallet.
## Processes
The pallet may track multiple parachains at once and those parachains may use different primitives. So the
parachain header decoding never happens at the pallet level. For maintaining the headers order, the pallet
uses relay chain header number.
High level sequence charts of the process can be found in [a separate document](./high-level.html).
More: [code](../modules/parachains/).
### Substrate (GRANDPA) Header Sync
### Bridge Messages Pallet
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 is responsible for queuing messages at the source chain and receiving the messages proofs at the
target chain. The messages are sent to the particular _lane_, where they are guaranteed to be received in the
same order they are sent. The pallet supports many lanes.
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.
The lane has two ends. Outbound lane end is storing number of messages that have been sent and the number of
messages that have been received. Inbound lane end stores the number of messages that have been received and
also a map that maps messages to relayers that have delivered those messages to the target chain.
Referer to the [pallet documentation](../modules/grandpa/src/lib.rs) for more details.
The pallet has three main entrypoints:
- the `send_message` may be used by the other runtime pallets to send the messages;
- the `receive_messages_proof` is responsible for parsing the messages proof and handing messages over to the
dispatch code;
- the `receive_messages_delivery_proof` is responsible for parsing the messages delivery proof and rewarding
relayers that have delivered the message.
#### Header Relayer strategy
Many things are abstracted by the pallet:
- the message itself may mean anything, the pallet doesn't care about its content;
- the message dispatch happens during delivery, but it is decoupled from the pallet code;
- the messages proof and messages delivery proof are verified outside of the pallet;
- the relayers incentivization scheme is defined outside of the pallet.
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.
Outside of the messaging pallet, we have a set of adapters, where messages and delivery proofs are regular
storage proofs. The proofs are generated at the bridged chain and require bridged chain finality. So messages
pallet, in this case, depends on one of the finality pallets. The messages are XCM messages and we are using
XCM executor to dispatch them on receival. You may find more info in [Polkadot <> Kusama Bridge](./polkadot-kusama-bridge-overview.md)
document.
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.
More: [code](../modules/messages/).
### Message Passing
### Bridge Relayers Pallet
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.
The pallet is quite simple. It just registers relayer rewards and has an entrypoint to collect them. When
the rewards are registered and the reward amount is configured outside of the pallet.
#### Message Lanes Delivery
More: [code](../modules/relayers/).
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.
## Offchain Components
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.
Offchain bridge components are separate processes, called relayers. Relayers are connected both to the
source chain and target chain nodes. Relayers are reading state of the source chain, compare it to the
state of the target chain and, if state at target chain needs to be updated, submits target chain
transaction.
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.
### GRANDPA Finality Relay
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.
The task of relay is to submit source chain GRANDPA justifications and their corresponding headers to
the Bridge GRANDPA Finality Pallet, deployed at the target chain. For that, the relay subscribes to
the source chain GRANDPA justifications stream and submits every new justification it sees to the
target chain GRANDPA light client. In addition, relay is searching for mandatory headers and
submits their justifications - without that the pallet will be unable to move forward.
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.
More: [GRANDPA Finality Relay Sequence Diagram](./grandpa-finality-relay.html), [code](../relays/finality/).
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.
### Parachains Finality Relay
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).
The relay connects to the source _relay_ chain and the target chain nodes. It doesn't need to connect to the
tracked parachain nodes. The relay looks at the [`Heads`](https://github.com/paritytech/polkadot/blob/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras/mod.rs#L642)
map of the [`paras` pallet](https://github.com/paritytech/polkadot/tree/1a034bd6de0e76721d19aed02a538bcef0787260/runtime/parachains/src/paras)
in source chain, and compares the value with the best parachain head, stored in the bridge parachains pallet at
the taget chain. If new parachain head appears at the relay chain block `B`, the relay process **waits**
until header `B` or one of its ancestors appears at the target chain. Once it is available, the storage
proof of the map entry is generated and is submitted to the target chain.
#### Dispatching Messages
As its on-chain component (which requires bridge GRANDPA pallet to be deployed nearby), the parachains
finality relay requires GRANDPA finality relay to be running in parallel. Without it, the header `B` or
any of its children's finality at source won't be relayed at target, and target chain
won't be able to verify generated storage proof.
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.
More: [Parachains Finality Relay Sequence Diagram](./parachains-finality-relay.html), [code](../relays/parachains/).
An example `Call` of the target chain would look something like this:
### Messages Relay
```rust
target_runtime::Call::Balances(target_runtime::pallet_balances::Call::transfer(recipient, amount))
```
Messages relay is actually two relays that are running in a single process: messages delivery relay and
delivery confirmation relay. Even though they are more complex and have many caveats, the overall algorithm
is the same as in other relays.
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.
Message delivery relay connects to the source chain and looks at the outbound lane end, waiting until new
messages are queued there. Once they appear at the source block `B`, the relay start waiting for the block
`B` or its descendant appear at the target chain. Then the messages storage proof is generated and submitted
to the bridge messages pallet at the target chain. In addition, the transaction may include the storage proof
of the outbound lane state - that proves that relayer rewards have been paid and this data (map of relay
accounts to the delivered messages) may be pruned from the inbound lane state at the target 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
Delivery confirmation relay connects to the target chain and starts watching the inbound lane end. When new
messages are delivered to the target chain, the corresponding _source chain account_ is inserted to the
map in the inbound lane data. Relay detects that, say, at the target chain block `B` and waits until that
block or its descendant appears at the source chain. Once that happens, the relay crafts a storage proof of
that data and sends it to the messages pallet, deployed at the source chain.
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.
As you can see, the messages relay also requires finality relay to be operating in parallel. Since messages
relay submits transactions to both source and target chains, it requires both _source-to-target_ and
_target-to-source_ finality relays. They can be GRANDPA finality relays or GRANDPA+parachains finality relays,
depending on the type of connected chain.
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.
More: [Messages Relay Sequence Diagram](./messages-relay.html), [code](../relays/messages/).
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.
### Complex Relay
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.
Every relay transaction has its cost. The only transaction, that is "free" to relayer is when the mandatory
GRANDPA header is submitted. The relay that feeds the bridge with every relay chain and/or parachain head it
sees, will have to pay a (quite large) cost. And if no messages are sent through the bridge, that is just
waste of money.
See [`CallOrigin` documentation](../primitives/message-dispatch/src/lib.rs) for more details.
We have a special relay mode, called _complex relay_, where relay mostly sleeps and only submits transactions
that are required for the messages/confirmations delivery. This mode starts two message relays (in both
directions). All required finality relays are also started in a special _on-demand_ mode. In this mode they
do not submit any headers without special request. As always, the only exception is when GRANDPA finality
relay sees the mandatory header - it is submitted without such request.
#### Message Relayers Strategy
The message relays are watching their lanes and when, at some block `B`, they see new messages/confirmations
to be delivered, they are asking on-demand relays to relay this block `B`. On-demand relays does that and
then message relay may perform its job. If on-demand relay is a parachain finality relay, it also runs its
own on-demand GRANDPA relay, which is used to relay required relay chain headers.
More: [Complex Relay Sequence Diagram](./complex-relay.html), [code](../relays/bin-substrate/src/cli/relay_headers_and_messages/).