referrerpolicy=no-referrer-when-downgrade

pallet_bridge_messages/
lanes_manager.rs

1// Copyright 2019-2021 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
17use crate::{
18	BridgedChainOf, Config, InboundLane, InboundLaneStorage, InboundLanes, OutboundLane,
19	OutboundLaneStorage, OutboundLanes, OutboundMessages, StoredInboundLaneData,
20	StoredMessagePayload,
21};
22
23use bp_messages::{
24	target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneState, MessageKey,
25	MessageNonce, OutboundLaneData,
26};
27use bp_runtime::AccountIdOf;
28use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
29use frame_support::{ensure, sp_runtime::RuntimeDebug, PalletError};
30use scale_info::TypeInfo;
31use sp_std::marker::PhantomData;
32
33/// Lanes manager errors.
34#[derive(
35	Encode, Decode, DecodeWithMemTracking, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo,
36)]
37pub enum LanesManagerError {
38	/// Inbound lane already exists.
39	InboundLaneAlreadyExists,
40	/// Outbound lane already exists.
41	OutboundLaneAlreadyExists,
42	/// No inbound lane with given id.
43	UnknownInboundLane,
44	/// No outbound lane with given id.
45	UnknownOutboundLane,
46	/// Inbound lane with given id is closed.
47	ClosedInboundLane,
48	/// Outbound lane with given id is closed.
49	ClosedOutboundLane,
50	/// Message dispatcher is inactive at given inbound lane. This is logical equivalent
51	/// of the [`Self::ClosedInboundLane`] variant.
52	LaneDispatcherInactive,
53}
54
55/// Message lanes manager.
56pub struct LanesManager<T, I>(PhantomData<(T, I)>);
57
58impl<T: Config<I>, I: 'static> Default for LanesManager<T, I> {
59	fn default() -> Self {
60		Self::new()
61	}
62}
63
64impl<T: Config<I>, I: 'static> LanesManager<T, I> {
65	/// Create new lanes manager.
66	pub fn new() -> Self {
67		Self(PhantomData)
68	}
69
70	/// Create new inbound lane in `Opened` state.
71	pub fn create_inbound_lane(
72		&self,
73		lane_id: T::LaneId,
74	) -> Result<InboundLane<RuntimeInboundLaneStorage<T, I>>, LanesManagerError> {
75		InboundLanes::<T, I>::try_mutate(lane_id, |lane| match lane {
76			Some(_) => Err(LanesManagerError::InboundLaneAlreadyExists),
77			None => {
78				*lane = Some(StoredInboundLaneData(InboundLaneData {
79					state: LaneState::Opened,
80					..Default::default()
81				}));
82				Ok(())
83			},
84		})?;
85
86		self.active_inbound_lane(lane_id)
87	}
88
89	/// Create new outbound lane in `Opened` state.
90	pub fn create_outbound_lane(
91		&self,
92		lane_id: T::LaneId,
93	) -> Result<OutboundLane<RuntimeOutboundLaneStorage<T, I>>, LanesManagerError> {
94		OutboundLanes::<T, I>::try_mutate(lane_id, |lane| match lane {
95			Some(_) => Err(LanesManagerError::OutboundLaneAlreadyExists),
96			None => {
97				*lane = Some(OutboundLaneData { state: LaneState::Opened, ..Default::default() });
98				Ok(())
99			},
100		})?;
101
102		self.active_outbound_lane(lane_id)
103	}
104
105	/// Get existing inbound lane, checking that it is in usable state.
106	pub fn active_inbound_lane(
107		&self,
108		lane_id: T::LaneId,
109	) -> Result<InboundLane<RuntimeInboundLaneStorage<T, I>>, LanesManagerError> {
110		Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, true)?))
111	}
112
113	/// Get existing outbound lane, checking that it is in usable state.
114	pub fn active_outbound_lane(
115		&self,
116		lane_id: T::LaneId,
117	) -> Result<OutboundLane<RuntimeOutboundLaneStorage<T, I>>, LanesManagerError> {
118		Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, true)?))
119	}
120
121	/// Get existing inbound lane without any additional state checks.
122	pub fn any_state_inbound_lane(
123		&self,
124		lane_id: T::LaneId,
125	) -> Result<InboundLane<RuntimeInboundLaneStorage<T, I>>, LanesManagerError> {
126		Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, false)?))
127	}
128
129	/// Get existing outbound lane without any additional state checks.
130	pub fn any_state_outbound_lane(
131		&self,
132		lane_id: T::LaneId,
133	) -> Result<OutboundLane<RuntimeOutboundLaneStorage<T, I>>, LanesManagerError> {
134		Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, false)?))
135	}
136}
137
138/// Runtime inbound lane storage.
139pub struct RuntimeInboundLaneStorage<T: Config<I>, I: 'static = ()> {
140	pub(crate) lane_id: T::LaneId,
141	pub(crate) cached_data: InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>>,
142}
143
144impl<T: Config<I>, I: 'static> RuntimeInboundLaneStorage<T, I> {
145	/// Creates new runtime inbound lane storage for given **existing** lane.
146	fn from_lane_id(
147		lane_id: T::LaneId,
148		check_active: bool,
149	) -> Result<RuntimeInboundLaneStorage<T, I>, LanesManagerError> {
150		let cached_data =
151			InboundLanes::<T, I>::get(lane_id).ok_or(LanesManagerError::UnknownInboundLane)?;
152
153		if check_active {
154			// check that the lane is not explicitly closed
155			ensure!(cached_data.state.is_active(), LanesManagerError::ClosedInboundLane);
156			// apart from the explicit closure, the lane may be unable to receive any messages.
157			// Right now we do an additional check here, but it may be done later (e.g. by
158			// explicitly closing the lane and reopening it from
159			// `pallet-xcm-bridge-hub::on-initialize`)
160			//
161			// The fact that we only check it here, means that the `MessageDispatch` may switch
162			// to inactive state during some message dispatch in the middle of message delivery
163			// transaction. But we treat result of `MessageDispatch::is_active()` as a hint, so
164			// we know that it won't drop messages - just it experiences problems with processing.
165			// This would allow us to check that in our signed extensions, and invalidate
166			// transaction early, thus avoiding losing honest relayers funds. This problem should
167			// gone with relayers coordination protocol.
168			//
169			// There's a limit on number of messages in the message delivery transaction, so even
170			// if we dispatch (enqueue) some additional messages, we'll know the maximal queue
171			// length;
172			ensure!(
173				T::MessageDispatch::is_active(lane_id),
174				LanesManagerError::LaneDispatcherInactive
175			);
176		}
177
178		Ok(RuntimeInboundLaneStorage { lane_id, cached_data: cached_data.into() })
179	}
180
181	/// Returns number of bytes that may be subtracted from the PoV component of
182	/// `receive_messages_proof` call, because the actual inbound lane state is smaller than the
183	/// maximal configured.
184	///
185	/// Maximal inbound lane state set size is configured by the
186	/// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` constant from the pallet configuration. The PoV
187	/// of the call includes the maximal size of inbound lane state. If the actual size is smaller,
188	/// we may subtract extra bytes from this component.
189	pub fn extra_proof_size_bytes(&self) -> u64 {
190		let max_encoded_len = StoredInboundLaneData::<T, I>::max_encoded_len();
191		let relayers_count = self.data().relayers.len();
192		let actual_encoded_len =
193			InboundLaneData::<AccountIdOf<BridgedChainOf<T, I>>>::encoded_size_hint(relayers_count)
194				.unwrap_or(usize::MAX);
195		max_encoded_len.saturating_sub(actual_encoded_len) as _
196	}
197}
198
199impl<T: Config<I>, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage<T, I> {
200	type Relayer = AccountIdOf<BridgedChainOf<T, I>>;
201	type LaneId = T::LaneId;
202
203	fn id(&self) -> Self::LaneId {
204		self.lane_id
205	}
206
207	fn max_unrewarded_relayer_entries(&self) -> MessageNonce {
208		BridgedChainOf::<T, I>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX
209	}
210
211	fn max_unconfirmed_messages(&self) -> MessageNonce {
212		BridgedChainOf::<T, I>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX
213	}
214
215	fn data(&self) -> InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>> {
216		self.cached_data.clone()
217	}
218
219	fn set_data(&mut self, data: InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>>) {
220		self.cached_data = data.clone();
221		InboundLanes::<T, I>::insert(self.lane_id, StoredInboundLaneData::<T, I>(data))
222	}
223
224	fn purge(self) {
225		InboundLanes::<T, I>::remove(self.lane_id)
226	}
227}
228
229/// Runtime outbound lane storage.
230#[derive(Debug, PartialEq, Eq)]
231pub struct RuntimeOutboundLaneStorage<T: Config<I>, I: 'static> {
232	pub(crate) lane_id: T::LaneId,
233	pub(crate) cached_data: OutboundLaneData,
234	pub(crate) _phantom: PhantomData<(T, I)>,
235}
236
237impl<T: Config<I>, I: 'static> RuntimeOutboundLaneStorage<T, I> {
238	/// Creates new runtime outbound lane storage for given **existing** lane.
239	fn from_lane_id(lane_id: T::LaneId, check_active: bool) -> Result<Self, LanesManagerError> {
240		let cached_data =
241			OutboundLanes::<T, I>::get(lane_id).ok_or(LanesManagerError::UnknownOutboundLane)?;
242		ensure!(
243			!check_active || cached_data.state.is_active(),
244			LanesManagerError::ClosedOutboundLane
245		);
246		Ok(Self { lane_id, cached_data, _phantom: PhantomData })
247	}
248}
249
250impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage<T, I> {
251	type StoredMessagePayload = StoredMessagePayload<T, I>;
252	type LaneId = T::LaneId;
253
254	fn id(&self) -> Self::LaneId {
255		self.lane_id
256	}
257
258	fn data(&self) -> OutboundLaneData {
259		self.cached_data.clone()
260	}
261
262	fn set_data(&mut self, data: OutboundLaneData) {
263		self.cached_data = data.clone();
264		OutboundLanes::<T, I>::insert(self.lane_id, data)
265	}
266
267	#[cfg(test)]
268	fn message(&self, nonce: &MessageNonce) -> Option<Self::StoredMessagePayload> {
269		OutboundMessages::<T, I>::get(MessageKey { lane_id: self.lane_id, nonce: *nonce })
270			.map(Into::into)
271	}
272
273	fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload) {
274		OutboundMessages::<T, I>::insert(
275			MessageKey { lane_id: self.lane_id, nonce },
276			message_payload,
277		);
278	}
279
280	fn remove_message(&mut self, nonce: &MessageNonce) {
281		OutboundMessages::<T, I>::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce });
282	}
283
284	fn purge(self) {
285		OutboundLanes::<T, I>::remove(self.lane_id)
286	}
287}