diff --git a/README.md b/README.md index d45b328b2bd..b5885026426 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,6 @@ Substrate chains. 🚧 The bridges are currently under construction - a hardhat is recommended beyond this point 🚧 -**IMPORTANT**: this documentation is outdated and it is mostly related to the previous version of our -bridge. Right there's an ongoing work to make our bridge work with XCM messages. Old bridge is still -available at [encoded-calls-messaging](https://github.com/paritytech/parity-bridges-common/releases/tag/encoded-calls-messaging) -tag. - ## Contents - [Installation](#installation) @@ -97,7 +92,7 @@ description of the bridge interaction. ## Project Layout -Here's an overview of how the project is laid out. The main bits are the `node`, which is the actual +Here's an overview of how the project is laid out. The main bits are the `bin`, which is the actual "blockchain", the `modules` which are used to build the blockchain's logic (a.k.a the runtime) and the `relays` which are used to pass messages between chains. @@ -106,16 +101,16 @@ the `relays` which are used to pass messages between chains. │ └── ... ├── deployments // Useful tools for deploying test networks │ └── ... -├── diagrams // Pretty pictures of the project architecture -│ └── ... ├── modules // Substrate Runtime Modules (a.k.a Pallets) +│ ├── beefy // On-Chain BEEFY Light Client (in progress) │ ├── grandpa // On-Chain GRANDPA Light Client │ ├── messages // Cross Chain Message Passing -│ ├── dispatch // Target Chain Message Execution +│ ├── parachains // On-Chain Parachains Light Client +│ ├── relayers // Relayer rewards registry │ └── ... ├── primitives // Code shared between modules, runtimes, and relays │ └── ... -├── relays // Application for sending headers and messages between chains +├── relays // Application for sending finality proofs and messages between chains │ └── ... └── scripts // Useful development and maintenance scripts ``` @@ -127,8 +122,11 @@ on each side of the bridge (source and target chain). There are 2 ways to run the bridge, described below: -- building & running from source -- running a Docker Compose setup (recommended). +- building & running from source: with this option, you'll be able to run the bridge between two standalone +chains that are running GRANDPA finality gadget to achieve finality; + +- running a Docker Compose setup: this is a recommended option, where you'll see bridges with parachains, +complex relays and more. ### Using the Source @@ -204,7 +202,33 @@ You will also see the message lane relayers listening for new messages. To send a message see the ["How to send a message" section](#how-to-send-a-message). -### Full Network Docker Compose Setup +### How to send a message + +In this section we'll show you how to quickly send a bridge message. The message is just an encoded XCM +`Trap(43)` message. + +```bash +# In `parity-bridges-common` folder +./scripts/send-message-from-millau-rialto.sh +``` + +After sending a message you will see the following logs showing a message was successfully sent: + +``` +INFO bridge Sending message to Rialto. Size: 5. +TRACE bridge Sent transaction to Millau node: 0x5e68... +``` + +And at the Rialto node logs you'll something like this: + +``` +... runtime::bridge-dispatch: Going to execute message ([0, 0, 0, 0], 1) (...), Trap(43)]) +... runtime::bridge-dispatch: Incoming message ([0, 0, 0, 0], 1) dispatched with result: Incomplete(2000000000, Trap(43)) +``` + +It means that the message has been delivered and successfully dispatched. + +## Full Network Docker Compose Setup For a more sophisticated deployment which includes bidirectional header sync, message passing, monitoring dashboards, etc. see the [Deployments README](./deployments/README.md). @@ -220,24 +244,6 @@ docker run -p 30333:30333 -p 9933:9933 -p 9944:9944 \ --rpc-cors=all --unsafe-rpc-external --unsafe-ws-external ``` -### How to send a message - -In this section we'll show you how to quickly send a bridge message, if you want to -interact with and test the bridge see more details in [send message](./docs/send-message.md) - -```bash -# In `parity-bridges-common` folder -./scripts/send-message-from-millau-rialto.sh remark -``` - -After sending a message you will see the following logs showing a message was successfully sent: - -``` -INFO bridge Sending message to Rialto. Size: 286. Dispatch weight: 1038000. Fee: 275,002,568 -INFO bridge Signed Millau Call: 0x7904... -TRACE bridge Sent transaction to Millau node: 0x5e68... -``` - ## Community Main hangout for the community is [Element](https://element.io/) (formerly Riot). Element is a chat diff --git a/deployments/README.md b/deployments/README.md index 2f804b3ad32..e478f7df84a 100644 --- a/deployments/README.md +++ b/deployments/README.md @@ -1,11 +1,13 @@ # Bridge Deployments ## Requirements + Make sure to install `docker` and `docker-compose` to be able to run and test bridge deployments. If for whatever reason you can't or don't want to use Docker, you can find some scripts for running the -bridge [here](https://github.com/svyatonik/parity-bridges-common.test). +bridge [here](./local-scripts/). ## Networks + One of the building blocks we use for our deployments are _networks_. A network is a collection of homogenous blockchain nodes. We have Docker Compose files for each network that we want to bridge. Each of the compose files found in the `./networks` folder is able to independently spin up a @@ -18,6 +20,7 @@ docker-compose -f ./networks/rialto.yml up After running this command we would have a network of several nodes producing blocks. ## Bridges + A _bridge_ is a way for several _networks_ to connect to one another. Bridge deployments have their own Docker Compose files which can be found in the `./bridges` folder. These Compose files typically contain bridge relayers, which are services external to blockchain nodes, and other components such @@ -43,10 +46,11 @@ and Grafana. We cover these in more details in the [Monitoring](#monitoring) sec the monitoring Compose file is _not_ optional, and must be included for bridge deployments. ### Running and Updating Deployments + We currently support three bridge deployments 1. Rialto Substrate to Millau Substrate 2. Rialto Parachain Substrate to Millau Substrate -2. Westend Substrate to Millau Substrate +2. Westend Substrate to Millau Substrate (only finality bridge) These bridges can be deployed using our [`./run.sh`](./run.sh) script. @@ -71,11 +75,12 @@ You can also bring down a deployment using the script with the `stop` argument. ``` ### Adding Deployments + We need two main things when adding a new deployment. First, the new network which we want to bridge. A compose file for the network should be added in the `/networks/` folder. Secondly we'll need a new bridge Compose file in `./bridges/`. This should configure the bridge relayer nodes correctly for the two networks, and add any additional components needed for the deployment. If you -want you can also add support in the `./run` script for the new deployment. While recommended it's +want you can also add support in the `./run.sh` script for the new deployment. While recommended it's not strictly required. ## General Notes @@ -111,8 +116,8 @@ is not recommended, because this may lead to nonces conflict. Following accounts are used when `rialto-millau` bridge is running: -- Millau's `Rialto.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on Millau chain; -- Rialto's `Millau.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on Rialto chain; +- Millau's `Rialto.HeadersAndMessagesRelay1` signs complex headers+messages relay transactions on Millau chain; +- Rialto's `Millau.HeadersAndMessagesRelay1` signs complex headers+messages relay transactions on Rialto chain; - Millau's `Rialto.MessagesSender` signs Millau transactions which contain messages for Rialto; - Rialto's `Millau.MessagesSender` signs Rialto transactions which contain messages for Millau; - Millau's `Rialto.OutboundMessagesRelay.Lane00000001` signs relay transactions with message delivery confirmations (lane 00000001) from Rialto to Millau; @@ -136,18 +141,22 @@ Following accounts are used when `rialto-parachain-millau` bridge is running: - RialtoParachain's `Millau.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on RialtoParachain chain. ### Docker Usage + When the network is running you can query logs from individual nodes using: ```bash docker logs rialto_millau-node-charlie_1 -f ``` +You may use the [dump-logs.sh](../scripts/dump-logs.sh) to dump logs of most of running containers. + To kill all leftover containers and start the network from scratch next time: ```bash docker ps -a --format "{{.ID}}" | xargs docker rm # This removes all containers! ``` ### Docker Compose Usage + If you're not familiar with how to use `docker-compose` here are some useful commands you'll need when interacting with the bridge deployments: @@ -172,10 +181,12 @@ docker-compose -f docker-compose.yml -f docker-compose.override.yml config > doc ``` ## Docker and Git Deployment + It is also possible to avoid using images from the Docker Hub and instead build containers from Git. There are two ways to build the images this way. ### Git Repo + If you have cloned the bridges repo you can build local Docker images by running the following command at the top level of the repo: @@ -189,16 +200,17 @@ This will build a local image of a particular component with a tag of You can configure the build using Docker [build arguments](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg). Here are the arguments currently supported: - - `BRIDGE_REPO`: Git repository of the bridge node and relay code - - `BRIDGE_HASH`: Commit hash within that repo (can also be a branch or tag) - - `ETHEREUM_REPO`: Git repository of the OpenEthereum client - - `ETHEREUM_HASH`: Commit hash within that repo (can also be a branch or tag) - `PROJECT`: Project to build withing bridges repo. Can be one of: - `rialto-bridge-node` - `millau-bridge-node` + - `rialto-parachain-collator` - `substrate-relay` +You may use the [build-containers.sh](../scripts/build-containers.sh) script to build all available +containers. + ### GitHub Actions + We have a nightly job which runs and publishes Docker images for the different nodes and relayers to the [ParityTech Docker Hub](https://hub.docker.com/u/paritytech) organization. These images are used for our ephemeral (temporary) test networks. Additionally, any time a tag in the form of `v*` is @@ -209,6 +221,7 @@ With images built using either method, all you have to do to use them in a deplo `image` field in the existing Docker Compose files to point to the tag of the image you want to use. ### Monitoring + [Prometheus](https://prometheus.io/) is used by the bridge relay to monitor information such as system resource use, and block data (e.g the best blocks it knows about). In order to visualize this data a [Grafana](https://grafana.com/) dashboard can be used. @@ -223,6 +236,7 @@ dashboard can be accessed at `http://localhost:9090`. The Grafana dashboard can `http://localhost:3000`. Note that the default log-in credentials for Grafana are `admin:admin`. ### Environment Variables + Here is an example `.env` file which is used for production deployments and network updates. For security reasons it is not kept as part of version control. When deploying a network this file should be correctly populated and kept in the appropriate [`bridges`](`./bridges`) deployment @@ -247,13 +261,8 @@ UI_EXPECTED_ETHEREUM_NETWORK_ID=105 ### UI -Use [wss://rialto.bridges.test-installations.parity.io/](https://polkadot.js.org/apps/) -as a custom endpoint for [https://polkadot.js.org/apps/](https://polkadot.js.org/apps/). - -### Polkadot.js UI - -To teach the UI decode our custom types used in the pallet, go to: `Settings -> Developer` -and import the [`./types.json`](./types.json) +Use [wss://wss.rialto.brucke.link](https://polkadot.js.org/apps/) as a custom endpoint for +[https://polkadot.js.org/apps/](https://polkadot.js.org/apps/). ## Scripts diff --git a/docs/complex-relay.html b/docs/complex-relay.html new file mode 100644 index 00000000000..21524bfd049 --- /dev/null +++ b/docs/complex-relay.html @@ -0,0 +1,85 @@ + + + + + + Complex Relay + + +

