referrerpolicy=no-referrer-when-downgrade

bp_relayers/
extension.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//! All runtime calls, supported by `pallet-bridge-relayers` when it acts as a signed
18//! extension.
19
20use bp_header_chain::SubmitFinalityProofInfo;
21use bp_messages::MessagesCallInfo;
22use bp_parachains::SubmitParachainHeadsInfo;
23use bp_runtime::StaticStrProvider;
24use codec::{Decode, Encode};
25use frame_support::{
26	dispatch::CallableCallFor, traits::IsSubType, weights::Weight, RuntimeDebugNoBound,
27};
28use frame_system::Config as SystemConfig;
29use pallet_utility::{Call as UtilityCall, Pallet as UtilityPallet};
30use sp_runtime::{
31	traits::Get,
32	transaction_validity::{TransactionPriority, TransactionValidityError},
33	RuntimeDebug,
34};
35use sp_std::{fmt::Debug, marker::PhantomData, vec, vec::Vec};
36
37/// Type of the call that the signed extension recognizes.
38#[derive(PartialEq, RuntimeDebugNoBound)]
39pub enum ExtensionCallInfo<RemoteGrandpaChainBlockNumber: Debug, LaneId: Clone + Copy + Debug> {
40	/// Relay chain finality + parachain finality + message delivery/confirmation calls.
41	AllFinalityAndMsgs(
42		SubmitFinalityProofInfo<RemoteGrandpaChainBlockNumber>,
43		SubmitParachainHeadsInfo,
44		MessagesCallInfo<LaneId>,
45	),
46	/// Relay chain finality + message delivery/confirmation calls.
47	RelayFinalityAndMsgs(
48		SubmitFinalityProofInfo<RemoteGrandpaChainBlockNumber>,
49		MessagesCallInfo<LaneId>,
50	),
51	/// Parachain finality + message delivery/confirmation calls.
52	///
53	/// This variant is used only when bridging with parachain.
54	ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo<LaneId>),
55	/// Standalone message delivery/confirmation call.
56	Msgs(MessagesCallInfo<LaneId>),
57}
58
59impl<RemoteGrandpaChainBlockNumber: Clone + Copy + Debug, LaneId: Clone + Copy + Debug>
60	ExtensionCallInfo<RemoteGrandpaChainBlockNumber, LaneId>
61{
62	/// Returns true if call is a message delivery call (with optional finality calls).
63	pub fn is_receive_messages_proof_call(&self) -> bool {
64		match self.messages_call_info() {
65			MessagesCallInfo::ReceiveMessagesProof(_) => true,
66			MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => false,
67		}
68	}
69
70	/// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call.
71	pub fn submit_finality_proof_info(
72		&self,
73	) -> Option<SubmitFinalityProofInfo<RemoteGrandpaChainBlockNumber>> {
74		match *self {
75			Self::AllFinalityAndMsgs(info, _, _) => Some(info),
76			Self::RelayFinalityAndMsgs(info, _) => Some(info),
77			_ => None,
78		}
79	}
80
81	/// Returns the pre-dispatch `SubmitParachainHeadsInfo`.
82	pub fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> {
83		match self {
84			Self::AllFinalityAndMsgs(_, info, _) => Some(info),
85			Self::ParachainFinalityAndMsgs(info, _) => Some(info),
86			_ => None,
87		}
88	}
89
90	/// Returns the pre-dispatch `ReceiveMessagesProofInfo`.
91	pub fn messages_call_info(&self) -> &MessagesCallInfo<LaneId> {
92		match self {
93			Self::AllFinalityAndMsgs(_, _, info) => info,
94			Self::RelayFinalityAndMsgs(_, info) => info,
95			Self::ParachainFinalityAndMsgs(_, info) => info,
96			Self::Msgs(info) => info,
97		}
98	}
99}
100
101/// Extra post-dispatch data, associated with the supported runtime call.
102#[derive(Default, RuntimeDebug)]
103pub struct ExtensionCallData {
104	/// Extra weight, consumed by the call. We have some assumptions about normal weight
105	/// that may be consumed by expected calls. If the actual weight is larger than that,
106	/// we do not refund relayer for this extra weight.
107	pub extra_weight: Weight,
108	/// Extra size, consumed by the call. We have some assumptions about normal size
109	/// of the encoded call. If the actual size is larger than that, we do not refund relayer
110	/// for this extra size.
111	pub extra_size: u32,
112}
113
114/// Signed extension configuration.
115///
116/// The single `pallet-bridge-relayers` instance may be shared by multiple messages
117/// pallet instances, bridging with different remote networks. We expect every instance
118/// of the messages pallet to add a separate signed extension to runtime. So it must
119/// have a separate configuration.
120pub trait ExtensionConfig {
121	/// Unique identifier of the signed extension that will use this configuration.
122	type IdProvider: StaticStrProvider;
123	/// Runtime that optionally supports batched calls. We assume that batched call
124	/// succeeds if and only if all of its nested calls succeed.
125	type Runtime: frame_system::Config;
126	/// Relayers pallet instance.
127	type BridgeRelayersPalletInstance: 'static;
128	/// Messages pallet instance.
129	type BridgeMessagesPalletInstance: 'static;
130	/// Additional priority that is added to base message delivery transaction priority
131	/// for every additional bundled message.
132	type PriorityBoostPerMessage: Get<TransactionPriority>;
133	/// Block number for the remote **GRANDPA chain**. Mind that this chain is not
134	/// necessarily the chain that we are bridging with. If we are bridging with
135	/// parachain, it must be its parent relay chain. If we are bridging with the
136	/// GRANDPA chain, it must be it.
137	type RemoteGrandpaChainBlockNumber: Clone + Copy + Debug;
138	/// Lane identifier type.
139	type LaneId: Clone + Copy + Decode + Encode + Debug;
140
141	/// Given runtime call, check if it is supported by the transaction extension. Additionally,
142	/// check if call (or any of batched calls) are obsolete.
143	fn parse_and_check_for_obsolete_call(
144		call: &<Self::Runtime as SystemConfig>::RuntimeCall,
145	) -> Result<
146		Option<ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>>,
147		TransactionValidityError,
148	>;
149
150	/// Check if runtime call is already obsolete.
151	fn check_obsolete_parsed_call(
152		call: &<Self::Runtime as SystemConfig>::RuntimeCall,
153	) -> Result<&<Self::Runtime as SystemConfig>::RuntimeCall, TransactionValidityError>;
154
155	/// Given runtime call info, check that this call has been successful and has updated
156	/// runtime storage accordingly.
157	fn check_call_result(
158		call_info: &ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>,
159		call_data: &mut ExtensionCallData,
160		relayer: &<Self::Runtime as SystemConfig>::AccountId,
161	) -> bool;
162}
163
164/// Something that can unpack batch calls (all-or-nothing flavor) of given size.
165pub trait BatchCallUnpacker<Runtime: frame_system::Config> {
166	/// Unpack batch call with no more than `max_packed_calls` calls.
167	fn unpack(call: &Runtime::RuntimeCall, max_packed_calls: u32) -> Vec<&Runtime::RuntimeCall>;
168}
169
170/// An `BatchCallUnpacker` adapter for runtimes with utility pallet.
171pub struct RuntimeWithUtilityPallet<Runtime>(PhantomData<Runtime>);
172
173impl<Runtime> BatchCallUnpacker<Runtime> for RuntimeWithUtilityPallet<Runtime>
174where
175	Runtime: pallet_utility::Config<RuntimeCall = <Runtime as SystemConfig>::RuntimeCall>,
176	<Runtime as SystemConfig>::RuntimeCall:
177		IsSubType<CallableCallFor<UtilityPallet<Runtime>, Runtime>>,
178{
179	fn unpack(
180		call: &<Runtime as frame_system::Config>::RuntimeCall,
181		max_packed_calls: u32,
182	) -> Vec<&<Runtime as frame_system::Config>::RuntimeCall> {
183		match call.is_sub_type() {
184			Some(UtilityCall::<Runtime>::batch_all { ref calls })
185				if calls.len() <= max_packed_calls as usize =>
186				calls.iter().collect(),
187			Some(_) => vec![],
188			None => vec![call],
189		}
190	}
191}
192
193impl<Runtime: frame_system::Config> BatchCallUnpacker<Runtime> for () {
194	fn unpack(call: &Runtime::RuntimeCall, _max_packed_calls: u32) -> Vec<&Runtime::RuntimeCall> {
195		vec![call]
196	}
197}