use crate::{
BridgedChainOf, Config, InboundLane, InboundLaneStorage, InboundLanes, OutboundLane,
OutboundLaneStorage, OutboundLanes, OutboundMessages, StoredInboundLaneData,
StoredMessagePayload,
};
use bp_messages::{
target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneState, MessageKey,
MessageNonce, OutboundLaneData,
};
use bp_runtime::AccountIdOf;
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{ensure, sp_runtime::RuntimeDebug, PalletError};
use scale_info::TypeInfo;
use sp_std::marker::PhantomData;
#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)]
pub enum LanesManagerError {
InboundLaneAlreadyExists,
OutboundLaneAlreadyExists,
UnknownInboundLane,
UnknownOutboundLane,
ClosedInboundLane,
ClosedOutboundLane,
LaneDispatcherInactive,
}
pub struct LanesManager<T, I>(PhantomData<(T, I)>);
impl<T: Config<I>, I: 'static> Default for LanesManager<T, I> {
fn default() -> Self {
Self::new()
}
}
impl<T: Config<I>, I: 'static> LanesManager<T, I> {
pub fn new() -> Self {
Self(PhantomData)
}
pub fn create_inbound_lane(
&self,
lane_id: T::LaneId,
) -> Result<InboundLane<RuntimeInboundLaneStorage<T, I>>, LanesManagerError> {
InboundLanes::<T, I>::try_mutate(lane_id, |lane| match lane {
Some(_) => Err(LanesManagerError::InboundLaneAlreadyExists),
None => {
*lane = Some(StoredInboundLaneData(InboundLaneData {
state: LaneState::Opened,
..Default::default()
}));
Ok(())
},
})?;
self.active_inbound_lane(lane_id)
}
pub fn create_outbound_lane(
&self,
lane_id: T::LaneId,
) -> Result<OutboundLane<RuntimeOutboundLaneStorage<T, I>>, LanesManagerError> {
OutboundLanes::<T, I>::try_mutate(lane_id, |lane| match lane {
Some(_) => Err(LanesManagerError::OutboundLaneAlreadyExists),
None => {
*lane = Some(OutboundLaneData { state: LaneState::Opened, ..Default::default() });
Ok(())
},
})?;
self.active_outbound_lane(lane_id)
}
pub fn active_inbound_lane(
&self,
lane_id: T::LaneId,
) -> Result<InboundLane<RuntimeInboundLaneStorage<T, I>>, LanesManagerError> {
Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, true)?))
}
pub fn active_outbound_lane(
&self,
lane_id: T::LaneId,
) -> Result<OutboundLane<RuntimeOutboundLaneStorage<T, I>>, LanesManagerError> {
Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, true)?))
}
pub fn any_state_inbound_lane(
&self,
lane_id: T::LaneId,
) -> Result<InboundLane<RuntimeInboundLaneStorage<T, I>>, LanesManagerError> {
Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, false)?))
}
pub fn any_state_outbound_lane(
&self,
lane_id: T::LaneId,
) -> Result<OutboundLane<RuntimeOutboundLaneStorage<T, I>>, LanesManagerError> {
Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, false)?))
}
}
pub struct RuntimeInboundLaneStorage<T: Config<I>, I: 'static = ()> {
pub(crate) lane_id: T::LaneId,
pub(crate) cached_data: InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>>,
}
impl<T: Config<I>, I: 'static> RuntimeInboundLaneStorage<T, I> {
fn from_lane_id(
lane_id: T::LaneId,
check_active: bool,
) -> Result<RuntimeInboundLaneStorage<T, I>, LanesManagerError> {
let cached_data =
InboundLanes::<T, I>::get(lane_id).ok_or(LanesManagerError::UnknownInboundLane)?;
if check_active {
ensure!(cached_data.state.is_active(), LanesManagerError::ClosedInboundLane);
ensure!(
T::MessageDispatch::is_active(lane_id),
LanesManagerError::LaneDispatcherInactive
);
}
Ok(RuntimeInboundLaneStorage { lane_id, cached_data: cached_data.into() })
}
pub fn extra_proof_size_bytes(&self) -> u64 {
let max_encoded_len = StoredInboundLaneData::<T, I>::max_encoded_len();
let relayers_count = self.data().relayers.len();
let actual_encoded_len =
InboundLaneData::<AccountIdOf<BridgedChainOf<T, I>>>::encoded_size_hint(relayers_count)
.unwrap_or(usize::MAX);
max_encoded_len.saturating_sub(actual_encoded_len) as _
}
}
impl<T: Config<I>, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage<T, I> {
type Relayer = AccountIdOf<BridgedChainOf<T, I>>;
type LaneId = T::LaneId;
fn id(&self) -> Self::LaneId {
self.lane_id
}
fn max_unrewarded_relayer_entries(&self) -> MessageNonce {
BridgedChainOf::<T, I>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX
}
fn max_unconfirmed_messages(&self) -> MessageNonce {
BridgedChainOf::<T, I>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX
}
fn data(&self) -> InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>> {
self.cached_data.clone()
}
fn set_data(&mut self, data: InboundLaneData<AccountIdOf<BridgedChainOf<T, I>>>) {
self.cached_data = data.clone();
InboundLanes::<T, I>::insert(self.lane_id, StoredInboundLaneData::<T, I>(data))
}
fn purge(self) {
InboundLanes::<T, I>::remove(self.lane_id)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct RuntimeOutboundLaneStorage<T: Config<I>, I: 'static> {
pub(crate) lane_id: T::LaneId,
pub(crate) cached_data: OutboundLaneData,
pub(crate) _phantom: PhantomData<(T, I)>,
}
impl<T: Config<I>, I: 'static> RuntimeOutboundLaneStorage<T, I> {
fn from_lane_id(lane_id: T::LaneId, check_active: bool) -> Result<Self, LanesManagerError> {
let cached_data =
OutboundLanes::<T, I>::get(lane_id).ok_or(LanesManagerError::UnknownOutboundLane)?;
ensure!(
!check_active || cached_data.state.is_active(),
LanesManagerError::ClosedOutboundLane
);
Ok(Self { lane_id, cached_data, _phantom: PhantomData })
}
}
impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage<T, I> {
type StoredMessagePayload = StoredMessagePayload<T, I>;
type LaneId = T::LaneId;
fn id(&self) -> Self::LaneId {
self.lane_id
}
fn data(&self) -> OutboundLaneData {
self.cached_data.clone()
}
fn set_data(&mut self, data: OutboundLaneData) {
self.cached_data = data.clone();
OutboundLanes::<T, I>::insert(self.lane_id, data)
}
#[cfg(test)]
fn message(&self, nonce: &MessageNonce) -> Option<Self::StoredMessagePayload> {
OutboundMessages::<T, I>::get(MessageKey { lane_id: self.lane_id, nonce: *nonce })
.map(Into::into)
}
fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload) {
OutboundMessages::<T, I>::insert(
MessageKey { lane_id: self.lane_id, nonce },
message_payload,
);
}
fn remove_message(&mut self, nonce: &MessageNonce) {
OutboundMessages::<T, I>::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce });
}
fn purge(self) {
OutboundLanes::<T, I>::remove(self.lane_id)
}
}