Complex Relay

+

+ Both Source Chain and Target Chains have Bridge Messages pallets deployed. They also have required + finality pallets deployed - we don't care about finality type here - they can be either Bridge GRANDPA, + or Bridge Parachains finality pallets, or any combination of those.
+

+

+ There are 4-6 relayer subprocesses inside the Complex Relayer. They include two message relayers, + serving the lane in both directions and 2-4 Complex Relayers (depending on the finality type of Source + and Target Chains).
+

+

+ The following diagram shows the way the complex relayer serves the lane in single direction. Everything + below may be applied to the opposite direction if you'll swap the Source and Target Chains. +

+
+ sequenceDiagram + participant Source Chain + participant Complex Relayer + participant Target Chain + + Note right of Source Chain: Finalized: 480, Target Finalized: 50, Sent Messages: 42, Confirmed Messages: 42 + Note left of Target Chain: Finalized: 60, Source Finalized: 420, Received Messages: 42 + + Source Chain ->> Source Chain: someone Sends Message 43 + Source Chain ->> Source Chain: Import and Finalize Block 481 + + Source Chain ->> Complex Relayer: notes new outbound message 43 at Source Chain Block 481 + Note right of Complex Relayer: can't deliver message 43, Source Chain Block 481 is not relayed + Complex Relayer ->> Complex Relayer: asks on-demand Finality Relayer to relay Source Chain Block 481 + + Source Chain ->> Complex Relayer: Read Finality Proof of Block 481 + Complex Relayer ->> Target Chain: Submit Finality Proof of Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 61 + Note left of Target Chain: Finalized: 61, Source Finalized: 481, Received Messages: 42 + + Source Chain ->> Complex Relayer: Read Proof of Message 43 at Block 481 + Complex Relayer ->> Target Chain: Submit Proof of Message 43 at Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 62 + Note left of Target Chain: Finalized: 62, Source Finalized: 481, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Target Chain ->> Complex Relayer: notes new unrewarded relayer at Target Chain Block 62 + Note right of Complex Relayer: can't relay delivery confirmations because Target Chain Block 62 is not relayed + Complex Relayer ->> Complex Relayer: asks on-demand Finality Relayer to relay Target Chain Block 62 + + Target Chain ->> Complex Relayer: Read Finality Proof of Block 62 + Complex Relayer ->> Source Chain: Submit Finality Proof of Block 62 + Source Chain ->> Source Chain: Import and Finalize Block 482 + Note right of Source Chain: Finalized: 482, Target Finalized: 62, Confirmed Messages: 42 + + Target Chain ->> Complex Relayer: Read Proof of Message 43 Delivery at Block 62 + Complex Relayer ->> Source Chain: Submit Proof of Message 43 Delivery at Block 612 + Source Chain ->> Source Chain: rewards messages-relayer-account for delivering message [43] + Source Chain ->> Source Chain: prune delivered message 43 from runtime storage + Note right of Source Chain: Finalized: 482, Target Finalized: 61, Confirmed Messages: 43 + + Source Chain ->> Source Chain: someone Sends Message 44 + Source Chain ->> Source Chain: Import and Finalize Block 483 + + Source Chain ->> Complex Relayer: notes new outbound message 44 at Source Chain Block 483 and new confirmed message 43 + Note right of Complex Relayer: can't deliver message 44, Source Chain Block 483 is not relayed + Complex Relayer ->> Complex Relayer: asks on-demand Finality Relayer to relay Source Chain Block 483 + + Source Chain ->> Complex Relayer: Read Finality Proof of Block 483 + Complex Relayer ->> Target Chain: Submit Finality Proof of Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 63 + Note left of Target Chain: Finalized: 63, Source Finalized: 483, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Source Chain ->> Complex Relayer: Read Proof of Message 44 and Proof of Message 43 reward at Block 483 + Complex Relayer ->> Target Chain: Submit Proof of Message 44 and Proof of Message 43 reward at Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 64 + Note left of Target Chain: Finalized: 64, Source Finalized: 483, Received Messages: { rewarded: 43, messages-relayer-account: [44] }--> +
+ + + + diff --git a/docs/grandpa-finality-relay.html b/docs/grandpa-finality-relay.html new file mode 100644 index 00000000000..4136621b1a4 --- /dev/null +++ b/docs/grandpa-finality-relay.html @@ -0,0 +1,47 @@ + + + + + + GRANDPA Finality Relay + + +

