Skip to main content

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