referrerpolicy=no-referrer-when-downgrade

snowbridge_pallet_outbound_queue/
send_message_impl.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3//! Implementation for [`snowbridge_outbound_queue_primitives::v1::SendMessage`]
4use 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
21/// The maximal length of an enqueued message, as determined by the MessageQueue pallet
22pub 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		// The inner payload should not be too large
45		let payload = message.command.abi_encode();
46		ensure!(
47			payload.len() < T::MaxMessagePayloadSize::get() as usize,
48			SendError::MessageTooLarge
49		);
50
51		// Ensure there is a registered channel we can transmit this message on
52		ensure!(T::Channels::contains(&message.channel_id), SendError::InvalidChannel);
53
54		// Generate a unique message id unless one is provided
55		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		// The whole message should not be too large
69		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	/// The local component of the message processing fees in native currency
95	fn local_fee() -> Self::Balance {
96		Self::calculate_local_fee()
97	}
98}