GRANDPA Finality Relay

+

+ Source Chain is running GRANDPA Finality Gadget. Bridge GRANDPA finality pallet is deployed at + Target Chain runtime. Relayer is configured to relay Source Chain finality to Target Chain. +

+
+ sequenceDiagram + participant Source Chain + participant Relayer + participant Target Chain + Note left of Source Chain: Best: 500, Finalized: 480, Authorities Set Index: 42 + Note right of Target Chain: Uninitialized + + Source Chain ->> Relayer: Read Initialization Data + Relayer ->> Target Chain: Initialize Bridge GRANDPA Finality Pallet + Note right of Target Chain: Finalized: 480, Authorities Set Index: 42 + + Source Chain ->> Source Chain: Import Block 501 + Source Chain ->> Source Chain: Import Block 502 + Source Chain ->> Source Chain: Finalize Block 495 + Source Chain ->> Relayer: Read Finality Proof of Block 495 + Relayer ->> Target Chain: Finality Proof of Block 495 + Note right of Target Chain: Finalized: 495, Authorities Set Index: 42 + + Source Chain ->> Source Chain: Import Block 503 that changes Authorities Set to 43 + Source Chain ->> Source Chain: Finalize Block 500 + Note left of Relayer: Relayer Misses Finality Notification for Block 500 + + Source Chain ->> Source Chain: Import Block 504 + Source Chain ->> Source Chain: Finalize Mandatory Block 503 + Source Chain ->> Source Chain: Finalize Block 504 + Source Chain ->> Relayer: Read Finality Proof of Mandatory Block 503 + Relayer ->> Target Chain: Finality Proof of Block 503 + Note right of Target Chain: Finalized: 503, Authorities Set Index: 43 +
+ + + + diff --git a/docs/high-level-overview.md b/docs/high-level-overview.md index 2642c20c86a..2c174dbc98a 100644 --- a/docs/high-level-overview.md +++ b/docs/high-level-overview.md @@ -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. + +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. + +## Terminology + +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 has both on-chain (pallets) and offchain (relayers) components. + +## On-chain components -## Overview +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. -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. +### Bridge GRANDPA Finality Pallet -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. +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. -The bridge is built from various components. Here is a quick overview of the important ones. +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. -### Header Sync +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). -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. +More: [code](../modules/grandpa/). -### Headers Relayer +### Bridge Parachains Finality Pallet -A standalone application connected to both chains. It submits every source chain header it sees to -the target chain through RPC. +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. -### Message Delivery +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. -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 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. -### Message Dispatch +More: [code](../modules/parachains/). -A FRAME pallet responsible for interpreting the payload of delivered messages. +### Bridge Messages Pallet -### Message Relayer +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. -A standalone application handling delivery of the messages from source chain to the target chain. +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. -## Processes +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. -High level sequence charts of the process can be found in [a separate document](./high-level.html). +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. -### Substrate (GRANDPA) Header Sync +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. -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. +More: [code](../modules/messages/). -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. +### Bridge Relayers Pallet -Referer to the [pallet documentation](../modules/grandpa/src/lib.rs) for more details. +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. -#### Header Relayer strategy +More: [code](../modules/relayers/). -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. +## Offchain Components -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. +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. -### Message Passing +### GRANDPA Finality Relay -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 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. -#### Message Lanes Delivery +More: [GRANDPA Finality Relay Sequence Diagram](./grandpa-finality-relay.html), [code](../relays/finality/). -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. +### Parachains Finality Relay -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 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. -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. +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. -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. +More: [Parachains Finality Relay Sequence Diagram](./parachains-finality-relay.html), [code](../relays/parachains/). -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. +### Messages Relay -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. +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. -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). +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. -#### Dispatching Messages +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. -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. +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. -An example `Call` of the target chain would look something like this: +More: [Messages Relay Sequence Diagram](./messages-relay.html), [code](../relays/messages/). -```rust -target_runtime::Call::Balances(target_runtime::pallet_balances::Call::transfer(recipient, amount)) -``` +### Complex Relay -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. +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. -When dispatching messages there are three Origins which can be used by the target chain: -1. Root Origin -2. Source Origin -3. Target Origin +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. -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 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. -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 +More: [Complex Relay Sequence Diagram](./complex-relay.html), [code](../relays/bin-substrate/src/cli/relay_headers_and_messages/). diff --git a/docs/high-level.html b/docs/high-level.html deleted file mode 100644 index 3c4c6178c95..00000000000 --- a/docs/high-level.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - High Level Bridge Components - - -

