1use super::storage::Footprint;
21use crate::defensive;
22
23use alloc::vec::Vec;
24use codec::{Decode, DecodeWithMemTracking, Encode, FullCodec, MaxEncodedLen};
25use core::{cmp::Ordering, fmt::Debug, marker::PhantomData};
26use scale_info::TypeInfo;
27use sp_core::{ConstU32, Get, TypedGet};
28use sp_runtime::{traits::Convert, BoundedSlice};
29use sp_weights::{Weight, WeightMeter};
30
31#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug)]
34pub enum ProcessMessageError {
35 BadFormat,
37 Corrupt,
39 Unsupported,
41 Overweight(Weight),
45 Yield,
52 StackLimitReached,
54}
55
56pub trait ProcessMessage {
58 type Origin: FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug;
60
61 fn process_message(
65 message: &[u8],
66 origin: Self::Origin,
67 meter: &mut WeightMeter,
68 id: &mut [u8; 32],
69 ) -> Result<bool, ProcessMessageError>;
70}
71
72#[derive(Eq, PartialEq, Debug)]
75pub enum ExecuteOverweightError {
76 NotFound,
78 AlreadyProcessed,
82 InsufficientWeight,
84 QueuePaused,
88 Other,
90 RecursiveDisallowed,
92}
93
94pub trait ServiceQueues {
96 type OverweightMessageAddress;
98
99 fn service_queues(weight_limit: Weight) -> Weight;
107
108 fn execute_overweight(
111 _weight_limit: Weight,
112 _address: Self::OverweightMessageAddress,
113 ) -> Result<Weight, ExecuteOverweightError> {
114 Err(ExecuteOverweightError::NotFound)
115 }
116}
117
118pub struct NoopServiceQueues<OverweightAddr>(PhantomData<OverweightAddr>);
120impl<OverweightAddr> ServiceQueues for NoopServiceQueues<OverweightAddr> {
121 type OverweightMessageAddress = OverweightAddr;
122
123 fn service_queues(_: Weight) -> Weight {
124 Weight::zero()
125 }
126}
127
128pub trait EnqueueMessage<Origin: MaxEncodedLen> {
130 type MaxMessageLen: Get<u32>;
132
133 fn enqueue_message(message: BoundedSlice<u8, Self::MaxMessageLen>, origin: Origin);
135
136 fn enqueue_messages<'a>(
138 messages: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
139 origin: Origin,
140 );
141
142 fn sweep_queue(origin: Origin);
144}
145
146impl<Origin: MaxEncodedLen> EnqueueMessage<Origin> for () {
147 type MaxMessageLen = ConstU32<0>;
148 fn enqueue_message(_: BoundedSlice<u8, Self::MaxMessageLen>, _: Origin) {}
149 fn enqueue_messages<'a>(
150 _: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
151 _: Origin,
152 ) {
153 }
154 fn sweep_queue(_: Origin) {}
155}
156
157#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]
159pub struct QueueFootprint {
160 pub pages: u32,
162 pub ready_pages: u32,
164 pub storage: Footprint,
166}
167
168#[derive(Default, Copy, Clone, PartialEq, Debug)]
170pub struct BatchFootprint {
171 pub msgs_count: usize,
173 pub size_in_bytes: usize,
175 pub new_pages_count: u32,
177}
178
179#[derive(Default, Debug)]
185pub struct BatchesFootprints {
186 pub first_page_pos: usize,
195 pub footprints: Vec<BatchFootprint>,
196}
197
198impl BatchesFootprints {
199 pub fn push(&mut self, msg: &[u8], new_page: bool) {
206 let previous_footprint =
207 self.footprints.last().map(|footprint| *footprint).unwrap_or_default();
208
209 let mut new_pages_count = previous_footprint.new_pages_count;
210 if new_page {
211 new_pages_count = new_pages_count.saturating_add(1);
212 }
213 self.footprints.push(BatchFootprint {
214 msgs_count: previous_footprint.msgs_count.saturating_add(1),
215 size_in_bytes: previous_footprint.size_in_bytes.saturating_add(msg.len()),
216 new_pages_count,
217 });
218 }
219
220 pub fn search_best_by<F>(&self, f: F) -> &BatchFootprint
222 where
223 F: FnMut(&BatchFootprint) -> Ordering,
224 {
225 let maybe_best_idx = match self.footprints.binary_search_by(f) {
227 Ok(last_ok_idx) => Some(last_ok_idx),
228 Err(first_err_idx) => first_err_idx.checked_sub(1),
229 };
230 if let Some(best_idx) = maybe_best_idx {
231 match self.footprints.get(best_idx) {
232 Some(best_footprint) => return best_footprint,
233 None => {
234 defensive!("Invalid best_batch_idx: {}", best_idx);
235 },
236 }
237 }
238 &BatchFootprint { msgs_count: 0, size_in_bytes: 0, new_pages_count: 0 }
239 }
240}
241
242pub trait QueueFootprintQuery<Origin> {
244 type MaxMessageLen: Get<u32>;
246
247 fn footprint(origin: Origin) -> QueueFootprint;
249
250 fn get_batches_footprints<'a>(
279 origin: Origin,
280 msgs: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
281 total_pages_limit: u32,
282 ) -> BatchesFootprints;
283}
284
285impl<Origin: MaxEncodedLen> QueueFootprintQuery<Origin> for () {
286 type MaxMessageLen = ConstU32<0>;
287
288 fn footprint(_: Origin) -> QueueFootprint {
289 QueueFootprint::default()
290 }
291
292 fn get_batches_footprints<'a>(
293 _origin: Origin,
294 _msgs: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
295 _total_pages_limit: u32,
296 ) -> BatchesFootprints {
297 BatchesFootprints::default()
298 }
299}
300
301pub struct TransformOrigin<E, O, N, C>(PhantomData<(E, O, N, C)>);
303impl<E: EnqueueMessage<O>, O: MaxEncodedLen, N: MaxEncodedLen, C: Convert<N, O>> EnqueueMessage<N>
304 for TransformOrigin<E, O, N, C>
305{
306 type MaxMessageLen = E::MaxMessageLen;
307
308 fn enqueue_message(message: BoundedSlice<u8, Self::MaxMessageLen>, origin: N) {
309 E::enqueue_message(message, C::convert(origin));
310 }
311
312 fn enqueue_messages<'a>(
313 messages: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
314 origin: N,
315 ) {
316 E::enqueue_messages(messages, C::convert(origin));
317 }
318
319 fn sweep_queue(origin: N) {
320 E::sweep_queue(C::convert(origin));
321 }
322}
323
324impl<E: QueueFootprintQuery<O>, O: MaxEncodedLen, N: MaxEncodedLen, C: Convert<N, O>>
325 QueueFootprintQuery<N> for TransformOrigin<E, O, N, C>
326{
327 type MaxMessageLen = E::MaxMessageLen;
328
329 fn footprint(origin: N) -> QueueFootprint {
330 E::footprint(C::convert(origin))
331 }
332
333 fn get_batches_footprints<'a>(
334 origin: N,
335 msgs: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
336 total_pages_limit: u32,
337 ) -> BatchesFootprints {
338 E::get_batches_footprints(C::convert(origin), msgs, total_pages_limit)
339 }
340}
341
342pub trait HandleMessage {
344 type MaxMessageLen: Get<u32>;
346
347 fn handle_message(message: BoundedSlice<u8, Self::MaxMessageLen>);
349
350 fn handle_messages<'a>(
352 messages: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
353 );
354
355 fn sweep_queue();
357}
358
359impl HandleMessage for () {
360 type MaxMessageLen = ConstU32<0>;
361
362 fn handle_message(_: BoundedSlice<u8, Self::MaxMessageLen>) {}
363
364 fn handle_messages<'a>(_: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>) {}
365
366 fn sweep_queue() {}
367}
368
369pub struct EnqueueWithOrigin<E, O>(PhantomData<(E, O)>);
371impl<E: EnqueueMessage<O::Type>, O: TypedGet> HandleMessage for EnqueueWithOrigin<E, O>
372where
373 O::Type: MaxEncodedLen,
374{
375 type MaxMessageLen = E::MaxMessageLen;
376
377 fn handle_message(message: BoundedSlice<u8, Self::MaxMessageLen>) {
378 E::enqueue_message(message, O::get());
379 }
380
381 fn handle_messages<'a>(
382 messages: impl Iterator<Item = BoundedSlice<'a, u8, Self::MaxMessageLen>>,
383 ) {
384 E::enqueue_messages(messages, O::get());
385 }
386
387 fn sweep_queue() {
388 E::sweep_queue(O::get());
389 }
390}
391
392pub trait QueuePausedQuery<Origin> {
394 fn is_paused(origin: &Origin) -> bool;
396}
397
398#[impl_trait_for_tuples::impl_for_tuples(8)]
399impl<Origin> QueuePausedQuery<Origin> for Tuple {
400 fn is_paused(origin: &Origin) -> bool {
401 for_tuples!( #(
402 if Tuple::is_paused(origin) {
403 return true;
404 }
405 )* );
406 false
407 }
408}