snowbridge_pallet_outbound_queue/
send_message_impl.rs1use super::*;
5use bridge_hub_common::AggregateMessageOrigin;
6use codec::Encode;
7use frame_support::{
8 ensure,
9 traits::{EnqueueMessage, Get},
10 CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound,
11};
12use frame_system::unique;
13use snowbridge_core::{ChannelId, PRIMARY_GOVERNANCE_CHANNEL};
14use snowbridge_outbound_queue_primitives::{
15 v1::{Fee, Message, QueuedMessage, SendMessage, VersionedQueuedMessage},
16 SendError, SendMessageFeeProvider,
17};
18use sp_core::H256;
19use sp_runtime::BoundedVec;
20
21pub type MaxEnqueuedMessageSizeOf<T> =
23 <<T as Config>::MessageQueue as EnqueueMessage<AggregateMessageOrigin>>::MaxMessageLen;
24
25#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound)]
26pub struct Ticket<T>
27where
28 T: Config,
29{
30 pub message_id: H256,
31 pub channel_id: ChannelId,
32 pub message: BoundedVec<u8, MaxEnqueuedMessageSizeOf<T>>,
33}
34
35impl<T> SendMessage for Pallet<T>
36where
37 T: Config,
38{
39 type Ticket = Ticket<T>;
40
41 fn validate(
42 message: &Message,
43 ) -> Result<(Self::Ticket, Fee<<Self as SendMessageFeeProvider>::Balance>), SendError> {
44 let payload = message.command.abi_encode();
46 ensure!(
47 payload.len() < T::MaxMessagePayloadSize::get() as usize,
48 SendError::MessageTooLarge
49 );
50
51 ensure!(T::Channels::contains(&message.channel_id), SendError::InvalidChannel);
53
54 let message_id: H256 = message
56 .id
57 .unwrap_or_else(|| unique((message.channel_id, &message.command)).into());
58
59 let gas_used_at_most = T::GasMeter::maximum_gas_used_at_most(&message.command);
60 let fee = Self::calculate_fee(gas_used_at_most, T::PricingParameters::get());
61
62 let queued_message: VersionedQueuedMessage = QueuedMessage {
63 id: message_id,
64 channel_id: message.channel_id,
65 command: message.command.clone(),
66 }
67 .into();
68 let encoded = queued_message.encode().try_into().map_err(|_| SendError::MessageTooLarge)?;
70
71 let ticket = Ticket { message_id, channel_id: message.channel_id, message: encoded };
72
73 Ok((ticket, fee))
74 }
75
76 fn deliver(ticket: Self::Ticket) -> Result<H256, SendError> {
77 let origin = AggregateMessageOrigin::Snowbridge(ticket.channel_id);
78
79 if ticket.channel_id != PRIMARY_GOVERNANCE_CHANNEL {
80 ensure!(!Self::operating_mode().is_halted(), SendError::Halted);
81 }
82
83 let message = ticket.message.as_bounded_slice();
84
85 T::MessageQueue::enqueue_message(message, origin);
86 Self::deposit_event(Event::MessageQueued { id: ticket.message_id });
87 Ok(ticket.message_id)
88 }
89}
90
91impl<T: Config> SendMessageFeeProvider for Pallet<T> {
92 type Balance = T::Balance;
93
94 fn local_fee() -> Self::Balance {
96 Self::calculate_local_fee()
97 }
98}