Header Sync

-

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.

-
- 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' -
-

Message Delivery (single lane)

-

Pending messages are stored on-chain (source) so the relayer code is completely stateless - it can read all the details from the chain.

-

Delivering pending messages requires finality first.

-
- 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.
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,
it's bundled with the "Deliver Messages" proof) -
- - - - diff --git a/docs/messages-relay.html b/docs/messages-relay.html new file mode 100644 index 00000000000..c4dab9901e0 --- /dev/null +++ b/docs/messages-relay.html @@ -0,0 +1,78 @@ + + + + + + Messages Relay + + +

Messages Relay

+

+ Both Source Chain and Target Chains have Bridge Messages pallets deployed. They also have required + finality pallets deployed - we don't care about finality type here - they can be either Bridge GRANDPA, + or Bridge Parachains finality pallets, or any combination of those. +

+

+ Finality Relayer represents two actual relayers - one relays Source Chain Finality to Target Chain. + And another one relays Target Chain Finality to Source Chain. +

+
+ sequenceDiagram + participant Source Chain + participant Finality Relayer + participant Messages Relayer + participant Target Chain + + Note right of Source Chain: Finalized: 480, Target Finalized: 50, Sent Messages: 42, Confirmed Messages: 42 + Note left of Target Chain: Finalized: 60, Source Finalized: 420, Received Messages: 42 + + Source Chain ->> Source Chain: someone Sends Message 43 + Source Chain ->> Source Chain: Import and Finalize Block 481 + + Source Chain ->> Messages Relayer: notes new outbound message 43 at Source Chain Block 481 + Note right of Messages Relayer: can't deliver message 43, Source Chain Block 481 is not relayed + + Source Chain ->> Finality Relayer: Read Finality Proof of Block 481 + Finality Relayer ->> Target Chain: Submit Finality Proof of Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 61 + Note left of Target Chain: Finalized: 61, Source Finalized: 481, Received Messages: 42 + + Source Chain ->> Messages Relayer: Read Proof of Message 43 at Block 481 + Messages Relayer ->> Target Chain: Submit Proof of Message 43 at Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 62 + Note left of Target Chain: Finalized: 62, Source Finalized: 481, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Target Chain ->> Messages Relayer: notes new unrewarded relayer at Target Chain Block 62 + Note right of Messages Relayer: can't relay delivery confirmations because Target Chain Block 62 is not relayed + + Target Chain ->> Finality Relayer: Read Finality Proof of Block 62 + Finality Relayer ->> Source Chain: Submit Finality Proof of Block 62 + Source Chain ->> Source Chain: Import and Finalize Block 482 + Note right of Source Chain: Finalized: 482, Target Finalized: 62, Confirmed Messages: 42 + + Target Chain ->> Messages Relayer: Read Proof of Message 43 Delivery at Block 62 + Messages Relayer ->> Source Chain: Submit Proof of Message 43 Delivery at Block 612 + Source Chain ->> Source Chain: rewards messages-relayer-account for delivering message [43] + Source Chain ->> Source Chain: prune delivered message 43 from runtime storage + Note right of Source Chain: Finalized: 482, Target Finalized: 61, Confirmed Messages: 43 + + Source Chain ->> Source Chain: someone Sends Message 44 + Source Chain ->> Source Chain: Import and Finalize Block 483 + + Source Chain ->> Messages Relayer: notes new outbound message 44 at Source Chain Block 483 and new confirmed message 43 + Note right of Messages Relayer: can't deliver message 44, Source Chain Block 483 is not relayed + + Source Chain ->> Finality Relayer: Read Finality Proof of Block 483 + Finality Relayer ->> Target Chain: Submit Finality Proof of Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 63 + Note left of Target Chain: Finalized: 63, Source Finalized: 483, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Source Chain ->> Messages Relayer: Read Proof of Message 44 and Proof of Message 43 reward at Block 483 + Messages Relayer ->> Target Chain: Submit Proof of Message 44 and Proof of Message 43 reward at Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 64 + Note left of Target Chain: Finalized: 64, Source Finalized: 483, Received Messages: { rewarded: 43, messages-relayer-account: [44] } +
+ + + + diff --git a/docs/parachains-finality-relay.html b/docs/parachains-finality-relay.html new file mode 100644 index 00000000000..4fc1392b87d --- /dev/null +++ b/docs/parachains-finality-relay.html @@ -0,0 +1,55 @@ + + + + + + Parachains Finality Relay + + +

