referrerpolicy=no-referrer-when-downgrade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// 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/>.

//! Default generic implementation of equivocation source for basic Substrate client.

use crate::{
	equivocation::{
		EquivocationDetectionPipelineAdapter, EquivocationProofOf, ReportEquivocationCallBuilder,
		SubstrateEquivocationDetectionPipeline,
	},
	finality_base::{engine::Engine, finality_proofs, SubstrateFinalityProofsStream},
	TransactionParams,
};

use async_trait::async_trait;
use bp_runtime::{HashOf, TransactionEra};
use equivocation_detector::SourceClient;
use finality_relay::SourceClientBase;
use relay_substrate_client::{
	AccountKeyPairOf, Client, Error, TransactionTracker, UnsignedTransaction,
};
use relay_utils::relay_loop::Client as RelayClient;

/// Substrate node as equivocation source.
pub struct SubstrateEquivocationSource<P: SubstrateEquivocationDetectionPipeline, SourceClnt> {
	client: SourceClnt,
	transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
}

impl<P: SubstrateEquivocationDetectionPipeline, SourceClnt: Client<P::SourceChain>>
	SubstrateEquivocationSource<P, SourceClnt>
{
	/// Create new instance of `SubstrateEquivocationSource`.
	pub fn new(
		client: SourceClnt,
		transaction_params: TransactionParams<AccountKeyPairOf<P::SourceChain>>,
	) -> Self {
		Self { client, transaction_params }
	}
}

impl<P: SubstrateEquivocationDetectionPipeline, SourceClnt: Client<P::SourceChain>> Clone
	for SubstrateEquivocationSource<P, SourceClnt>
{
	fn clone(&self) -> Self {
		Self { client: self.client.clone(), transaction_params: self.transaction_params.clone() }
	}
}

#[async_trait]
impl<P: SubstrateEquivocationDetectionPipeline, SourceClnt: Client<P::SourceChain>> RelayClient
	for SubstrateEquivocationSource<P, SourceClnt>
{
	type Error = Error;

	async fn reconnect(&mut self) -> Result<(), Error> {
		self.client.reconnect().await
	}
}

#[async_trait]
impl<P: SubstrateEquivocationDetectionPipeline, SourceClnt: Client<P::SourceChain>>
	SourceClientBase<EquivocationDetectionPipelineAdapter<P>>
	for SubstrateEquivocationSource<P, SourceClnt>
{
	type FinalityProofsStream = SubstrateFinalityProofsStream<P>;

	async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
		finality_proofs::<P>(&self.client).await
	}
}

#[async_trait]
impl<P: SubstrateEquivocationDetectionPipeline, SourceClnt: Client<P::SourceChain>>
	SourceClient<EquivocationDetectionPipelineAdapter<P>>
	for SubstrateEquivocationSource<P, SourceClnt>
{
	type TransactionTracker = TransactionTracker<P::SourceChain, SourceClnt>;

	async fn report_equivocation(
		&self,
		at: HashOf<P::SourceChain>,
		equivocation: EquivocationProofOf<P>,
	) -> Result<Self::TransactionTracker, Self::Error> {
		let key_owner_proof =
			P::FinalityEngine::generate_source_key_ownership_proof(&self.client, at, &equivocation)
				.await?;

		let mortality = self.transaction_params.mortality;
		let call = P::ReportEquivocationCallBuilder::build_report_equivocation_call(
			equivocation,
			key_owner_proof,
		);
		self.client
			.submit_and_watch_signed_extrinsic(
				&self.transaction_params.signer,
				move |best_block_id, transaction_nonce| {
					Ok(UnsignedTransaction::new(call.into(), transaction_nonce)
						.era(TransactionEra::new(best_block_id, mortality)))
				},
			)
			.await
	}
}