High-Level Documentation (#565)

* High level docs - start.

* Clean up README

* Start adding details to high level docs

* More docs on the header sync pallet

* Testing scenarios document.

* Add some scenarios.

* Add multi-sig scenario.

* Start writing about message dispatch pallet

* Move content from old README into PoA specific doc

* Apply suggestions from code review

Co-authored-by: Andreas Doerr <adoerr@users.noreply.github.com>

* GRANDPA for consistency.

* Describe scenario steps.

* WiP

* Add notes about block production and forks

* Update.

* Add sequence diagram for Millau to Rialto transfer

* Clean up header sync pallet overview

* Remove leftover example code

* Clean up testing scenarios and amend sequence diagram.

* Linking docs.

* Add some more docs.

* Do a bit of cleanup on the high-level docs

* Clean up the testing scenario

* Fix typos in flow charts

* Fix small typo

* Fix indentation of Rust block

* Another attempt at rendering block correctly

* TIL about lazy list numbering in Markdown

* Add list numbers across sections

* Start counting from correct number

* Update README to use correct path to local scripts

* Wrap ASCII art in code block

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>
Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Andreas Doerr <adoerr@users.noreply.github.com>
This commit is contained in:
Hernando Castano
2020-12-14 18:44:19 -05:00
committed by Bastian Köcher
parent 5a790c9874
commit d47658c92e
8 changed files with 283 additions and 188 deletions
+81 -163
View File
@@ -2,20 +2,18 @@
This is a collection of components for building bridges.
These components include runtime modules to help you construct your bridge's runtime, as well as
bridge relays for cross-chain communication.
These components include Substrate pallets for syncing headers, passing arbitrary messages, as well
as libraries for building relayers to provide cross-chain communication capabilities.
A bridge node is also available. The node can be used to run a test network which has support for bridging Ethereum
PoA chains to Substrate. We're working on expanding this functionality in the future.
Three bridge nodes are also available. The nodes can be used to run test networks which bridge other
Substrate chains or Ethereum Proof-of-Authority chains.
🚧 The bridges are currently under construction - a hardhat is recommended beyond this point 🚧
## Contents
- [Installation](#installation)
- [High-Level Architecture](#high-level-architecture)
- [Project Layout](#project-layout)
- [Rialto Runtime](#rialto-runtime)
- [Ethereum Node](#ethereum-node)
- [Bridge Relay](#bridge-relay)
- [Running the Bridge](#running-the-bridge)
## Installation
@@ -40,199 +38,119 @@ If you need more information about setting up your development environment Subst
[Getting Started](https://substrate.dev/docs/en/knowledgebase/getting-started/) page is a good
resource.
## High-Level Architecture
This repo has support for bridging foreign chains together using a combination of Substrate pallets
and external processes called relayers. A bridge chain is one that is able to follow the consensus
of a foreign chain independently. For example, consider the case below where we want to bridge two
Substrate based chains.
```
+---------------+ +---------------+
| | | |
| Rialto | | Millau |
| | | |
+-------+-------+ +-------+-------+
^ ^
| +---------------+ |
| | | |
+-----> | Bridge Relay | <-------+
| |
+---------------+
```
The Millau chain must be able to accept Rialto headers and verify their integrity. It does this by
using a runtime module designed to track GRANDPA finality. Since two blockchains can't interact
directly they need an external service, called a relayer, to communicate. The relayer will subscribe
to new Rialto headers via RPC and submit them to the Millau chain for verification.
Take a look at [Bridge High Level Documentation](./docs/high-level-overview.md) for more in-depth
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
"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.
```
├── bin
│ └── node // Bridge ready chain implementation
├── modules // Runtime Modules
── ethereum // Manage Ethereum PoA chain info
├── ethereum-contract // Ethereum built-in for validating Substrate block info
── currency-exchange // Cross-chain fund transfers
│ └── substrate // Manage Substrate chain info
├── primitives // Shared runtime and node code
── ethereum-poa // Helpers for Ethereum PoA
├── relays // Cross-chain communication
── ethereum // Sync and communicate between Ethereum PoA + Substrate chains
│ └── substrate // 🚧 WIP 🚧
```
## Rialto Runtime
The node runtime consists of several runtime modules, however not all of them are used at the same
time. When running an Ethereum PoA to Substrate bridge the modules required are the Ethereum module
and the currency exchange module. When running a Substrate to Substrate bridge the Substrate and
currency exchange modules are required.
Below is a brief description of each of the runtime modules.
### Ethereum Bridge Runtime Module
The main job of this runtime module is to keep track of useful information an Ethereum PoA chain
which has been submitted by a bridge relayer. This includes:
- Ethereum headers and their status (e.g are they the best header, are they finalized, etc.)
- Current validator set, and upcoming validator sets
This runtime module has more responsibilties than simply storing headers and validator sets. It is
able to perform checks on the incoming headers to verify their general integrity, as well as whether
or not they've been finalized by the authorities on the PoA chain.
This module is laid out as so:
```
├── ethereum
│ └── src
│ ├── error.rs // Runtime error handling
│ ├── finality.rs // Manage finality operations
│ ├── import.rs // Import new Ethereum headers
│ ├── lib.rs // Store headers and validator set info
│ ├── validators.rs // Track current and future PoA validator sets
│ └── verification.rs // Verify validity of incoming Ethereum headers
```
### Currency Exchange Runtime Module
The currency exchange module is used to faciliate cross-chain funds transfers. It works by accepting
a transaction which proves that funds were locked on one chain, and releases a corresponding amount
of funds on the recieving chain.
For example: Alice would like to send funds from chain A to chain B. What she would do is send a
transaction to chain A indicating that she would like to send funds to an address on chain B. This
transaction would contain the amount of funds she would like to send, as well as the address of the
recipient on chain B. These funds would now be locked on chain A. Once the block containing this
"locked-funds" transaction is finalized it can be relayed to chain B. Chain B will verify that this
transaction was included in a finalized block on chain A, and if successful deposit funds into the
recipient account on chain B.
Chain B would need a way to convert from a foreign currency to its local currency. How this is done
is left to the runtime developer for chain B.
This module is one example of how an on-chain light client can be used to prove a particular action
was taken on a foreign chain. In particular it enables transfers of the foreign chain's native
currency, but more sophisticated modules such as ERC20 token transfers or arbitrary message transfers
are being worked on as well.
### Substrate Bridge Runtime Module
👷 Under Construction 👷‍♀️
## Ethereum Node
On the Ethereum side of things, we require two things. First, a Solidity smart contract to track the
Substrate headers which have been submitted to the bridge (by the relay), and a built-in contract to
be able to verify that headers have been finalized by the Grandpa finality gadget. Together this
allows the Ethereum PoA chain to verify the integrity and finality of incoming Substrate headers.
The Solidity smart contract is not part of this repo, but can be found
[here](https://github.com/svyatonik/substrate-bridge-sol/blob/master/substrate-bridge.sol) if you're
curious. We have the contract ABI in the `ethereum/relays/res` directory.
## Bridge Relay
The bridge relay is responsible for syncing the chains which are being bridged, and passing messages
between them. The current implementation of the relay supportings syncing and interacting with
Ethereum PoA and Substrate chains.
The folder structure of the bridge relay is as follows:
```
├── relays
│ ├── ethereum
│ │ ├── res
│ │ │ └── ...
│ │ └── src
│ │ ├── ethereum_client.rs // Interface for Ethereum RPC
│ │ ├── ethereum_deploy_contract.rs // Utility for deploying bridge contract to Ethereum
│ │ ├── ethereum_exchange.rs // Relay proof of PoA -> Substrate exchange transactions
│ │ ├── ethereum_sync_loop.rs // Sync headers from Ethereum, submit to Substrate
│ │ ├── ethereum_types.rs // Useful Ethereum types
│ │ ├── exchange.rs // Relay proof of exchange transactions
│ │ ├── headers.rs // Track synced and incoming block headers
│ │ ├── main.rs // Entry point to binary
│ │ ├── substrate_client.rs // Interface for Substrate RPC
│ │ ├── substrate_sync_loop.rs // Sync headers from Substrate, submit to Ethereum
│ │ ├── substrate_types.rs // Useful Ethereum types
│ │ ├── sync.rs // Sync configuration and helpers
│ │ ├── sync_loop.rs // Header synchronization between source and target chains
│ │ ├── sync_types.rs // Useful sync types
│ │ └── utils.rs // General utilities
```
├── bin // Node and Runtime for the various Substrate chains
│ └── ...
├── deployments // Useful tools for deploying test networks
── ...
├── diagrams // Pretty pictures of the project architecture
── ...
├── modules // Substrate Runtime Modules (a.k.a Pallets)
├── ethereum // Ethereum PoA Header Sync Module
── substrate // Substrate Based Chain Header Sync Module
├── message-lane // Cross Chain Message Passing
── ...
├── primitives // Code shared between modules, runtimes, and relays
│ └── ...
├── relays // Application for sending headers and messages between chains
│ └── ...
└── scripts // Useful development and maintenence scripts
```
## Running the Bridge
To run the Bridge you need to be able to connect the bridge relay node to the RPC interface of nodes
on each side of the bridge (home & foreign chain). An easy way to build all the required nodes is
through Docker.
on each side of the bridge (source and target chain).
### Local Development Build
There are 3 ways to run the bridge, described below:
- building & running from source,
- building or using Docker images for each individual component,
- running a Docker Compose setup (recommended).
#### Building
### Building
First you'll need to build the bridge node and relay. This can be done as follows:
First you'll need to build the bridge nodes and relay. This can be done as follows:
```bash
# In `parity-bridges-common` folder
cargo build -p rialto-bridge-node
cargo build -p ethereum-poa-relay
cargo build -p millau-bridge-node
cargo build -p substrate-relay
```
Next you'll need to clone the following [fork of OpenEthereum](https://github.com/paritytech/openethereum).
If you're doing development which only involves the Ethereum to Substrate side of the bridge you may
use the `master` branch. Otherwise you'll need to checkout the `substrate-builtins-stubs` branch.
```bash
# Should be at the same level as `parity-bridges-common` folder
git clone https://github.com/paritytech/openethereum.git openethereum
git fetch
git checkout substrate-builtins-stubs
```
If you've checked out the `substrate-builtins-stubs` branch make sure you've cloned the OpenEthereum
repo at the same level as `parity-bridges-common` since it references the repo.
Next you'll need to build the Ethereum node:
```bash
# In `openethereum` folder
cargo build
```
#### Running
### Running
To run a simple dev network you'll can use the scripts located in
[the `scripts` folder](./scripts). Since the relay connects to both the Substrate and Ethereum
chains it must be run last.
[the `scripts` folder](./scripts). Since the relay connects to both Substrate chains it must be run
last.
```bash
# In `parity-bridges-common` folder
./scripts/run-openethereum-node.sh
./scripts/run-rialto-bridge-node.sh
./scripts/run-eth2sub-relay.sh
./deployments/local-scripts/run-rialto-bridge-node.sh
./deployments/local-scripts/run-millau-bridge-node.sh
./deployments/local-scripts/run-millau-to-rialto-relay.sh
./deployments/local-scripts/run-rialto-to-millau-relay.sh
```
At this point you should see the relayer submitting blocks from the Ethereum chain
to the Substrate chain.
At this point you should see the relayer submitting blocks from the Millau Substrate chain to the
Rialto Substrate chain and vice-versa.
### Local Docker Build
If you want to make a Docker container using your local source files you can run the following
command at the top level of the repository:
```bash
docker build . -t bridge-relay-dev
docker build . -t local/rialto-bridge-node --build-arg PROJECT=rialto-bridge-node
docker build . -t local/millau-bridge-node --build-arg PROJECT=millau-bridge-node
docker build . -t local/substrate-relay --build-arg PROJECT=substrate-relay
```
You can also build and run the Substrate based node as follows:
You can then run the network as follows:
```bash
docker build . -t bridge-node-dev --build-arg PROJECT=rialto-bridge-node
```
To run the Substrate node you can do the following:
```bash
docker run -it bridge-node-dev --dev --tmp
docker run -it local/rialto-bridge-node --dev --tmp
docker run -it local/millau-bridge-node --dev --tmp
docker run -it local/substrate-relay
```
Notice that the `docker run` command will accept all the normal Substrate flags. For local
development you should at minimum run with the `--dev` flag or else no blocks will be produced.
### Full Network Docker Setup
See [Deployments README](./deployments/README.md) to learn more about how to run
a more sophisticated test network using `docker-compose` setup.
### 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).
+177
View File
@@ -0,0 +1,177 @@
# High-Level Bridge Documentation
## Purpose
Trustless connecting between two Substrate-based chains using GRANDPA finality.
## Overview
Even though we support two-way bridging, the documentation will generally talk about a one-sided
interaction. That's to say, we will only talk about syncing headers and messages from a _source_
chain to a _target_ chain. This is because the two-sided interaction is really just the one-sided
interaction with the source and target chains switched.
To understand the full interaction with the bridge, take a look at the
[testing scenarios](./testing-scenarios.md) document. It describes potential use cases and describes
how each of the layers outlined below is involved.
The bridge is built from various components. Here is a quick overview of the important ones.
### Header Sync
A light client of the source chain built into the target chain's runtime. It is a single FRAME
pallet. It provides a "source of truth" about the source chain headers which have been finalized.
This is useful for higher level applications.
### Headers Relayer
A standalone application connected to both chains. It submits every source chain header it sees to
the target chain through RPC.
### Message Delivery
A FRAME pallet built on top of the header sync pallet. It allows users to submit messages to the
source chain, which are to be delivered to the target chain. The delivery protocol doesn't care
about the payload more than it has to. Handles replay protection and message ordering.
### Message Dispatch
A FRAME pallet responsible for interpreting the payload of delivered messages.
### Message Relayer
A standalone application handling delivery of the messages from source chain to the target chain.
## Processes
High level sequence charts of the process can be found in [a separate document](./high-level.html).
### Substrate (GRANDPA) Header Sync
The header sync pallet (`pallet-substrate-bridge`) is an on-chain light client for chains which use
GRANDPA finality. It is part of the target chain's runtime, and accepts headers from the source
chain. Its main goals are to accept valid headers, track GRANDPA finality set changes, and verify
GRANDPA finality proofs (a.k.a justifications).
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. Due to this it is possible for
the pallet to import (but not necessarily finalize) headers which are _not_ valid according to the
source chain's block production mechanism.
The pallet has support for tracking forks and uses the longest chain rule to determine what the
canonical chain is. The pallet allows headers to be imported on a different fork from the canonical
one as long as the headers being imported don't conflict with already finalized headers (for
example, it will not allow importing a header at a lower height than the best finalized header).
When tracking authority set changes, the pallet - unlike the full GRANDPA protocol - does not
support tracking multiple authority set changes across forks. Each fork can have at most one pending
authority set change. This is done to prevent DoS attacks if GRANDPA on the source chain were to
stall for a long time (the pallet would have to do a lot of expensive ancestry checks to catch up).
Referer to the [pallet documentation](../modules/substrate/src/lib.rs) for more details.
#### Header Relayer strategy
There is currently no reward strategy for the relayers at all. They also are not required to be
staked or registered on-chain, unlike in other bridge designs. We consider the header sync to be
an essential part of the bridge and the incentivisation should be happening on the higher layers.
At the moment, signed transactions are the only way to submit headers to the header sync pallet.
However, in the future we would like to use unsigned transactions for headers delivery. This will
allow transaction de-duplication to be done at the transaction pool level and also remove the cost
for message relayers to run header relayers.
### Message Passing
Once header sync is maintained, the target side of the bridge can receive and verify proofs about
events happening on the source chain, or its internal state. On top of this, we built a message
passing protocol which consists of two parts described in following sections: message delivery and
message dispatch.
#### Message Lanes Delivery
The [Message delivery pallet](../modules/message-lane/src/lib.rs) is responsible for queueing up
messages and delivering them in order on the target chain. It also dispatches messages, but we will
cover that in the next section.
The pallet supports multiple lanes (channels) where messages can be added. Every lane can be
considered completely independent from others, which allows them to make progress in parallel.
Different lanes can be configured to validated messages differently (e.g higher rewards, specific
types of payload, etc.) and may be associated with a particular "user application" built on top of
the bridge. Note that messages in the same lane MUST be delivered _in the same order_ they were
queued up.
The message delivery protocol does not care about the payload it transports and can be coupled
with an arbitrary message dispatch mechanism that will interpret and execute the payload if delivery
conditions are met. Each delivery on the target chain is confirmed back to the source chain by the
relayer. This is so that she can collect the reward for delivering these messages.
Users of the pallet add their messages to an "outbound lane" on the source chain. When a block is
finalized message relayers are responsible for reading the current queue of messages and submitting
some (or all) of them to the "inbound lane" of the target chain. Each message has a `nonce`
associated with it, which serves as the ordering of messages. The inbound lane stores the last
delivered nonce to prevent replaying messages. To succesfuly deliver the message to the inbound lane
on target chain the relayer has to present present a storage proof which shows that the message was
part of the outbound lane on the source chain.
During delivery of messages they are immediately dispatched on the target chain and the relayer is
required to declare the correct `weight` to cater for all messages dispatch and pay all required
fees of the target chain. To make sure the relayer is incentivised to do so, on the source chain:
- the user provides a declared dispatch weight of the payload
- the pallet calculates the expected fee on the target chain based on the declared weight
- the pallet converts the target fee into source tokens (based on a price oracle) and reserves
enough tokens to cover for the delivery, dispatch, confirmation and additional relayers reward.
If the declared weight turns out to be too low on the target chain the message is delivered but
it immediately fails to dispatch. The fee and reward is collected by the relayer upon confirmation
of delivery.
Due to the fact that message lanes require delivery confirmation transactions, they also strictly
require bi-directional header sync (i.e. you can't use message delivery with one-way header sync).
#### Dispatching Messages
The [Message dispatch pallet](../modules/call-dispatch/src/lib.rs) is used to perform the actions
specified by messages which have come over the bridge. For Substrate-based chains this means
interpreting the source chain's message as a `Call` on the target chain.
An example `Call` of the target chain would look something like this:
```rust
target_runtime::Call::Balances(target_runtime::pallet_balances::Call::transfer(recipient, amount))
```
When sending a `Call` it must first be SCALE encoded and then sent to the source chain. The `Call`
is then delivered by the message lane delivery mechanism from the source chain to the target chain.
When a message is received the inbound message lane on the target chain will try and decode the
message payload into a `Call` enum. If it's successful it will be dispatched after we check that the
weight of the call does not exceed the weight declared by the sender. The relayer pays fees for
executing the transaction on the target chain, but her costs should be covered by the sender on the
source chain.
When dispatching messages there are three Origins which can be used by the target chain:
1. Root Origin
2. Source Origin
3. Target Origin
Senders of a message can indicate which one of the three origins they would like to dispatch their
message with. However, there are restrictions on who/what is allowed to dispatch messages with a
particular origin.
The Root origin represents the source chain's Root account on the target chain. This origin can can
only be dispatched on the target chain if the "send message" request was made by the Root origin of
the source chain - otherwise the message will fail to be dispatched.
The Source origin represents an account without a private key on the target chain. This account will
be generated/derived using the account ID of the sender on the source chain. We don't necessarily
require the source account id to be associated with a private key on the source chain either. This
is useful for representing things such as source chain proxies or pallets.
The Target origin represents an account with a private key on the target chain. The sender on the
source chain needs to prove ownership of this account by using their target chain private key to
sign: `(Call, SourceChainAccountId).encode()`. This will be included in the message payload and
verified by the target chain before dispatch.
See [`CallOrigin` documentation](../modules/call-dispatch/src/lib.rs) for more details.
#### Message Relayers Strategy
+3 -3
View File
@@ -134,7 +134,7 @@ fn fork_does_not_allow_competing_finality_proofs() {
//
// Not allowed to import 3 until we get F2
//
// Note: Grandpa would technically allow 3 to be imported as long as it didn't try and enact an
// Note: GRANDPA would technically allow 3 to be imported as long as it didn't try and enact an
// authority set change. However, since we expect finality proofs to be imported quickly we've
// decided to simplify our import process and disallow header imports until we get a finality proof.
#[test]
@@ -161,9 +161,9 @@ fn fork_waits_for_finality_proof_before_importing_header_past_one_which_enacts_a
//
// [1] <- [2: S|1] <- [3: S|0]
//
// Grandpa can have multiple authority set changes pending on the same fork. However, we've decided
// GRANDPA can have multiple authority set changes pending on the same fork. However, we've decided
// to introduce a limit of _one_ pending authority set change per fork in order to simplify pallet
// logic and to prevent DoS attacks if Grandpa finality were to temporarily stall for a long time
// logic and to prevent DoS attacks if GRANDPA finality were to temporarily stall for a long time
// (we'd have to perform a lot of expensive ancestry checks to catch back up).
#[test]
fn fork_does_not_allow_multiple_scheduled_changes_on_the_same_fork() {
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Module for checking Grandpa Finality Proofs.
//! Module for checking GRANDPA Finality Proofs.
//!
//! Adapted copy of substrate/client/finality-grandpa/src/justification.rs. If origin
//! will ever be moved to the sp_finality_grandpa, we should reuse that implementation.
@@ -123,7 +123,7 @@ where
Ok(())
}
/// A Grandpa Justification is a proof that a given header was finalized
/// A GRANDPA Justification is a proof that a given header was finalized
/// at a certain height and with a certain set of authorities.
///
/// This particular proof is used to prove that headers on a bridged chain
+8 -8
View File
@@ -21,7 +21,7 @@
//! It has a simple interface for achieving this. First it can import headers to the runtime
//! storage. During this it will check the validity of the headers and ensure they don't conflict
//! with any existing headers (e.g they're on a different finalized chain). Secondly it can finalize
//! an already imported header (and its ancestors) given a valid Grandpa justification.
//! an already imported header (and its ancestors) given a valid GRANDPA justification.
//!
//! With these two functions the pallet is able to form a "source of truth" for what headers have
//! been finalized on a given Substrate chain. This can be a useful source of info for other
@@ -94,17 +94,17 @@ decl_storage! {
/// Hash of the best finalized header.
BestFinalized: BridgedBlockHash<T>;
/// The set of header IDs (number, hash) which enact an authority set change and therefore
/// require a Grandpa justification.
/// require a GRANDPA justification.
RequiresJustification: map hasher(identity) BridgedBlockHash<T> => BridgedBlockNumber<T>;
/// Headers which have been imported into the pallet.
ImportedHeaders: map hasher(identity) BridgedBlockHash<T> => Option<ImportedHeader<BridgedHeader<T>>>;
/// The current Grandpa Authority set.
/// The current GRANDPA Authority set.
CurrentAuthoritySet: AuthoritySet;
/// The next scheduled authority set change for a given fork.
///
/// The fork is indicated by the header which _signals_ the change (key in the mapping).
/// Note that this is different than a header which _enacts_ a change.
// Grandpa doesn't require there to always be a pending change. In fact, most of the time
// GRANDPA doesn't require there to always be a pending change. In fact, most of the time
// there will be no pending change available.
NextScheduledChange: map hasher(identity) BridgedBlockHash<T> => Option<ScheduledChange<BridgedBlockNumber<T>>>;
/// Optional pallet owner.
@@ -448,10 +448,10 @@ pub trait BridgeStorage {
/// Returns None if it is not known to the pallet.
fn header_by_hash(&self, hash: <Self::Header as HeaderT>::Hash) -> Option<ImportedHeader<Self::Header>>;
/// Get the current Grandpa authority set.
/// Get the current GRANDPA authority set.
fn current_authority_set(&self) -> AuthoritySet;
/// Update the current Grandpa authority set.
/// Update the current GRANDPA authority set.
///
/// Should only be updated when a scheduled change has been triggered.
fn update_current_authority_set(&self, new_set: AuthoritySet);
@@ -462,13 +462,13 @@ pub trait BridgeStorage {
#[allow(clippy::result_unit_err)]
fn enact_authority_set(&mut self, signal_hash: <Self::Header as HeaderT>::Hash) -> Result<(), ()>;
/// Get the next scheduled Grandpa authority set change.
/// Get the next scheduled GRANDPA authority set change.
fn scheduled_set_change(
&self,
signal_hash: <Self::Header as HeaderT>::Hash,
) -> Option<ScheduledChange<<Self::Header as HeaderT>::Number>>;
/// Schedule a Grandpa authority set change in the future.
/// Schedule a GRANDPA authority set change in the future.
///
/// Takes the hash of the header which scheduled this particular change.
fn schedule_next_set_change(
+5 -5
View File
@@ -42,24 +42,24 @@ pub struct InitializationData<H: HeaderT> {
pub is_halted: bool,
}
/// A Grandpa Authority List and ID.
/// A GRANDPA Authority List and ID.
#[derive(Default, Encode, Decode, RuntimeDebug, PartialEq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct AuthoritySet {
/// List of Grandpa authorities for the current round.
/// List of GRANDPA authorities for the current round.
pub authorities: AuthorityList,
/// Monotonic identifier of the current Grandpa authority set.
/// Monotonic identifier of the current GRANDPA authority set.
pub set_id: SetId,
}
impl AuthoritySet {
/// Create a new Grandpa Authority Set.
/// Create a new GRANDPA Authority Set.
pub fn new(authorities: AuthorityList, set_id: SetId) -> Self {
Self { authorities, set_id }
}
}
/// Keeps track of when the next Grandpa authority set change will occur.
/// Keeps track of when the next GRANDPA authority set change will occur.
#[derive(Default, Encode, Decode, RuntimeDebug, PartialEq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ScheduledChange<N> {
+6 -6
View File
@@ -19,7 +19,7 @@
//!
//! When importing headers it performs checks to ensure that no invariants are broken (like
//! importing the same header twice). When it imports finality proofs it will ensure that the proof
//! has been signed off by the correct Grandpa authorities, and also enact any authority set changes
//! has been signed off by the correct GRANDPA authorities, and also enact any authority set changes
//! if required.
use crate::justification::verify_justification;
@@ -34,8 +34,8 @@ use sp_std::{prelude::Vec, vec};
/// The finality proof used by the pallet.
///
/// For a Substrate based chain using Grandpa this will
/// be an encoded Grandpa Justification.
/// For a Substrate based chain using GRANDPA this will
/// be an encoded GRANDPA Justification.
#[derive(RuntimeDebug)]
pub struct FinalityProof(Vec<u8>);
@@ -139,7 +139,7 @@ where
// we need to make a note of it.
//
// Note: This assumes that we can only have one authority set change pending per fork at a
// time. While this is not strictly true of Grandpa (it can have multiple pending changes,
// time. While this is not strictly true of GRANDPA (it can have multiple pending changes,
// even across forks), this assumption simplifies our tracking of authority set changes.
let mut signal_hash = parent_header.signal_hash;
let scheduled_change = find_scheduled_change(&header);
@@ -213,7 +213,7 @@ where
Ok(())
}
/// Verify that a previously imported header can be finalized with the given Grandpa finality
/// Verify that a previously imported header can be finalized with the given GRANDPA finality
/// proof. If the header enacts an authority set change the change will be applied once the
/// header has been finalized.
pub fn import_finality_proof(&mut self, hash: H::Hash, proof: FinalityProof) -> Result<(), FinalizationError> {
@@ -680,7 +680,7 @@ mod tests {
let mut storage = PalletStorage::<TestRuntime>::new();
let _imported_headers = write_default_headers(&mut storage, vec![1]);
// Nothing special about this header, yet Grandpa may have created a justification
// Nothing special about this header, yet GRANDPA may have created a justification
// for it since it does that periodically
let header = test_header(2);
+1 -1
View File
@@ -29,7 +29,7 @@ pub trait Chain: Send + Sync + 'static {
// See here for more info:
// https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Number
//
// Note that the `AsPrimitive<usize>` trait is required by the Grandpa justification
// Note that the `AsPrimitive<usize>` trait is required by the GRANDPA justification
// verifier, and is not usually part of a Substrate Header's Number type.
type BlockNumber: Parameter
+ Member