1#![cfg_attr(not(feature = "std"), no_std)]
19
20pub mod endpoint;
21pub mod messages;
22
23#[cfg(not(feature = "std"))]
24extern crate alloc;
25
26use crate::messages::{ChannelStateWithNonce, MessageKey, MessagesWithStorageKey, Nonce};
27#[cfg(not(feature = "std"))]
28use alloc::collections::BTreeMap;
29#[cfg(not(feature = "std"))]
30use alloc::collections::BTreeSet;
31#[cfg(not(feature = "std"))]
32use alloc::vec::Vec;
33#[cfg(feature = "std")]
34use frame_support::inherent::InherentData;
35use frame_support::inherent::{InherentIdentifier, IsFatalError};
36#[cfg(feature = "runtime-benchmarks")]
37use frame_support::storage::storage_prefix;
38#[cfg(feature = "runtime-benchmarks")]
39use frame_support::{Identity, StorageHasher};
40use messages::{
41 BlockMessagesQuery, BlockMessagesWithStorageKey, ChannelId, CrossDomainMessage, MessageId,
42};
43use parity_scale_codec::{Decode, Encode};
44use scale_info::TypeInfo;
45use sp_domains::{ChainId, DomainAllowlistUpdates, DomainId};
46use sp_subspace_mmr::ConsensusChainMmrLeafProof;
47#[cfg(feature = "std")]
48use std::collections::BTreeMap;
49#[cfg(feature = "std")]
50use std::collections::BTreeSet;
51
52pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"messengr";
54
55pub const MAX_FUTURE_ALLOWED_NONCES: u32 = 256;
64
65pub trait OnXDMRewards<Balance> {
67 fn on_xdm_rewards(rewards: Balance);
68 fn on_chain_protocol_fees(chain_id: ChainId, fees: Balance);
69}
70
71pub trait NoteChainTransfer<Balance> {
73 fn note_transfer_in(amount: Balance, from_chain_id: ChainId) -> bool;
74 fn note_transfer_out(amount: Balance, to_chain_id: ChainId) -> bool;
75}
76
77impl<Balance> NoteChainTransfer<Balance> for () {
78 fn note_transfer_in(_amount: Balance, _from_chain_id: ChainId) -> bool {
79 true
80 }
81 fn note_transfer_out(_amount: Balance, _to_chain_id: ChainId) -> bool {
82 true
83 }
84}
85
86impl<Balance> OnXDMRewards<Balance> for () {
87 fn on_xdm_rewards(_: Balance) {}
88
89 fn on_chain_protocol_fees(_chain_id: ChainId, _fees: Balance) {}
90}
91
92pub trait DomainRegistration {
94 fn is_domain_registered(domain_id: DomainId) -> bool;
95}
96
97impl DomainRegistration for () {
98 fn is_domain_registered(_domain_id: DomainId) -> bool {
99 false
100 }
101}
102
103pub trait StorageKeys {
105 fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Option<Vec<u8>>;
107
108 fn outbox_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>>;
110
111 fn inbox_responses_storage_key(chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>>;
113}
114
115impl StorageKeys for () {
116 fn confirmed_domain_block_storage_key(_domain_id: DomainId) -> Option<Vec<u8>> {
117 None
118 }
119
120 fn outbox_storage_key(_chain_id: ChainId, _message_key: MessageKey) -> Option<Vec<u8>> {
121 None
122 }
123
124 fn inbox_responses_storage_key(
125 _chain_id: ChainId,
126 _message_key: MessageKey,
127 ) -> Option<Vec<u8>> {
128 None
129 }
130}
131
132#[cfg(feature = "runtime-benchmarks")]
133pub struct BenchmarkStorageKeys;
134
135#[cfg(feature = "runtime-benchmarks")]
136impl StorageKeys for BenchmarkStorageKeys {
137 fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Option<Vec<u8>> {
138 let storage_prefix = storage_prefix(
139 "Domains".as_bytes(),
140 "LatestConfirmedDomainExecutionReceipt".as_bytes(),
141 );
142 let key_hashed = domain_id.using_encoded(Identity::hash);
143
144 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
145
146 final_key.extend_from_slice(&storage_prefix);
147 final_key.extend_from_slice(key_hashed.as_ref());
148
149 Some(final_key)
150 }
151
152 fn outbox_storage_key(_chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
153 let storage_prefix = storage_prefix("Messenger".as_bytes(), "Outbox".as_bytes());
154 let key_hashed = message_key.using_encoded(Identity::hash);
155
156 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
157
158 final_key.extend_from_slice(&storage_prefix);
159 final_key.extend_from_slice(key_hashed.as_ref());
160
161 Some(final_key)
162 }
163
164 fn inbox_responses_storage_key(_chain_id: ChainId, message_key: MessageKey) -> Option<Vec<u8>> {
165 let storage_prefix = storage_prefix("Messenger".as_bytes(), "InboxResponses".as_bytes());
166 let key_hashed = message_key.using_encoded(Identity::hash);
167
168 let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
169
170 final_key.extend_from_slice(&storage_prefix);
171 final_key.extend_from_slice(key_hashed.as_ref());
172
173 Some(final_key)
174 }
175}
176
177#[derive(Debug, Encode, Decode)]
179pub struct InherentType {
180 pub maybe_updates: Option<DomainAllowlistUpdates>,
181}
182
183#[derive(Debug, Encode)]
185#[cfg_attr(feature = "std", derive(Decode))]
186pub enum InherentError {
187 MissingAllowlistUpdates,
188 IncorrectAllowlistUpdates,
189}
190
191impl IsFatalError for InherentError {
192 fn is_fatal_error(&self) -> bool {
193 true
194 }
195}
196
197#[cfg(feature = "std")]
199pub struct InherentDataProvider {
200 data: InherentType,
201}
202
203#[cfg(feature = "std")]
204impl InherentDataProvider {
205 pub fn new(data: InherentType) -> Self {
207 Self { data }
208 }
209
210 pub fn data(&self) -> &InherentType {
212 &self.data
213 }
214}
215
216#[cfg(feature = "std")]
217#[async_trait::async_trait]
218impl sp_inherents::InherentDataProvider for InherentDataProvider {
219 async fn provide_inherent_data(
220 &self,
221 inherent_data: &mut InherentData,
222 ) -> Result<(), sp_inherents::Error> {
223 inherent_data.put_data(INHERENT_IDENTIFIER, &self.data)
224 }
225
226 async fn try_handle_error(
227 &self,
228 identifier: &InherentIdentifier,
229 error: &[u8],
230 ) -> Option<Result<(), sp_inherents::Error>> {
231 if *identifier != INHERENT_IDENTIFIER {
232 return None;
233 }
234
235 let error = InherentError::decode(&mut &*error).ok()?;
236
237 Some(Err(sp_inherents::Error::Application(Box::from(format!(
238 "{error:?}"
239 )))))
240 }
241}
242
243#[derive(Debug, Encode, Decode, TypeInfo, Copy, Clone)]
245pub enum XdmId {
246 RelayMessage(MessageKey),
247 RelayResponseMessage(MessageKey),
248}
249
250impl XdmId {
251 pub fn get_chain_id_and_channel_id(&self) -> (ChainId, ChannelId) {
252 match self {
253 XdmId::RelayMessage(key) => (key.0, key.1),
254 XdmId::RelayResponseMessage(key) => (key.0, key.1),
255 }
256 }
257}
258
259#[derive(Debug, Encode, Decode, TypeInfo, Copy, Clone)]
260pub struct ChannelNonce {
261 pub relay_msg_nonce: Option<Nonce>,
264 pub relay_response_msg_nonce: Option<Nonce>,
267}
268
269sp_api::decl_runtime_apis! {
270 #[api_version(3)]
272 pub trait RelayerApi<BlockNumber, CNumber, CHash>
273 where
274 BlockNumber: Encode + Decode,
275 CNumber: Encode + Decode,
276 CHash: Encode + Decode,
277 {
278 fn block_messages() -> BlockMessagesWithStorageKey;
281
282 fn outbox_message_unsigned(
284 msg: CrossDomainMessage<CNumber, CHash, sp_core::H256>,
285 ) -> Option<Block::Extrinsic>;
286
287 fn inbox_response_message_unsigned(
289 msg: CrossDomainMessage<CNumber, CHash, sp_core::H256>,
290 ) -> Option<Block::Extrinsic>;
291
292 fn should_relay_outbox_message(dst_chain_id: ChainId, msg_id: MessageId) -> bool;
294
295 fn should_relay_inbox_message_response(dst_chain_id: ChainId, msg_id: MessageId) -> bool;
297
298 fn updated_channels() -> BTreeSet<(ChainId, ChannelId)>;
300
301 fn channel_storage_key(chain_id: ChainId, channel_id: ChannelId) -> Vec<u8>;
303
304 fn open_channels() -> BTreeSet<(ChainId, ChannelId)>;
306
307 fn block_messages_with_query(query: BlockMessagesQuery) -> MessagesWithStorageKey;
310
311 fn channels_and_state() -> Vec<(ChainId, ChannelId, ChannelStateWithNonce)>;
313
314 fn first_outbox_message_nonce_to_relay(dst_chain_id: ChainId, channel_id: ChannelId, from_nonce: Nonce) -> Option<Nonce>;
316
317 fn first_inbox_message_response_nonce_to_relay(dst_chain_id: ChainId,channel_id: ChannelId, from_nonce: Nonce) -> Option<Nonce>;
319 }
320
321 #[api_version(3)]
323 pub trait MessengerApi<CNumber, CHash>
324 where
325 CNumber: Encode + Decode,
326 CHash: Encode + Decode,
327 {
328 fn is_xdm_mmr_proof_valid(
331 ext: &Block::Extrinsic
332 ) -> Option<bool>;
333
334 fn extract_xdm_mmr_proof(ext: &Block::Extrinsic) -> Option<ConsensusChainMmrLeafProof<CNumber, CHash, sp_core::H256>>;
336
337 #[allow(clippy::ptr_arg)]
341 fn batch_extract_xdm_mmr_proof(ext: &Vec<Block::Extrinsic>) -> BTreeMap<u32, ConsensusChainMmrLeafProof<CNumber, CHash, sp_core::H256>>;
342
343 fn confirmed_domain_block_storage_key(domain_id: DomainId) -> Vec<u8>;
345
346 fn outbox_storage_key(message_key: MessageKey) -> Vec<u8>;
348
349 fn inbox_response_storage_key(message_key: MessageKey) -> Vec<u8>;
351
352 fn domain_chains_allowlist_update(domain_id: DomainId) -> Option<DomainAllowlistUpdates>;
354
355 fn xdm_id(ext: &Block::Extrinsic) -> Option<XdmId>;
357
358 fn channel_nonce(chain_id: ChainId, channel_id: ChannelId) -> Option<ChannelNonce>;
360 }
361}