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