1use 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#[derive(
35 Encode, Decode, DecodeWithMemTracking, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo,
36)]
37pub enum LanesManagerError {
38 InboundLaneAlreadyExists,
40 OutboundLaneAlreadyExists,
42 UnknownInboundLane,
44 UnknownOutboundLane,
46 ClosedInboundLane,
48 ClosedOutboundLane,
50 LaneDispatcherInactive,
53}
54
55pub 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 pub fn new() -> Self {
67 Self(PhantomData)
68 }
69
70 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 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 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 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 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 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
138pub 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 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 ensure!(cached_data.state.is_active(), LanesManagerError::ClosedInboundLane);
156 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 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#[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 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}