224 lines
8.3 KiB
Rust
224 lines
8.3 KiB
Rust
// Copyright 2019-2023 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/>.
|
|
|
|
//! Types and functions intended to ease adding of new Bizinikiwi -> Bizinikiwi
|
|
//! equivocation detection pipelines.
|
|
|
|
mod source;
|
|
mod target;
|
|
|
|
use crate::{
|
|
equivocation::{source::BizinikiwiEquivocationSource, target::BizinikiwiEquivocationTarget},
|
|
finality_base::{engine::Engine, BizinikiwiFinalityPipeline, BizinikiwiFinalityProof},
|
|
TransactionParams,
|
|
};
|
|
|
|
use async_trait::async_trait;
|
|
use pez_equivocation_detector::EquivocationDetectionPipeline;
|
|
use pez_finality_relay::FinalityPipeline;
|
|
use pezbp_runtime::{AccountIdOf, BlockNumberOf, HashOf};
|
|
use pezpallet_grandpa::{Call as GrandpaCall, Config as GrandpaConfig};
|
|
use pezsp_core::Pair;
|
|
use pezsp_runtime::traits::{Block, Header};
|
|
use relay_bizinikiwi_client::{AccountKeyPairOf, CallOf, Chain, ChainWithTransactions, Client};
|
|
use relay_utils::metrics::MetricsParams;
|
|
use std::marker::PhantomData;
|
|
|
|
/// Convenience trait that adds bounds to `BizinikiwiEquivocationDetectionPipeline`.
|
|
pub trait BaseBizinikiwiEquivocationDetectionPipeline:
|
|
BizinikiwiFinalityPipeline<SourceChain = Self::BoundedSourceChain>
|
|
{
|
|
/// Bounded `BizinikiwiFinalityPipeline::SourceChain`.
|
|
type BoundedSourceChain: ChainWithTransactions<AccountId = Self::BoundedSourceChainAccountId>;
|
|
|
|
/// Bounded `AccountIdOf<BizinikiwiFinalityPipeline::SourceChain>`.
|
|
type BoundedSourceChainAccountId: From<<AccountKeyPairOf<Self::BoundedSourceChain> as Pair>::Public>
|
|
+ Send;
|
|
}
|
|
|
|
impl<T> BaseBizinikiwiEquivocationDetectionPipeline for T
|
|
where
|
|
T: BizinikiwiFinalityPipeline,
|
|
T::SourceChain: ChainWithTransactions,
|
|
AccountIdOf<T::SourceChain>: From<<AccountKeyPairOf<Self::SourceChain> as Pair>::Public>,
|
|
{
|
|
type BoundedSourceChain = T::SourceChain;
|
|
type BoundedSourceChainAccountId = AccountIdOf<T::SourceChain>;
|
|
}
|
|
|
|
/// Bizinikiwi -> Bizinikiwi equivocation detection pipeline.
|
|
#[async_trait]
|
|
pub trait BizinikiwiEquivocationDetectionPipeline:
|
|
BaseBizinikiwiEquivocationDetectionPipeline
|
|
{
|
|
/// How the `report_equivocation` call is built ?
|
|
type ReportEquivocationCallBuilder: ReportEquivocationCallBuilder<Self>;
|
|
|
|
/// Add relay guards if required.
|
|
async fn start_relay_guards(
|
|
source_client: &impl Client<Self::SourceChain>,
|
|
enable_version_guard: bool,
|
|
) -> relay_bizinikiwi_client::Result<()> {
|
|
if enable_version_guard {
|
|
relay_bizinikiwi_client::guard::abort_on_spec_version_change(
|
|
source_client.clone(),
|
|
source_client.simple_runtime_version().await?.spec_version,
|
|
);
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
type FinalityProoffOf<P> = <<P as BizinikiwiFinalityPipeline>::FinalityEngine as Engine<
|
|
<P as BizinikiwiFinalityPipeline>::SourceChain,
|
|
>>::FinalityProof;
|
|
type FinalityVerificationContextfOf<P> =
|
|
<<P as BizinikiwiFinalityPipeline>::FinalityEngine as Engine<
|
|
<P as BizinikiwiFinalityPipeline>::SourceChain,
|
|
>>::FinalityVerificationContext;
|
|
/// The type of the equivocation proof used by the `BizinikiwiEquivocationDetectionPipeline`
|
|
pub type EquivocationProofOf<P> = <<P as BizinikiwiFinalityPipeline>::FinalityEngine as Engine<
|
|
<P as BizinikiwiFinalityPipeline>::SourceChain,
|
|
>>::EquivocationProof;
|
|
type EquivocationsFinderOf<P> = <<P as BizinikiwiFinalityPipeline>::FinalityEngine as Engine<
|
|
<P as BizinikiwiFinalityPipeline>::SourceChain,
|
|
>>::EquivocationsFinder;
|
|
/// The type of the key owner proof used by the `BizinikiwiEquivocationDetectionPipeline`
|
|
pub type KeyOwnerProofOf<P> = <<P as BizinikiwiFinalityPipeline>::FinalityEngine as Engine<
|
|
<P as BizinikiwiFinalityPipeline>::SourceChain,
|
|
>>::KeyOwnerProof;
|
|
|
|
/// Adapter that allows a `BizinikiwiEquivocationDetectionPipeline` to act as an
|
|
/// `EquivocationDetectionPipeline`.
|
|
#[derive(Clone, Debug)]
|
|
pub struct EquivocationDetectionPipelineAdapter<P: BizinikiwiEquivocationDetectionPipeline> {
|
|
_phantom: PhantomData<P>,
|
|
}
|
|
|
|
impl<P: BizinikiwiEquivocationDetectionPipeline> FinalityPipeline
|
|
for EquivocationDetectionPipelineAdapter<P>
|
|
{
|
|
const SOURCE_NAME: &'static str = P::SourceChain::NAME;
|
|
const TARGET_NAME: &'static str = P::TargetChain::NAME;
|
|
|
|
type Hash = HashOf<P::SourceChain>;
|
|
type Number = BlockNumberOf<P::SourceChain>;
|
|
type FinalityProof = BizinikiwiFinalityProof<P>;
|
|
}
|
|
|
|
impl<P: BizinikiwiEquivocationDetectionPipeline> EquivocationDetectionPipeline
|
|
for EquivocationDetectionPipelineAdapter<P>
|
|
{
|
|
type TargetNumber = BlockNumberOf<P::TargetChain>;
|
|
type FinalityVerificationContext = FinalityVerificationContextfOf<P>;
|
|
type EquivocationProof = EquivocationProofOf<P>;
|
|
type EquivocationsFinder = EquivocationsFinderOf<P>;
|
|
}
|
|
|
|
/// Different ways of building `report_equivocation` calls.
|
|
pub trait ReportEquivocationCallBuilder<P: BizinikiwiEquivocationDetectionPipeline> {
|
|
/// Build a `report_equivocation` call to be executed on the source chain.
|
|
fn build_report_equivocation_call(
|
|
equivocation_proof: EquivocationProofOf<P>,
|
|
key_owner_proof: KeyOwnerProofOf<P>,
|
|
) -> CallOf<P::SourceChain>;
|
|
}
|
|
|
|
/// Building the `report_equivocation` call when having direct access to the target chain runtime.
|
|
pub struct DirectReportGrandpaEquivocationCallBuilder<P, R> {
|
|
_phantom: PhantomData<(P, R)>,
|
|
}
|
|
|
|
impl<P, R> ReportEquivocationCallBuilder<P> for DirectReportGrandpaEquivocationCallBuilder<P, R>
|
|
where
|
|
P: BizinikiwiEquivocationDetectionPipeline,
|
|
P::FinalityEngine: Engine<
|
|
P::SourceChain,
|
|
EquivocationProof = pezsp_consensus_grandpa::EquivocationProof<
|
|
HashOf<P::SourceChain>,
|
|
BlockNumberOf<P::SourceChain>,
|
|
>,
|
|
>,
|
|
R: pezframe_system::Config<Hash = HashOf<P::SourceChain>>
|
|
+ GrandpaConfig<KeyOwnerProof = KeyOwnerProofOf<P>>,
|
|
<R::Block as Block>::Header: Header<Number = BlockNumberOf<P::SourceChain>>,
|
|
CallOf<P::SourceChain>: From<GrandpaCall<R>>,
|
|
{
|
|
fn build_report_equivocation_call(
|
|
equivocation_proof: EquivocationProofOf<P>,
|
|
key_owner_proof: KeyOwnerProofOf<P>,
|
|
) -> CallOf<P::SourceChain> {
|
|
GrandpaCall::<R>::report_equivocation {
|
|
equivocation_proof: Box::new(equivocation_proof),
|
|
key_owner_proof,
|
|
}
|
|
.into()
|
|
}
|
|
}
|
|
|
|
/// Macro that generates `ReportEquivocationCallBuilder` implementation for the case where
|
|
/// we only have access to the mocked version of the source chain runtime.
|
|
#[rustfmt::skip]
|
|
#[macro_export]
|
|
macro_rules! generate_report_equivocation_call_builder {
|
|
($pipeline:ident, $mocked_builder:ident, $grandpa:path, $report_equivocation:path) => {
|
|
pub struct $mocked_builder;
|
|
|
|
impl $crate::equivocation::ReportEquivocationCallBuilder<$pipeline>
|
|
for $mocked_builder
|
|
{
|
|
fn build_report_equivocation_call(
|
|
equivocation_proof: $crate::equivocation::EquivocationProofOf<$pipeline>,
|
|
key_owner_proof: $crate::equivocation::KeyOwnerProofOf<$pipeline>,
|
|
) -> relay_bizinikiwi_client::CallOf<
|
|
<$pipeline as $crate::finality_base::BizinikiwiFinalityPipeline>::SourceChain
|
|
> {
|
|
pezbp_runtime::paste::item! {
|
|
$grandpa($report_equivocation {
|
|
equivocation_proof: Box::new(equivocation_proof),
|
|
key_owner_proof: key_owner_proof
|
|
})
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/// Run Bizinikiwi-to-Bizinikiwi equivocations detection loop.
|
|
pub async fn run<P: BizinikiwiEquivocationDetectionPipeline>(
|
|
source_client: impl Client<P::SourceChain>,
|
|
target_client: impl Client<P::TargetChain>,
|
|
source_transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
|
|
metrics_params: MetricsParams,
|
|
) -> anyhow::Result<()> {
|
|
tracing::info!(
|
|
target: "bridge",
|
|
source=%P::SourceChain::NAME,
|
|
target=%P::TargetChain::NAME,
|
|
"Starting equivocations detection loop"
|
|
);
|
|
|
|
pez_equivocation_detector::run(
|
|
BizinikiwiEquivocationSource::<P, _>::new(source_client, source_transaction_params),
|
|
BizinikiwiEquivocationTarget::<P, _>::new(target_client),
|
|
P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
|
metrics_params,
|
|
futures::future::pending(),
|
|
)
|
|
.await
|
|
.map_err(|e| anyhow::format_err!("{}", e))
|
|
}
|