use core::marker::PhantomData;
use cumulus_primitives_core::AggregateMessageOrigin;
use frame_support::pallet_prelude::Get;
use frame_support::traits::{EnqueueMessage, ProcessMessage};
use frame_support::{ensure, BoundedVec};
use pallet_xcm_bridge::BridgeId;
use parity_scale_codec::{Decode, Encode};
use sp_std::vec::Vec;
use xcm::latest::{InteriorLocation, Location, SendError, SendResult, SendXcm, Xcm, XcmHash};
use xcm::{VersionedLocation, VersionedXcm};
use xcm_builder::{BridgeMessage, DispatchBlob, DispatchBlobError, InspectMessageQueues};
const MESSAGE_QUEUE_CONGESTION_THRESHOLD: u32 = 32;
pub const LOG_TARGET: &str = "moonbeam-bridge";
pub struct BridgeXcmRouter<MessageExporter>(PhantomData<MessageExporter>);
impl<MessageExporter: SendXcm> SendXcm for BridgeXcmRouter<MessageExporter> {
type Ticket = MessageExporter::Ticket;
fn validate(
dest: &mut Option<Location>,
xcm: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
log::trace!(target: LOG_TARGET, "validate - msg: {xcm:?}, destination: {dest:?}");
MessageExporter::validate(dest, xcm)
}
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
MessageExporter::deliver(ticket)
}
}
impl<MessageExporter> InspectMessageQueues for BridgeXcmRouter<MessageExporter> {
fn clear_messages() {}
fn get_messages() -> Vec<(VersionedLocation, Vec<VersionedXcm<()>>)> {
Vec::new()
}
}
pub struct LocalBlobDispatcher<MQ, OurPlace, OurPlaceBridgeInstance>(
PhantomData<(MQ, OurPlace, OurPlaceBridgeInstance)>,
);
impl<
MQ: EnqueueMessage<AggregateMessageOrigin>,
OurPlace: Get<InteriorLocation>,
OurPlaceBridgeInstance: Get<Option<InteriorLocation>>,
> DispatchBlob for LocalBlobDispatcher<MQ, OurPlace, OurPlaceBridgeInstance>
{
fn dispatch_blob(blob: Vec<u8>) -> Result<(), DispatchBlobError> {
let our_universal = OurPlace::get();
let our_global = our_universal
.global_consensus()
.map_err(|()| DispatchBlobError::Unbridgable)?;
let BridgeMessage {
universal_dest,
message,
} = Decode::decode(&mut &blob[..]).map_err(|_| DispatchBlobError::InvalidEncoding)?;
let universal_dest: InteriorLocation = universal_dest
.try_into()
.map_err(|_| DispatchBlobError::UnsupportedLocationVersion)?;
let intended_global = universal_dest
.global_consensus()
.map_err(|()| DispatchBlobError::NonUniversalDestination)?;
ensure!(
intended_global == our_global,
DispatchBlobError::WrongGlobal
);
let xcm: Xcm<()> = message
.try_into()
.map_err(|_| DispatchBlobError::UnsupportedXcmVersion)?;
let msg: BoundedVec<u8, MQ::MaxMessageLen> = xcm::opaque::VersionedXcm::V5(xcm)
.encode()
.try_into()
.map_err(|_| DispatchBlobError::InvalidEncoding)?;
MQ::enqueue_message(
msg.as_bounded_slice(),
AggregateMessageOrigin::Here, );
Ok(())
}
}
pub struct CongestionManager<Runtime>(PhantomData<Runtime>);
impl<Runtime: pallet_message_queue::Config> pallet_xcm_bridge::LocalXcmChannelManager
for CongestionManager<Runtime>
where
<Runtime as pallet_message_queue::Config>::MessageProcessor:
ProcessMessage<Origin = AggregateMessageOrigin>,
{
type Error = SendError;
fn is_congested(_with: &Location) -> bool {
let book_state =
pallet_message_queue::Pallet::<Runtime>::footprint(AggregateMessageOrigin::Here);
book_state.ready_pages >= MESSAGE_QUEUE_CONGESTION_THRESHOLD
}
fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> {
Ok(())
}
fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> {
Ok(())
}
}