1#![warn(missing_docs)]
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use bp_header_chain::HeaderChainError;
23use bp_runtime::{
24 messages::MessageDispatchResult, BasicOperatingMode, Chain, OperatingMode, RangeInclusiveExt,
25 StorageProofError, UnderlyingChainOf, UnderlyingChainProvider,
26};
27use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
28use frame_support::PalletError;
29pub use frame_support::weights::Weight;
31use scale_info::TypeInfo;
32use serde::{Deserialize, Serialize};
33use source_chain::RelayersRewards;
34use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*};
35use Debug;
36
37pub use call_info::{
38 BaseMessagesProofInfo, BridgeMessagesCall, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo,
39 ReceiveMessagesProofInfo, UnrewardedRelayerOccupation,
40};
41pub use lane::{HashedLaneId, LaneIdType, LaneState, LegacyLaneId};
42
43mod call_info;
44mod lane;
45pub mod source_chain;
46pub mod storage_keys;
47pub mod target_chain;
48
49pub const HARD_MESSAGE_SIZE_LIMIT: u32 = 64 * 1024;
51
52pub trait ChainWithMessages: Chain {
54 const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str;
60
61 const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce;
70 const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce;
86
87 fn maximal_incoming_message_dispatch_weight() -> Weight {
89 Self::max_extrinsic_weight() / 2
91 }
92
93 fn maximal_incoming_message_size() -> u32 {
95 maximal_incoming_message_size(Self::max_extrinsic_size())
96 }
97}
98
99pub fn maximal_incoming_message_size(max_extrinsic_size: u32) -> u32 {
101 sp_std::cmp::min(max_extrinsic_size / 3 * 2, HARD_MESSAGE_SIZE_LIMIT)
119}
120
121impl<T> ChainWithMessages for T
122where
123 T: Chain + UnderlyingChainProvider,
124 UnderlyingChainOf<T>: ChainWithMessages,
125{
126 const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str =
127 UnderlyingChainOf::<T>::WITH_CHAIN_MESSAGES_PALLET_NAME;
128 const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
129 UnderlyingChainOf::<T>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
130 const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
131 UnderlyingChainOf::<T>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
132}
133
134#[derive(
136 Encode,
137 Decode,
138 DecodeWithMemTracking,
139 Clone,
140 Copy,
141 PartialEq,
142 Eq,
143 Debug,
144 TypeInfo,
145 MaxEncodedLen,
146 Serialize,
147 Deserialize,
148)]
149pub enum MessagesOperatingMode {
150 Basic(BasicOperatingMode),
152 RejectingOutboundMessages,
160}
161
162impl Default for MessagesOperatingMode {
163 fn default() -> Self {
164 MessagesOperatingMode::Basic(BasicOperatingMode::Normal)
165 }
166}
167
168impl OperatingMode for MessagesOperatingMode {
169 fn is_halted(&self) -> bool {
170 match self {
171 Self::Basic(operating_mode) => operating_mode.is_halted(),
172 _ => false,
173 }
174 }
175}
176
177pub type MessageNonce = u64;
179
180pub type MessagePayload = Vec<u8>;
182
183#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo, MaxEncodedLen)]
185pub struct MessageKey<LaneId: Encode> {
186 pub lane_id: LaneId,
188 pub nonce: MessageNonce,
190}
191
192#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, TypeInfo)]
194pub struct Message<LaneId: Encode> {
195 pub key: MessageKey<LaneId>,
197 pub payload: MessagePayload,
199}
200
201#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)]
203pub struct InboundLaneData<RelayerId> {
204 pub relayers: VecDeque<UnrewardedRelayer<RelayerId>>,
222
223 pub last_confirmed_nonce: MessageNonce,
232
233 pub state: LaneState,
237}
238
239impl<RelayerId> Default for InboundLaneData<RelayerId> {
240 fn default() -> Self {
241 InboundLaneData {
242 state: LaneState::Closed,
243 relayers: VecDeque::new(),
244 last_confirmed_nonce: 0,
245 }
246 }
247}
248
249impl<RelayerId> InboundLaneData<RelayerId> {
250 pub fn opened() -> Self {
252 InboundLaneData { state: LaneState::Opened, ..Default::default() }
253 }
254
255 pub fn encoded_size_hint(relayers_entries: usize) -> Option<usize>
260 where
261 RelayerId: MaxEncodedLen,
262 {
263 relayers_entries
264 .checked_mul(UnrewardedRelayer::<RelayerId>::max_encoded_len())?
265 .checked_add(MessageNonce::max_encoded_len())
266 }
267
268 pub fn encoded_size_hint_u32(relayers_entries: usize) -> u32
273 where
274 RelayerId: MaxEncodedLen,
275 {
276 Self::encoded_size_hint(relayers_entries)
277 .and_then(|x| u32::try_from(x).ok())
278 .unwrap_or(u32::MAX)
279 }
280
281 pub fn last_delivered_nonce(&self) -> MessageNonce {
283 self.relayers
284 .back()
285 .map(|entry| entry.messages.end)
286 .unwrap_or(self.last_confirmed_nonce)
287 }
288
289 pub fn total_unrewarded_messages(&self) -> MessageNonce {
292 let relayers = &self.relayers;
293 match (relayers.front(), relayers.back()) {
294 (Some(front), Some(back)) => {
295 (front.messages.begin..=back.messages.end).saturating_len()
296 },
297 _ => 0,
298 }
299 }
300}
301
302#[derive(Clone, Encode, Decode, Debug, PartialEq, Eq, TypeInfo)]
304pub struct OutboundMessageDetails {
305 pub nonce: MessageNonce,
307 pub dispatch_weight: Weight,
312 pub size: u32,
314}
315
316#[derive(Clone, Encode, Decode, Debug, PartialEq, Eq, TypeInfo)]
318pub struct InboundMessageDetails {
319 pub dispatch_weight: Weight,
326}
327
328#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
333pub struct UnrewardedRelayer<RelayerId> {
334 pub relayer: RelayerId,
336 pub messages: DeliveredMessages,
338}
339
340#[derive(Clone, Encode, Decode, DecodeWithMemTracking, Debug, PartialEq, Eq, TypeInfo)]
342pub struct ReceivedMessages<DispatchLevelResult, LaneId> {
343 pub lane: LaneId,
345 pub receive_results: Vec<(MessageNonce, ReceptionResult<DispatchLevelResult>)>,
347}
348
349impl<DispatchLevelResult, LaneId> ReceivedMessages<DispatchLevelResult, LaneId> {
350 pub fn new(
352 lane: LaneId,
353 receive_results: Vec<(MessageNonce, ReceptionResult<DispatchLevelResult>)>,
354 ) -> Self {
355 ReceivedMessages { lane: lane.into(), receive_results }
356 }
357
358 pub fn push(&mut self, message: MessageNonce, result: ReceptionResult<DispatchLevelResult>) {
360 self.receive_results.push((message, result));
361 }
362}
363
364#[derive(Debug, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, Clone, TypeInfo)]
366pub enum ReceptionResult<DispatchLevelResult> {
367 Dispatched(MessageDispatchResult<DispatchLevelResult>),
372 InvalidNonce,
374 TooManyUnrewardedRelayers,
376 TooManyUnconfirmedMessages,
378}
379
380#[derive(
382 Clone,
383 Default,
384 Encode,
385 Decode,
386 DecodeWithMemTracking,
387 Debug,
388 PartialEq,
389 Eq,
390 TypeInfo,
391 MaxEncodedLen,
392)]
393pub struct DeliveredMessages {
394 pub begin: MessageNonce,
396 pub end: MessageNonce,
398}
399
400impl DeliveredMessages {
401 pub fn new(nonce: MessageNonce) -> Self {
404 DeliveredMessages { begin: nonce, end: nonce }
405 }
406
407 pub fn total_messages(&self) -> MessageNonce {
409 (self.begin..=self.end).saturating_len()
410 }
411
412 pub fn note_dispatched_message(&mut self) {
414 self.end += 1;
415 }
416
417 pub fn contains_message(&self, nonce: MessageNonce) -> bool {
419 (self.begin..=self.end).contains(&nonce)
420 }
421}
422
423#[derive(Clone, Default, Encode, Decode, DecodeWithMemTracking, Debug, PartialEq, Eq, TypeInfo)]
425pub struct UnrewardedRelayersState {
426 pub unrewarded_relayer_entries: MessageNonce,
428 pub messages_in_oldest_entry: MessageNonce,
431 pub total_messages: MessageNonce,
433 pub last_delivered_nonce: MessageNonce,
438}
439
440impl UnrewardedRelayersState {
441 pub fn is_valid<RelayerId>(&self, lane_data: &InboundLaneData<RelayerId>) -> bool {
443 self == &lane_data.into()
444 }
445}
446
447impl<RelayerId> From<&InboundLaneData<RelayerId>> for UnrewardedRelayersState {
448 fn from(lane: &InboundLaneData<RelayerId>) -> UnrewardedRelayersState {
449 UnrewardedRelayersState {
450 unrewarded_relayer_entries: lane.relayers.len() as _,
451 messages_in_oldest_entry: lane
452 .relayers
453 .front()
454 .map(|entry| entry.messages.total_messages())
455 .unwrap_or(0),
456 total_messages: lane.total_unrewarded_messages(),
457 last_delivered_nonce: lane.last_delivered_nonce(),
458 }
459 }
460}
461
462#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
464pub struct OutboundLaneData {
465 pub oldest_unpruned_nonce: MessageNonce,
468 pub latest_received_nonce: MessageNonce,
470 pub latest_generated_nonce: MessageNonce,
472 pub state: LaneState,
476}
477
478impl OutboundLaneData {
479 pub fn opened() -> Self {
481 OutboundLaneData { state: LaneState::Opened, ..Default::default() }
482 }
483}
484
485impl Default for OutboundLaneData {
486 fn default() -> Self {
487 OutboundLaneData {
488 state: LaneState::Closed,
489 oldest_unpruned_nonce: 1,
492 latest_received_nonce: 0,
493 latest_generated_nonce: 0,
494 }
495 }
496}
497
498impl OutboundLaneData {
499 pub fn queued_messages(&self) -> RangeInclusive<MessageNonce> {
502 (self.latest_received_nonce + 1)..=self.latest_generated_nonce
503 }
504}
505
506pub fn calc_relayers_rewards<AccountId>(
508 messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
509 received_range: &RangeInclusive<MessageNonce>,
510) -> RelayersRewards<AccountId>
511where
512 AccountId: sp_std::cmp::Ord,
513{
514 let mut relayers_rewards = RelayersRewards::new();
517 for entry in messages_relayers {
518 let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start());
519 let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end());
520 if nonce_end >= nonce_begin {
521 let relayer_reward = relayers_rewards.entry(entry.relayer).or_default();
522 *relayer_reward =
523 relayer_reward.saturating_add((nonce_begin..=nonce_end).saturating_len());
524 }
525 }
526 relayers_rewards
527}
528
529#[derive(Encode, Decode, DecodeWithMemTracking, Debug, PartialEq, Eq, PalletError, TypeInfo)]
531pub enum VerificationError {
532 EmptyMessageProof,
534 HeaderChain(HeaderChainError),
536 InboundLaneStorage(StorageProofError),
538 InvalidMessageWeight,
540 MessagesCountMismatch,
542 MessageStorage(StorageProofError),
544 MessageTooLarge,
546 OutboundLaneStorage(StorageProofError),
548 StorageProof(StorageProofError),
550 Other(#[codec(skip)] &'static str),
552}
553
554#[cfg(test)]
555mod tests {
556 use super::*;
557
558 #[test]
559 fn lane_is_closed_by_default() {
560 assert_eq!(InboundLaneData::<()>::default().state, LaneState::Closed);
561 assert_eq!(OutboundLaneData::default().state, LaneState::Closed);
562 }
563
564 #[test]
565 fn total_unrewarded_messages_does_not_overflow() {
566 let lane_data = InboundLaneData {
567 state: LaneState::Opened,
568 relayers: vec![
569 UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) },
570 UnrewardedRelayer {
571 relayer: 2,
572 messages: DeliveredMessages::new(MessageNonce::MAX),
573 },
574 ]
575 .into_iter()
576 .collect(),
577 last_confirmed_nonce: 0,
578 };
579 assert_eq!(lane_data.total_unrewarded_messages(), MessageNonce::MAX);
580 }
581
582 #[test]
583 fn calc_relayers_rewards_does_not_overflow() {
584 let relayers = vec![
585 UnrewardedRelayer {
586 relayer: 1,
587 messages: DeliveredMessages { begin: 0, end: MessageNonce::MAX },
588 },
589 UnrewardedRelayer {
590 relayer: 1,
591 messages: DeliveredMessages { begin: 0, end: MessageNonce::MAX },
592 },
593 UnrewardedRelayer { relayer: 2, messages: DeliveredMessages { begin: 0, end: 1 } },
594 ]
595 .into_iter()
596 .collect();
597
598 let rewards = calc_relayers_rewards(relayers, &(0..=MessageNonce::MAX));
599 assert_eq!(rewards.get(&1), Some(&MessageNonce::MAX));
600 assert_eq!(rewards.get(&2), Some(&2));
601 }
602
603 #[test]
604 fn inbound_lane_data_returns_correct_hint() {
605 let test_cases = vec![
606 (1, 128u8),
608 (128u8, 128u8),
610 (13u8, 128u8),
612 ];
613 for (relayer_entries, messages_count) in test_cases {
614 let expected_size = InboundLaneData::<u8>::encoded_size_hint(relayer_entries as _);
615 let actual_size = InboundLaneData {
616 state: LaneState::Opened,
617 relayers: (1u8..=relayer_entries)
618 .map(|i| UnrewardedRelayer {
619 relayer: i,
620 messages: DeliveredMessages::new(i as _),
621 })
622 .collect(),
623 last_confirmed_nonce: messages_count as _,
624 }
625 .encode()
626 .len();
627 let difference = (expected_size.unwrap() as f64 - actual_size as f64).abs();
628 assert!(
629 difference / (std::cmp::min(actual_size, expected_size.unwrap()) as f64) < 0.1,
630 "Too large difference between actual ({actual_size}) and expected ({expected_size:?}) inbound lane data size. Test case: {relayer_entries}+{messages_count}",
631 );
632 }
633 }
634
635 #[test]
636 fn contains_result_works() {
637 let delivered_messages = DeliveredMessages { begin: 100, end: 150 };
638
639 assert!(!delivered_messages.contains_message(99));
640 assert!(delivered_messages.contains_message(100));
641 assert!(delivered_messages.contains_message(150));
642 assert!(!delivered_messages.contains_message(151));
643 }
644}