diff --git a/Cargo.lock b/Cargo.lock index f41fa41fe..4f6843560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5792,6 +5792,7 @@ dependencies = [ name = "reth-rpc-types" version = "0.1.0-alpha.4" dependencies = [ + "itertools 0.10.5", "jsonrpsee-types", "rand 0.8.5", "reth-primitives", diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index cd4913698..d181a462f 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -22,7 +22,7 @@ crunchy = { version = "0.2.2", default-features = false, features = ["limit_256" ruint = { version = "1.9.0", features = ["primitive-types", "rlp"] } # Bloom -fixed-hash = { version = "0.8", default-features = false, features = ["rustc-hex"] } + fixed-hash = { version = "0.8", default-features = false, features = ["rustc-hex"] } # crypto secp256k1 = { workspace = true, default-features = false, features = [ diff --git a/crates/rpc/rpc-types/Cargo.toml b/crates/rpc/rpc-types/Cargo.toml index 71c1b80be..0ebeeff0c 100644 --- a/crates/rpc/rpc-types/Cargo.toml +++ b/crates/rpc/rpc-types/Cargo.toml @@ -19,6 +19,7 @@ reth-rlp.workspace = true thiserror.workspace = true # misc +itertools = "0.10" serde = { workspace = true, features = ["derive"] } serde_json.workspace = true jsonrpsee-types = { version = "0.18" } diff --git a/crates/rpc/rpc-types/src/eth/filter.rs b/crates/rpc/rpc-types/src/eth/filter.rs index d4b6365cc..29ca1f412 100644 --- a/crates/rpc/rpc-types/src/eth/filter.rs +++ b/crates/rpc/rpc-types/src/eth/filter.rs @@ -1,4 +1,5 @@ use crate::Log as RpcLog; +use itertools::{EitherOrBoth::*, Itertools}; use jsonrpsee_types::SubscriptionId; use reth_primitives::{ bloom::{Bloom, Input}, @@ -9,13 +10,120 @@ use serde::{ ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer, }; -use std::ops::{Range, RangeFrom, RangeTo}; +use std::{ + collections::HashSet, + hash::Hash, + ops::{Range, RangeFrom, RangeTo}, +}; /// Helper type to represent a bloom filter used for matching logs. -pub type BloomFilter = Vec>; +#[derive(Default, Debug)] +pub struct BloomFilter(Vec); + +impl From> for BloomFilter { + fn from(src: Vec) -> Self { + BloomFilter(src) + } +} + +impl BloomFilter { + /// Returns whether the given bloom matches the list of Blooms in the current filter. + /// If the filter is empty (the list is empty), then any bloom matches + /// Otherwise, there must be at least one matche for the BloomFilter to match. + pub fn matches(&self, bloom: Bloom) -> bool { + self.0.is_empty() || self.0.iter().any(|a| bloom.contains_bloom(a)) + } +} + +#[derive(Default, Debug, PartialEq, Eq, Clone, Deserialize)] +/// FilterSet is a set of values that will be used to filter logs +pub struct FilterSet(HashSet); + +impl From for FilterSet { + fn from(src: T) -> Self { + FilterSet(HashSet::from([src])) + } +} + +impl From> for FilterSet { + fn from(src: Vec) -> Self { + FilterSet(HashSet::from_iter(src.into_iter().map(Into::into))) + } +} + +impl From> for FilterSet { + fn from(src: ValueOrArray) -> Self { + match src { + ValueOrArray::Value(val) => val.into(), + ValueOrArray::Array(arr) => arr.into(), + } + } +} + +impl From>> for FilterSet { + fn from(src: ValueOrArray>) -> Self { + match src { + ValueOrArray::Value(None) => FilterSet(HashSet::new()), + ValueOrArray::Value(Some(val)) => val.into(), + ValueOrArray::Array(arr) => { + // If the array contains at least one `null` (ie. None), as it's considered + // a "wildcard" value, the whole filter should be treated as matching everything, + // thus is empty. + if arr.iter().contains(&None) { + FilterSet(HashSet::new()) + } else { + // Otherwise, we flatten the array, knowing there are no `None` values + arr.into_iter().flatten().collect::>().into() + } + } + } + } +} + +impl FilterSet { + /// Returns wheter the filter is empty + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Returns whether the given value matches the filter. It the filter is empty + /// any value matches. Otherwise, the filter must include the value + pub fn matches(&self, value: &T) -> bool { + self.is_empty() || self.0.contains(value) + } +} + +impl + Eq + Hash> FilterSet { + /// Returns a list of Bloom (BloomFilter) corresponding to the filter's values + pub fn to_bloom_filter(&self) -> BloomFilter { + self.0.iter().map(|a| Input::Raw(a.as_ref()).into()).collect::>().into() + } +} + +impl FilterSet { + /// Returns a ValueOrArray inside an Option, so that: + /// - If the filter is empty, it returns None + /// - If the filter has only 1 value, it returns the single value + /// - Otherwise it returns an array of values + /// This should be useful for serialization + pub fn to_value_or_array(&self) -> Option> { + let mut values = self.0.iter().cloned().collect::>(); + match values.len() { + 0 => None, + 1 => Some(ValueOrArray::Value(values.pop().expect("values length is one"))), + _ => Some(ValueOrArray::Array(values)), + } + } +} /// A single topic -pub type Topic = ValueOrArray>; +pub type Topic = FilterSet; + +impl From for Topic { + fn from(src: U256) -> Self { + Into::::into(src).into() + } +} /// Represents the target range of blocks for the filter #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -141,16 +249,16 @@ impl FilterBlockOption { } /// Filter for -#[derive(Default, Debug, PartialEq, Eq, Clone, Hash)] +#[derive(Default, Debug, PartialEq, Eq, Clone)] pub struct Filter { /// Filter block options, specifying on which blocks the filter should /// match. // https://eips.ethereum.org/EIPS/eip-234 pub block_option: FilterBlockOption, /// Address - pub address: Option>, + pub address: FilterSet
, /// Topics (maxmimum of 4) - pub topics: [Option; 4], + pub topics: [Topic; 4], } impl Filter { @@ -279,7 +387,7 @@ impl Filter { /// ``` #[must_use] pub fn address>>(mut self, address: T) -> Self { - self.address = Some(address.into()); + self.address = address.into().into(); self } @@ -300,28 +408,28 @@ impl Filter { /// Sets topic0 (the event name for non-anonymous events) #[must_use] pub fn topic0>(mut self, topic: T) -> Self { - self.topics[0] = Some(topic.into()); + self.topics[0] = topic.into(); self } /// Sets the 1st indexed topic #[must_use] pub fn topic1>(mut self, topic: T) -> Self { - self.topics[1] = Some(topic.into()); + self.topics[1] = topic.into(); self } /// Sets the 2nd indexed topic #[must_use] pub fn topic2>(mut self, topic: T) -> Self { - self.topics[2] = Some(topic.into()); + self.topics[2] = topic.into(); self } /// Sets the 3rd indexed topic #[must_use] pub fn topic3>(mut self, topic: T) -> Self { - self.topics[3] = Some(topic.into()); + self.topics[3] = topic.into(); self } @@ -348,64 +456,9 @@ impl Filter { } } - /// Flattens the topics using the cartesian product - fn flatten(&self) -> Vec>> { - fn cartesian(lists: &[Vec>]) -> Vec>> { - let mut res = Vec::new(); - let mut list_iter = lists.iter(); - if let Some(first_list) = list_iter.next() { - for &i in first_list { - res.push(vec![i]); - } - } - for l in list_iter { - let mut tmp = Vec::new(); - for r in res { - for &el in l { - let mut tmp_el = r.clone(); - tmp_el.push(el); - tmp.push(tmp_el); - } - } - res = tmp; - } - res - } - let mut out = Vec::new(); - let mut tmp = Vec::new(); - for v in self.topics.iter() { - let v = if let Some(v) = v { - match v { - ValueOrArray::Value(s) => { - vec![*s] - } - ValueOrArray::Array(s) => { - if s.is_empty() { - vec![None] - } else { - s.clone() - } - } - } - } else { - vec![None] - }; - tmp.push(v); - } - for v in cartesian(&tmp) { - out.push(ValueOrArray::Array(v)); - } - out - } - - /// Returns an iterator over all existing topics - pub fn topics(&self) -> impl Iterator + '_ { - self.topics.iter().flatten() - } - /// Returns true if at least one topic is set pub fn has_topics(&self) -> bool { - self.topics.iter().any(|t| t.is_some()) + self.topics.iter().any(|t| !t.is_empty()) } } @@ -429,27 +482,28 @@ impl Serialize for Filter { FilterBlockOption::AtBlockHash(ref h) => s.serialize_field("blockHash", h)?, } - if let Some(ref address) = self.address { - s.serialize_field("address", address)?; + if let Some(address) = self.address.to_value_or_array() { + s.serialize_field("address", &address)?; } let mut filtered_topics = Vec::new(); - for i in 0..4 { - if self.topics[i].is_some() { - filtered_topics.push(&self.topics[i]); - } else { - // TODO: This can be optimized - if self.topics[i + 1..].iter().any(|x| x.is_some()) { - filtered_topics.push(&None); - } + let mut filtered_topics_len = 0; + for (i, topic) in self.topics.iter().enumerate() { + if !topic.is_empty() { + filtered_topics_len = i + 1; } + filtered_topics.push(topic.to_value_or_array()); } + filtered_topics.truncate(filtered_topics_len); s.serialize_field("topics", &filtered_topics)?; s.end() } } +type RawAddressFilter = ValueOrArray>; +type RawTopicsFilter = Vec>>>; + impl<'de> Deserialize<'de> for Filter { fn deserialize(deserializer: D) -> Result where @@ -471,8 +525,8 @@ impl<'de> Deserialize<'de> for Filter { let mut from_block: Option> = None; let mut to_block: Option> = None; let mut block_hash: Option> = None; - let mut address: Option>> = None; - let mut topics: Option>>> = None; + let mut address: Option> = None; + let mut topics: Option> = None; while let Some(key) = map.next_key::()? { match key.as_str() { @@ -534,16 +588,21 @@ impl<'de> Deserialize<'de> for Filter { let from_block = from_block.unwrap_or_default(); let to_block = to_block.unwrap_or_default(); let block_hash = block_hash.unwrap_or_default(); - let address = address.unwrap_or_default(); + let address = address.flatten().map(|a| a.into()).unwrap_or_default(); let topics_vec = topics.flatten().unwrap_or_default(); // maximum allowed filter len if topics_vec.len() > 4 { return Err(serde::de::Error::custom("exceeded maximum topics len")) } - let mut topics: [Option; 4] = [None, None, None, None]; + let mut topics: [Topic; 4] = [ + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ]; for (idx, topic) in topics_vec.into_iter().enumerate() { - topics[idx] = topic; + topics[idx] = topic.map(|t| t.into()).unwrap_or_default(); } let block_option = if let Some(block_hash) = block_hash { @@ -581,47 +640,12 @@ impl From> for ValueOrArray { } } -impl From for Topic { - fn from(src: H256) -> Self { - ValueOrArray::Value(Some(src)) - } -} - impl From> for ValueOrArray { fn from(src: Vec) -> Self { ValueOrArray::Array(src) } } -impl From> for Topic { - fn from(src: ValueOrArray) -> Self { - match src { - ValueOrArray::Value(val) => ValueOrArray::Value(Some(val)), - ValueOrArray::Array(arr) => arr.into(), - } - } -} - -impl> From> for Topic { - fn from(src: Vec) -> Self { - ValueOrArray::Array(src.into_iter().map(Into::into).map(Some).collect()) - } -} - -impl From
for Topic { - fn from(src: Address) -> Self { - let mut bytes = [0; 32]; - bytes[12..32].copy_from_slice(src.as_bytes()); - ValueOrArray::Value(Some(H256::from(bytes))) - } -} - -impl From for Topic { - fn from(src: U256) -> Self { - ValueOrArray::Value(Some(src.into())) - } -} - impl Serialize for ValueOrArray where T: Serialize, @@ -672,8 +696,6 @@ where pub struct FilteredParams { /// The original filter, if any pub filter: Option, - /// Flattened topics of the `filter` used to determine if the the filter matches a log. - pub flat_topics: Vec>>, } impl FilteredParams { @@ -681,86 +703,43 @@ impl FilteredParams { /// for matching pub fn new(filter: Option) -> Self { if let Some(filter) = filter { - let flat_topics = filter.flatten(); - FilteredParams { filter: Some(filter), flat_topics } + FilteredParams { filter: Some(filter) } } else { Default::default() } } /// Returns the [BloomFilter] for the given address - pub fn address_filter(address: &Option>) -> BloomFilter { - address.as_ref().map(address_to_bloom_filter).unwrap_or_default() + pub fn address_filter(address: &FilterSet
) -> BloomFilter { + address.to_bloom_filter() } /// Returns the [BloomFilter] for the given topics - pub fn topics_filter(topics: &Option>>>) -> Vec { - let mut output = Vec::new(); - if let Some(topics) = topics { - output.extend(topics.iter().map(topics_to_bloom_filter)); - } - output + pub fn topics_filter(topics: &[FilterSet]) -> Vec { + topics.iter().map(|t| t.to_bloom_filter()).collect() } /// Returns `true` if the bloom matches the topics - pub fn matches_topics(bloom: Bloom, topic_filters: &[BloomFilter]) -> bool { + pub fn matches_topics(bloom: Bloom, topic_filters: &Vec) -> bool { if topic_filters.is_empty() { return true } - // returns true if a filter matches + // for each filter, iterate through the list of filter blooms. for each set of filter + // (each BloomFilter), the given `bloom` must match at least one of them, unless the list is + // empty (no filters). for filter in topic_filters.iter() { - let mut is_match = false; - for maybe_bloom in filter { - is_match = maybe_bloom.as_ref().map(|b| bloom.contains_bloom(b)).unwrap_or(true); - if !is_match { - break - } - } - if is_match { - return true + if !filter.matches(bloom) { + return false } } - false + true } - /// Returns `true` if the bloom contains the address + /// Returns `true` if the bloom contains one of the address blooms, or the address blooms + /// list is empty (thus, no filters) pub fn matches_address(bloom: Bloom, address_filter: &BloomFilter) -> bool { - if address_filter.is_empty() { - return true - } else { - for maybe_bloom in address_filter { - if maybe_bloom.as_ref().map(|b| bloom.contains_bloom(b)).unwrap_or(true) { - return true - } - } - } - false - } - - /// Replace None values - aka wildcards - for the log input value in that position. - pub fn replace(&self, log: &Log, topic: Topic) -> Option> { - let mut out: Vec = Vec::new(); - match topic { - ValueOrArray::Value(value) => { - if let Some(value) = value { - out.push(value); - } - } - ValueOrArray::Array(value) => { - for (k, v) in value.into_iter().enumerate() { - if let Some(v) = v { - out.push(v); - } else { - out.push(log.topics[k]); - } - } - } - }; - if out.is_empty() { - return None - } - Some(out) + address_filter.matches(bloom) } /// Returns true if the filter matches the given block number @@ -805,18 +784,30 @@ impl FilteredParams { /// Returns `true` if the filter matches the given log. pub fn filter_address(&self, log: &Log) -> bool { - if let Some(input_address) = &self.filter.as_ref().and_then(|f| f.address.clone()) { - match input_address { - ValueOrArray::Value(x) => { - if log.address != *x { + self.filter.as_ref().map(|f| f.address.matches(&log.address)).unwrap_or(true) + } + + /// Returns `true` if the log matches the filter's topics + pub fn filter_topics(&self, log: &Log) -> bool { + let topics = match self.filter.as_ref() { + None => return true, + Some(f) => &f.topics, + }; + for topic_tuple in topics.iter().zip_longest(log.topics.iter()) { + match topic_tuple { + // We exhausted the `log.topics`, so if there's a filter set for + // this topic index, there is no match. Otherwise (empty filter), continue. + Left(filter_topic) => { + if !filter_topic.is_empty() { return false } } - ValueOrArray::Array(x) => { - if x.is_empty() { - return true - } - if !x.contains(&log.address) { + // We exhausted the filter topics, therefore any subsequent log topic + // will match. + Right(_) => return true, + // Check that `log_topic` is included in `filter_topic` + Both(filter_topic, log_topic) => { + if !filter_topic.matches(log_topic) { return false } } @@ -824,98 +815,6 @@ impl FilteredParams { } true } - - /// Returns `true` if the log matches any topic - pub fn filter_topics(&self, log: &Log) -> bool { - let mut out: bool = true; - for topic in self.flat_topics.iter().cloned() { - match topic { - ValueOrArray::Value(single) => { - if let Some(single) = single { - if !log.topics.starts_with(&[single]) { - out = false; - } - } - } - ValueOrArray::Array(multi) => { - if multi.is_empty() { - out = true; - continue - } - // Shrink the topics until the last item is Some. - let mut new_multi = multi; - while new_multi.iter().last().unwrap_or(&Some(H256::default())).is_none() { - new_multi.pop(); - } - // We can discard right away any logs with lesser topics than the filter. - if new_multi.len() > log.topics.len() { - out = false; - break - } - let replaced: Option> = - self.replace(log, ValueOrArray::Array(new_multi)); - if let Some(replaced) = replaced { - out = false; - if log.topics.starts_with(&replaced[..]) { - out = true; - break - } - } - } - } - } - out - } -} - -fn topics_to_bloom_filter(topics: &ValueOrArray>) -> BloomFilter { - let mut blooms = BloomFilter::new(); - match topics { - ValueOrArray::Value(topic) => { - if let Some(topic) = topic { - let bloom: Bloom = Input::Raw(topic.as_ref()).into(); - blooms.push(Some(bloom)); - } else { - blooms.push(None); - } - } - ValueOrArray::Array(topics) => { - if topics.is_empty() { - blooms.push(None); - } else { - for topic in topics.iter() { - if let Some(topic) = topic { - let bloom: Bloom = Input::Raw(topic.as_ref()).into(); - blooms.push(Some(bloom)); - } else { - blooms.push(None); - } - } - } - } - } - blooms -} - -fn address_to_bloom_filter(address: &ValueOrArray
) -> BloomFilter { - let mut blooms = BloomFilter::new(); - match address { - ValueOrArray::Value(address) => { - let bloom: Bloom = Input::Raw(address.as_ref()).into(); - blooms.push(Some(bloom)) - } - ValueOrArray::Array(addresses) => { - if addresses.is_empty() { - blooms.push(None); - } else { - for address in addresses.iter() { - let bloom: Bloom = Input::Raw(address.as_ref()).into(); - blooms.push(Some(bloom)); - } - } - } - } - blooms } /// Response of the `eth_getFilterChanges` RPC. @@ -1007,6 +906,7 @@ impl From> for FilterId { #[cfg(test)] mod tests { use super::*; + use reth_primitives::U256; use serde_json::json; fn serialize(t: &T) -> serde_json::Value { @@ -1020,40 +920,36 @@ mod tests { similar_asserts::assert_eq!( filter.topics, [ - Some(ValueOrArray::Array(vec![Some( - "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" - .parse() - .unwrap() - ),])), - Some(ValueOrArray::Array(vec![])), - Some(ValueOrArray::Array(vec![Some( - "0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778" - .parse() - .unwrap() - )])), - None + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + .parse::() + .unwrap() + .into(), + Default::default(), + "0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778" + .parse::() + .unwrap() + .into(), + Default::default(), ] ); + } - let filtered_params = FilteredParams::new(Some(filter)); - let topics = filtered_params.flat_topics; - assert_eq!( - topics, - vec![ValueOrArray::Array(vec![ - Some( - "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" - .parse() - .unwrap() - ), - None, - Some( - "0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778" - .parse() - .unwrap() - ), - None - ])] - ) + #[test] + fn test_filter_topics_middle_wildcard() { + let s = r#"{"fromBlock": "0xfc359e", "toBlock": "0xfc359e", "topics": [["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"], [], [null, "0x0000000000000000000000000c17e776cd218252adfca8d4e761d3fe757e9778"]]}"#; + let filter = serde_json::from_str::(s).unwrap(); + similar_asserts::assert_eq!( + filter.topics, + [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + .parse::() + .unwrap() + .into(), + Default::default(), + Default::default(), + Default::default(), + ] + ); } #[test] @@ -1076,11 +972,13 @@ mod tests { #[test] fn filter_serialization_test() { - let t1 = "9729a6fbefefc8f6005933898b13dc45c3a2c8b7".parse::
().unwrap(); + let t1 = "0000000000000000000000009729a6fbefefc8f6005933898b13dc45c3a2c8b7" + .parse::() + .unwrap(); let t2 = H256::from([0; 32]); let t3 = U256::from(123); - let t1_padded = H256::from(t1); + let t1_padded = t1; let t3_padded = H256::from({ let mut x = [0; 32]; x[31] = 123; @@ -1143,24 +1041,17 @@ mod tests { block_bloom } - fn topic_filter( - topic1: H256, - topic2: H256, - topic3: H256, - ) -> (Filter, Option>>>) { - let filter = Filter { + fn topic_filter(topic1: H256, topic2: H256, topic3: H256) -> Filter { + Filter { block_option: Default::default(), - address: None, + address: Default::default(), topics: [ - Some(ValueOrArray::Value(Some(topic1))), - Some(ValueOrArray::Array(vec![Some(topic2), Some(topic3)])), - None, - None, + topic1.into(), + vec![topic2, topic3].into(), + Default::default(), + Default::default(), ], - }; - let filtered_params = FilteredParams::new(Some(filter.clone())); - - (filter, Some(filtered_params.flat_topics)) + } } #[test] @@ -1169,7 +1060,7 @@ mod tests { let topic2 = H256::random(); let topic3 = H256::random(); - let (_, topics) = topic_filter(topic1, topic2, topic3); + let topics = topic_filter(topic1, topic2, topic3).topics; let topics_bloom = FilteredParams::topics_filter(&topics); assert!(!FilteredParams::matches_topics( build_bloom(Address::random(), H256::random(), H256::random()), @@ -1183,7 +1074,7 @@ mod tests { let topic2 = H256::random(); let topic3 = H256::random(); - let (_, topics) = topic_filter(topic1, topic2, topic3); + let topics = topic_filter(topic1, topic2, topic3).topics; let _topics_bloom = FilteredParams::topics_filter(&topics); let topics_bloom = FilteredParams::topics_filter(&topics); @@ -1195,11 +1086,12 @@ mod tests { #[test] fn can_match_empty_topics() { - let filter = - Filter { block_option: Default::default(), address: None, topics: Default::default() }; - - let filtered_params = FilteredParams::new(Some(filter)); - let topics = Some(filtered_params.flat_topics); + let filter = Filter { + block_option: Default::default(), + address: Default::default(), + topics: Default::default(), + }; + let topics = filter.topics; let topics_bloom = FilteredParams::topics_filter(&topics); assert!(FilteredParams::matches_topics( @@ -1217,16 +1109,16 @@ mod tests { let filter = Filter { block_option: Default::default(), - address: Some(ValueOrArray::Value(rng_address)), + address: rng_address.into(), topics: [ - Some(ValueOrArray::Value(Some(topic1))), - Some(ValueOrArray::Array(vec![Some(topic2), Some(topic3)])), - None, - None, + topic1.into(), + vec![topic2, topic3].into(), + Default::default(), + Default::default(), ], }; - let filtered_params = FilteredParams::new(Some(filter.clone())); - let topics = Some(filtered_params.flat_topics); + let topics = filter.topics; + let address_filter = FilteredParams::address_filter(&filter.address); let topics_filter = FilteredParams::topics_filter(&topics); assert!( @@ -1248,11 +1140,16 @@ mod tests { let filter = Filter { block_option: Default::default(), - address: None, - topics: [None, Some(ValueOrArray::Array(vec![Some(topic2), Some(topic3)])), None, None], + address: Default::default(), + topics: [ + Default::default(), + vec![topic2, topic3].into(), + Default::default(), + Default::default(), + ], }; - let filtered_params = FilteredParams::new(Some(filter)); - let topics = Some(filtered_params.flat_topics); + let topics = filter.topics; + let topics_bloom = FilteredParams::topics_filter(&topics); assert!(FilteredParams::matches_topics( build_bloom(Address::random(), topic1, topic2), @@ -1264,16 +1161,16 @@ mod tests { fn can_match_topics_wildcard_mismatch() { let filter = Filter { block_option: Default::default(), - address: None, + address: Default::default(), topics: [ - None, - Some(ValueOrArray::Array(vec![Some(H256::random()), Some(H256::random())])), - None, - None, + Default::default(), + vec![H256::random(), H256::random()].into(), + Default::default(), + Default::default(), ], }; - let filtered_params = FilteredParams::new(Some(filter)); - let topics_input = Some(filtered_params.flat_topics); + let topics_input = filter.topics; + let topics_bloom = FilteredParams::topics_filter(&topics_input); assert!(!FilteredParams::matches_topics( build_bloom(Address::random(), H256::random(), H256::random()), @@ -1286,7 +1183,7 @@ mod tests { let rng_address = Address::random(); let filter = Filter { block_option: Default::default(), - address: Some(ValueOrArray::Value(rng_address)), + address: rng_address.into(), topics: Default::default(), }; let address_bloom = FilteredParams::address_filter(&filter.address); @@ -1302,7 +1199,7 @@ mod tests { let rng_address = Address::random(); let filter = Filter { block_option: Default::default(), - address: Some(ValueOrArray::Value(rng_address)), + address: rng_address.into(), topics: Default::default(), }; let address_bloom = FilteredParams::address_filter(&filter.address); @@ -1335,26 +1232,24 @@ mod tests { from_block: Some(4365627u64.into()), to_block: Some(4365627u64.into()), }, - address: Some(ValueOrArray::Value( - "0xb59f67a8bff5d8cd03f6ac17265c550ed8f33907".parse().unwrap() - )), + address: "0xb59f67a8bff5d8cd03f6ac17265c550ed8f33907" + .parse::
() + .unwrap() + .into(), topics: [ - Some(ValueOrArray::Value(Some( - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" - .parse() - .unwrap(), - ))), - Some(ValueOrArray::Value(Some( - "0x00000000000000000000000000b46c2526e227482e2ebb8f4c69e4674d262e75" - .parse() - .unwrap(), - ))), - Some(ValueOrArray::Value(Some( - "0x00000000000000000000000054a2d42a40f51259dedd1978f6c118a0f0eff078" - .parse() - .unwrap(), - ))), - None, + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + .parse::() + .unwrap() + .into(), + "0x00000000000000000000000000b46c2526e227482e2ebb8f4c69e4674d262e75" + .parse::() + .unwrap() + .into(), + "0x00000000000000000000000054a2d42a40f51259dedd1978f6c118a0f0eff078" + .parse::() + .unwrap() + .into(), + Default::default(), ], } ); @@ -1379,8 +1274,8 @@ mod tests { from_block: Some(4365627u64.into()), to_block: Some(4365627u64.into()), }, - address: None, - topics: [None, None, None, None,], + address: Default::default(), + topics: Default::default(), } ); } diff --git a/crates/rpc/rpc-types/src/eth/pubsub.rs b/crates/rpc/rpc-types/src/eth/pubsub.rs index d54f6f849..bf2b3b55d 100644 --- a/crates/rpc/rpc-types/src/eth/pubsub.rs +++ b/crates/rpc/rpc-types/src/eth/pubsub.rs @@ -97,7 +97,7 @@ pub enum SubscriptionKind { } /// Any additional parameters for a subscription. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub enum Params { /// No parameters passed. #[default] diff --git a/crates/rpc/rpc/src/eth/filter.rs b/crates/rpc/rpc/src/eth/filter.rs index e7b397307..280bc0817 100644 --- a/crates/rpc/rpc/src/eth/filter.rs +++ b/crates/rpc/rpc/src/eth/filter.rs @@ -363,11 +363,9 @@ where let mut all_logs = Vec::new(); let filter_params = FilteredParams::new(Some(filter.clone())); - let topics = filter.has_topics().then(|| filter_params.flat_topics.clone()); - // derive bloom filters from filter input let address_filter = FilteredParams::address_filter(&filter.address); - let topics_filter = FilteredParams::topics_filter(&topics); + let topics_filter = FilteredParams::topics_filter(&filter.topics); let is_multi_block_range = from_block != to_block; diff --git a/examples/db-access.rs b/examples/db-access.rs index 5b8aec77f..60089dba7 100644 --- a/examples/db-access.rs +++ b/examples/db-access.rs @@ -186,8 +186,8 @@ fn receipts_provider_example