Relay Millau && Rialto headers using (future) finality verifier API (#761)

* finality proofs relay

* SyncHeader::is_mandatory

* empty ancestry proof

* logs

* fixed submit condition

* fixed wrong split index

* tick comment

* recent_finality_proofs

* basic finality loop tests

* removed obsolete files

* rename files in substrate relay

* fmt

* clippy

* fixed TODOs

* clippy

* stop syncing if target node is out of sync

* more clippy

* more clippy

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* docs

* moved doc

* typo

* Update relays/finality-relay/src/finality_loop_tests.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update relays/finality-relay/src/finality_loop_tests.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* header_and_finality_proof_by_number -> header_and_finality_proof

* VecDeque isn't required (because of make_contiguous)

* fixed wrong expect

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update relays/substrate/src/rialto_headers_to_millau.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Update relays/substrate/src/rialto_headers_to_millau.rs

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* RialtoSyncHeader

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* removed wrong comment

* Update relays/finality-relay/src/finality_loop.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* fix used runtime methods names

* fix for new jsonrpsee

* fix comment

* initialize finality verifier pallet

* fmt

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
Svyatoslav Nikolsky
2021-03-08 13:18:53 +03:00
committed by Bastian Köcher
parent e13ff320ea
commit f87053c1cb
31 changed files with 1490 additions and 944 deletions
@@ -18,8 +18,10 @@ rand = "0.7"
# Bridge dependencies
bp-header-chain = { path = "../../primitives/header-chain" }
bp-message-lane = { path = "../../primitives/message-lane" }
bp-runtime = { path = "../../primitives/runtime" }
finality-relay = { path = "../finality-relay" }
headers-relay = { path = "../headers-relay" }
relay-utils = { path = "../utils" }
+10 -8
View File
@@ -23,7 +23,9 @@ use num_traits::{CheckedSub, Zero};
use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{
generic::SignedBlock,
traits::{AtLeast32Bit, Dispatchable, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, Member},
traits::{
AtLeast32Bit, Block as BlockT, Dispatchable, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, Member,
},
Justification,
};
use std::{fmt::Debug, time::Duration};
@@ -51,7 +53,7 @@ pub trait Chain: ChainBase {
+ AtLeast32Bit
+ Copy;
/// Block type.
type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification;
type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>;
/// The aggregated `Call` type.
type Call: Dispatchable + Debug;
}
@@ -67,7 +69,9 @@ pub trait ChainWithBalances: Chain {
}
/// Block with justification.
pub trait BlockWithJustification {
pub trait BlockWithJustification<Header> {
/// Return block header.
fn header(&self) -> Header;
/// Return block justification, if known.
fn justification(&self) -> Option<&Justification>;
}
@@ -90,13 +94,11 @@ pub trait TransactionSignScheme {
) -> Self::SignedTransaction;
}
impl BlockWithJustification for () {
fn justification(&self) -> Option<&Justification> {
None
impl<Block: BlockT> BlockWithJustification<Block::Header> for SignedBlock<Block> {
fn header(&self) -> Block::Header {
self.block.header().clone()
}
}
impl<Block> BlockWithJustification for SignedBlock<Block> {
fn justification(&self) -> Option<&Justification> {
self.justification.as_ref()
}
@@ -0,0 +1,147 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 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/>.
//! Default generic implementation of finality source for basic Substrate client.
use crate::chain::{BlockWithJustification, Chain};
use crate::client::Client;
use crate::error::Error;
use crate::sync_header::SyncHeader;
use async_trait::async_trait;
use finality_relay::{FinalityProof, FinalitySyncPipeline, SourceClient, SourceHeader};
use futures::stream::{unfold, Stream, StreamExt};
use relay_utils::relay_loop::Client as RelayClient;
use sp_runtime::traits::Header as HeaderT;
use std::{marker::PhantomData, pin::Pin};
/// Wrapped raw Justification.
#[derive(Debug, Clone)]
pub struct Justification<Header> {
raw_justification: sp_runtime::Justification,
_phantom: PhantomData<Header>,
}
impl<Header> Justification<Header> {
/// Extract raw justification.
pub fn into_inner(self) -> sp_runtime::Justification {
self.raw_justification
}
}
impl<Header> FinalityProof<Header::Number> for Justification<Header>
where
Header: HeaderT,
{
fn target_header_number(&self) -> Option<Header::Number> {
bp_header_chain::justification::decode_justification_target::<Header>(&self.raw_justification)
.ok()
.map(|(_, number)| number)
}
}
/// Substrate node as finality source.
pub struct FinalitySource<C: Chain, P> {
client: Client<C>,
_phantom: PhantomData<P>,
}
impl<C: Chain, P> FinalitySource<C, P> {
/// Create new headers source using given client.
pub fn new(client: Client<C>) -> Self {
FinalitySource {
client,
_phantom: Default::default(),
}
}
}
impl<C: Chain, P> Clone for FinalitySource<C, P> {
fn clone(&self) -> Self {
FinalitySource {
client: self.client.clone(),
_phantom: Default::default(),
}
}
}
#[async_trait]
impl<C: Chain, P: FinalitySyncPipeline> RelayClient for FinalitySource<C, P> {
type Error = Error;
async fn reconnect(&mut self) -> Result<(), Error> {
self.client.reconnect().await
}
}
#[async_trait]
impl<C, P> SourceClient<P> for FinalitySource<C, P>
where
C: Chain,
C::BlockNumber: relay_utils::BlockNumberBase,
P: FinalitySyncPipeline<
Hash = C::Hash,
Number = C::BlockNumber,
Header = SyncHeader<C::Header>,
FinalityProof = Justification<C::Header>,
>,
P::Header: SourceHeader<C::BlockNumber>,
{
type FinalityProofsStream = Pin<Box<dyn Stream<Item = Justification<C::Header>>>>;
async fn best_finalized_block_number(&self) -> Result<P::Number, Error> {
// we **CAN** continue to relay finality proofs if source node is out of sync, because
// target node may be missing proofs that are already available at the source
let finalized_header_hash = self.client.best_finalized_header_hash().await?;
let finalized_header = self.client.header_by_hash(finalized_header_hash).await?;
Ok(*finalized_header.number())
}
async fn header_and_finality_proof(
&self,
number: P::Number,
) -> Result<(P::Header, Option<P::FinalityProof>), Error> {
let header_hash = self.client.block_hash_by_number(number).await?;
let signed_block = self.client.get_block(Some(header_hash)).await?;
Ok((
signed_block.header().into(),
signed_block
.justification()
.cloned()
.map(|raw_justification| Justification {
raw_justification,
_phantom: Default::default(),
}),
))
}
async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
Ok(unfold(
self.client.clone().subscribe_justifications().await?,
move |mut subscription| async move {
let next_justification = subscription.next().await?;
Some((
Justification {
raw_justification: next_justification.0,
_phantom: Default::default(),
},
subscription,
))
},
)
.boxed())
}
}
+2 -1
View File
@@ -187,7 +187,8 @@ mod tests {
type AccountId = u32;
type Index = u32;
type SignedBlock = ();
type SignedBlock =
sp_runtime::generic::SignedBlock<sp_runtime::generic::Block<Self::Header, sp_runtime::OpaqueExtrinsic>>;
type Call = ();
}
@@ -24,6 +24,7 @@ mod error;
mod rpc;
mod sync_header;
pub mod finality_source;
pub mod guard;
pub mod headers_source;
@@ -14,6 +14,8 @@
// 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/>.
use bp_header_chain::find_grandpa_authorities_scheduled_change;
use finality_relay::SourceHeader as FinalitySourceHeader;
use headers_relay::sync_types::SourceHeader;
use num_traits::{CheckedSub, One};
use relay_utils::HeaderId;
@@ -47,7 +49,7 @@ impl<Header> From<Header> for SyncHeader<Header> {
impl<Header: HeaderT> SourceHeader<Header::Hash, Header::Number> for SyncHeader<Header> {
fn id(&self) -> HeaderId<Header::Hash, Header::Number> {
relay_utils::HeaderId(*self.number(), self.hash())
relay_utils::HeaderId(*self.0.number(), self.hash())
}
fn parent_id(&self) -> HeaderId<Header::Hash, Header::Number> {
@@ -59,3 +61,13 @@ impl<Header: HeaderT> SourceHeader<Header::Hash, Header::Number> for SyncHeader<
)
}
}
impl<Header: HeaderT> FinalitySourceHeader<Header::Number> for SyncHeader<Header> {
fn number(&self) -> Header::Number {
*self.0.number()
}
fn is_mandatory(&self) -> bool {
find_grandpa_authorities_scheduled_change(&self.0).is_some()
}
}