Parachains Finality Relay

+

+ Source Relay Chain is running GRANDPA Finality Gadget. Source Parachain is a parachain of the Source + Relay Chain. Bridge GRANDPA finality pallet is deployed at Target Chain runtime and is "connected" + to the Source Relay Chain. Bridge Parachains finality pallet is deployed at Target Chain and is + configured to track the Source Parachain. GRANDPA Relayer is configured to relay Source Relay Chain + finality to Target Chain. Parachains Relayer is configured to relay Source Parachain headers finality + to Target Chain. +

+
+ sequenceDiagram + participant Source Parachain + participant Source Relay Chain + participant GRANDPA Relayer + participant Parachains Relayer + participant Target Chain + + Note left of Source Parachain: Best: 125 + Note left of Source Relay Chain: Finalized: 500, Best Parachain at Finalized: 120 + Note right of Target Chain: Best Relay: 480, Best Parachain: 110 + + Source Parachain ->> Source Parachain: Import Block 126 + Source Parachain ->> Source Relay Chain: Receives the Parachain block 126 + + Source Relay Chain ->> Source Relay Chain: Import block 501 + Source Relay Chain ->> Source Relay Chain: Finalize block 501 + Note left of Source Relay Chain: Finalized: 501, Best Parachain at Finalized: 126 + + Source Relay Chain ->> Parachains Relayer: notes new Source Parachain Block 126 + Note left of Parachains Relayer: can't relay Source Parachain Block 126, because it requires at least Source Relay Block 501 at Target Chain + + Source Relay Chain ->> Source Relay Chain: Import block 502 + Source Relay Chain ->> Source Relay Chain: Finalize block 502 + + Source Relay Chain ->> GRANDPA Relayer: read GRANDPA Finality Proof of Block 502 + GRANDPA Relayer ->> Target Chain: submit GRANDPA Finality Proof of Block 502 + Note right of Target Chain: Best Relay: 502, Best Parachain: 110 + + Target Chain ->> Parachains Relayer: notes finalized Source Relay Block 502 at Target Chain + Source Relay Chain ->> Parachains Relayer: read Parachain Finality Proof at Relay Block 502 + Parachains Relayer ->> Target Chain: submit Parachain Finality Proof at Relay Block 502 + Note right of Target Chain: Best Relay: 502, Best Parachain: 126 +
+ + + + diff --git a/docs/plan.md b/docs/plan.md deleted file mode 100644 index 9c4106d9ade..00000000000 --- a/docs/plan.md +++ /dev/null @@ -1,22 +0,0 @@ -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] - diff --git a/docs/polkadot-kusama-bridge-overview.md b/docs/polkadot-kusama-bridge-overview.md new file mode 100644 index 00000000000..302196718b9 --- /dev/null +++ b/docs/polkadot-kusama-bridge-overview.md @@ -0,0 +1,132 @@ +# Polkadot <> Kusama Bridge Overview + +This document describes how we use all components, described in the [High-Level Bridge Documentation](./high-level-overview.md), +to build the XCM bridge between Kusama and Polkadot. In this case, our components merely work as a XCM transport +(like XCMP/UMP/HRMP), between chains that are not a part of the same consensus system. + +The overall architecture may be seen in [this diagram](./polkadot-kusama-bridge.html). + +## Bridge Hubs + +All operations at relay chain are expensive. Ideally all non-mandatory transactions must happen on parachains. +That's why we are planning to have two parachains - Polkadot Bridge Hub under Polkadot consensus and Kusama +Bridge Hub under Kusama consensus. + +The Bridge Hub will have all required bridge pallets in its runtime. We hope that later, other teams will be able to +use our bridge hubs too and have their pallets there. + +The Bridge Hub will use the base token of the ecosystem - KSM at Kusama Bridge Hub and DOT at Polkadot Bridge Hub. +The runtime will have minimal set of non-bridge pallets, so there's not much you can do directly on bridge hubs. + +## Connecting Parachains + +You won't be able to directly use bridge hub transactions to send XCM messages over the bridge. Instead, you'll need +to use other parachains transactions, which will use HRMP to deliver message to the Bridge Hub. The Bridge Hub will +just queue this messages in its outbound lane, which is dedicated to deliver messages between two parachains. + +Our first planned bridge will connect the Polkadot' Statemint and Kusama' Statemine. Bridge between those two +parachains would allow Statemint accounts to hold wrapped KSM tokens and Statemine accounts to hold wrapped DOT +tokens. + +For that bridge (pair of parachains under different consensus systems) we'll be using the lane 00000000. Later, +when other parachains will join the bridge, they will be using other lanes for their messages. + +## Running Relayers + +We are planning to run our own complex relayer for the lane 00000000. The relayer will relay Kusama/Polkadot GRANDPA +justifications to the bridge hubs at the other side. It'll also relay finalized Kusama Bridge Hub and Polkadot Bridge +Hub heads. This will only happen when messages will be queued at hubs. So most of time relayer will be idle. + +There's no any active relayer sets, or something like that. Anyone may start its own relayer and relay queued messages. +We are not against that and, as always, appreciate any community efforts. Of course, running relayer has the cost. +Apart from paying for the CPU and network, the relayer pays for transactions at both sides of the bridge. We have +a mechanism for rewarding relayers. + +### Compensating the Cost of Message Delivery Transactions + +One part of our rewarding scheme is that the cost of message delivery, for honest relayer, is zero. The honest relayer +is the relayer, which is following our rules: + +- we do not reward relayers for submitting GRANDPA finality transactions. The only exception is submitting mandatory + headers (headers which are changing the GRANDPA authorities set) - the cost of such transaction is zero. The relayer + will pay the full cost for submitting all other headers; + +- we do not reward relayers for submitting parachain finality transactions. The relayer will pay the full cost for + submitting parachain finality transactions; + +- we compensate the cost of message delivery transactions that have actually delivered the messages. So if your + transaction has claimed to deliver messages `[42, 43, 44]`, but, because of some reasons, has actually delivered + messages `[42, 43]`, the transaction will be free for relayer. If it has not delivered any messages, then + the relayer pays the full cost of the transaction; + +- we compensate the cost of message delivery and all required finality calls, if they are part of the same + [`frame_utility::batch_all`](https://github.com/paritytech/substrate/blob/891d6a5c870ab88521183facafc811a203bb6541/frame/utility/src/lib.rs#L326) + transaction. Of course, the calls inside the batch must be linked - e.g. the submitted parachain head must be used + to prove messages. Relay header must be used to prove parachain head finality. If one of calls fails, or if they + are not linked together, the relayer pays the full transaction cost. + +Please keep in mind that the fee of "zero-cost" transactions is still withdrawn from the relayer account. But the +compensation is registered in the `pallet_bridge_relayers::RelayerRewards` map at the target bridge hub. The relayer +may later claim all its rewards later, using the `pallet_bridge_relayers::claim_rewards` call. + +*A side note*: why we don't simply set the cost of useful transactions to zero? That's because the bridge has its cost. +If we won't take any fees, it would mean that the sender is not obliged to pay for its messages. And Bridge Hub +collators (and, maybe, "treasury") are not receiving any payment for including transactions. More about this later, +in the [Who is Rewarding Relayers](#who-is-rewarding-relayers) section. + +### Message Delivery Confirmation Rewards + +In addition to the "zero-cost" message delivery transactions, the relayer is also rewarded for: + +- delivering every message. The reward is registered during delivery confirmation transaction at the Source Bridge + Hub.; + +- submitting delivery confirmation transaction. The relayer may submit delivery confirmation that e.g. confirms + delivery of four messages, of which the only one (or zero) messages is actually delivered by this relayer. It + receives some fee for confirming messages, delivered by other relayers. + +Both rewards may be claimed using the `pallet_bridge_relayers::claim_rewards` call at the Source Bridge Hub. + +### Who is Rewarding Relayers + +Obviously, there should be someone who is paying relayer rewards. We want bridge transactions to have a cost, so we +can't use fees for rewards. Instead, the parachains using the bridge, use sovereign accounts on both sides +of the bridge to cover relayer rewards. + +Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Statemine (Kusama Parachain) will +have an account at the Polkadot Bridge Hub. The Statemint (Polkadot Parachain) will have an account at the Kusama +Bridge Hub. The sovereign accounts are used as a source of funds when the relayer is calling the +`pallet_bridge_relayers::claim_rewards`. + +Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. +Statemine will only reward relayers that are delivering messages from Statemine. The Statemine sovereign account +is not used to cover rewards of bridging with some other Polkadot Parachain. + +### Multiple Relayers and Rewards + +Our goal is to incentivize running honest relayers. But we have no relayers sets, so at any time anyone may submit +message delivery transaction, hoping that the cost of this transaction will be compensated. So what if some message is +currently queued and two relayers are submitting two identical message delivery transactions at once? Without any +special means, the cost of first included transacton will be compensated and the cost of the other one won't. A honest, +but unlucky relayer will lose some money. In addition, we'll waste some portion of block size and weight, which +may be used by other useful transactions. + +To solve the problem, we have two signed extensions ([generate_bridge_reject_obsolete_headers_and_messages! {}](../bin/runtime-common/src/lib.rs) +and [RefundRelayerForMessagesFromParachain](../bin/runtime-common/src/refund_relayer_extension.rs)), that are +preventing bridge transactions with obsolete data from including into the block. We are rejecting following +transactions: + +- transactions, that are submitting the GRANDPA justification for the best finalized header, or one of its ancestors; + +- transactions, that are submitting the proof of the current best parachain head, or one of its ancestors; + +- transactions, that are delivering already delivered messages. If at least one of messages is not yet delivered, + the transaction is not rejected; + +- transactions, that are confirming delivery of already confirmed messages. If at least one of confirmations is new, + the transaction is not rejected; + +- [`frame_utility::batch_all`](https://github.com/paritytech/substrate/blob/891d6a5c870ab88521183facafc811a203bb6541/frame/utility/src/lib.rs#L326) + transactions, that have both finality and message delivery calls. All restrictions from the + [Compensating the Cost of Message Delivery Transactions](#compensating-the-cost-of-message-delivery-transactions) + are applied. diff --git a/docs/polkadot-kusama-bridge.html b/docs/polkadot-kusama-bridge.html new file mode 100644 index 00000000000..dcbae0e7b17 --- /dev/null +++ b/docs/polkadot-kusama-bridge.html @@ -0,0 +1,67 @@ + + + + + + Polkadot <> Kusama Bridge + + +

