messages_relay/
message_race_limits.rs1use num_traits::Zero;
20use std::ops::RangeInclusive;
21
22use bp_messages::{MessageNonce, Weight};
23
24use crate::{
25 message_lane::MessageLane,
26 message_lane_loop::{MessageDetails, MessageDetailsMap},
27 message_race_loop::NoncesRange,
28 message_race_strategy::SourceRangesQueue,
29};
30
31pub struct RelayReference<P: MessageLane> {
33 pub selected_size: u32,
35
36 pub index: usize,
38 pub nonce: MessageNonce,
40 pub details: MessageDetails<P::SourceChainBalance>,
42}
43
44pub struct RelayMessagesBatchReference<P: MessageLane> {
46 pub max_messages_in_this_batch: MessageNonce,
48 pub max_messages_weight_in_single_batch: Weight,
50 pub max_messages_size_in_single_batch: u32,
52 pub best_target_nonce: MessageNonce,
55 pub nonces_queue: SourceRangesQueue<
57 P::SourceHeaderHash,
58 P::SourceHeaderNumber,
59 MessageDetailsMap<P::SourceChainBalance>,
60 >,
61 pub nonces_queue_range: RangeInclusive<usize>,
63}
64
65#[derive(Clone)]
67pub struct MessageRaceLimits;
68
69impl MessageRaceLimits {
70 pub async fn decide<P: MessageLane>(
71 reference: RelayMessagesBatchReference<P>,
72 ) -> Option<RangeInclusive<MessageNonce>> {
73 let mut hard_selected_count = 0;
74
75 let mut selected_weight = Weight::zero();
76 let mut selected_count: MessageNonce = 0;
77
78 let hard_selected_begin_nonce = std::cmp::max(
79 reference.best_target_nonce + 1,
80 reference.nonces_queue[*reference.nonces_queue_range.start()].1.begin(),
81 );
82
83 let mut relay_reference = RelayReference::<P> {
85 selected_size: 0,
86
87 index: 0,
88 nonce: 0,
89 details: MessageDetails {
90 dispatch_weight: Weight::zero(),
91 size: 0,
92 reward: P::SourceChainBalance::zero(),
93 },
94 };
95
96 let all_ready_nonces = reference
97 .nonces_queue
98 .range(reference.nonces_queue_range.clone())
99 .flat_map(|(_, ready_nonces)| ready_nonces.iter())
100 .filter(|(nonce, _)| **nonce >= hard_selected_begin_nonce)
101 .enumerate();
102 for (index, (nonce, details)) in all_ready_nonces {
103 relay_reference.index = index;
104 relay_reference.nonce = *nonce;
105 relay_reference.details = *details;
106
107 let new_selected_weight = match selected_weight.checked_add(&details.dispatch_weight) {
114 Some(new_selected_weight)
115 if new_selected_weight
116 .all_lte(reference.max_messages_weight_in_single_batch) =>
117 new_selected_weight,
118 new_selected_weight if selected_count == 0 => {
119 log::warn!(
120 target: "bridge",
121 "Going to submit message delivery transaction with declared dispatch \
122 weight {:?} that overflows maximal configured weight {}",
123 new_selected_weight,
124 reference.max_messages_weight_in_single_batch,
125 );
126 new_selected_weight.unwrap_or(Weight::MAX)
127 },
128 _ => break,
129 };
130
131 let new_selected_size = match relay_reference.selected_size.checked_add(details.size) {
133 Some(new_selected_size)
134 if new_selected_size <= reference.max_messages_size_in_single_batch =>
135 new_selected_size,
136 new_selected_size if selected_count == 0 => {
137 log::warn!(
138 target: "bridge",
139 "Going to submit message delivery transaction with message \
140 size {:?} that overflows maximal configured size {}",
141 new_selected_size,
142 reference.max_messages_size_in_single_batch,
143 );
144 new_selected_size.unwrap_or(u32::MAX)
145 },
146 _ => break,
147 };
148
149 let new_selected_count = selected_count + 1;
151 if new_selected_count > reference.max_messages_in_this_batch {
152 break
153 }
154 relay_reference.selected_size = new_selected_size;
155
156 hard_selected_count = index + 1;
157 selected_weight = new_selected_weight;
158 selected_count = new_selected_count;
159 }
160
161 if hard_selected_count != 0 {
162 let selected_max_nonce =
163 hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
164 Some(hard_selected_begin_nonce..=selected_max_nonce)
165 } else {
166 None
167 }
168 }
169}