1use crate::{BlockNumberOrTag, Log as RpcLog, Transaction};
2use alloc::{borrow::Cow, string::String, vec::Vec};
3use alloy_eips::BlockNumHash;
4use alloy_primitives::{
5 keccak256,
6 map::{hash_set, HashSet},
7 Address, BlockHash, Bloom, BloomInput, Log, LogData, B256, U256, U64,
8};
9use core::{
10 hash::Hash,
11 ops::{RangeFrom, RangeInclusive, RangeToInclusive},
12};
13use itertools::{
14 EitherOrBoth::{Both, Left, Right},
15 Itertools,
16};
17
18#[derive(Clone, Debug, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
21#[cfg_attr(feature = "serde", serde(from = "HashSet<T>"))]
22pub struct FilterSet<T: Eq + Hash> {
23 set: HashSet<T>,
24
25 #[cfg(feature = "std")]
26 #[cfg_attr(feature = "serde", serde(skip, default))]
27 bloom_filter: std::sync::OnceLock<BloomFilter>,
28}
29
30impl<T: Eq + Hash> Default for FilterSet<T> {
31 fn default() -> Self {
32 Self {
33 set: Default::default(),
34 #[cfg(feature = "std")]
35 bloom_filter: Default::default(),
36 }
37 }
38}
39
40impl<T: Eq + Hash> From<T> for FilterSet<T> {
41 fn from(src: T) -> Self {
42 Self { set: core::iter::once(src).collect(), ..Default::default() }
43 }
44}
45
46impl<T: Eq + Hash> Hash for FilterSet<T> {
47 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
48 for value in &self.set {
49 value.hash(state);
50 }
51 }
52}
53
54impl<T: Eq + Hash> From<HashSet<T>> for FilterSet<T> {
55 fn from(src: HashSet<T>) -> Self {
56 Self { set: src, ..Default::default() }
57 }
58}
59
60impl<T: Eq + Hash> From<Vec<T>> for FilterSet<T> {
61 fn from(src: Vec<T>) -> Self {
62 src.into_iter().collect::<HashSet<_>>().into()
63 }
64}
65
66impl<T: Eq + Hash> From<ValueOrArray<T>> for FilterSet<T> {
67 fn from(src: ValueOrArray<T>) -> Self {
68 match src {
69 ValueOrArray::Value(val) => val.into(),
70 ValueOrArray::Array(arr) => arr.into(),
71 }
72 }
73}
74
75impl<T: Eq + Hash> From<ValueOrArray<Option<T>>> for FilterSet<T> {
76 fn from(src: ValueOrArray<Option<T>>) -> Self {
77 match src {
78 ValueOrArray::Value(None) => Default::default(),
79 ValueOrArray::Value(Some(val)) => val.into(),
80 ValueOrArray::Array(arr) => {
81 if arr.iter().contains(&None) {
85 Default::default()
86 } else {
87 arr.into_iter().flatten().collect::<Vec<T>>().into()
89 }
90 }
91 }
92 }
93}
94
95impl<T: Eq + Hash> IntoIterator for FilterSet<T> {
96 type Item = T;
97 type IntoIter = hash_set::IntoIter<T>;
98
99 fn into_iter(self) -> Self::IntoIter {
100 self.set.into_iter()
101 }
102}
103
104impl<T: Eq + Hash> FromIterator<T> for FilterSet<T> {
105 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
106 HashSet::from_iter(iter).into()
107 }
108}
109
110impl<T: Eq + Hash> FilterSet<T> {
111 pub fn is_empty(&self) -> bool {
113 self.set.is_empty()
114 }
115
116 pub fn len(&self) -> usize {
118 self.set.len()
119 }
120
121 pub fn matches(&self, value: &T) -> bool {
124 self.is_empty() || self.set.contains(value)
125 }
126
127 pub fn iter(&self) -> hash_set::Iter<'_, T> {
130 self.set.iter()
131 }
132
133 pub fn contains(&self, value: &T) -> bool {
135 self.set.contains(value)
136 }
137
138 fn unseal(&mut self) {
141 #[cfg(feature = "std")]
142 self.bloom_filter.take();
143 }
144
145 pub fn insert(&mut self, value: T) -> bool {
147 self.unseal();
148 self.set.insert(value)
149 }
150
151 pub fn remove(&mut self, value: &T) -> bool {
153 if self.contains(value) {
154 self.unseal();
155 self.set.remove(value)
156 } else {
157 false
158 }
159 }
160}
161
162impl<T: AsRef<[u8]> + Eq + Hash> FilterSet<T> {
163 #[cfg(feature = "std")]
165 pub fn bloom_filter_ref(&self) -> &BloomFilter {
166 self.bloom_filter.get_or_init(|| self.make_bloom_filter())
167 }
168
169 pub fn bloom_filter(&self) -> Cow<'_, BloomFilter> {
171 #[cfg(feature = "std")]
172 {
173 Cow::Borrowed(self.bloom_filter_ref())
174 }
175
176 #[cfg(not(feature = "std"))]
177 {
178 Cow::Owned(self.make_bloom_filter())
179 }
180 }
181
182 fn make_bloom_filter(&self) -> BloomFilter {
184 self.set.iter().map(|a| BloomInput::Raw(a.as_ref()).into()).collect::<Vec<Bloom>>().into()
185 }
186}
187
188impl<T: Clone + Eq + Hash> FilterSet<T> {
189 pub fn to_value_or_array(&self) -> Option<ValueOrArray<T>> {
194 let mut values = self.set.iter().cloned().collect::<Vec<T>>();
195 match values.len() {
196 0 => None,
197 1 => Some(ValueOrArray::Value(values.pop().expect("values length is one"))),
198 _ => Some(ValueOrArray::Array(values)),
199 }
200 }
201}
202
203pub type Topic = FilterSet<B256>;
205
206impl Topic {
207 pub fn extend<T: Into<Self>>(mut self, value: T) -> Self {
209 self.unseal();
210 self.set.extend(value.into());
211 self
212 }
213}
214
215impl From<U256> for Topic {
216 fn from(src: U256) -> Self {
217 Into::<B256>::into(src).into()
218 }
219}
220
221impl From<Address> for Topic {
222 fn from(address: Address) -> Self {
223 let mut bytes = [0u8; 32];
224 bytes[12..].copy_from_slice(address.as_slice());
225 B256::from(bytes).into()
226 }
227}
228
229impl From<bool> for Topic {
230 fn from(value: bool) -> Self {
231 let mut bytes = [0u8; 32];
232 bytes[31] = if value { 1 } else { 0 };
233 B256::from(bytes).into()
234 }
235}
236
237impl From<[u8; 32]> for Topic {
238 fn from(bytes: [u8; 32]) -> Self {
239 B256::from(bytes).into()
240 }
241}
242
243#[derive(Debug, PartialEq, Eq, thiserror::Error)]
245pub enum FilterBlockError {
246 #[error("`from_block` ({from}) is greater than `to_block` ({to})")]
248 FromBlockGreaterThanToBlock {
249 from: u64,
251 to: u64,
253 },
254}
255
256#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
258pub enum FilterBlockOption {
259 Range {
263 from_block: Option<BlockNumberOrTag>,
265 to_block: Option<BlockNumberOrTag>,
267 },
268 AtBlockHash(BlockHash),
270}
271
272impl FilterBlockOption {
273 pub const fn get_to_block(&self) -> Option<&BlockNumberOrTag> {
275 match self {
276 Self::Range { to_block, .. } => to_block.as_ref(),
277 Self::AtBlockHash(_) => None,
278 }
279 }
280
281 pub const fn get_from_block(&self) -> Option<&BlockNumberOrTag> {
283 match self {
284 Self::Range { from_block, .. } => from_block.as_ref(),
285 Self::AtBlockHash(_) => None,
286 }
287 }
288
289 pub const fn as_range(&self) -> (Option<&BlockNumberOrTag>, Option<&BlockNumberOrTag>) {
291 match self {
292 Self::Range { from_block, to_block } => (from_block.as_ref(), to_block.as_ref()),
293 Self::AtBlockHash(_) => (None, None),
294 }
295 }
296
297 pub const fn as_block_hash(&self) -> Option<&BlockHash> {
299 match self {
300 Self::AtBlockHash(hash) => Some(hash),
301 Self::Range { .. } => None,
302 }
303 }
304
305 pub const fn is_range(&self) -> bool {
307 matches!(self, Self::Range { .. })
308 }
309
310 pub const fn is_block_hash(&self) -> bool {
312 matches!(self, Self::AtBlockHash(_))
313 }
314
315 pub fn ensure_valid_block_range(&self) -> Result<(), FilterBlockError> {
317 if let (Some(from), Some(to)) = (
319 self.get_from_block().and_then(|from| from.as_number()),
320 self.get_to_block().and_then(|to| to.as_number()),
321 ) {
322 if from > to {
323 return Err(FilterBlockError::FromBlockGreaterThanToBlock { from, to });
324 }
325 }
326 Ok(())
327 }
328
329 #[must_use]
331 pub const fn with_from_block(&self, block: BlockNumberOrTag) -> Self {
332 Self::Range { from_block: Some(block), to_block: self.get_to_block().copied() }
333 }
334
335 #[must_use]
337 pub const fn with_to_block(&self, block: BlockNumberOrTag) -> Self {
338 Self::Range { from_block: self.get_from_block().copied(), to_block: Some(block) }
339 }
340
341 #[must_use]
343 pub const fn with_block_hash(&self, hash: B256) -> Self {
344 Self::AtBlockHash(hash)
345 }
346}
347
348impl From<BlockNumberOrTag> for FilterBlockOption {
349 fn from(block: BlockNumberOrTag) -> Self {
350 let block = Some(block);
351 Self::Range { from_block: block, to_block: block }
352 }
353}
354
355impl From<U64> for FilterBlockOption {
356 fn from(block: U64) -> Self {
357 BlockNumberOrTag::from(block).into()
358 }
359}
360
361impl From<u64> for FilterBlockOption {
362 fn from(block: u64) -> Self {
363 BlockNumberOrTag::from(block).into()
364 }
365}
366
367impl<T: Into<BlockNumberOrTag>> From<RangeInclusive<T>> for FilterBlockOption {
368 fn from(r: RangeInclusive<T>) -> Self {
369 let (start, end) = r.into_inner();
370 let from_block = Some(start.into());
371 let to_block = Some(end.into());
372 Self::Range { from_block, to_block }
373 }
374}
375
376impl<T: Into<BlockNumberOrTag>> From<RangeToInclusive<T>> for FilterBlockOption {
377 fn from(r: RangeToInclusive<T>) -> Self {
378 let to_block = Some(r.end.into());
379 Self::Range { from_block: Some(BlockNumberOrTag::Earliest), to_block }
380 }
381}
382
383impl<T: Into<BlockNumberOrTag>> From<RangeFrom<T>> for FilterBlockOption {
384 fn from(r: RangeFrom<T>) -> Self {
385 let from_block = Some(r.start.into());
386 Self::Range { from_block, to_block: Some(BlockNumberOrTag::Latest) }
387 }
388}
389
390impl From<B256> for FilterBlockOption {
391 fn from(hash: B256) -> Self {
392 Self::AtBlockHash(hash)
393 }
394}
395
396impl Default for FilterBlockOption {
397 fn default() -> Self {
398 Self::Range { from_block: None, to_block: None }
399 }
400}
401
402#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
404pub struct Filter {
405 pub block_option: FilterBlockOption,
408 pub address: FilterSet<Address>,
419 pub topics: [Topic; 4],
421}
422
423impl Filter {
424 pub fn new() -> Self {
426 Self::default()
427 }
428
429 #[must_use]
493 pub fn select(mut self, filter: impl Into<FilterBlockOption>) -> Self {
494 self.block_option = filter.into();
495 self
496 }
497
498 #[must_use]
500 pub fn from_block<T: Into<BlockNumberOrTag>>(mut self, block: T) -> Self {
501 self.block_option = self.block_option.with_from_block(block.into());
502 self
503 }
504
505 #[must_use]
507 pub fn to_block<T: Into<BlockNumberOrTag>>(mut self, block: T) -> Self {
508 self.block_option = self.block_option.with_to_block(block.into());
509 self
510 }
511
512 pub fn is_pending_block_filter(&self) -> bool {
515 self.block_option.get_from_block().is_some_and(BlockNumberOrTag::is_pending)
516 && self.block_option.get_to_block().is_some_and(BlockNumberOrTag::is_pending)
517 }
518
519 #[must_use]
521 pub fn at_block_hash<T: Into<B256>>(mut self, hash: T) -> Self {
522 self.block_option = self.block_option.with_block_hash(hash.into());
523 self
524 }
525
526 #[must_use]
556 pub fn address<T: Into<ValueOrArray<Address>>>(mut self, address: T) -> Self {
557 self.address = address.into().into();
558 self
559 }
560
561 #[must_use]
563 pub fn event(self, event_name: &str) -> Self {
564 let hash = keccak256(event_name.as_bytes());
565 self.event_signature(hash)
566 }
567
568 #[must_use]
570 pub fn events(self, events: impl IntoIterator<Item = impl AsRef<[u8]>>) -> Self {
571 let events = events.into_iter().map(|e| keccak256(e.as_ref())).collect::<Vec<_>>();
572 self.event_signature(events)
573 }
574
575 #[must_use]
577 pub fn event_signature<T: Into<Topic>>(mut self, topic: T) -> Self {
578 self.topics[0] = topic.into();
579 self
580 }
581
582 #[must_use]
584 #[deprecated(note = "use `event_signature` instead")]
585 pub fn topic0<T: Into<Topic>>(mut self, topic: T) -> Self {
586 self.topics[0] = topic.into();
587 self
588 }
589
590 #[must_use]
592 pub fn topic1<T: Into<Topic>>(mut self, topic: T) -> Self {
593 self.topics[1] = topic.into();
594 self
595 }
596
597 #[must_use]
599 pub fn topic2<T: Into<Topic>>(mut self, topic: T) -> Self {
600 self.topics[2] = topic.into();
601 self
602 }
603
604 #[must_use]
606 pub fn topic3<T: Into<Topic>>(mut self, topic: T) -> Self {
607 self.topics[3] = topic.into();
608 self
609 }
610
611 pub fn is_paginatable(&self) -> bool {
613 self.get_from_block().is_some()
614 }
615
616 pub fn get_to_block(&self) -> Option<u64> {
618 self.block_option.get_to_block().and_then(|b| b.as_number())
619 }
620
621 pub fn get_from_block(&self) -> Option<u64> {
623 self.block_option.get_from_block().and_then(|b| b.as_number())
624 }
625
626 pub const fn get_block_hash(&self) -> Option<B256> {
628 match self.block_option {
629 FilterBlockOption::AtBlockHash(hash) => Some(hash),
630 FilterBlockOption::Range { .. } => None,
631 }
632 }
633
634 pub fn has_topics(&self) -> bool {
636 self.topics.iter().any(|t| !t.is_empty())
637 }
638
639 pub fn address_bloom_filter(&self) -> Cow<'_, BloomFilter> {
641 self.address.bloom_filter()
642 }
643
644 pub fn topics_bloom_filter(&self) -> [Cow<'_, BloomFilter>; 4] {
646 self.topics.each_ref().map(|t| t.bloom_filter())
647 }
648
649 pub fn matches_bloom(&self, bloom: Bloom) -> bool {
652 self.address_bloom_filter().matches(bloom)
653 && self.topics_bloom_filter().iter().all(|topic_bloom| topic_bloom.matches(bloom))
654 }
655
656 pub fn matches_topics(&self, topics: &[B256]) -> bool {
658 self.topics.iter().zip_longest(topics.iter()).all(|topic| match topic {
659 Both(filter, log) => filter.matches(log),
660 Left(filter) => filter.is_empty(),
661 Right(_) => false,
662 })
663 }
664
665 pub fn matches_address(&self, address: Address) -> bool {
667 self.address.matches(&address)
668 }
669
670 pub const fn matches_block_range(&self, block_number: u64) -> bool {
672 let mut res = true;
673
674 if let Some(BlockNumberOrTag::Number(num)) = self.block_option.get_from_block() {
675 if *num > block_number {
676 res = false;
677 }
678 }
679
680 if let Some(to) = self.block_option.get_to_block() {
681 match to {
682 BlockNumberOrTag::Number(num) => {
683 if *num < block_number {
684 res = false;
685 }
686 }
687 BlockNumberOrTag::Earliest => {
688 res = false;
689 }
690 _ => {}
691 }
692 }
693 res
694 }
695
696 pub fn matches_block_hash(&self, block_hash: B256) -> bool {
698 match self.block_option {
699 FilterBlockOption::AtBlockHash(hash) => hash == block_hash,
700 FilterBlockOption::Range { .. } => false,
701 }
702 }
703
704 pub fn matches_block(&self, block: &BlockNumHash) -> bool {
707 self.matches_block_range(block.number) || self.matches_block_hash(block.hash)
708 }
709
710 pub fn matches_log_block<T>(&self, log: &crate::Log<T>) -> bool {
715 if self.is_pending_block_filter() {
716 return log.block_number.is_none();
719 }
720
721 let Some(number) = log.block_number else { return false };
723 let Some(hash) = log.block_hash else { return false };
724 let num_hash = BlockNumHash { number, hash };
725
726 self.matches_block(&num_hash)
727 }
728
729 pub fn matches(&self, log: &Log) -> bool {
739 if !self.matches_address(log.address) {
740 return false;
741 }
742
743 self.matches_topics(log.topics())
744 }
745
746 pub fn rpc_matches(&self, log: &crate::Log) -> bool {
756 self.matches_log_block(log) && self.matches(&log.inner)
757 }
758
759 pub fn matches_parsed<T, U>(&self, log: &T) -> bool
772 where
773 T: AsRef<Log<U>>,
774 for<'a> &'a U: Into<LogData>,
775 {
776 let log = log.as_ref().reserialize();
777 self.matches(&log)
778 }
779
780 pub fn rpc_matches_parsed<U>(&self, log: &crate::Log<U>) -> bool
795 where
796 for<'a> &'a U: Into<LogData>,
797 {
798 self.matches_log_block(log) && self.matches_parsed(log)
799 }
800
801 pub fn append_matching_block_logs<'a, I, R>(
814 &self,
815 all_logs: &mut Vec<crate::Log>,
816 block_num_hash: BlockNumHash,
817 block_timestamp: u64,
818 tx_hashes_and_receipts: I,
819 removed: bool,
820 ) where
821 I: IntoIterator<Item = (B256, &'a R)>,
822 R: alloy_consensus::TxReceipt<Log = alloy_primitives::Log> + 'a,
823 {
824 if !self.matches_block(&block_num_hash) {
826 return;
827 }
828
829 let mut log_index: u64 = 0;
831
832 for (receipt_idx, (tx_hash, receipt)) in tx_hashes_and_receipts.into_iter().enumerate() {
834 for log in receipt.logs() {
835 if self.matches(log) {
836 let log = crate::Log {
837 inner: log.clone(),
838 block_hash: Some(block_num_hash.hash),
839 block_number: Some(block_num_hash.number),
840 transaction_hash: Some(tx_hash),
841 transaction_index: Some(receipt_idx as u64),
843 log_index: Some(log_index),
844 removed,
845 block_timestamp: Some(block_timestamp),
846 };
847 all_logs.push(log);
848 }
849
850 log_index += 1;
851 }
852 }
853 }
854
855 pub fn matching_block_logs<'a, I, R>(
864 &self,
865 block_num_hash: BlockNumHash,
866 block_timestamp: u64,
867 tx_hashes_and_receipts: I,
868 removed: bool,
869 ) -> Vec<crate::Log>
870 where
871 I: IntoIterator<Item = (B256, &'a R)>,
872 R: alloy_consensus::TxReceipt<Log = alloy_primitives::Log> + 'a,
873 {
874 let mut logs = Vec::new();
875 self.append_matching_block_logs(
876 &mut logs,
877 block_num_hash,
878 block_timestamp,
879 tx_hashes_and_receipts,
880 removed,
881 );
882 logs
883 }
884
885 pub fn filter_receipts<I, R>(&self, receipts: I) -> FilterReceiptsIter<'_, I::IntoIter, R>
905 where
906 I: IntoIterator,
907 I::Item: IntoIterator<Item = R>,
908 R: alloy_consensus::TxReceipt<Log = alloy_primitives::Log>,
909 {
910 FilterReceiptsIter {
911 filter: self,
912 blocks_iter: receipts.into_iter(),
913 current_block: None,
914 current_logs: None,
915 }
916 }
917}
918
919#[cfg(feature = "serde")]
920impl serde::Serialize for Filter {
921 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
922 where
923 S: serde::Serializer,
924 {
925 use serde::ser::SerializeStruct;
926
927 let mut s = serializer.serialize_struct("Filter", 5)?;
928 match self.block_option {
929 FilterBlockOption::Range { from_block, to_block } => {
930 if let Some(ref from_block) = from_block {
931 s.serialize_field("fromBlock", from_block)?;
932 }
933
934 if let Some(ref to_block) = to_block {
935 s.serialize_field("toBlock", to_block)?;
936 }
937 }
938
939 FilterBlockOption::AtBlockHash(ref h) => s.serialize_field("blockHash", h)?,
940 }
941
942 if let Some(address) = self.address.to_value_or_array() {
943 s.serialize_field("address", &address)?;
944 }
945
946 let mut filtered_topics = Vec::new();
947 let mut filtered_topics_len = 0;
948 for (i, topic) in self.topics.iter().enumerate() {
949 if !topic.is_empty() {
950 filtered_topics_len = i + 1;
951 }
952 filtered_topics.push(topic.to_value_or_array());
953 }
954 filtered_topics.truncate(filtered_topics_len);
955 s.serialize_field("topics", &filtered_topics)?;
956
957 s.end()
958 }
959}
960
961#[cfg(feature = "serde")]
962impl<'de> serde::Deserialize<'de> for Filter {
963 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
964 where
965 D: serde::Deserializer<'de>,
966 {
967 type RawAddressFilter = ValueOrArray<Option<Address>>;
968 type RawTopicsFilter = Vec<Option<ValueOrArray<Option<B256>>>>;
969
970 struct FilterVisitor;
971
972 impl<'de> serde::de::Visitor<'de> for FilterVisitor {
973 type Value = Filter;
974
975 fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
976 formatter.write_str("Filter object")
977 }
978
979 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
980 where
981 A: serde::de::MapAccess<'de>,
982 {
983 let mut from_block: Option<Option<BlockNumberOrTag>> = None;
984 let mut to_block: Option<Option<BlockNumberOrTag>> = None;
985 let mut block_hash: Option<Option<B256>> = None;
986 let mut address: Option<Option<RawAddressFilter>> = None;
987 let mut topics: Option<Option<RawTopicsFilter>> = None;
988
989 while let Some(key) = map.next_key::<String>()? {
990 match key.as_str() {
991 "fromBlock" => {
992 if from_block.is_some() {
993 return Err(serde::de::Error::duplicate_field("fromBlock"));
994 }
995 from_block = Some(map.next_value()?)
996 }
997 "toBlock" => {
998 if to_block.is_some() {
999 return Err(serde::de::Error::duplicate_field("toBlock"));
1000 }
1001 to_block = Some(map.next_value()?)
1002 }
1003 "blockHash" => {
1004 if block_hash.is_some() {
1005 return Err(serde::de::Error::duplicate_field("blockHash"));
1006 }
1007 block_hash = Some(map.next_value()?)
1008 }
1009 "address" => {
1010 if address.is_some() {
1011 return Err(serde::de::Error::duplicate_field("address"));
1012 }
1013 address = Some(map.next_value()?)
1014 }
1015 "topics" => {
1016 if topics.is_some() {
1017 return Err(serde::de::Error::duplicate_field("topics"));
1018 }
1019 topics = Some(map.next_value()?)
1020 }
1021
1022 key => {
1023 return Err(serde::de::Error::unknown_field(
1024 key,
1025 &["fromBlock", "toBlock", "address", "topics", "blockHash"],
1026 ))
1027 }
1028 }
1029 }
1030
1031 let (block_hash, from_block, to_block) = if let Some(Some(hash)) = block_hash {
1033 if from_block.is_some_and(|inner| inner.is_some())
1034 || to_block.is_some_and(|inner| inner.is_some())
1035 {
1036 return Err(serde::de::Error::custom(
1037 "cannot specify both blockHash and fromBlock/toBlock, choose one or the other",
1038 ));
1039 }
1040 (Some(hash), None, None)
1041 } else {
1042 (None, from_block.unwrap_or_default(), to_block.unwrap_or_default())
1043 };
1044
1045 let address = address.flatten().map(|a| a.into()).unwrap_or_default();
1046 let topics_vec = topics.flatten().unwrap_or_default();
1047
1048 if topics_vec.len() > 4 {
1050 return Err(serde::de::Error::custom("exceeded maximum topics len"));
1051 }
1052 let mut topics: [Topic; 4] = [
1053 Default::default(),
1054 Default::default(),
1055 Default::default(),
1056 Default::default(),
1057 ];
1058 for (idx, topic) in topics_vec.into_iter().enumerate() {
1059 topics[idx] = topic.map(|t| t.into()).unwrap_or_default();
1060 }
1061
1062 let block_option = block_hash
1063 .map_or(FilterBlockOption::Range { from_block, to_block }, |block_hash| {
1064 FilterBlockOption::AtBlockHash(block_hash)
1065 });
1066
1067 Ok(Filter { block_option, address, topics })
1068 }
1069 }
1070
1071 deserializer.deserialize_any(FilterVisitor)
1072 }
1073}
1074
1075#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1078pub enum ValueOrArray<T> {
1079 Value(T),
1081 Array(Vec<T>),
1083}
1084
1085impl<T> ValueOrArray<T> {
1086 pub const fn as_value(&self) -> Option<&T> {
1088 if let Self::Value(value) = self {
1089 Some(value)
1090 } else {
1091 None
1092 }
1093 }
1094
1095 pub fn as_array(&self) -> Option<&[T]> {
1097 if let Self::Array(array) = self {
1098 Some(array)
1099 } else {
1100 None
1101 }
1102 }
1103
1104 pub const fn is_value(&self) -> bool {
1106 matches!(self, Self::Value(_))
1107 }
1108
1109 pub const fn is_array(&self) -> bool {
1111 matches!(self, Self::Array(_))
1112 }
1113}
1114
1115impl From<Address> for ValueOrArray<Address> {
1116 fn from(src: Address) -> Self {
1117 Self::Value(src)
1118 }
1119}
1120
1121impl From<Vec<Address>> for ValueOrArray<Address> {
1122 fn from(src: Vec<Address>) -> Self {
1123 Self::Array(src)
1124 }
1125}
1126
1127impl From<Vec<B256>> for ValueOrArray<B256> {
1128 fn from(src: Vec<B256>) -> Self {
1129 Self::Array(src)
1130 }
1131}
1132
1133#[cfg(feature = "serde")]
1134impl<T> serde::Serialize for ValueOrArray<T>
1135where
1136 T: serde::Serialize,
1137{
1138 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1139 where
1140 S: serde::Serializer,
1141 {
1142 match self {
1143 Self::Value(inner) => inner.serialize(serializer),
1144 Self::Array(inner) => inner.serialize(serializer),
1145 }
1146 }
1147}
1148
1149#[cfg(feature = "serde")]
1150impl<'a, T> serde::Deserialize<'a> for ValueOrArray<T>
1151where
1152 T: serde::de::DeserializeOwned,
1153{
1154 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1155 where
1156 D: serde::Deserializer<'a>,
1157 {
1158 let value = serde_json::Value::deserialize(deserializer)?;
1159
1160 if value.is_null() {
1161 return Ok(Self::Array(Vec::new()));
1162 }
1163
1164 #[derive(serde::Deserialize)]
1165 #[serde(untagged)]
1166 enum Variadic<T> {
1167 Value(T),
1168 Array(Vec<T>),
1169 }
1170
1171 match serde_json::from_value::<Variadic<T>>(value).map_err(|err| {
1172 serde::de::Error::custom(format!("Invalid variadic value or array type: {err}"))
1173 })? {
1174 Variadic::Value(val) => Ok(Self::Value(val)),
1175 Variadic::Array(arr) => Ok(Self::Array(arr)),
1176 }
1177 }
1178}
1179
1180#[derive(Default, Clone, Debug, PartialEq, Eq)]
1182#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1183#[cfg_attr(feature = "serde", serde(untagged))]
1184pub enum FilterChanges<T = Transaction> {
1185 #[cfg_attr(feature = "serde", serde(with = "empty_array"))]
1187 #[default]
1188 Empty,
1189 Logs(Vec<RpcLog>),
1191 Hashes(Vec<B256>),
1193 Transactions(Vec<T>),
1195}
1196
1197impl From<Vec<RpcLog>> for FilterChanges {
1198 fn from(logs: Vec<RpcLog>) -> Self {
1199 Self::Logs(logs)
1200 }
1201}
1202
1203impl From<Vec<B256>> for FilterChanges {
1204 fn from(hashes: Vec<B256>) -> Self {
1205 Self::Hashes(hashes)
1206 }
1207}
1208
1209impl From<Vec<Transaction>> for FilterChanges {
1210 fn from(transactions: Vec<Transaction>) -> Self {
1211 Self::Transactions(transactions)
1212 }
1213}
1214
1215impl<T> FilterChanges<T> {
1216 pub fn as_hashes(&self) -> Option<&[B256]> {
1218 if let Self::Hashes(hashes) = self {
1219 Some(hashes)
1220 } else {
1221 None
1222 }
1223 }
1224
1225 pub fn as_logs(&self) -> Option<&[RpcLog]> {
1227 if let Self::Logs(logs) = self {
1228 Some(logs)
1229 } else {
1230 None
1231 }
1232 }
1233
1234 pub fn as_transactions(&self) -> Option<&[T]> {
1236 if let Self::Transactions(transactions) = self {
1237 Some(transactions)
1238 } else {
1239 None
1240 }
1241 }
1242
1243 pub const fn is_empty(&self) -> bool {
1245 matches!(self, Self::Empty)
1246 }
1247
1248 pub const fn is_logs(&self) -> bool {
1250 matches!(self, Self::Logs(_))
1251 }
1252
1253 pub const fn is_hashes(&self) -> bool {
1255 matches!(self, Self::Hashes(_))
1256 }
1257
1258 pub const fn is_transactions(&self) -> bool {
1260 matches!(self, Self::Transactions(_))
1261 }
1262}
1263
1264#[cfg(feature = "serde")]
1265mod empty_array {
1266 use serde::{Serialize, Serializer};
1267
1268 pub(super) fn serialize<S>(s: S) -> Result<S::Ok, S::Error>
1269 where
1270 S: Serializer,
1271 {
1272 (&[] as &[()]).serialize(s)
1273 }
1274}
1275
1276#[cfg(feature = "serde")]
1277impl<'de, T> serde::Deserialize<'de> for FilterChanges<T>
1278where
1279 T: serde::Deserialize<'de>,
1280{
1281 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1282 where
1283 D: serde::Deserializer<'de>,
1284 {
1285 #[derive(serde::Deserialize)]
1286 #[serde(untagged)]
1287 enum Changes<T = Transaction> {
1288 Hashes(Vec<B256>),
1289 Logs(Vec<RpcLog>),
1290 Transactions(Vec<T>),
1291 }
1292
1293 let changes = Changes::deserialize(deserializer)?;
1294 let changes = match changes {
1295 Changes::Logs(vals) => {
1296 if vals.is_empty() {
1297 Self::Empty
1298 } else {
1299 Self::Logs(vals)
1300 }
1301 }
1302 Changes::Hashes(vals) => {
1303 if vals.is_empty() {
1304 Self::Empty
1305 } else {
1306 Self::Hashes(vals)
1307 }
1308 }
1309 Changes::Transactions(vals) => {
1310 if vals.is_empty() {
1311 Self::Empty
1312 } else {
1313 Self::Transactions(vals)
1314 }
1315 }
1316 };
1317 Ok(changes)
1318 }
1319}
1320
1321#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1323#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1324#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
1325#[cfg_attr(feature = "serde", serde(untagged))]
1326pub enum FilterId {
1327 Num(u64),
1329 Str(String),
1331}
1332
1333impl From<u64> for FilterId {
1334 fn from(num: u64) -> Self {
1335 Self::Num(num)
1336 }
1337}
1338
1339impl From<String> for FilterId {
1340 fn from(str: String) -> Self {
1341 Self::Str(str)
1342 }
1343}
1344
1345#[cfg(feature = "jsonrpsee-types")]
1346impl From<FilterId> for jsonrpsee_types::SubscriptionId<'_> {
1347 fn from(value: FilterId) -> Self {
1348 match value {
1349 FilterId::Num(n) => jsonrpsee_types::SubscriptionId::Num(n),
1350 FilterId::Str(s) => jsonrpsee_types::SubscriptionId::Str(s.into()),
1351 }
1352 }
1353}
1354
1355#[cfg(feature = "jsonrpsee-types")]
1356impl From<jsonrpsee_types::SubscriptionId<'_>> for FilterId {
1357 fn from(value: jsonrpsee_types::SubscriptionId<'_>) -> Self {
1358 match value {
1359 jsonrpsee_types::SubscriptionId::Num(n) => n.into(),
1360 jsonrpsee_types::SubscriptionId::Str(s) => s.into_owned().into(),
1361 }
1362 }
1363}
1364
1365#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1372pub enum PendingTransactionFilterKind {
1373 #[default]
1375 Hashes,
1376 Full,
1378}
1379
1380#[cfg(feature = "serde")]
1381impl serde::Serialize for PendingTransactionFilterKind {
1382 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1386 where
1387 S: serde::Serializer,
1388 {
1389 match self {
1390 Self::Hashes => false.serialize(serializer),
1391 Self::Full => true.serialize(serializer),
1392 }
1393 }
1394}
1395
1396#[cfg(feature = "serde")]
1397impl<'a> serde::Deserialize<'a> for PendingTransactionFilterKind {
1398 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1402 where
1403 D: serde::Deserializer<'a>,
1404 {
1405 let val = Option::<bool>::deserialize(deserializer)?;
1406 match val {
1407 Some(true) => Ok(Self::Full),
1408 _ => Ok(Self::Hashes),
1409 }
1410 }
1411}
1412
1413#[derive(Debug, Default, Clone, PartialEq, Eq)]
1415pub struct BloomFilter(Vec<Bloom>);
1416
1417impl From<Vec<Bloom>> for BloomFilter {
1418 fn from(src: Vec<Bloom>) -> Self {
1419 Self(src)
1420 }
1421}
1422
1423impl BloomFilter {
1424 pub fn matches(&self, bloom: Bloom) -> bool {
1428 self.0.is_empty() || self.0.iter().any(|a| bloom.contains(a))
1429 }
1430}
1431
1432#[derive(Debug, Default)]
1434pub struct FilteredParams {
1435 pub filter: Option<Filter>,
1437}
1438
1439impl FilteredParams {
1440 pub fn new(filter: Option<Filter>) -> Self {
1443 filter.map_or_else(Default::default, |filter| Self { filter: Some(filter) })
1444 }
1445
1446 pub fn address_filter(address: &FilterSet<Address>) -> BloomFilter {
1448 address.make_bloom_filter()
1449 }
1450
1451 pub fn topics_filter(topics: &[FilterSet<B256>]) -> Vec<BloomFilter> {
1453 topics.iter().map(|t| t.make_bloom_filter()).collect()
1454 }
1455
1456 pub fn matches_topics(bloom: Bloom, topic_filters: &[BloomFilter]) -> bool {
1458 if topic_filters.is_empty() {
1459 return true;
1460 }
1461
1462 for filter in topic_filters {
1466 if !filter.matches(bloom) {
1467 return false;
1468 }
1469 }
1470 true
1471 }
1472
1473 pub fn matches_address(bloom: Bloom, address_filter: &BloomFilter) -> bool {
1476 address_filter.matches(bloom)
1477 }
1478
1479 pub const fn filter_block_range(&self, block_number: u64) -> bool {
1481 if self.filter.is_none() {
1482 return true;
1483 }
1484 let filter = self.filter.as_ref().unwrap();
1485 let mut res = true;
1486
1487 if let Some(BlockNumberOrTag::Number(num)) = filter.block_option.get_from_block() {
1488 if *num > block_number {
1489 res = false;
1490 }
1491 }
1492
1493 if let Some(to) = filter.block_option.get_to_block() {
1494 match to {
1495 BlockNumberOrTag::Number(num) => {
1496 if *num < block_number {
1497 res = false;
1498 }
1499 }
1500 BlockNumberOrTag::Earliest => {
1501 res = false;
1502 }
1503 _ => {}
1504 }
1505 }
1506 res
1507 }
1508
1509 pub fn filter_block_hash(&self, block_hash: B256) -> bool {
1511 if let Some(h) = self.filter.as_ref().and_then(|f| f.get_block_hash()) {
1512 if h != block_hash {
1513 return false;
1514 }
1515 }
1516 true
1517 }
1518
1519 pub fn is_pending_block_filter(&self) -> bool {
1523 self.filter.as_ref().is_some_and(|f| f.is_pending_block_filter())
1524 }
1525
1526 pub fn filter_address(&self, address: &Address) -> bool {
1528 self.filter.as_ref().map(|f| f.address.matches(address)).unwrap_or(true)
1529 }
1530
1531 pub fn filter_topics(&self, log_topics: &[B256]) -> bool {
1533 let topics = match self.filter.as_ref() {
1534 None => return true,
1535 Some(f) => &f.topics,
1536 };
1537 for topic_tuple in topics.iter().zip_longest(log_topics.iter()) {
1538 match topic_tuple {
1539 Left(filter_topic) => {
1542 if !filter_topic.is_empty() {
1543 return false;
1544 }
1545 }
1546 Right(_) => return true,
1549 Both(filter_topic, log_topic) => {
1551 if !filter_topic.matches(log_topic) {
1552 return false;
1553 }
1554 }
1555 }
1556 }
1557 true
1558 }
1559}
1560
1561pub struct FilterReceiptsIter<'a, I, R>
1566where
1567 I: Iterator,
1568 I::Item: IntoIterator<Item = R>,
1569 R: alloy_consensus::TxReceipt<Log = alloy_primitives::Log>,
1570{
1571 filter: &'a Filter,
1572 blocks_iter: I,
1573 current_block: Option<<I::Item as IntoIterator>::IntoIter>,
1574 current_logs: Option<alloc::vec::IntoIter<alloy_primitives::Log>>,
1575}
1576
1577impl<'a, I, R> core::fmt::Debug for FilterReceiptsIter<'a, I, R>
1578where
1579 I: Iterator,
1580 I::Item: IntoIterator<Item = R>,
1581 R: alloy_consensus::TxReceipt<Log = alloy_primitives::Log>,
1582{
1583 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1584 f.debug_struct("FilterReceiptsIter")
1585 .field("filter", &self.filter)
1586 .field("has_current_block", &self.current_block.is_some())
1587 .field("has_current_logs", &self.current_logs.is_some())
1588 .finish()
1589 }
1590}
1591
1592impl<'a, I, R> Iterator for FilterReceiptsIter<'a, I, R>
1593where
1594 I: Iterator,
1595 I::Item: IntoIterator<Item = R>,
1596 R: alloy_consensus::TxReceipt<Log = alloy_primitives::Log>,
1597{
1598 type Item = alloy_primitives::Log;
1599
1600 fn next(&mut self) -> Option<Self::Item> {
1601 loop {
1602 if let Some(ref mut logs) = self.current_logs {
1604 if let Some(log) = logs.next() {
1605 if self.filter.matches(&log) {
1606 return Some(log);
1607 }
1608 continue;
1609 }
1610 }
1611
1612 if let Some(ref mut receipts) = self.current_block {
1614 if let Some(receipt) = receipts.next() {
1615 self.current_logs = Some(receipt.into_logs().into_iter());
1617 continue;
1618 }
1619 }
1620
1621 match self.blocks_iter.next() {
1623 Some(block) => {
1624 self.current_block = Some(block.into_iter());
1625 self.current_logs = None;
1626 }
1627 None => return None,
1628 }
1629 }
1630 }
1631}
1632
1633#[cfg(test)]
1634mod tests {
1635 use super::*;
1636 use alloy_primitives::{bloom, LogData};
1637 #[cfg(feature = "serde")]
1638 use serde_json::json;
1639 use similar_asserts::assert_eq;
1640
1641 #[cfg(feature = "serde")]
1642 fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
1643 serde_json::to_value(t).expect("Failed to serialize value")
1644 }
1645
1646 #[test]
1648 #[cfg(feature = "serde")]
1649 fn test_any_addresses() {
1650 let s = r#"{
1651 "fromBlock": "0x61A80",
1652 "toBlock": "0x61B48",
1653 "address": [
1654 "0x8CBabC07717038DA6fAf1bC477a39F1627988a3a",
1655 "0x927F9c03d1Ac6e2630d31E614F226b5Ed028d443"
1656 ]
1657 }"#;
1658 let filter = serde_json::from_str::<Filter>(s).unwrap();
1659
1660 let bloom = bloom!("0x10000000000010000000000000000200000002000000000000400000000000000000000400100000000900000000000000000000000000000000000000000000000000000000000000000008400000000000000080000000000080000000000000000000000000000000000000000000000000000002000000000010000000000000000000800000000000000000000000000000000000000020000000000000000000000000000000000000000000002000000000000000000000000000000000000002000000000000000000000000000000000000000000000000100000000000000000000000000000004000000000000000000000000000000000000000");
1662 assert!(filter.matches_bloom(bloom));
1663
1664 let bloom = bloom!("0x10000000000010000000000000000200000002000000000000400000000000000000000400100000000900000000000000000000000000000000000000000000000000000000000000000008400000000000000080000000000080000000000000000000000000000000000000000000000000000002000000000010000000000000000000800000000000000000000000000000000000000020000000000000000000000000000000000000000000002000000000000000000000000000000000000002000000000000000000000000000000000000000000000000100000000000000000000000000000004000000000000000000000000000000000000000");
1666 assert!(filter.matches_bloom(bloom));
1667 }
1668
1669 #[test]
1670 #[cfg(feature = "serde")]
1671 fn test_empty_filter_topics_list() {
1672 let s = r#"{"fromBlock": "0xfc359e", "toBlock": "0xfc359e", "topics": [["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"], [], ["0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778"]]}"#;
1673 let filter = serde_json::from_str::<Filter>(s).unwrap();
1674 assert_eq!(
1675 filter.topics,
1676 [
1677 "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
1678 .parse::<B256>()
1679 .unwrap()
1680 .into(),
1681 Default::default(),
1682 "0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778"
1683 .parse::<B256>()
1684 .unwrap()
1685 .into(),
1686 Default::default(),
1687 ]
1688 );
1689 }
1690
1691 #[test]
1692 fn test_with_from_block_correct_range() {
1693 let original = FilterBlockOption::Range {
1695 from_block: Some(BlockNumberOrTag::Number(1)),
1696 to_block: Some(BlockNumberOrTag::Number(10)),
1697 };
1698 let updated = original.with_from_block(BlockNumberOrTag::Number(5));
1699 assert!(updated.ensure_valid_block_range().is_ok());
1700 }
1701
1702 #[test]
1703 fn test_with_from_block_failure() {
1704 let original = FilterBlockOption::Range {
1706 from_block: Some(BlockNumberOrTag::Number(10)),
1707 to_block: Some(BlockNumberOrTag::Number(5)),
1708 };
1709
1710 assert!(matches!(
1711 original.ensure_valid_block_range(),
1712 Err(FilterBlockError::FromBlockGreaterThanToBlock { .. })
1713 ));
1714 }
1715
1716 #[test]
1717 #[cfg(feature = "serde")]
1718 fn test_block_hash() {
1719 let s =
1720 r#"{"blockHash":"0x58dc57ab582b282c143424bd01e8d923cddfdcda9455bad02a29522f6274a948"}"#;
1721 let filter = serde_json::from_str::<Filter>(s).unwrap();
1722 assert_eq!(
1723 filter.block_option,
1724 FilterBlockOption::AtBlockHash(
1725 "0x58dc57ab582b282c143424bd01e8d923cddfdcda9455bad02a29522f6274a948"
1726 .parse()
1727 .unwrap()
1728 )
1729 );
1730 }
1731
1732 #[test]
1733 #[cfg(feature = "serde")]
1734 fn test_filter_topics_middle_wildcard() {
1735 let s = r#"{"fromBlock": "0xfc359e", "toBlock": "0xfc359e", "topics": [["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"], [], [null, "0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778"]]}"#;
1736 let filter = serde_json::from_str::<Filter>(s).unwrap();
1737 assert_eq!(
1738 filter.topics,
1739 [
1740 "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
1741 .parse::<B256>()
1742 .unwrap()
1743 .into(),
1744 Default::default(),
1745 Default::default(),
1746 Default::default(),
1747 ]
1748 );
1749 }
1750
1751 #[test]
1752 #[cfg(feature = "serde")]
1753 fn can_serde_value_or_array() {
1754 #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1755 struct Item {
1756 value: ValueOrArray<U256>,
1757 }
1758
1759 let item = Item { value: ValueOrArray::Value(U256::from(1u64)) };
1760 let json = serde_json::to_value(item.clone()).unwrap();
1761 let deserialized: Item = serde_json::from_value(json).unwrap();
1762 assert_eq!(item, deserialized);
1763
1764 let item = Item { value: ValueOrArray::Array(vec![U256::from(1u64), U256::ZERO]) };
1765 let json = serde_json::to_value(item.clone()).unwrap();
1766 let deserialized: Item = serde_json::from_value(json).unwrap();
1767 assert_eq!(item, deserialized);
1768 }
1769
1770 #[test]
1771 #[cfg(feature = "serde")]
1772 fn filter_serialization_test() {
1773 let t1 = "0000000000000000000000009729a6fbefefc8f6005933898b13dc45c3a2c8b7"
1774 .parse::<B256>()
1775 .unwrap();
1776 let t2 = B256::from([0; 32]);
1777 let t3 = U256::from(123);
1778
1779 let t1_padded = t1;
1780 let t3_padded = B256::from({
1781 let mut x = [0; 32];
1782 x[31] = 123;
1783 x
1784 });
1785
1786 let event = "ValueChanged(address,string,string)";
1787 let t0 = keccak256(event.as_bytes());
1788 let addr: Address = "f817796F60D268A36a57b8D2dF1B97B14C0D0E1d".parse().unwrap();
1789 let filter = Filter::new();
1790
1791 let ser = serialize(&filter);
1792 assert_eq!(ser, json!({ "topics": [] }));
1793
1794 let filter = filter.address(ValueOrArray::Value(addr));
1795
1796 let ser = serialize(&filter);
1797 assert_eq!(ser, json!({"address" : addr, "topics": []}));
1798
1799 let filter = filter.event(event);
1800
1801 let ser = serialize(&filter);
1803 assert_eq!(ser, json!({ "address" : addr, "topics": [t0]}));
1804
1805 let ser = serialize(&filter.clone().topic1(t1));
1807 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, t1_padded]}));
1808
1809 let ser = serialize(&filter.clone().topic2(t2));
1811 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, null, t2]}));
1812
1813 let ser = serialize(&filter.clone().topic3(t3));
1815 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, null, null, t3_padded]}));
1816
1817 let ser = serialize(&filter.clone().topic1(t1).topic2(t2));
1819 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, t1_padded, t2]}));
1820
1821 let ser = serialize(&filter.clone().topic1(t1).topic3(t3));
1823 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, t1_padded, null, t3_padded]}));
1824
1825 let ser = serialize(&filter.clone().topic2(t2).topic3(t3));
1827 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, null, t2, t3_padded]}));
1828
1829 let ser = serialize(&filter.topic1(t1).topic2(t2).topic3(t3));
1831 assert_eq!(ser, json!({ "address" : addr, "topics": [t0, t1_padded, t2, t3_padded]}));
1832 }
1833
1834 fn topic_filter(topic1: B256, topic2: B256, topic3: B256) -> Filter {
1835 Filter {
1836 block_option: Default::default(),
1837 address: Default::default(),
1838 topics: [
1839 topic1.into(),
1840 vec![topic2, topic3].into(),
1841 Default::default(),
1842 Default::default(),
1843 ],
1844 }
1845 }
1846
1847 #[test]
1848 fn can_detect_different_topics() {
1849 let topic1 = B256::with_last_byte(1);
1850 let topic2 = B256::with_last_byte(2);
1851 let topic3 = B256::with_last_byte(3);
1852
1853 let filter = topic_filter(topic1, topic2, topic3);
1854
1855 assert!(filter.matches_topics(&[topic1, topic2, topic3]));
1856 }
1857
1858 #[test]
1859 fn can_match_empty_topics() {
1860 let filter = Filter {
1861 block_option: Default::default(),
1862 address: Default::default(),
1863 topics: Default::default(),
1864 };
1865
1866 assert!(filter.matches_topics(&[
1867 B256::with_last_byte(1),
1868 B256::with_last_byte(2),
1869 B256::with_last_byte(3),
1870 B256::with_last_byte(4),
1871 ]));
1872 }
1873
1874 #[test]
1875 fn can_match_address_and_topics() {
1876 let address = Address::with_last_byte(1);
1877 let topic1 = B256::with_last_byte(2);
1878 let topic2 = B256::with_last_byte(3);
1879 let topic3 = B256::with_last_byte(4);
1880
1881 let filter = Filter {
1882 block_option: Default::default(),
1883 address: address.into(),
1884 topics: [
1885 topic1.into(),
1886 vec![topic2, topic3].into(),
1887 Default::default(),
1888 Default::default(),
1889 ],
1890 };
1891
1892 let log =
1893 Log { address, data: LogData::new_unchecked(vec![topic1, topic2], Default::default()) };
1894
1895 assert!(filter.matches(&log));
1896 }
1897
1898 #[test]
1899 fn can_match_topics_wildcard() {
1900 let address = Address::with_last_byte(1);
1901 let topic1 = B256::with_last_byte(2);
1902 let topic2 = B256::with_last_byte(3);
1903 let topic3 = B256::with_last_byte(4);
1904
1905 let filter = Filter {
1906 block_option: Default::default(),
1907 address: Default::default(),
1908 topics: [
1909 Default::default(),
1910 vec![topic2, topic3].into(),
1911 Default::default(),
1912 Default::default(),
1913 ],
1914 };
1915
1916 let log =
1917 Log { address, data: LogData::new_unchecked(vec![topic1, topic2], Default::default()) };
1918
1919 assert!(filter.matches(&log));
1920 }
1921
1922 #[test]
1923 fn can_match_topics_wildcard_mismatch() {
1924 let address = Address::with_last_byte(1);
1925 let topic1 = B256::with_last_byte(2);
1926 let topic2 = B256::with_last_byte(3);
1927 let bad_topic = B256::with_last_byte(4);
1928
1929 let filter = Filter {
1930 block_option: Default::default(),
1931 address: Default::default(),
1932 topics: [
1933 Default::default(),
1934 vec![topic1, topic2].into(),
1935 Default::default(),
1936 Default::default(),
1937 ],
1938 };
1939
1940 let log = Log {
1941 address,
1942 data: LogData::new_unchecked(vec![bad_topic, bad_topic], Default::default()),
1943 };
1944
1945 assert!(!filter.matches(&log));
1946 }
1947
1948 #[test]
1949 fn can_match_address_filter() {
1950 let address = Address::with_last_byte(1);
1951 let filter = Filter {
1952 block_option: Default::default(),
1953 address: address.into(),
1954 topics: Default::default(),
1955 };
1956
1957 assert!(filter.matches_address(address));
1958 }
1959
1960 #[test]
1961 fn can_detect_different_address() {
1962 let address = Address::with_last_byte(1);
1963 let bad_address = Address::with_last_byte(2);
1964 let filter = Filter {
1965 block_option: Default::default(),
1966 address: address.into(),
1967 topics: Default::default(),
1968 };
1969
1970 assert!(!filter.matches_address(bad_address));
1971 }
1972
1973 #[test]
1974 #[cfg(feature = "serde")]
1975 fn can_convert_to_ethers_filter() {
1976 let json = json!(
1977 {
1978 "fromBlock": "0x429d3b",
1979 "toBlock": "0x429d3b",
1980 "address": "0xb59f67a8bff5d8cd03f6ac17265c550ed8f33907",
1981 "topics": [
1982 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
1983 "0x00000000000000000000000000b46c2526e227482e2ebb8f4c69e4674d262e75",
1984 "0x00000000000000000000000054a2d42a40f51259dedd1978f6c118a0f0eff078"
1985 ]
1986 }
1987 );
1988
1989 let filter: Filter = serde_json::from_value(json).unwrap();
1990 assert_eq!(
1991 filter,
1992 Filter {
1993 block_option: FilterBlockOption::Range {
1994 from_block: Some(4365627u64.into()),
1995 to_block: Some(4365627u64.into()),
1996 },
1997 address: "0xb59f67a8bff5d8cd03f6ac17265c550ed8f33907"
1998 .parse::<Address>()
1999 .unwrap()
2000 .into(),
2001 topics: [
2002 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
2003 .parse::<B256>()
2004 .unwrap()
2005 .into(),
2006 "0x00000000000000000000000000b46c2526e227482e2ebb8f4c69e4674d262e75"
2007 .parse::<B256>()
2008 .unwrap()
2009 .into(),
2010 "0x00000000000000000000000054a2d42a40f51259dedd1978f6c118a0f0eff078"
2011 .parse::<B256>()
2012 .unwrap()
2013 .into(),
2014 Default::default(),
2015 ],
2016 }
2017 );
2018 }
2019
2020 #[test]
2021 #[cfg(feature = "serde")]
2022 fn can_convert_to_ethers_filter_with_null_fields() {
2023 let json = json!(
2024 {
2025 "fromBlock": "0x429d3b",
2026 "toBlock": "0x429d3b",
2027 "address": null,
2028 "topics": null
2029 }
2030 );
2031
2032 let filter: Filter = serde_json::from_value(json).unwrap();
2033 assert_eq!(
2034 filter,
2035 Filter {
2036 block_option: FilterBlockOption::Range {
2037 from_block: Some(4365627u64.into()),
2038 to_block: Some(4365627u64.into()),
2039 },
2040 address: Default::default(),
2041 topics: Default::default(),
2042 }
2043 );
2044 }
2045
2046 #[test]
2047 #[cfg(feature = "serde")]
2048 fn test_filter_with_null_range_block() {
2049 let json = json!(
2050 {
2051 "fromBlock": null,
2052 "toBlock": null,
2053 "blockHash": "0xe903ebc49101d30b28d7256be411f81418bf6809ddbaefc40201b1b97f2e64ee",
2054 "address": null,
2055 "topics": null
2056 }
2057 );
2058
2059 let filter: Filter = serde_json::from_value(json).unwrap();
2060 assert_eq!(
2061 filter.block_option,
2062 FilterBlockOption::AtBlockHash(
2063 "0xe903ebc49101d30b28d7256be411f81418bf6809ddbaefc40201b1b97f2e64ee"
2064 .parse()
2065 .unwrap()
2066 )
2067 );
2068 }
2069
2070 #[test]
2071 #[cfg(feature = "serde")]
2072 fn test_filter_with_null_block_hash() {
2073 let json = json!(
2074 {
2075 "fromBlock": "0x1",
2076 "toBlock": "0x2",
2077 "blockHash": null,
2078 "address": null,
2079 "topics": null
2080 }
2081 );
2082
2083 let filter: Filter = serde_json::from_value(json).unwrap();
2084 assert_eq!(
2085 filter.block_option,
2086 FilterBlockOption::Range { from_block: Some(1u64.into()), to_block: Some(2u64.into()) }
2087 );
2088 }
2089
2090 #[test]
2091 #[cfg(feature = "serde")]
2092 fn test_filter_with_null_block_hash_and_null_from_block() {
2093 let json = json!(
2094 {
2095 "fromBlock": null,
2096 "toBlock": "0x2",
2097 "blockHash": null,
2098 "address": null,
2099 "topics": null
2100 }
2101 );
2102
2103 let filter: Filter = serde_json::from_value(json).unwrap();
2104 assert_eq!(
2105 filter.block_option,
2106 FilterBlockOption::Range { from_block: None, to_block: Some(2u64.into()) }
2107 );
2108 }
2109
2110 #[test]
2111 #[cfg(feature = "serde")]
2112 fn test_filter_with_null_block_hash_and_null_to_block() {
2113 let json = json!(
2114 {
2115 "fromBlock": "0x1",
2116 "toBlock": null,
2117 "blockHash": null,
2118 "address": null,
2119 "topics": null
2120 }
2121 );
2122
2123 let filter: Filter = serde_json::from_value(json).unwrap();
2124 assert_eq!(
2125 filter.block_option,
2126 FilterBlockOption::Range { from_block: Some(1u64.into()), to_block: None }
2127 );
2128 }
2129
2130 #[test]
2131 fn test_is_pending_block_filter() {
2132 let filter = Filter {
2133 block_option: FilterBlockOption::Range {
2134 from_block: Some(BlockNumberOrTag::Pending),
2135 to_block: Some(BlockNumberOrTag::Pending),
2136 },
2137 address: "0xb59f67a8bff5d8cd03f6ac17265c550ed8f33907"
2138 .parse::<Address>()
2139 .unwrap()
2140 .into(),
2141 topics: [
2142 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
2143 .parse::<B256>()
2144 .unwrap()
2145 .into(),
2146 "0x00000000000000000000000000b46c2526e227482e2ebb8f4c69e4674d262e75"
2147 .parse::<B256>()
2148 .unwrap()
2149 .into(),
2150 "0x00000000000000000000000054a2d42a40f51259dedd1978f6c118a0f0eff078"
2151 .parse::<B256>()
2152 .unwrap()
2153 .into(),
2154 Default::default(),
2155 ],
2156 };
2157 assert!(filter.is_pending_block_filter());
2158
2159 let filter = Filter {
2160 block_option: FilterBlockOption::Range {
2161 from_block: Some(4365627u64.into()),
2162 to_block: Some(4365627u64.into()),
2163 },
2164 address: "0xb59f67a8bff5d8cd03f6ac17265c550ed8f33907"
2165 .parse::<Address>()
2166 .unwrap()
2167 .into(),
2168 topics: [
2169 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
2170 .parse::<B256>()
2171 .unwrap()
2172 .into(),
2173 "0x00000000000000000000000000b46c2526e227482e2ebb8f4c69e4674d262e75"
2174 .parse::<B256>()
2175 .unwrap()
2176 .into(),
2177 "0x00000000000000000000000054a2d42a40f51259dedd1978f6c118a0f0eff078"
2178 .parse::<B256>()
2179 .unwrap()
2180 .into(),
2181 Default::default(),
2182 ],
2183 };
2184 assert!(!filter.is_pending_block_filter());
2185 }
2186
2187 #[test]
2188 fn test_filter_set_topic_extend() {
2189 let mut topic = Topic::default();
2190
2191 topic =
2193 topic.extend(U256::from(123)).extend(Address::random()).extend(true).extend([0u8; 32]);
2194
2195 assert_eq!(topic.set.len(), 4);
2196
2197 topic = topic.extend(U256::from(123));
2198 assert_eq!(topic.set.len(), 4);
2199
2200 topic = topic.extend(U256::from(456));
2201 assert_eq!(topic.set.len(), 5);
2202 }
2203
2204 #[test]
2205 fn test_append_matching_block_logs() {
2206 use alloy_consensus::Receipt;
2207 use alloy_primitives::Bytes;
2208
2209 let addr1 = Address::from([0x11; 20]);
2211 let addr2 = Address::from([0x22; 20]);
2212 let topic1 = B256::from([0x01; 32]);
2213 let topic2 = B256::from([0x02; 32]);
2214
2215 let receipt1 = Receipt {
2217 status: alloy_consensus::Eip658Value::Eip658(true),
2218 cumulative_gas_used: 100000,
2219 logs: vec![
2220 alloy_primitives::Log {
2221 address: addr1,
2222 data: LogData::new(vec![topic1], Bytes::from(vec![0x01, 0x02])).unwrap(),
2223 },
2224 alloy_primitives::Log {
2225 address: addr2,
2226 data: LogData::new(vec![topic2], Bytes::from(vec![0x03, 0x04])).unwrap(),
2227 },
2228 ],
2229 };
2230
2231 let receipt2 = Receipt {
2232 status: alloy_consensus::Eip658Value::Eip658(true),
2233 cumulative_gas_used: 200000,
2234 logs: vec![alloy_primitives::Log {
2235 address: addr1,
2236 data: LogData::new(vec![topic2], Bytes::from(vec![0x05])).unwrap(),
2237 }],
2238 };
2239
2240 let receipts = [receipt1, receipt2];
2241 let tx_hashes = [B256::from([0xaa; 32]), B256::from([0xbb; 32])];
2242
2243 let block_num_hash = BlockNumHash::new(1000, B256::from([0xff; 32]));
2244 let block_timestamp = 1234567890;
2245
2246 let filter = Filter::new().address(addr1);
2248 let mut result = Vec::new();
2249 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2250 filter.append_matching_block_logs(
2251 &mut result,
2252 block_num_hash,
2253 block_timestamp,
2254 tx_receipt_pairs,
2255 false,
2256 );
2257
2258 assert_eq!(result.len(), 2);
2259 assert_eq!(result[0].inner.address, addr1);
2260 assert_eq!(result[0].transaction_hash, Some(tx_hashes[0]));
2261 assert_eq!(result[0].log_index, Some(0));
2262 assert_eq!(result[0].transaction_index, Some(0));
2263 assert_eq!(result[1].inner.address, addr1);
2264 assert_eq!(result[1].transaction_hash, Some(tx_hashes[1]));
2265 assert_eq!(result[1].log_index, Some(2));
2266 assert_eq!(result[1].transaction_index, Some(1));
2267
2268 let filter = Filter::new().event_signature(topic2);
2270 let mut result = Vec::new();
2271 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2272 filter.append_matching_block_logs(
2273 &mut result,
2274 block_num_hash,
2275 block_timestamp,
2276 tx_receipt_pairs,
2277 false,
2278 );
2279
2280 assert_eq!(result.len(), 2);
2281 assert_eq!(result[0].inner.data.topics()[0], topic2);
2282 assert_eq!(result[0].transaction_hash, Some(tx_hashes[0]));
2283 assert_eq!(result[0].log_index, Some(1));
2284 assert_eq!(result[1].inner.data.topics()[0], topic2);
2285 assert_eq!(result[1].transaction_hash, Some(tx_hashes[1]));
2286 assert_eq!(result[1].log_index, Some(2));
2287
2288 let filter = Filter::new().address(Address::from([0x99; 20]));
2290 let mut result = Vec::new();
2291 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2292 filter.append_matching_block_logs(
2293 &mut result,
2294 block_num_hash,
2295 block_timestamp,
2296 tx_receipt_pairs,
2297 false,
2298 );
2299
2300 assert_eq!(result.len(), 0);
2301
2302 let filter = Filter::new();
2304 let mut result = Vec::new();
2305 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2306 filter.append_matching_block_logs(
2307 &mut result,
2308 block_num_hash,
2309 block_timestamp,
2310 tx_receipt_pairs,
2311 true, );
2313
2314 assert_eq!(result.len(), 3);
2315 for log in &result {
2316 assert_eq!(log.block_hash, Some(block_num_hash.hash));
2317 assert_eq!(log.block_number, Some(block_num_hash.number));
2318 assert_eq!(log.block_timestamp, Some(block_timestamp));
2319 assert!(log.removed);
2320 }
2321
2322 let filter = Filter::new().from_block(1000u64).to_block(1000u64).address(addr1);
2324 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2325 let result =
2326 filter.matching_block_logs(block_num_hash, block_timestamp, tx_receipt_pairs, false);
2327
2328 assert_eq!(result.len(), 2);
2329 assert_eq!(result[0].inner.address, addr1);
2330 assert_eq!(result[1].inner.address, addr1);
2331
2332 let filter = Filter::new().from_block(2000u64).to_block(2000u64);
2334 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2335 let result =
2336 filter.matching_block_logs(block_num_hash, block_timestamp, tx_receipt_pairs, false);
2337
2338 assert_eq!(result.len(), 0); let filter = Filter::new().from_block(2000u64).to_block(2000u64);
2342 let mut result = Vec::new();
2343 let tx_receipt_pairs: Vec<_> = tx_hashes.iter().copied().zip(receipts.iter()).collect();
2344 filter.append_matching_block_logs(
2345 &mut result,
2346 block_num_hash,
2347 block_timestamp,
2348 tx_receipt_pairs,
2349 false,
2350 );
2351
2352 assert_eq!(result.len(), 0); }
2354
2355 #[test]
2356 fn test_filter_receipts_iterator() {
2357 use alloy_consensus::Receipt;
2358 use alloy_primitives::Bytes;
2359
2360 let addr1 = Address::from([0x11; 20]);
2362 let addr2 = Address::from([0x22; 20]);
2363 let topic1 = B256::from([0x01; 32]);
2364 let topic2 = B256::from([0x02; 32]);
2365
2366 let block1_receipts = vec![
2368 Receipt {
2369 status: alloy_consensus::Eip658Value::Eip658(true),
2370 cumulative_gas_used: 100000,
2371 logs: vec![
2372 alloy_primitives::Log {
2373 address: addr1,
2374 data: LogData::new(vec![topic1], Bytes::from(vec![0x01, 0x02])).unwrap(),
2375 },
2376 alloy_primitives::Log {
2377 address: addr2,
2378 data: LogData::new(vec![topic2], Bytes::from(vec![0x03, 0x04])).unwrap(),
2379 },
2380 ],
2381 },
2382 Receipt {
2383 status: alloy_consensus::Eip658Value::Eip658(true),
2384 cumulative_gas_used: 200000,
2385 logs: vec![alloy_primitives::Log {
2386 address: addr1,
2387 data: LogData::new(vec![topic2], Bytes::from(vec![0x05])).unwrap(),
2388 }],
2389 },
2390 ];
2391
2392 let block2_receipts = vec![Receipt {
2394 status: alloy_consensus::Eip658Value::Eip658(true),
2395 cumulative_gas_used: 300000,
2396 logs: vec![
2397 alloy_primitives::Log {
2398 address: addr1,
2399 data: LogData::new(vec![topic1], Bytes::from(vec![0x06])).unwrap(),
2400 },
2401 alloy_primitives::Log {
2402 address: addr2,
2403 data: LogData::new(vec![topic1], Bytes::from(vec![0x07])).unwrap(),
2404 },
2405 ],
2406 }];
2407
2408 let all_receipts = vec![block1_receipts, block2_receipts];
2409
2410 let filter = Filter::new().address(addr1);
2412 let logs: Vec<_> = filter.filter_receipts(all_receipts.clone()).collect();
2413 assert_eq!(logs.len(), 3); assert!(logs.iter().all(|log| log.address == addr1));
2415
2416 let filter = Filter::new().event_signature(topic1);
2418 let logs: Vec<_> = filter.filter_receipts(all_receipts.clone()).collect();
2419
2420 assert_eq!(logs.len(), 3); assert!(logs.iter().all(|log| log.topics()[0] == topic1));
2426
2427 let filter = Filter::new().address(addr1).event_signature(topic2);
2429 let logs: Vec<_> = filter.filter_receipts(all_receipts.clone()).collect();
2430 assert_eq!(logs.len(), 1); assert_eq!(logs[0].address, addr1);
2432 assert_eq!(logs[0].topics()[0], topic2);
2433
2434 let filter = Filter::new().address(Address::from([0x99; 20]));
2436 let logs: Vec<_> = filter.filter_receipts(all_receipts.clone()).collect();
2437 assert_eq!(logs.len(), 0);
2438
2439 let filter = Filter::new();
2441 let logs: Vec<_> = filter.filter_receipts(all_receipts).collect();
2442 assert_eq!(logs.len(), 5); }
2444}