Polkadot <> Kusama Bridge

+

+ Our bridge connects two parachains - Kusama Bridge Hub and Polkadot Bridge Hub. Messages that + are sent over bridge have XCM format and we are using existing architecture to dispatch them. + Since both Polkadot, Kusama and their parachains already have means to exchange XCM messages + within the same consensus system (HRMP, VMP, ...), it means that we are able to connect all those + chains with our bridge. +

+

+ In our architecture, the lane that is used to relay messages over the bridge is determined by + the XCM source and destinations. So e.g. bridge between Statemint and Statemine (and opposite direction) + will use the lane 00000000, bridge between some other Polkadot Parachain and some other Kusama Parachain + will use the lane 00000001 and so on. +

+
+ flowchart LR + subgraph Polkadot Consensus + polkadot(((Polkadot))) + statemint(((Statemint))) + polkadot_bh(((Polkadot Bridge Hub))) + + polkadot---statemint + polkadot---polkadot_bh + + statemint-->|Send Message Using HRMP|polkadot_bh + + polkadot_bh-->|Send Message Using HRMP|statemint + statemint-->|Dispatch the Message|statemint + end + subgraph Kusama Consensus + kusama_bh(((Kusama Bridge Hub))) + statemine(((Statemine))) + kusama(((Kusama))) + + kusama---statemine + kusama---kusama_bh + + kusama_bh-->|Send Message Using HRMP|statemine + statemine-->|Dispatch the Message|statemine + + statemine-->|Send Message Using HRMP|kusama_bh + end + + polkadot_bh<===>|Message is relayed to the Bridged Chain using lane 00000000|kusama_bh + + linkStyle 2 stroke:red + linkStyle 7 stroke:red + linkStyle 8 stroke:red + + linkStyle 3 stroke:green + linkStyle 4 stroke:green + linkStyle 9 stroke:green +
+ + + \ No newline at end of file diff --git a/docs/scenario1.html b/docs/scenario1.html deleted file mode 100644 index 808a0c34f0d..00000000000 --- a/docs/scenario1.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - Flow Chart of Millau to Rialto Transfer - - -

