1const MATCHERS_TASK_CHANNEL_BUFFER_SIZE: usize = 80_000;
35
36const SUBSCRIPTION_BUFFER_SIZE: usize = 128;
38const STOP_RESERVE_CHANNEL_SLOTS: usize = 1;
39
40pub const MAX_FILTERS_PER_SUBSCRIPTION: usize = 128;
45pub(crate) const REPLAY_CHUNK_RAW_BYTES: usize = 4 * 1024 * 1024;
48use futures::{Stream, StreamExt};
49use itertools::Itertools;
50use parking_lot::Mutex;
51
52use crate::LOG_TARGET;
53use sc_utils::id_sequence::SeqID;
54use sp_core::{traits::SpawnNamed, Bytes, Encode};
55pub use sp_statement_store::StatementStore;
56use sp_statement_store::{
57 FilterId, LiveStatementEvent, OptimizedTopicFilter, Result, Statement, StatementEvent, Topic,
58 MAX_TOPICS,
59};
60use std::{
61 collections::{hash_map::Entry, HashMap, HashSet, VecDeque},
62 sync::{atomic::AtomicU64, Arc},
63};
64
65#[derive(Debug, Clone, PartialEq, Eq)]
67pub enum AddFilterError {
68 LimitReached,
70 Stopped,
73}
74
75pub trait StatementStoreSubscriptionApi: Send + Sync {
77 fn subscribe_statement(
82 &self,
83 topic_filter: OptimizedTopicFilter,
84 ) -> Result<(Vec<Vec<u8>>, async_channel::Sender<StatementEvent>, SubscriptionStatementsStream)>;
85}
86
87pub trait MultiFilterSubscriptionApi: Send + Sync {
89 fn create_subscription(&self) -> (SubscriptionHandle, MultiFilterEventStream);
91}
92
93pub(crate) trait ReplaySnapshotProvider: Send + Sync {
95 fn register_replay(&self, enqueue: &mut dyn FnMut(u64) -> bool) -> Result<Option<u64>>;
102
103 fn replay_batch(
105 &self,
106 filter: &OptimizedTopicFilter,
107 cursor: u64,
108 watermark: u64,
109 ) -> Result<ReplayBatch>;
110}
111
112pub(crate) struct ReplayBatch {
113 pub(crate) statements: Vec<Vec<u8>>,
114 pub(crate) cursor: u64,
115 pub(crate) done: bool,
116}
117
118#[derive(Clone)]
120pub struct SubscriptionHandle {
121 pub(crate) sub_id: SeqID,
122 pub(crate) inner: Arc<Mutex<SubscriptionHandleInner>>,
123 pub(crate) matchers: SubscriptionsMatchersHandlers,
124 pub(crate) snapshot_provider: Arc<dyn ReplaySnapshotProvider>,
125}
126
127pub(crate) struct SubscriptionHandleInner {
128 active_filter_ids: HashSet<FilterId>,
129 next_filter_id: u64,
130}
131
132impl SubscriptionHandleInner {
133 pub(crate) fn new() -> Self {
134 Self { active_filter_ids: HashSet::new(), next_filter_id: 0 }
135 }
136}
137
138impl SubscriptionHandle {
139 pub fn add_filter(
141 &self,
142 filter: OptimizedTopicFilter,
143 ) -> std::result::Result<FilterId, AddFilterError> {
144 let mut inner = self.inner.lock();
145 if inner.active_filter_ids.len() >= MAX_FILTERS_PER_SUBSCRIPTION {
146 return Err(AddFilterError::LimitReached);
147 }
148
149 let filter_id = FilterId::new(inner.next_filter_id);
150 let sub_id = self.sub_id;
151
152 let (result_tx, result_rx) = async_channel::bounded(1);
153 let mut result_tx = Some(result_tx);
154 let Some(_watermark) = self
155 .snapshot_provider
156 .register_replay(&mut |watermark| {
157 let result_tx =
158 result_tx.take().expect("register_replay invokes enqueue at most once; qed");
159 self.matchers
160 .try_send_by_seq_id(
161 sub_id,
162 MatcherMessage::RegisterFilter {
163 sub_id,
164 filter_id,
165 filter: filter.clone(),
166 watermark,
167 result_tx,
168 },
169 )
170 .is_ok()
171 })
172 .map_err(|_| AddFilterError::Stopped)?
173 else {
174 return Err(AddFilterError::Stopped);
175 };
176 match result_rx.recv_blocking() {
177 Ok(result) => result?,
178 Err(_) => return Err(AddFilterError::Stopped),
179 }
180 inner.next_filter_id = inner.next_filter_id.wrapping_add(1);
181 inner.active_filter_ids.insert(filter_id);
182 Ok(filter_id)
183 }
184
185 pub fn remove_filter(&self, filter_id: FilterId) -> bool {
187 let mut inner = self.inner.lock();
188 if !inner.active_filter_ids.remove(&filter_id) {
189 return false;
190 }
191 self.matchers.send_by_seq_id(
192 self.sub_id,
193 MatcherMessage::RemoveFilter { sub_id: self.sub_id, filter_id },
194 );
195 true
196 }
197}
198
199struct PendingReplay {
200 filter_id: FilterId,
201 filter: OptimizedTopicFilter,
202 cursor: u64,
203 watermark: u64,
204}
205
206pub(crate) struct MultiFilterSubscriptionState {
207 pending_replays: VecDeque<PendingReplay>,
208 stopped: bool,
209 stop_emitted: bool,
210}
211
212impl MultiFilterSubscriptionState {
213 pub(crate) fn new() -> Self {
214 Self { pending_replays: VecDeque::new(), stopped: false, stop_emitted: false }
215 }
216
217 fn record_filter_added(
218 &mut self,
219 filter_id: FilterId,
220 filter: OptimizedTopicFilter,
221 watermark: u64,
222 ) {
223 self.pending_replays
224 .push_back(PendingReplay { filter_id, filter, cursor: 0, watermark });
225 }
226
227 fn record_filter_removed(&mut self, filter_id: FilterId) {
228 self.pending_replays.retain(|replay| replay.filter_id != filter_id);
229 }
230
231 fn next_event(
232 &mut self,
233 snapshot_provider: &dyn ReplaySnapshotProvider,
234 ) -> Option<MultiFilterSubscriptionEvent> {
235 if !self.stopped {
236 if let Some(event) = self.next_replay_event(snapshot_provider) {
237 return Some(event);
238 }
239 }
240
241 if self.stopped && !self.stop_emitted {
242 self.stop_emitted = true;
243 return Some(MultiFilterSubscriptionEvent::Stop);
244 }
245 None
246 }
247
248 fn next_replay_event(
249 &mut self,
250 snapshot_provider: &dyn ReplaySnapshotProvider,
251 ) -> Option<MultiFilterSubscriptionEvent> {
252 let replay = self.pending_replays.front_mut()?;
253 let filter_id = replay.filter_id;
254 if replay.cursor >= replay.watermark {
255 self.pending_replays.pop_front();
256 return Some(MultiFilterSubscriptionEvent::ReplayDone { filter_id });
257 }
258 let batch =
259 match snapshot_provider.replay_batch(&replay.filter, replay.cursor, replay.watermark) {
260 Ok(batch) => batch,
261 Err(e) => {
262 log::error!(
263 target: LOG_TARGET,
264 "Stopping subscription: replaying filter {:?} from {} failed: {:?}",
265 filter_id,
266 replay.cursor,
267 e
268 );
269 self.stopped = true;
270 return None;
271 },
272 };
273 replay.cursor = batch.cursor;
274 if batch.done && batch.statements.is_empty() {
275 self.pending_replays.pop_front();
276 return Some(MultiFilterSubscriptionEvent::ReplayDone { filter_id });
277 }
278 Some(MultiFilterSubscriptionEvent::ReplayStatements {
279 filter_id,
280 statements: batch.statements,
281 })
282 }
283
284 fn new_statement_event(
285 &mut self,
286 hash: sp_statement_store::Hash,
287 encoded: Vec<u8>,
288 filter_ids: &HashSet<FilterId>,
289 ) -> Option<MultiFilterSubscriptionEvent> {
290 let matched_filter_ids: Vec<FilterId> = filter_ids.iter().copied().collect();
291
292 if matched_filter_ids.is_empty() {
293 return None;
294 }
295
296 Some(MultiFilterSubscriptionEvent::NewStatement(LiveStatementEvent {
297 hash,
298 encoded,
299 matched_filter_ids,
300 }))
301 }
302}
303
304#[derive(Debug, Clone)]
306pub enum MultiFilterSubscriptionEvent {
307 ReplayStatements {
309 filter_id: FilterId,
311 statements: Vec<Vec<u8>>,
313 },
314 ReplayDone {
316 filter_id: FilterId,
318 },
319 NewStatement(LiveStatementEvent),
321 Stop,
323}
324
325pub struct MultiFilterEventStream {
327 sub_id: SeqID,
328 matchers: SubscriptionsMatchersHandlers,
329 rx: async_channel::Receiver<MultiFilterSubscriptionEvent>,
330}
331
332impl Stream for MultiFilterEventStream {
333 type Item = MultiFilterSubscriptionEvent;
334
335 fn poll_next(
336 self: std::pin::Pin<&mut Self>,
337 cx: &mut std::task::Context<'_>,
338 ) -> std::task::Poll<Option<Self::Item>> {
339 self.get_mut().rx.poll_next_unpin(cx)
340 }
341}
342
343impl Drop for MultiFilterEventStream {
344 fn drop(&mut self) {
345 self.matchers
346 .send_by_seq_id(self.sub_id, MatcherMessage::Unsubscribe(self.sub_id));
347 }
348}
349
350enum MatcherMessage {
352 NewStatement(u64, Statement),
354 Subscribe { info: IndexedSubscription, tx: async_channel::Sender<StatementEvent> },
356 SubscribeEmpty {
358 seq_id: SeqID,
359 snapshot_provider: Arc<dyn ReplaySnapshotProvider>,
360 tx: async_channel::Sender<MultiFilterSubscriptionEvent>,
361 },
362 RegisterFilter {
365 sub_id: SeqID,
366 filter_id: FilterId,
367 filter: OptimizedTopicFilter,
368 watermark: u64,
369 result_tx: async_channel::Sender<std::result::Result<(), AddFilterError>>,
370 },
371 RemoveFilter { sub_id: SeqID, filter_id: FilterId },
373
374 Unsubscribe(SeqID),
376}
377
378pub struct SubscriptionsHandle {
380 id_sequence: AtomicU64,
383 matchers: SubscriptionsMatchersHandlers,
385}
386
387impl SubscriptionsHandle {
388 pub(crate) fn new(
390 task_spawner: Box<dyn SpawnNamed>,
391 num_matcher_workers: usize,
392 ) -> SubscriptionsHandle {
393 let mut subscriptions_matchers_senders = Vec::with_capacity(num_matcher_workers);
394
395 for task in 0..num_matcher_workers {
396 let (subscription_matcher_sender, subscription_matcher_receiver) =
397 async_channel::bounded(MATCHERS_TASK_CHANNEL_BUFFER_SIZE);
398 subscriptions_matchers_senders.push(subscription_matcher_sender);
399 task_spawner.spawn_blocking(
400 "statement-store-subscription-filters",
401 Some("statement-store"),
402 Box::pin(async move {
403 let mut subscriptions = SubscriptionsInfo::new();
404 log::debug!(
405 target: LOG_TARGET,
406 "Started statement subscription matcher task: {task}"
407 );
408 loop {
409 let res = subscription_matcher_receiver.recv().await;
410 match res {
411 Ok(MatcherMessage::NewStatement(seq, statement)) => {
412 subscriptions.notify_matching_filters(seq, &statement);
413 },
414 Ok(MatcherMessage::Subscribe { info, tx }) => {
415 subscriptions.subscribe(info, tx);
416 },
417 Ok(MatcherMessage::SubscribeEmpty {
418 seq_id,
419 snapshot_provider,
420 tx,
421 }) => {
422 subscriptions.subscribe_empty(seq_id, snapshot_provider, tx);
423 },
424 Ok(MatcherMessage::RegisterFilter {
425 sub_id,
426 filter_id,
427 filter,
428 watermark,
429 result_tx,
430 }) => {
431 let result = subscriptions
432 .register_filter(sub_id, filter_id, filter, watermark);
433 let registered = result.is_ok();
434 let _ = result_tx.try_send(result);
435 if registered {
436 subscriptions.drain_ready_events(sub_id);
437 }
438 },
439 Ok(MatcherMessage::RemoveFilter { sub_id, filter_id }) => {
440 subscriptions.remove_filter(sub_id, filter_id);
441 },
442 Ok(MatcherMessage::Unsubscribe(seq_id)) => {
443 subscriptions.unsubscribe(seq_id);
444 },
445 Err(_) => {
446 log::debug!(
448 target: LOG_TARGET,
449 "Statement subscription matcher channel closed: {task}"
450 );
451 break;
452 },
453 };
454 }
455 }),
456 );
457 }
458 SubscriptionsHandle {
459 id_sequence: AtomicU64::new(0),
460 matchers: SubscriptionsMatchersHandlers::new(subscriptions_matchers_senders),
461 }
462 }
463
464 fn next_id(&self) -> SeqID {
466 let id = self.id_sequence.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
467 SeqID::from(id)
468 }
469
470 pub(crate) fn subscribe(
472 &self,
473 topic_filter: OptimizedTopicFilter,
474 watermark: u64,
475 ) -> (async_channel::Sender<StatementEvent>, SubscriptionStatementsStream) {
476 let next_id = self.next_id();
477 let (tx, rx) = async_channel::bounded(SUBSCRIPTION_BUFFER_SIZE);
478 let subscription_info = IndexedSubscription {
479 topic_filter: topic_filter.clone(),
480 seq_id: next_id,
481 filter_key: SubscriptionFilterKey::Fixed,
482 watermark,
483 };
484 let subscription_tx = tx.clone();
485
486 let result = (
487 tx,
488 SubscriptionStatementsStream {
489 rx,
490 sub_id: subscription_info.seq_id,
491 matchers: self.matchers.clone(),
492 },
493 );
494
495 self.matchers.send_by_seq_id(
496 subscription_info.seq_id,
497 MatcherMessage::Subscribe { info: subscription_info, tx: subscription_tx },
498 );
499 result
500 }
501
502 pub(crate) fn subscribe_empty(
503 &self,
504 snapshot_provider: Arc<dyn ReplaySnapshotProvider>,
505 ) -> (SeqID, MultiFilterEventStream) {
506 let sub_id = self.next_id();
507 let (tx, rx) =
508 async_channel::bounded(SUBSCRIPTION_BUFFER_SIZE + STOP_RESERVE_CHANNEL_SLOTS);
509 self.matchers.send_by_seq_id(
510 sub_id,
511 MatcherMessage::SubscribeEmpty { seq_id: sub_id, snapshot_provider, tx },
512 );
513
514 let stream = MultiFilterEventStream { sub_id, matchers: self.matchers.clone(), rx };
515 (sub_id, stream)
516 }
517
518 pub(crate) fn notify(&self, seq: u64, statement: Statement) {
519 self.matchers.send_all(seq, statement);
520 }
521
522 pub(crate) fn matchers(&self) -> SubscriptionsMatchersHandlers {
523 self.matchers.clone()
524 }
525}
526
527#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
528enum SubscriptionFilterKey {
529 Fixed,
530 Dynamic(FilterId),
531}
532
533enum SubscriptionRecord {
534 SingleFilter {
535 tx: async_channel::Sender<StatementEvent>,
536 filter: OptimizedTopicFilter,
537 },
538 MultiFilter {
539 filters: HashMap<FilterId, OptimizedTopicFilter>,
540 state: MultiFilterSubscriptionState,
541 tx: async_channel::Sender<MultiFilterSubscriptionEvent>,
542 snapshot_provider: Arc<dyn ReplaySnapshotProvider>,
543 },
544}
545
546enum MatchedSubscription {
547 Statements,
548 Live(HashSet<FilterId>),
549}
550
551enum ReadyEventDelivery {
552 Continue,
553 Stopped,
554 Closed,
555}
556
557enum PostLiveSendAction {
558 None,
559 Unsubscribe,
560}
561
562type IndexedSubscriptionKey = (SeqID, SubscriptionFilterKey);
563
564struct SubscriptionsInfo {
567 subscriptions_match_all_by_topic:
576 HashMap<Topic, [HashMap<IndexedSubscriptionKey, IndexedSubscription>; MAX_TOPICS]>,
577 subscriptions_match_any_by_topic:
579 HashMap<Topic, HashMap<IndexedSubscriptionKey, IndexedSubscription>>,
580 subscriptions_any: HashMap<IndexedSubscriptionKey, IndexedSubscription>,
582 by_sub_id: HashMap<SeqID, SubscriptionRecord>,
584}
585
586#[derive(Clone, Debug)]
588struct IndexedSubscription {
589 topic_filter: OptimizedTopicFilter,
591 seq_id: SeqID,
593 filter_key: SubscriptionFilterKey,
595 watermark: u64,
598}
599
600impl SubscriptionsInfo {
601 fn new() -> SubscriptionsInfo {
602 SubscriptionsInfo {
603 subscriptions_match_all_by_topic: HashMap::new(),
604 subscriptions_match_any_by_topic: HashMap::new(),
605 subscriptions_any: HashMap::new(),
606 by_sub_id: HashMap::new(),
607 }
608 }
609
610 fn subscribe(
612 &mut self,
613 subscription_info: IndexedSubscription,
614 tx: async_channel::Sender<StatementEvent>,
615 ) {
616 self.by_sub_id.insert(
617 subscription_info.seq_id,
618 SubscriptionRecord::SingleFilter { tx, filter: subscription_info.topic_filter.clone() },
619 );
620 self.index_filter(subscription_info);
621 }
622
623 fn subscribe_empty(
624 &mut self,
625 seq_id: SeqID,
626 snapshot_provider: Arc<dyn ReplaySnapshotProvider>,
627 tx: async_channel::Sender<MultiFilterSubscriptionEvent>,
628 ) {
629 self.by_sub_id.insert(
630 seq_id,
631 SubscriptionRecord::MultiFilter {
632 filters: HashMap::new(),
633 state: MultiFilterSubscriptionState::new(),
634 tx,
635 snapshot_provider,
636 },
637 );
638 }
639
640 #[cfg(test)]
641 fn add_filter(
642 &mut self,
643 sub_id: SeqID,
644 filter_id: FilterId,
645 filter: OptimizedTopicFilter,
646 snapshot_hashes: Vec<sp_statement_store::Hash>,
647 ) {
648 self.add_filter_with_cursor(sub_id, filter_id, filter, snapshot_hashes.len() as u64);
649 self.drain_ready_events(sub_id);
650 }
651
652 fn register_filter(
653 &mut self,
654 sub_id: SeqID,
655 filter_id: FilterId,
656 filter: OptimizedTopicFilter,
657 watermark: u64,
658 ) -> std::result::Result<(), AddFilterError> {
659 let Some(SubscriptionRecord::MultiFilter { filters, .. }) = self.by_sub_id.get(&sub_id)
660 else {
661 return Err(AddFilterError::Stopped);
662 };
663 if filters.contains_key(&filter_id) {
664 return Err(AddFilterError::Stopped);
665 }
666 let output_closed = matches!(
667 self.by_sub_id.get(&sub_id),
668 Some(SubscriptionRecord::MultiFilter { tx, .. }) if tx.is_closed()
669 );
670 if output_closed {
671 self.unsubscribe(sub_id);
672 return Err(AddFilterError::Stopped);
673 }
674 self.add_filter_with_cursor(sub_id, filter_id, filter, watermark);
675 Ok(())
676 }
677
678 fn add_filter_with_cursor(
679 &mut self,
680 sub_id: SeqID,
681 filter_id: FilterId,
682 filter: OptimizedTopicFilter,
683 watermark: u64,
684 ) {
685 let filter_key = SubscriptionFilterKey::Dynamic(filter_id);
686 {
687 let Some(SubscriptionRecord::MultiFilter { filters, state, .. }) =
688 self.by_sub_id.get_mut(&sub_id)
689 else {
690 return;
691 };
692
693 let Entry::Vacant(entry) = filters.entry(filter_id) else {
694 return;
695 };
696 entry.insert(filter.clone());
697 state.record_filter_added(filter_id, filter.clone(), watermark);
698 }
699 self.index_filter(IndexedSubscription {
700 topic_filter: filter,
701 seq_id: sub_id,
702 filter_key,
703 watermark,
704 });
705 }
706
707 fn remove_filter(&mut self, sub_id: SeqID, filter_id: FilterId) {
708 let Some(record) = self.by_sub_id.get_mut(&sub_id) else {
709 return;
710 };
711 let SubscriptionRecord::MultiFilter { filters, state, .. } = record else {
712 return;
713 };
714 let Some(filter) = filters.remove(&filter_id) else {
715 return;
716 };
717 state.record_filter_removed(filter_id);
718 self.remove_indexed_filter(sub_id, SubscriptionFilterKey::Dynamic(filter_id), &filter);
719 self.drain_ready_events(sub_id);
720 }
721
722 fn send_stop(tx: &async_channel::Sender<MultiFilterSubscriptionEvent>) {
723 let _ = tx.try_send(MultiFilterSubscriptionEvent::Stop);
724 tx.close();
725 }
726
727 fn send_ready_event(
728 state: &mut MultiFilterSubscriptionState,
729 tx: &async_channel::Sender<MultiFilterSubscriptionEvent>,
730 event: MultiFilterSubscriptionEvent,
731 ) -> ReadyEventDelivery {
732 if tx.is_closed() {
733 return ReadyEventDelivery::Closed;
734 }
735 if matches!(event, MultiFilterSubscriptionEvent::Stop) {
736 Self::send_stop(tx);
737 return ReadyEventDelivery::Stopped;
738 }
739 if tx.len() >= SUBSCRIPTION_BUFFER_SIZE {
740 state.stopped = true;
741 Self::send_stop(tx);
742 return ReadyEventDelivery::Stopped;
743 }
744 match tx.try_send(event) {
745 Ok(()) => ReadyEventDelivery::Continue,
746 Err(async_channel::TrySendError::Full(_)) => {
747 state.stopped = true;
748 Self::send_stop(tx);
749 ReadyEventDelivery::Stopped
750 },
751 Err(async_channel::TrySendError::Closed(_)) => ReadyEventDelivery::Closed,
752 }
753 }
754
755 fn drain_ready_events(&mut self, sub_id: SeqID) {
756 loop {
757 let result = {
758 let Some(record) = self.by_sub_id.get_mut(&sub_id) else {
759 return;
760 };
761 let SubscriptionRecord::MultiFilter { state, tx, snapshot_provider, .. } = record
762 else {
763 return;
764 };
765 let Some(event) = state.next_event(snapshot_provider.as_ref()) else {
766 return;
767 };
768 match Self::send_ready_event(state, tx, event) {
769 ReadyEventDelivery::Continue => Ok(()),
770 ReadyEventDelivery::Stopped => return,
771 ReadyEventDelivery::Closed => Err(()),
772 }
773 };
774 if result.is_err() {
775 self.unsubscribe(sub_id);
776 return;
777 }
778 }
779 }
780
781 fn deliver_live_statement(
783 &mut self,
784 sub_id: SeqID,
785 hash: sp_statement_store::Hash,
786 encoded: Vec<u8>,
787 matched_filter_ids: HashSet<FilterId>,
788 ) {
789 let action = {
790 let Some(SubscriptionRecord::MultiFilter { state, tx, .. }) =
791 self.by_sub_id.get_mut(&sub_id)
792 else {
793 return;
794 };
795
796 match state.new_statement_event(hash, encoded, &matched_filter_ids) {
797 Some(event) => match Self::send_ready_event(state, tx, event) {
798 ReadyEventDelivery::Closed => PostLiveSendAction::Unsubscribe,
799 ReadyEventDelivery::Continue | ReadyEventDelivery::Stopped => {
800 PostLiveSendAction::None
801 },
802 },
803 None => PostLiveSendAction::None,
804 }
805 };
806
807 match action {
808 PostLiveSendAction::Unsubscribe => self.unsubscribe(sub_id),
809 PostLiveSendAction::None => {},
810 }
811 }
812
813 fn index_filter(&mut self, subscription_info: IndexedSubscription) {
814 let index_key = (subscription_info.seq_id, subscription_info.filter_key);
815 match &subscription_info.topic_filter {
816 OptimizedTopicFilter::Any => {
817 self.subscriptions_any.insert(index_key, subscription_info);
818 },
819 OptimizedTopicFilter::MatchAll(topics) => {
820 for topic in topics {
821 self.subscriptions_match_all_by_topic.entry(*topic).or_default()
822 [topics.len() - 1]
823 .insert(index_key, subscription_info.clone());
824 }
825 },
826 OptimizedTopicFilter::MatchAny(topics) => {
827 for topic in topics {
828 self.subscriptions_match_any_by_topic
829 .entry(*topic)
830 .or_default()
831 .insert(index_key, subscription_info.clone());
832 }
833 },
834 };
835 }
836
837 fn notify_matching_filters(&mut self, seq: u64, statement: &Statement) {
843 let mut matches = HashMap::new();
844 self.collect_match_all_subscribers(seq, statement, &mut matches);
845 self.collect_match_any_subscribers(seq, statement, &mut matches);
846 self.collect_any_subscribers(seq, &mut matches);
847
848 let encoded = statement.encode();
849 let bytes_to_send: Bytes = encoded.clone().into();
850 let mut needs_unsubscribing = HashSet::new();
851
852 for (sub_id, matched) in matches {
853 match matched {
854 MatchedSubscription::Statements => {
855 let Some(SubscriptionRecord::SingleFilter { tx, .. }) =
856 self.by_sub_id.get(&sub_id)
857 else {
858 continue;
859 };
860 if let Err(err) = tx.try_send(StatementEvent::NewStatements {
861 statements: vec![bytes_to_send.clone()],
862 remaining: None,
863 }) {
864 log::debug!(
865 target: LOG_TARGET,
866 "Failed to send statement to subscriber {:?}: {:?} unsubscribing it", sub_id, err
867 );
868 needs_unsubscribing.insert(sub_id);
869 }
870 },
871 MatchedSubscription::Live(filter_ids) if !filter_ids.is_empty() => {
872 self.deliver_live_statement(
873 sub_id,
874 statement.hash(),
875 encoded.clone(),
876 filter_ids,
877 );
878 },
879 _ => {},
880 }
881 }
882
883 for sub_id in needs_unsubscribing {
884 self.unsubscribe(sub_id);
885 }
886 }
887
888 fn record_match(
892 matches: &mut HashMap<SeqID, MatchedSubscription>,
893 subscription: &IndexedSubscription,
894 seq: u64,
895 ) {
896 if seq < subscription.watermark {
897 return;
898 }
899 match subscription.filter_key {
900 SubscriptionFilterKey::Fixed => {
901 matches.entry(subscription.seq_id).or_insert(MatchedSubscription::Statements);
902 },
903 SubscriptionFilterKey::Dynamic(filter_id) => {
904 let entry = matches
905 .entry(subscription.seq_id)
906 .or_insert_with(|| MatchedSubscription::Live(HashSet::new()));
907 if let MatchedSubscription::Live(filter_ids) = entry {
908 filter_ids.insert(filter_id);
909 }
910 },
911 }
912 }
913
914 fn collect_match_any_subscribers(
916 &self,
917 seq: u64,
918 statement: &Statement,
919 matches: &mut HashMap<SeqID, MatchedSubscription>,
920 ) {
921 for statement_topic in statement.topics() {
922 if let Some(subscriptions) = self.subscriptions_match_any_by_topic.get(statement_topic)
923 {
924 for subscription in subscriptions.values() {
925 Self::record_match(matches, subscription, seq);
926 }
927 }
928 }
929 }
930
931 fn collect_match_all_subscribers(
933 &self,
934 seq: u64,
935 statement: &Statement,
936 matches: &mut HashMap<SeqID, MatchedSubscription>,
937 ) {
938 let num_topics = statement.topics().len();
939
940 for num_topics_to_check in 1..=num_topics {
943 for topics_combination in statement.topics().iter().combinations(num_topics_to_check) {
944 let Some(Some(topic_with_fewest)) = topics_combination
946 .iter()
947 .map(|topic| self.subscriptions_match_all_by_topic.get(*topic))
948 .min_by_key(|subscriptions| {
949 subscriptions.map_or(0, |subscriptions_by_length| {
950 subscriptions_by_length[num_topics_to_check - 1].len()
951 })
952 })
953 else {
954 continue;
955 };
956
957 for subscription in topic_with_fewest[num_topics_to_check - 1]
958 .values()
959 .filter(|subscription| subscription.topic_filter.matches(statement))
960 {
961 Self::record_match(matches, subscription, seq);
962 }
963 }
964 }
965 }
966
967 fn collect_any_subscribers(&self, seq: u64, matches: &mut HashMap<SeqID, MatchedSubscription>) {
969 for subscription in self.subscriptions_any.values() {
970 Self::record_match(matches, subscription, seq);
971 }
972 }
973
974 fn unsubscribe(&mut self, id: SeqID) {
976 let Some(entry) = self.by_sub_id.remove(&id) else {
977 return;
978 };
979
980 match entry {
981 SubscriptionRecord::SingleFilter { filter, .. } => {
982 self.remove_indexed_filter(id, SubscriptionFilterKey::Fixed, &filter);
983 },
984 SubscriptionRecord::MultiFilter { filters, .. } => {
985 for (filter_id, filter) in filters {
986 self.remove_indexed_filter(
987 id,
988 SubscriptionFilterKey::Dynamic(filter_id),
989 &filter,
990 );
991 }
992 },
993 }
994 }
995
996 fn remove_indexed_filter(
997 &mut self,
998 id: SeqID,
999 filter_key: SubscriptionFilterKey,
1000 filter: &OptimizedTopicFilter,
1001 ) {
1002 let topics = match filter {
1003 OptimizedTopicFilter::Any => {
1004 self.subscriptions_any.remove(&(id, filter_key));
1005 return;
1006 },
1007 OptimizedTopicFilter::MatchAll(topics) => topics,
1008 OptimizedTopicFilter::MatchAny(topics) => topics,
1009 };
1010
1011 for topic in topics {
1013 if let Entry::Occupied(mut entry) = self.subscriptions_match_any_by_topic.entry(*topic)
1015 {
1016 entry.get_mut().remove(&(id, filter_key));
1017 if entry.get().is_empty() {
1018 entry.remove();
1019 }
1020 }
1021 if let Entry::Occupied(mut entry) = self.subscriptions_match_all_by_topic.entry(*topic)
1023 {
1024 for subscriptions in entry.get_mut().iter_mut() {
1025 if subscriptions.remove(&(id, filter_key)).is_some() {
1026 break;
1027 }
1028 }
1029 if entry.get().iter().all(|s| s.is_empty()) {
1030 entry.remove();
1031 }
1032 }
1033 }
1034 }
1035}
1036
1037#[derive(Clone)]
1039pub struct SubscriptionsMatchersHandlers {
1040 matchers: Vec<async_channel::Sender<MatcherMessage>>,
1042}
1043
1044impl SubscriptionsMatchersHandlers {
1045 fn new(matchers: Vec<async_channel::Sender<MatcherMessage>>) -> SubscriptionsMatchersHandlers {
1047 SubscriptionsMatchersHandlers { matchers }
1048 }
1049
1050 fn send_by_seq_id(&self, id: SeqID, message: MatcherMessage) {
1052 if let Err(err) = self.try_send_by_seq_id(id, message) {
1055 log::error!(
1056 target: LOG_TARGET,
1057 "Failed to send statement to matcher task: {:?}", err
1058 );
1059 }
1060 }
1061
1062 fn try_send_by_seq_id(
1063 &self,
1064 id: SeqID,
1065 message: MatcherMessage,
1066 ) -> std::result::Result<(), async_channel::TrySendError<MatcherMessage>> {
1067 self.sender_by_seq_id(id).try_send(message)
1068 }
1069
1070 fn sender_by_seq_id(&self, id: SeqID) -> async_channel::Sender<MatcherMessage> {
1071 let index: u64 = id.into();
1072 self.matchers[index as usize % self.matchers.len()].clone()
1073 }
1074
1075 fn send_all(&self, seq: u64, statement: Statement) {
1077 for sender in &self.matchers {
1078 if let Err(err) =
1079 sender.send_blocking(MatcherMessage::NewStatement(seq, statement.clone()))
1080 {
1081 log::error!(
1082 target: LOG_TARGET,
1083 "Failed to send message to matcher task: {:?}", err
1084 );
1085 }
1086 }
1087 }
1088}
1089
1090pub struct SubscriptionStatementsStream {
1092 pub rx: async_channel::Receiver<StatementEvent>,
1094 sub_id: SeqID,
1096 matchers: SubscriptionsMatchersHandlers,
1098}
1099
1100impl Drop for SubscriptionStatementsStream {
1102 fn drop(&mut self) {
1103 self.matchers
1104 .send_by_seq_id(self.sub_id, MatcherMessage::Unsubscribe(self.sub_id));
1105 }
1106}
1107
1108impl Stream for SubscriptionStatementsStream {
1109 type Item = StatementEvent;
1110
1111 fn poll_next(
1112 mut self: std::pin::Pin<&mut Self>,
1113 cx: &mut std::task::Context<'_>,
1114 ) -> std::task::Poll<Option<Self::Item>> {
1115 self.rx.poll_next_unpin(cx)
1116 }
1117}
1118
1119#[cfg(test)]
1120mod tests {
1121
1122 use crate::tests::signed_statement;
1123
1124 use super::*;
1125 use sp_core::Decode;
1126 use sp_statement_store::Topic;
1127 use std::{
1128 sync::{mpsc, Mutex as StdMutex},
1129 thread,
1130 time::{Duration, Instant},
1131 };
1132
1133 fn unwrap_statement(item: StatementEvent) -> Bytes {
1134 match item {
1135 StatementEvent::NewStatements { mut statements, .. } => {
1136 assert_eq!(statements.len(), 1, "Expected exactly one statement in batch");
1137 statements.remove(0)
1138 },
1139 }
1140 }
1141
1142 fn fixed_subscription(seq_id: u64, topic_filter: OptimizedTopicFilter) -> IndexedSubscription {
1143 IndexedSubscription {
1144 topic_filter,
1145 seq_id: SeqID::from(seq_id),
1146 filter_key: SubscriptionFilterKey::Fixed,
1147 watermark: 0,
1148 }
1149 }
1150
1151 fn live_event_for(statement: &Statement, filter_ids: Vec<FilterId>) -> LiveStatementEvent {
1152 LiveStatementEvent {
1153 hash: statement.hash(),
1154 encoded: statement.encode(),
1155 matched_filter_ids: filter_ids,
1156 }
1157 }
1158
1159 struct TestReplaySnapshotProvider {
1160 statements: HashMap<sp_statement_store::Hash, Vec<u8>>,
1161 snapshot_hashes: Vec<sp_statement_store::Hash>,
1162 batch_len: u64,
1163 }
1164
1165 impl TestReplaySnapshotProvider {
1166 fn with_snapshot(snapshot: &[Statement], statements: &[Statement]) -> Self {
1167 Self {
1168 statements: statements
1169 .iter()
1170 .map(|statement| (statement.hash(), statement.encode()))
1171 .collect(),
1172 snapshot_hashes: snapshot.iter().map(Statement::hash).collect(),
1173 batch_len: snapshot.len() as u64,
1174 }
1175 }
1176 }
1177
1178 impl ReplaySnapshotProvider for TestReplaySnapshotProvider {
1179 fn register_replay(&self, enqueue: &mut dyn FnMut(u64) -> bool) -> Result<Option<u64>> {
1180 let watermark = self.snapshot_hashes.len() as u64;
1181 Ok(enqueue(watermark).then_some(watermark))
1182 }
1183
1184 fn replay_batch(
1185 &self,
1186 _filter: &OptimizedTopicFilter,
1187 cursor: u64,
1188 watermark: u64,
1189 ) -> Result<ReplayBatch> {
1190 let end = watermark.min(self.snapshot_hashes.len() as u64).min(cursor + self.batch_len);
1191 let statements = self.snapshot_hashes[cursor as usize..end as usize]
1192 .iter()
1193 .filter_map(|hash| self.statements.get(hash).cloned())
1194 .collect();
1195 Ok(ReplayBatch { statements, cursor: end, done: end >= watermark })
1196 }
1197 }
1198
1199 struct BlockingReplaySnapshotProvider {
1200 statements: HashMap<sp_statement_store::Hash, Vec<u8>>,
1201 snapshot_hashes: Vec<sp_statement_store::Hash>,
1202 scan_started: mpsc::SyncSender<()>,
1203 continue_scan: StdMutex<mpsc::Receiver<()>>,
1204 }
1205
1206 impl ReplaySnapshotProvider for BlockingReplaySnapshotProvider {
1207 fn register_replay(&self, enqueue: &mut dyn FnMut(u64) -> bool) -> Result<Option<u64>> {
1208 let watermark = self.snapshot_hashes.len() as u64;
1209 Ok(enqueue(watermark).then_some(watermark))
1210 }
1211
1212 fn replay_batch(
1213 &self,
1214 _filter: &OptimizedTopicFilter,
1215 cursor: u64,
1216 watermark: u64,
1217 ) -> Result<ReplayBatch> {
1218 self.scan_started.send(()).expect("test receiver remains open");
1219 self.continue_scan
1220 .lock()
1221 .expect("test mutex is not poisoned")
1222 .recv()
1223 .expect("test sender remains open");
1224 let end = watermark.min(self.snapshot_hashes.len() as u64);
1225 let statements = self.snapshot_hashes[cursor as usize..end as usize]
1226 .iter()
1227 .filter_map(|hash| self.statements.get(hash).cloned())
1228 .collect();
1229 Ok(ReplayBatch { statements, cursor: end, done: end >= watermark })
1230 }
1231 }
1232
1233 struct ReplayLoadBlockingProvider {
1234 body: Vec<u8>,
1235 load_started: mpsc::SyncSender<()>,
1236 continue_load: StdMutex<mpsc::Receiver<()>>,
1237 }
1238
1239 impl ReplaySnapshotProvider for ReplayLoadBlockingProvider {
1240 fn register_replay(&self, enqueue: &mut dyn FnMut(u64) -> bool) -> Result<Option<u64>> {
1241 Ok(enqueue(1).then_some(1))
1242 }
1243
1244 fn replay_batch(
1245 &self,
1246 _filter: &OptimizedTopicFilter,
1247 cursor: u64,
1248 watermark: u64,
1249 ) -> Result<ReplayBatch> {
1250 assert_eq!(cursor, 0);
1251 assert_eq!(watermark, 1);
1252 self.load_started.send(()).expect("test receiver remains open");
1253 self.continue_load
1254 .lock()
1255 .expect("test mutex is not poisoned")
1256 .recv()
1257 .expect("test sender remains open");
1258 Ok(ReplayBatch { statements: vec![self.body.clone()], cursor: 1, done: true })
1259 }
1260 }
1261
1262 fn recv_multi_filter_event(
1263 stream: &MultiFilterEventStream,
1264 timeout: Duration,
1265 ) -> Option<MultiFilterSubscriptionEvent> {
1266 let deadline = Instant::now() + timeout;
1267 loop {
1268 match stream.rx.try_recv() {
1269 Ok(event) => return Some(event),
1270 Err(async_channel::TryRecvError::Closed) => return None,
1271 Err(async_channel::TryRecvError::Empty) if Instant::now() < deadline => {
1272 thread::sleep(Duration::from_millis(1));
1273 },
1274 Err(async_channel::TryRecvError::Empty) => return None,
1275 }
1276 }
1277 }
1278
1279 #[test]
1280 fn multi_filter_replays_before_live_submissions_committed_during_snapshot() {
1281 let subscriptions =
1282 SubscriptionsHandle::new(Box::new(sp_core::testing::TaskExecutor::new()), 1);
1283 let filter_id = FilterId::new(0);
1284 let replayed = signed_statement(41);
1285 let delayed = signed_statement(40);
1286 let delayed_hash = delayed.hash();
1287 let live = signed_statement(42);
1288 let (scan_started_tx, scan_started_rx) = mpsc::sync_channel(1);
1289 let (continue_scan_tx, continue_scan_rx) = mpsc::sync_channel(1);
1290 let provider = Arc::new(BlockingReplaySnapshotProvider {
1291 statements: [(replayed.hash(), replayed.encode())].into_iter().collect(),
1292 snapshot_hashes: vec![replayed.hash()],
1293 scan_started: scan_started_tx,
1294 continue_scan: StdMutex::new(continue_scan_rx),
1295 });
1296 let (sub_id, stream) = subscriptions.subscribe_empty(provider.clone());
1297 let handle = SubscriptionHandle {
1298 sub_id,
1299 inner: Arc::new(Mutex::new(SubscriptionHandleInner::new())),
1300 matchers: subscriptions.matchers(),
1301 snapshot_provider: provider,
1302 };
1303
1304 let add_filter = thread::spawn(move || handle.add_filter(OptimizedTopicFilter::Any));
1305 scan_started_rx.recv().expect("snapshot scan starts");
1306
1307 subscriptions.notify(0, replayed.clone());
1309 subscriptions.notify(1, delayed);
1310 subscriptions.notify(2, live.clone());
1311 continue_scan_tx.send(()).expect("snapshot scan is still waiting");
1312 assert_eq!(add_filter.join().expect("add-filter thread does not panic"), Ok(filter_id));
1313
1314 assert!(matches!(
1315 recv_multi_filter_event(&stream, Duration::from_secs(1)),
1316 Some(MultiFilterSubscriptionEvent::ReplayStatements { statements, .. })
1317 if statements == vec![replayed.encode()]
1318 ));
1319 assert!(matches!(
1320 recv_multi_filter_event(&stream, Duration::from_secs(1)),
1321 Some(MultiFilterSubscriptionEvent::ReplayDone { filter_id: done }) if done == filter_id
1322 ));
1323 assert!(matches!(
1324 recv_multi_filter_event(&stream, Duration::from_secs(1)),
1325 Some(MultiFilterSubscriptionEvent::NewStatement(event))
1326 if event.hash == delayed_hash && event.matched_filter_ids == vec![filter_id]
1327 ));
1328 assert!(matches!(
1329 recv_multi_filter_event(&stream, Duration::from_secs(1)),
1330 Some(MultiFilterSubscriptionEvent::NewStatement(event))
1331 if event.hash == live.hash() && event.matched_filter_ids == vec![filter_id]
1332 ));
1333 assert!(recv_multi_filter_event(&stream, Duration::from_millis(10)).is_none());
1334 }
1335
1336 #[test]
1337 fn add_filter_returns_before_matcher_drains_replay() {
1338 let subscriptions =
1339 SubscriptionsHandle::new(Box::new(sp_core::testing::TaskExecutor::new()), 1);
1340 let statement = signed_statement(43);
1341 let (load_started_tx, load_started_rx) = mpsc::sync_channel(1);
1342 let (continue_load_tx, continue_load_rx) = mpsc::sync_channel(1);
1343 let provider = Arc::new(ReplayLoadBlockingProvider {
1344 body: statement.encode(),
1345 load_started: load_started_tx,
1346 continue_load: StdMutex::new(continue_load_rx),
1347 });
1348 let (sub_id, _stream) = subscriptions.subscribe_empty(provider.clone());
1349 let handle = SubscriptionHandle {
1350 sub_id,
1351 inner: Arc::new(Mutex::new(SubscriptionHandleInner::new())),
1352 matchers: subscriptions.matchers(),
1353 snapshot_provider: provider,
1354 };
1355 let (result_tx, result_rx) = mpsc::sync_channel(1);
1356 let add_filter = thread::spawn(move || {
1357 result_tx
1358 .send(handle.add_filter(OptimizedTopicFilter::Any))
1359 .expect("test receiver remains open");
1360 });
1361
1362 load_started_rx.recv().expect("matcher starts loading replay");
1363 let result = result_rx.recv_timeout(Duration::from_secs(1));
1364 continue_load_tx.send(()).expect("replay load is still waiting");
1365 add_filter.join().expect("add-filter thread does not panic");
1366 assert_eq!(result, Ok(Ok(FilterId::new(0))));
1367 }
1368
1369 #[test]
1370 fn multi_filter_delivers_re_admitted_hash_skipped_during_replay() {
1371 let mut subscriptions = SubscriptionsInfo::new();
1372 let sub_id = SeqID::from(12);
1373 let filter_id = FilterId::new(1);
1374 let topic = Topic::from([9u8; 32]);
1375 let filter = OptimizedTopicFilter::MatchAny(vec![topic].into_iter().collect());
1376 let (tx, rx) = async_channel::bounded::<MultiFilterSubscriptionEvent>(10);
1377 let mut statement = signed_statement(42);
1378 statement.set_topic(0, topic);
1379 let provider = Arc::new(TestReplaySnapshotProvider::with_snapshot(
1382 std::slice::from_ref(&statement),
1383 &[],
1384 ));
1385
1386 subscriptions.subscribe_empty(sub_id, provider, tx);
1387 subscriptions.add_filter(sub_id, filter_id, filter, vec![statement.hash()]);
1388
1389 assert!(matches!(
1391 rx.try_recv(),
1392 Ok(MultiFilterSubscriptionEvent::ReplayDone { filter_id: done }) if done == filter_id
1393 ));
1394
1395 subscriptions.notify_matching_filters(1, &statement);
1398
1399 match rx.try_recv() {
1400 Ok(MultiFilterSubscriptionEvent::NewStatement(event)) => {
1401 assert_eq!(event.hash, statement.hash());
1402 assert_eq!(event.matched_filter_ids, vec![filter_id]);
1403 },
1404 other => {
1405 panic!("statement skipped during replay must be delivered live, got {other:?}")
1406 },
1407 }
1408
1409 subscriptions.notify_matching_filters(2, &statement);
1410 assert!(matches!(
1411 rx.try_recv(),
1412 Ok(MultiFilterSubscriptionEvent::NewStatement(event))
1413 if event.hash == statement.hash() && event.matched_filter_ids == vec![filter_id]
1414 ));
1415 }
1416
1417 #[test]
1418 fn multi_filter_replay_resumes_from_the_returned_cursor() {
1419 let mut subscriptions = SubscriptionsInfo::new();
1420 let sub_id = SeqID::from(11);
1421 let filter_id = FilterId::new(1);
1422 let topic = Topic::from([9u8; 32]);
1423 let filter = OptimizedTopicFilter::MatchAny(vec![topic].into_iter().collect());
1424 let (tx, rx) = async_channel::bounded::<MultiFilterSubscriptionEvent>(10);
1425 let replayed: Vec<Statement> = (0..3u8)
1426 .map(|seed| {
1427 let mut statement = signed_statement(seed);
1428 statement.set_topic(0, topic);
1429 statement
1430 })
1431 .collect();
1432 let mut provider = TestReplaySnapshotProvider::with_snapshot(&replayed, &replayed);
1433 provider.batch_len = 1;
1434
1435 subscriptions.subscribe_empty(sub_id, Arc::new(provider), tx);
1436 subscriptions.add_filter(
1437 sub_id,
1438 filter_id,
1439 filter,
1440 replayed.iter().map(Statement::hash).collect(),
1441 );
1442
1443 let mut delivered = Vec::new();
1444 let mut replay_done = 0;
1445 while let Ok(event) = rx.try_recv() {
1446 match event {
1447 MultiFilterSubscriptionEvent::ReplayStatements { filter_id: id, statements } => {
1448 assert_eq!(id, filter_id);
1449 delivered.extend(statements);
1450 },
1451 MultiFilterSubscriptionEvent::ReplayDone { filter_id: id } => {
1452 assert_eq!(id, filter_id);
1453 replay_done += 1;
1454 },
1455 other => panic!("expected replay events, got {other:?}"),
1456 }
1457 }
1458 assert_eq!(delivered, replayed.iter().map(Statement::encode).collect::<Vec<_>>());
1459 assert_eq!(replay_done, 1);
1460 }
1461
1462 #[test]
1463 fn multi_filter_pushes_ready_live_events_without_request_next() {
1464 let mut subscriptions = SubscriptionsInfo::new();
1465 let sub_id = SeqID::from(7);
1466 let filter_id = FilterId::new(1);
1467 let topic = Topic::from([9u8; 32]);
1468 let filter = OptimizedTopicFilter::MatchAny(vec![topic].into_iter().collect());
1469 let (tx, rx) = async_channel::bounded::<MultiFilterSubscriptionEvent>(10);
1470 let mut statement = signed_statement(42);
1471 statement.set_topic(0, topic);
1472 let provider = Arc::new(TestReplaySnapshotProvider::with_snapshot(
1473 &[],
1474 std::slice::from_ref(&statement),
1475 ));
1476
1477 subscriptions.subscribe_empty(sub_id, provider, tx);
1478 subscriptions.add_filter(sub_id, filter_id, filter, vec![]);
1479 assert!(matches!(
1480 rx.try_recv(),
1481 Ok(MultiFilterSubscriptionEvent::ReplayDone { filter_id: done_filter })
1482 if done_filter == filter_id
1483 ));
1484
1485 subscriptions.notify_matching_filters(0, &statement);
1486
1487 match rx.try_recv() {
1488 Ok(MultiFilterSubscriptionEvent::NewStatement(event)) => {
1489 assert_eq!(event.hash, statement.hash());
1490 assert_eq!(event.matched_filter_ids, vec![filter_id]);
1491 },
1492 other => panic!("expected pushed live statement, got {other:?}"),
1493 }
1494 }
1495
1496 #[test]
1497 fn multi_filter_reserves_output_slot_for_stop() {
1498 let mut subscriptions = SubscriptionsInfo::new();
1499 let sub_id = SeqID::from(8);
1500 let filter_id = FilterId::new(1);
1501 let topic = Topic::from([9u8; 32]);
1502 let filter = OptimizedTopicFilter::MatchAny(vec![topic].into_iter().collect());
1503 let mut statements =
1504 Vec::with_capacity(SUBSCRIPTION_BUFFER_SIZE + STOP_RESERVE_CHANNEL_SLOTS);
1505 for seed in 0..=SUBSCRIPTION_BUFFER_SIZE as u64 {
1506 let mut statement = signed_statement(seed as u8);
1507 statement.set_topic(0, topic);
1508 statements.push(statement);
1509 }
1510 let provider = Arc::new(TestReplaySnapshotProvider::with_snapshot(&[], &statements));
1511 let (tx, rx) = async_channel::bounded::<MultiFilterSubscriptionEvent>(
1512 SUBSCRIPTION_BUFFER_SIZE + STOP_RESERVE_CHANNEL_SLOTS,
1513 );
1514
1515 subscriptions.subscribe_empty(sub_id, provider, tx);
1516 subscriptions.add_filter(sub_id, filter_id, filter, vec![]);
1517 assert!(matches!(
1518 rx.try_recv(),
1519 Ok(MultiFilterSubscriptionEvent::ReplayDone { filter_id: done_filter })
1520 if done_filter == filter_id
1521 ));
1522
1523 for statement in statements.iter().take(SUBSCRIPTION_BUFFER_SIZE) {
1524 subscriptions.notify_matching_filters(0, statement);
1525 }
1526 assert_eq!(rx.len(), SUBSCRIPTION_BUFFER_SIZE);
1527
1528 subscriptions.notify_matching_filters(0, &statements[SUBSCRIPTION_BUFFER_SIZE]);
1529 assert_eq!(rx.len(), SUBSCRIPTION_BUFFER_SIZE + STOP_RESERVE_CHANNEL_SLOTS);
1530
1531 for _ in 0..SUBSCRIPTION_BUFFER_SIZE {
1532 assert!(matches!(rx.try_recv(), Ok(MultiFilterSubscriptionEvent::NewStatement(_))));
1533 }
1534 assert!(matches!(rx.try_recv(), Ok(MultiFilterSubscriptionEvent::Stop)));
1535 assert!(rx.is_closed());
1536 }
1537
1538 #[test]
1539 fn multi_filter_closed_channel_is_reported_as_closed_before_buffer_limit() {
1540 let mut state = MultiFilterSubscriptionState::new();
1541 let (tx, rx) = async_channel::bounded::<MultiFilterSubscriptionEvent>(
1542 SUBSCRIPTION_BUFFER_SIZE + STOP_RESERVE_CHANNEL_SLOTS,
1543 );
1544 for seed in 0..SUBSCRIPTION_BUFFER_SIZE {
1545 tx.try_send(MultiFilterSubscriptionEvent::NewStatement(live_event_for(
1546 &signed_statement(seed as u8),
1547 vec![FilterId::new(1)],
1548 )))
1549 .expect("channel capacity exceeds subscription buffer size; qed");
1550 }
1551 drop(rx);
1552
1553 assert!(matches!(
1554 SubscriptionsInfo::send_ready_event(
1555 &mut state,
1556 &tx,
1557 MultiFilterSubscriptionEvent::NewStatement(live_event_for(
1558 &signed_statement(42),
1559 vec![FilterId::new(1)],
1560 )),
1561 ),
1562 ReadyEventDelivery::Closed
1563 ));
1564 assert!(matches!(
1565 SubscriptionsInfo::send_ready_event(
1566 &mut state,
1567 &tx,
1568 MultiFilterSubscriptionEvent::Stop,
1569 ),
1570 ReadyEventDelivery::Closed
1571 ));
1572 assert!(!state.stopped);
1573 }
1574
1575 #[test]
1576 fn test_subscribe_unsubscribe() {
1577 let mut subscriptions = SubscriptionsInfo::new();
1578
1579 let (tx1, _rx1) = async_channel::bounded::<StatementEvent>(10);
1580 let topic1 = Topic::from([8u8; 32]);
1581 let topic2 = Topic::from([9u8; 32]);
1582 let sub_info1 = fixed_subscription(
1583 1,
1584 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1585 );
1586 subscriptions.subscribe(sub_info1.clone(), tx1);
1587 assert!(subscriptions.subscriptions_match_all_by_topic.contains_key(&topic1));
1588 assert!(subscriptions.subscriptions_match_all_by_topic.contains_key(&topic2));
1589 assert!(subscriptions.by_sub_id.contains_key(&sub_info1.seq_id));
1590 assert!(!subscriptions
1591 .subscriptions_any
1592 .contains_key(&(sub_info1.seq_id, sub_info1.filter_key)));
1593
1594 subscriptions.unsubscribe(sub_info1.seq_id);
1595 assert!(!subscriptions.subscriptions_match_all_by_topic.contains_key(&topic1));
1596 assert!(!subscriptions.subscriptions_match_all_by_topic.contains_key(&topic2));
1597 }
1598
1599 #[test]
1600 fn test_subscribe_any() {
1601 let mut subscriptions = SubscriptionsInfo::new();
1602 let (tx1, _rx1) = async_channel::bounded::<StatementEvent>(10);
1603 let sub_info1 = fixed_subscription(1, OptimizedTopicFilter::Any);
1604 subscriptions.subscribe(sub_info1.clone(), tx1);
1605 assert!(subscriptions
1606 .subscriptions_any
1607 .contains_key(&(sub_info1.seq_id, sub_info1.filter_key)));
1608 assert!(subscriptions.by_sub_id.contains_key(&sub_info1.seq_id));
1609 subscriptions.unsubscribe(sub_info1.seq_id);
1610 assert!(!subscriptions
1611 .subscriptions_any
1612 .contains_key(&(sub_info1.seq_id, sub_info1.filter_key)));
1613 }
1614
1615 #[test]
1616 fn test_subscribe_match_any() {
1617 let mut subscriptions = SubscriptionsInfo::new();
1618
1619 let (tx1, _rx1) = async_channel::bounded::<StatementEvent>(10);
1620 let topic1 = Topic::from([8u8; 32]);
1621 let topic2 = Topic::from([9u8; 32]);
1622 let sub_info1 = fixed_subscription(
1623 1,
1624 OptimizedTopicFilter::MatchAny(vec![topic1, topic2].into_iter().collect()),
1625 );
1626 subscriptions.subscribe(sub_info1.clone(), tx1);
1627 assert!(subscriptions.subscriptions_match_any_by_topic.contains_key(&topic1));
1628 assert!(subscriptions.subscriptions_match_any_by_topic.contains_key(&topic2));
1629 assert!(subscriptions.by_sub_id.contains_key(&sub_info1.seq_id));
1630 assert!(!subscriptions
1631 .subscriptions_any
1632 .contains_key(&(sub_info1.seq_id, sub_info1.filter_key)));
1633
1634 subscriptions.unsubscribe(sub_info1.seq_id);
1635 assert!(!subscriptions.subscriptions_match_all_by_topic.contains_key(&topic1));
1636 assert!(!subscriptions.subscriptions_match_all_by_topic.contains_key(&topic2));
1637 }
1638
1639 #[test]
1640 fn test_notify_matching_filters_any() {
1641 let mut subscriptions = SubscriptionsInfo::new();
1642
1643 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
1644 let sub_info1 = fixed_subscription(1, OptimizedTopicFilter::Any);
1645 subscriptions.subscribe(sub_info1.clone(), tx1);
1646
1647 let statement = signed_statement(1);
1648 subscriptions.notify_matching_filters(0, &statement);
1649
1650 let received = unwrap_statement(rx1.try_recv().expect("Should receive statement"));
1651 let decoded_statement: Statement =
1652 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1653 assert_eq!(decoded_statement, statement);
1654 }
1655
1656 #[test]
1657 fn test_notify_matching_filters_match_all() {
1658 let mut subscriptions = SubscriptionsInfo::new();
1659
1660 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
1661 let topic1 = Topic::from([8u8; 32]);
1662 let topic2 = Topic::from([9u8; 32]);
1663 let sub_info1 = fixed_subscription(
1664 1,
1665 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1666 );
1667 subscriptions.subscribe(sub_info1.clone(), tx1);
1668
1669 let mut statement = signed_statement(1);
1670 statement.set_topic(0, topic2);
1671 subscriptions.notify_matching_filters(0, &statement);
1672
1673 assert!(rx1.try_recv().is_err());
1675
1676 statement.set_topic(1, topic1);
1677 subscriptions.notify_matching_filters(1, &statement);
1678
1679 let received = unwrap_statement(rx1.try_recv().expect("Should receive statement"));
1680 let decoded_statement: Statement =
1681 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1682 assert_eq!(decoded_statement, statement);
1683 }
1684
1685 #[test]
1686 fn test_notify_matching_filters_match_any() {
1687 let mut subscriptions = SubscriptionsInfo::new();
1688 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
1689 let (tx2, rx2) = async_channel::bounded::<StatementEvent>(10);
1690
1691 let topic1 = Topic::from([8u8; 32]);
1692 let topic2 = Topic::from([9u8; 32]);
1693 let sub_info1 = fixed_subscription(
1694 1,
1695 OptimizedTopicFilter::MatchAny(vec![topic1, topic2].into_iter().collect()),
1696 );
1697
1698 let sub_info2 = fixed_subscription(
1699 2,
1700 OptimizedTopicFilter::MatchAny(vec![topic2].into_iter().collect()),
1701 );
1702
1703 subscriptions.subscribe(sub_info1.clone(), tx1);
1704 subscriptions.subscribe(sub_info2.clone(), tx2);
1705
1706 let mut statement = signed_statement(1);
1707 statement.set_topic(0, topic1);
1708 statement.set_topic(1, topic2);
1709 subscriptions.notify_matching_filters(0, &statement);
1710
1711 let received = unwrap_statement(rx1.try_recv().expect("Should receive statement"));
1712 let decoded_statement: Statement =
1713 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1714 assert_eq!(decoded_statement, statement);
1715
1716 let received = unwrap_statement(rx2.try_recv().expect("Should receive statement"));
1717 let decoded_statement: Statement =
1718 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1719 assert_eq!(decoded_statement, statement);
1720 }
1721
1722 #[tokio::test]
1723 async fn test_subscription_handle_with_different_workers_number() {
1724 for num_workers in 1..5 {
1725 let subscriptions_handle = SubscriptionsHandle::new(
1726 Box::new(sp_core::testing::TaskExecutor::new()),
1727 num_workers,
1728 );
1729
1730 let topic1 = Topic::from([8u8; 32]);
1731 let topic2 = Topic::from([9u8; 32]);
1732
1733 let streams = (0..5)
1734 .into_iter()
1735 .map(|_| {
1736 subscriptions_handle.subscribe(
1737 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1738 0,
1739 )
1740 })
1741 .collect::<Vec<_>>();
1742
1743 let mut statement = signed_statement(1);
1744 statement.set_topic(0, topic2);
1745 subscriptions_handle.notify(0, statement.clone());
1746
1747 statement.set_topic(1, topic1);
1748 subscriptions_handle.notify(1, statement.clone());
1749
1750 for (_tx, mut stream) in streams {
1751 let received =
1752 unwrap_statement(stream.next().await.expect("Should receive statement"));
1753 let decoded_statement: Statement =
1754 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1755 assert_eq!(decoded_statement, statement);
1756 }
1757 }
1758 }
1759
1760 #[tokio::test]
1761 async fn test_handle_unsubscribe() {
1762 let subscriptions_handle =
1763 SubscriptionsHandle::new(Box::new(sp_core::testing::TaskExecutor::new()), 2);
1764
1765 let topic1 = Topic::from([8u8; 32]);
1766 let topic2 = Topic::from([9u8; 32]);
1767
1768 let (tx, mut stream) = subscriptions_handle.subscribe(
1769 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1770 0,
1771 );
1772
1773 let mut statement = signed_statement(1);
1774 statement.set_topic(0, topic1);
1775 statement.set_topic(1, topic2);
1776
1777 subscriptions_handle.notify(0, statement.clone());
1779
1780 let received = unwrap_statement(stream.next().await.expect("Should receive statement"));
1781 let decoded_statement: Statement =
1782 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1783 assert_eq!(decoded_statement, statement);
1784
1785 drop(stream);
1787
1788 tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
1790
1791 let mut statement2 = signed_statement(2);
1793 statement2.set_topic(0, topic1);
1794 statement2.set_topic(1, topic2);
1795 subscriptions_handle.notify(1, statement2.clone());
1796
1797 tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
1800
1801 assert!(tx.is_closed(), "Sender should be closed after unsubscribe");
1804 }
1805
1806 #[test]
1807 fn test_unsubscribe_nonexistent() {
1808 let mut subscriptions = SubscriptionsInfo::new();
1809 subscriptions.unsubscribe(SeqID::from(999));
1811 assert!(subscriptions.by_sub_id.is_empty());
1813 assert!(subscriptions.subscriptions_any.is_empty());
1814 assert!(subscriptions.subscriptions_match_all_by_topic.is_empty());
1815 assert!(subscriptions.subscriptions_match_any_by_topic.is_empty());
1816 }
1817
1818 #[test]
1819 fn test_multiple_subscriptions_same_topic() {
1820 let mut subscriptions = SubscriptionsInfo::new();
1821
1822 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
1823 let (tx2, rx2) = async_channel::bounded::<StatementEvent>(10);
1824 let topic1 = Topic::from([8u8; 32]);
1825 let topic2 = Topic::from([9u8; 32]);
1826
1827 let sub_info1 = fixed_subscription(
1828 1,
1829 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1830 );
1831 let sub_info2 = fixed_subscription(
1832 2,
1833 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1834 );
1835
1836 subscriptions.subscribe(sub_info1.clone(), tx1);
1837 subscriptions.subscribe(sub_info2.clone(), tx2);
1838
1839 assert_eq!(
1841 subscriptions
1842 .subscriptions_match_all_by_topic
1843 .get(&topic1)
1844 .unwrap()
1845 .iter()
1846 .map(|s| s.len())
1847 .sum::<usize>(),
1848 2
1849 );
1850 assert_eq!(
1851 subscriptions
1852 .subscriptions_match_all_by_topic
1853 .get(&topic2)
1854 .unwrap()
1855 .iter()
1856 .map(|s| s.len())
1857 .sum::<usize>(),
1858 2
1859 );
1860
1861 let mut statement = signed_statement(1);
1863 statement.set_topic(0, topic1);
1864 statement.set_topic(1, topic2);
1865 subscriptions.notify_matching_filters(0, &statement);
1866
1867 assert!(rx1.try_recv().is_ok());
1869 assert!(rx2.try_recv().is_ok());
1870
1871 subscriptions.unsubscribe(sub_info1.seq_id);
1873
1874 assert_eq!(
1876 subscriptions
1877 .subscriptions_match_all_by_topic
1878 .get(&topic1)
1879 .unwrap()
1880 .iter()
1881 .map(|s| s.len())
1882 .sum::<usize>(),
1883 1
1884 );
1885 assert_eq!(
1886 subscriptions
1887 .subscriptions_match_all_by_topic
1888 .get(&topic2)
1889 .unwrap()
1890 .iter()
1891 .map(|s| s.len())
1892 .sum::<usize>(),
1893 1
1894 );
1895 assert!(!subscriptions.by_sub_id.contains_key(&sub_info1.seq_id));
1896 assert!(subscriptions.by_sub_id.contains_key(&sub_info2.seq_id));
1897
1898 subscriptions.notify_matching_filters(1, &statement);
1900
1901 assert!(rx2.try_recv().is_ok());
1903 assert!(rx1.try_recv().is_err());
1904 }
1905
1906 #[test]
1907 fn test_subscriber_auto_unsubscribe_on_channel_full() {
1908 let mut subscriptions = SubscriptionsInfo::new();
1909
1910 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(1);
1912 let topic1 = Topic::from([8u8; 32]);
1913
1914 let sub_info1 = fixed_subscription(
1915 1,
1916 OptimizedTopicFilter::MatchAny(vec![topic1].into_iter().collect()),
1917 );
1918 subscriptions.subscribe(sub_info1.clone(), tx1);
1919
1920 let mut statement = signed_statement(1);
1921 statement.set_topic(0, topic1);
1922
1923 subscriptions.notify_matching_filters(0, &statement);
1925 assert!(rx1.try_recv().is_ok());
1926
1927 subscriptions.notify_matching_filters(1, &statement);
1929 subscriptions.notify_matching_filters(2, &statement);
1933
1934 assert!(!subscriptions.by_sub_id.contains_key(&sub_info1.seq_id));
1936 assert!(!subscriptions.subscriptions_match_any_by_topic.contains_key(&topic1));
1937 }
1938
1939 #[test]
1940 fn test_match_any_receives_once_per_statement() {
1941 let mut subscriptions = SubscriptionsInfo::new();
1942
1943 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
1944 let topic1 = Topic::from([8u8; 32]);
1945 let topic2 = Topic::from([9u8; 32]);
1946
1947 let sub_info1 = fixed_subscription(
1949 1,
1950 OptimizedTopicFilter::MatchAny(vec![topic1, topic2].into_iter().collect()),
1951 );
1952 subscriptions.subscribe(sub_info1.clone(), tx1);
1953
1954 let mut statement = signed_statement(1);
1956 statement.set_topic(0, topic1);
1957 statement.set_topic(1, topic2);
1958
1959 subscriptions.notify_matching_filters(0, &statement);
1960
1961 let received = unwrap_statement(rx1.try_recv().expect("Should receive statement"));
1963 let decoded_statement: Statement =
1964 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
1965 assert_eq!(decoded_statement, statement);
1966
1967 assert!(rx1.try_recv().is_err());
1969 }
1970
1971 #[test]
1972 fn test_match_all_receives_once_per_statement() {
1973 let mut subscriptions = SubscriptionsInfo::new();
1977
1978 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
1979 let (tx2, _rx2) = async_channel::bounded::<StatementEvent>(10);
1980 let (tx3, _rx3) = async_channel::bounded::<StatementEvent>(10);
1981
1982 let topic1 = Topic::from([1u8; 32]);
1983 let topic2 = Topic::from([2u8; 32]);
1984 let topic3 = Topic::from([3u8; 32]);
1985 let topic4 = Topic::from([4u8; 32]);
1986
1987 let sub_info1 = fixed_subscription(
1989 1,
1990 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
1991 );
1992 subscriptions.subscribe(sub_info1, tx1);
1993
1994 let sub_info2 = fixed_subscription(
1998 2,
1999 OptimizedTopicFilter::MatchAll(vec![topic3, topic4].into_iter().collect()),
2000 );
2001 let sub_info3 = fixed_subscription(
2002 3,
2003 OptimizedTopicFilter::MatchAll(vec![topic3, topic4].into_iter().collect()),
2004 );
2005 subscriptions.subscribe(sub_info2, tx2);
2006 subscriptions.subscribe(sub_info3, tx3);
2007
2008 let mut statement = signed_statement(1);
2010 statement.set_topic(0, topic1);
2011 statement.set_topic(1, topic2);
2012 statement.set_topic(2, topic3);
2013
2014 subscriptions.notify_matching_filters(0, &statement);
2015
2016 let received = unwrap_statement(rx1.try_recv().expect("Should receive statement"));
2018 let decoded_statement: Statement =
2019 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2020 assert_eq!(decoded_statement, statement);
2021
2022 assert!(
2023 rx1.try_recv().is_err(),
2024 "MatchAll subscriber must receive each statement only once"
2025 );
2026 }
2027
2028 #[test]
2029 fn test_match_all_with_single_topic_matches_statement_with_two_topics() {
2030 let mut subscriptions = SubscriptionsInfo::new();
2031
2032 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
2033 let topic1 = Topic::from([8u8; 32]);
2034 let topic2 = Topic::from([9u8; 32]);
2035
2036 let sub_info1 = fixed_subscription(
2038 1,
2039 OptimizedTopicFilter::MatchAll(vec![topic1].into_iter().collect()),
2040 );
2041 subscriptions.subscribe(sub_info1.clone(), tx1);
2042
2043 let mut statement = signed_statement(1);
2045 statement.set_topic(0, topic1);
2046 statement.set_topic(1, topic2);
2047
2048 subscriptions.notify_matching_filters(0, &statement);
2049
2050 let received = unwrap_statement(rx1.try_recv().expect("Should receive statement"));
2052 let decoded_statement: Statement =
2053 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2054 assert_eq!(decoded_statement, statement);
2055
2056 assert!(rx1.try_recv().is_err());
2058 }
2059
2060 #[test]
2061 fn test_match_all_no_matching_topics() {
2062 let mut subscriptions = SubscriptionsInfo::new();
2063
2064 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
2065 let topic1 = Topic::from([8u8; 32]);
2066 let topic2 = Topic::from([9u8; 32]);
2067 let topic3 = Topic::from([10u8; 32]);
2068
2069 let sub_info1 = fixed_subscription(
2070 1,
2071 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
2072 );
2073 subscriptions.subscribe(sub_info1.clone(), tx1);
2074
2075 let mut statement = signed_statement(1);
2077 statement.set_topic(0, topic3);
2078
2079 subscriptions.notify_matching_filters(0, &statement);
2080
2081 assert!(rx1.try_recv().is_err());
2083 }
2084
2085 #[test]
2086 fn test_match_all_with_unsubscribed_topic_first_in_statement() {
2087 let mut subscriptions = SubscriptionsInfo::new();
2090
2091 let (tx1, rx1) = async_channel::bounded::<StatementEvent>(10);
2092 let topic1 = Topic::from([1u8; 32]);
2094 let topic2 = Topic::from([2u8; 32]);
2096
2097 let sub_info1 = fixed_subscription(
2099 1,
2100 OptimizedTopicFilter::MatchAll(vec![topic2].into_iter().collect()),
2101 );
2102 subscriptions.subscribe(sub_info1, tx1);
2103
2104 let mut statement = signed_statement(1);
2109 statement.set_topic(0, topic1);
2110 statement.set_topic(1, topic2);
2111
2112 subscriptions.notify_matching_filters(0, &statement);
2113
2114 let received = unwrap_statement(
2116 rx1.try_recv()
2117 .expect("Should receive statement from a later matching topic combination"),
2118 );
2119 let decoded_statement: Statement =
2120 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2121 assert_eq!(decoded_statement, statement);
2122 }
2123
2124 #[tokio::test]
2125 async fn test_handle_with_match_any_filter() {
2126 let subscriptions_handle =
2127 SubscriptionsHandle::new(Box::new(sp_core::testing::TaskExecutor::new()), 2);
2128
2129 let topic1 = Topic::from([8u8; 32]);
2130 let topic2 = Topic::from([9u8; 32]);
2131
2132 let (_tx, mut stream) = subscriptions_handle.subscribe(
2133 OptimizedTopicFilter::MatchAny(vec![topic1, topic2].into_iter().collect()),
2134 0,
2135 );
2136
2137 let mut statement1 = signed_statement(1);
2139 statement1.set_topic(0, topic1);
2140 subscriptions_handle.notify(0, statement1.clone());
2141
2142 let received = unwrap_statement(stream.next().await.expect("Should receive statement"));
2143 let decoded_statement: Statement =
2144 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2145 assert_eq!(decoded_statement, statement1);
2146
2147 let mut statement2 = signed_statement(2);
2149 statement2.set_topic(0, topic2);
2150 subscriptions_handle.notify(1, statement2.clone());
2151
2152 let received = unwrap_statement(stream.next().await.expect("Should receive statement"));
2153 let decoded_statement: Statement =
2154 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2155 assert_eq!(decoded_statement, statement2);
2156 }
2157
2158 #[tokio::test]
2159 async fn test_handle_with_any_filter() {
2160 let subscriptions_handle =
2161 SubscriptionsHandle::new(Box::new(sp_core::testing::TaskExecutor::new()), 2);
2162
2163 let (_tx, mut stream) = subscriptions_handle.subscribe(OptimizedTopicFilter::Any, 0);
2164
2165 let statement1 = signed_statement(1);
2167 subscriptions_handle.notify(0, statement1.clone());
2168
2169 let received = unwrap_statement(stream.next().await.expect("Should receive statement"));
2170 let decoded_statement: Statement =
2171 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2172 assert_eq!(decoded_statement, statement1);
2173
2174 let mut statement2 = signed_statement(2);
2175 statement2.set_topic(0, Topic::from([99u8; 32]));
2176 subscriptions_handle.notify(1, statement2.clone());
2177
2178 let received = unwrap_statement(stream.next().await.expect("Should receive statement"));
2179 let decoded_statement: Statement =
2180 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2181 assert_eq!(decoded_statement, statement2);
2182 }
2183
2184 #[tokio::test]
2185 async fn test_handle_multiple_subscribers_different_filters() {
2186 let subscriptions_handle =
2187 SubscriptionsHandle::new(Box::new(sp_core::testing::TaskExecutor::new()), 2);
2188
2189 let topic1 = Topic::from([8u8; 32]);
2190 let topic2 = Topic::from([9u8; 32]);
2191
2192 let (_tx1, mut stream1) = subscriptions_handle.subscribe(
2194 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
2195 0,
2196 );
2197
2198 let (_tx2, mut stream2) = subscriptions_handle
2200 .subscribe(OptimizedTopicFilter::MatchAny(vec![topic1].into_iter().collect()), 0);
2201
2202 let (_tx3, mut stream3) = subscriptions_handle.subscribe(OptimizedTopicFilter::Any, 0);
2204
2205 let mut statement1 = signed_statement(1);
2207 statement1.set_topic(0, topic1);
2208 subscriptions_handle.notify(0, statement1.clone());
2209
2210 let received2 = unwrap_statement(stream2.next().await.expect("stream2 should receive"));
2215 let decoded2: Statement = Statement::decode(&mut &received2.0[..]).unwrap();
2216 assert_eq!(decoded2, statement1);
2217
2218 let received3 = unwrap_statement(stream3.next().await.expect("stream3 should receive"));
2219 let decoded3: Statement = Statement::decode(&mut &received3.0[..]).unwrap();
2220 assert_eq!(decoded3, statement1);
2221
2222 let mut statement2 = signed_statement(2);
2224 statement2.set_topic(0, topic1);
2225 statement2.set_topic(1, topic2);
2226 subscriptions_handle.notify(1, statement2.clone());
2227
2228 let received1 = unwrap_statement(stream1.next().await.expect("stream1 should receive"));
2230 let decoded1: Statement = Statement::decode(&mut &received1.0[..]).unwrap();
2231 assert_eq!(decoded1, statement2);
2232
2233 let received2 = unwrap_statement(stream2.next().await.expect("stream2 should receive"));
2234 let decoded2: Statement = Statement::decode(&mut &received2.0[..]).unwrap();
2235 assert_eq!(decoded2, statement2);
2236
2237 let received3 = unwrap_statement(stream3.next().await.expect("stream3 should receive"));
2238 let decoded3: Statement = Statement::decode(&mut &received3.0[..]).unwrap();
2239 assert_eq!(decoded3, statement2);
2240 }
2241
2242 #[test]
2243 fn test_statement_without_topics_matches_only_any_filter() {
2244 let mut subscriptions = SubscriptionsInfo::new();
2245
2246 let (tx_match_all, rx_match_all) = async_channel::bounded::<StatementEvent>(10);
2247 let (tx_match_any, rx_match_any) = async_channel::bounded::<StatementEvent>(10);
2248 let (tx_any, rx_any) = async_channel::bounded::<StatementEvent>(10);
2249
2250 let topic1 = Topic::from([8u8; 32]);
2251 let topic2 = Topic::from([9u8; 32]);
2252
2253 let sub_match_all = fixed_subscription(
2255 1,
2256 OptimizedTopicFilter::MatchAll(vec![topic1, topic2].into_iter().collect()),
2257 );
2258 subscriptions.subscribe(sub_match_all, tx_match_all);
2259
2260 let sub_match_any = fixed_subscription(
2262 2,
2263 OptimizedTopicFilter::MatchAny(vec![topic1, topic2].into_iter().collect()),
2264 );
2265 subscriptions.subscribe(sub_match_any, tx_match_any);
2266
2267 let sub_any = fixed_subscription(3, OptimizedTopicFilter::Any);
2269 subscriptions.subscribe(sub_any, tx_any);
2270
2271 let statement = signed_statement(1);
2273 assert!(statement.topics().is_empty(), "Statement should have no topics");
2274
2275 subscriptions.notify_matching_filters(0, &statement);
2277
2278 let received =
2280 unwrap_statement(rx_any.try_recv().expect("Any filter should receive statement"));
2281 let decoded_statement: Statement =
2282 Statement::decode(&mut &received.0[..]).expect("Should decode statement");
2283 assert_eq!(decoded_statement, statement);
2284
2285 assert!(
2287 rx_match_all.try_recv().is_err(),
2288 "MatchAll should not receive statement without topics"
2289 );
2290
2291 assert!(
2293 rx_match_any.try_recv().is_err(),
2294 "MatchAny should not receive statement without topics"
2295 );
2296 }
2297}