referrerpolicy=no-referrer-when-downgrade

pallet_bridge_relayers/extension/
parachain_adapter.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the
18//! bridge with remote parachain.
19
20use crate::{
21	extension::{
22		grandpa_adapter::verify_submit_finality_proof_succeeded, verify_messages_call_succeeded,
23	},
24	Config as BridgeRelayersConfig, LOG_TARGET,
25};
26
27use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig};
28use bp_runtime::{Parachain, StaticStrProvider};
29use core::marker::PhantomData;
30use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
31use frame_system::Config as SystemConfig;
32use pallet_bridge_grandpa::{
33	CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig,
34};
35use pallet_bridge_messages::{
36	CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf,
37};
38use pallet_bridge_parachains::{
39	CallSubType as BridgeParachainsCallSubtype, Config as BridgeParachainsConfig,
40	SubmitParachainHeadsHelper,
41};
42use sp_runtime::{
43	traits::{Dispatchable, Get},
44	transaction_validity::{TransactionPriority, TransactionValidityError},
45};
46
47/// Adapter to be used in signed extension configuration, when bridging with remote parachains.
48pub struct WithParachainExtensionConfig<
49	// signed extension identifier
50	IdProvider,
51	// runtime that implements `BridgeMessagesConfig<BridgeMessagesPalletInstance>`, which
52	// uses `BridgeParachainsConfig<BridgeParachainsPalletInstance>` to receive messages and
53	// confirmations from the remote chain.
54	Runtime,
55	// batch call unpacker
56	BatchCallUnpacker,
57	// instance of the `pallet-bridge-parachains`, tracked by this extension
58	BridgeParachainsPalletInstance,
59	// instance of BridgedChain `pallet-bridge-messages`, tracked by this extension
60	BridgeMessagesPalletInstance,
61	// instance of `pallet-bridge-relayers`, tracked by this extension
62	BridgeRelayersPalletInstance,
63	// message delivery transaction priority boost for every additional message
64	PriorityBoostPerMessage,
65>(
66	PhantomData<(
67		IdProvider,
68		Runtime,
69		BatchCallUnpacker,
70		BridgeParachainsPalletInstance,
71		BridgeMessagesPalletInstance,
72		BridgeRelayersPalletInstance,
73		PriorityBoostPerMessage,
74	)>,
75);
76
77impl<ID, R, BCU, PI, MI, RI, P> ExtensionConfig
78	for WithParachainExtensionConfig<ID, R, BCU, PI, MI, RI, P>
79where
80	ID: StaticStrProvider,
81	R: BridgeRelayersConfig<RI>
82		+ BridgeMessagesConfig<MI>
83		+ BridgeParachainsConfig<PI>
84		+ BridgeGrandpaConfig<R::BridgesGrandpaPalletInstance>,
85	BCU: BatchCallUnpacker<R>,
86	PI: 'static,
87	MI: 'static,
88	RI: 'static,
89	P: Get<TransactionPriority>,
90	R::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>
91		+ BridgeGrandpaCallSubtype<R, R::BridgesGrandpaPalletInstance>
92		+ BridgeParachainsCallSubtype<R, PI>
93		+ BridgeMessagesCallSubType<R, MI>,
94	<R as BridgeMessagesConfig<MI>>::BridgedChain: Parachain,
95{
96	type IdProvider = ID;
97	type Runtime = R;
98	type BridgeMessagesPalletInstance = MI;
99	type BridgeRelayersPalletInstance = RI;
100	type PriorityBoostPerMessage = P;
101	type RemoteGrandpaChainBlockNumber =
102		pallet_bridge_grandpa::BridgedBlockNumber<R, R::BridgesGrandpaPalletInstance>;
103	type LaneId = LaneIdOf<R, Self::BridgeMessagesPalletInstance>;
104
105	fn parse_and_check_for_obsolete_call(
106		call: &R::RuntimeCall,
107	) -> Result<
108		Option<ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>>,
109		TransactionValidityError,
110	> {
111		let calls = BCU::unpack(call, 3);
112		let total_calls = calls.len();
113		let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev();
114
115		let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info());
116		let para_finality_call = calls.next().transpose()?.and_then(|c| {
117			let r = c.submit_parachain_heads_info_for(
118				<R as BridgeMessagesConfig<Self::BridgeMessagesPalletInstance>>::BridgedChain::PARACHAIN_ID,
119			);
120			r
121		});
122		let relay_finality_call =
123			calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info());
124		Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) {
125			(3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) =>
126				Some(ExtensionCallInfo::AllFinalityAndMsgs(
127					relay_finality_call,
128					para_finality_call,
129					msgs_call,
130				)),
131			(2, None, Some(para_finality_call), Some(msgs_call)) =>
132				Some(ExtensionCallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)),
133			(1, None, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)),
134			_ => None,
135		})
136	}
137
138	fn check_obsolete_parsed_call(
139		call: &R::RuntimeCall,
140	) -> Result<&R::RuntimeCall, TransactionValidityError> {
141		call.check_obsolete_submit_finality_proof()?;
142		call.check_obsolete_submit_parachain_heads()?;
143		call.check_obsolete_call()?;
144		Ok(call)
145	}
146
147	fn check_call_result(
148		call_info: &ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>,
149		call_data: &mut ExtensionCallData,
150		relayer: &R::AccountId,
151	) -> bool {
152		verify_submit_finality_proof_succeeded::<Self, R::BridgesGrandpaPalletInstance>(
153			call_info, call_data, relayer,
154		) && verify_submit_parachain_head_succeeded::<Self, PI>(call_info, call_data, relayer) &&
155			verify_messages_call_succeeded::<Self>(call_info, call_data, relayer)
156	}
157}
158
159/// If the batch call contains the parachain state update call, verify that it
160/// has been successful.
161///
162/// Only returns false when parachain state update call has failed.
163pub(crate) fn verify_submit_parachain_head_succeeded<C, PI>(
164	call_info: &ExtensionCallInfo<C::RemoteGrandpaChainBlockNumber, C::LaneId>,
165	_call_data: &mut ExtensionCallData,
166	relayer: &<C::Runtime as SystemConfig>::AccountId,
167) -> bool
168where
169	C: ExtensionConfig,
170	PI: 'static,
171	C::Runtime: BridgeParachainsConfig<PI>,
172{
173	let Some(para_proof_info) = call_info.submit_parachain_heads_info() else { return true };
174
175	if !SubmitParachainHeadsHelper::<C::Runtime, PI>::was_successful(para_proof_info) {
176		// we only refund relayer if all calls have updated chain state
177		tracing::trace!(
178			target: LOG_TARGET,
179			id_provider=%C::IdProvider::STR,
180			lane_id=?call_info.messages_call_info().lane_id(),
181			?relayer,
182			"Relayer has submitted invalid parachain finality proof"
183		);
184		return false
185	}
186
187	true
188}