Scenario: mDave sending RLT to rEve

-
- 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 -
- - - - diff --git a/docs/send-message.md b/docs/send-message.md deleted file mode 100644 index 6984c56d67f..00000000000 --- a/docs/send-message.md +++ /dev/null @@ -1,131 +0,0 @@ -# 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 - -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 - -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 --source-host --source-port --source-signer --origin --target-signer - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - --fee - Delivery and dispatch fee. If not passed, determined automatically - - --lane Hex-encoded lane id - --source-host Connect to Source node at given host - --source-port Connect to Source node websocket server at given port - --source-signer - The SURI of secret key to use when transactions are submitted to the Source node - - --source-signer-password - The password for the SURI of secret key to use when transactions are submitted to the Source node - - --origin - The origin to use when dispatching the message on the target chain [possible values: Target, Source] - - --target-signer - The SURI of secret key to use when transactions are submitted to the Target node - - --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. diff --git a/docs/testing-scenarios.md b/docs/testing-scenarios.md deleted file mode 100644 index 343720524ec..00000000000 --- a/docs/testing-scenarios.md +++ /dev/null @@ -1,221 +0,0 @@ -# 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::::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. diff --git a/scripts/send-message-from-millau-rialto.sh b/scripts/send-message-from-millau-rialto.sh index 539ca5fc06c..bcfc9df2f57 100755 --- a/scripts/send-message-from-millau-rialto.sh +++ b/scripts/send-message-from-millau-rialto.sh @@ -8,26 +8,11 @@ # TODO: Fix demeo scripts https://github.com/paritytech/parity-bridges-common/issues/1406 -MILLAU_PORT="${RIALTO_PORT:-9945}" +MILLAU_PORT="${MILLAU_PORT:-9945}" -case "$1" in - remark) - RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message millau-to-rialto \ - --source-host localhost \ - --source-port $MILLAU_PORT \ - --source-signer //Alice \ - raw 020419ac - ;; - transfer) - RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message millau-to-rialto \ - --source-host localhost \ - --source-port $MILLAU_PORT \ - --source-signer //Alice \ - transfer \ - --amount 100000000000000 \ - --recipient 5DZvVvd1udr61vL7Xks17TFQ4fi9NiagYLaBobnbPCP14ewA \ - ;; - *) echo "A message type is require. Supported messages: remark, transfer."; exit 1;; -esac +RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ +./target/debug/substrate-relay send-message millau-to-rialto \ + --source-host localhost \ + --source-port $MILLAU_PORT \ + --source-signer //Alice \ + raw 020419ac diff --git a/scripts/send-message-from-rialto-millau.sh b/scripts/send-message-from-rialto-millau.sh index 923f588ea47..e348c33f2a2 100755 --- a/scripts/send-message-from-rialto-millau.sh +++ b/scripts/send-message-from-rialto-millau.sh @@ -10,24 +10,9 @@ RIALTO_PORT="${RIALTO_PORT:-9944}" -case "$1" in - remark) - RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message rialto-to-millau \ - --source-host localhost \ - --source-port $RIALTO_PORT \ - --source-signer //Bob \ - raw 020419ac - ;; - transfer) - RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message rialto-to-millau \ - --source-host localhost \ - --source-port $RIALTO_PORT \ - --source-signer //Bob \ - transfer \ - --amount 100000000000000 \ - --recipient 5DZvVvd1udr61vL7Xks17TFQ4fi9NiagYLaBobnbPCP14ewA \ - ;; - *) echo "A message type is require. Supported messages: remark, transfer."; exit 1;; -esac +RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ +./target/debug/substrate-relay send-message rialto-to-millau \ + --source-host localhost \ + --source-port $RIALTO_PORT \ + --source-signer //Bob \ + raw 020419ac