From 06de4684a19f70eae28317e500c1e3e98b267168 Mon Sep 17 00:00:00 2001 From: tgmichel Date: Fri, 30 Apr 2021 16:59:14 +0200 Subject: [PATCH] Pre-calculate `Bloom` (#372) --- client/rpc-core/src/types/filter.rs | 90 ++++++++++++++--------------- client/rpc/src/eth.rs | 11 +++- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/client/rpc-core/src/types/filter.rs b/client/rpc-core/src/types/filter.rs index d9d1def7f8..90613d0576 100644 --- a/client/rpc-core/src/types/filter.rs +++ b/client/rpc-core/src/types/filter.rs @@ -59,6 +59,8 @@ pub type Topic = VariadicValue>; +pub type BloomFilter<'a> = Vec>; + /// Filter #[derive(Debug, PartialEq, Clone, Deserialize, Eq, Hash)] #[serde(deny_unknown_fields)] @@ -81,7 +83,7 @@ pub struct Filter { #[derive(Debug)] pub struct FilteredParams { pub filter: Option, - flat_topics: Vec, + pub flat_topics: Vec, } impl Default for FilteredParams { @@ -109,66 +111,64 @@ impl FilteredParams { } Self::default() } - /// Checks the possible existance of an address or topic(s) in a Bloom. - /// Wildcards (VariadicValue::Null) are matched as positive. - pub fn in_bloom(bloom: Bloom, filter: &Filter) -> bool { - fn ret>(inputs: Vec>, bloom: Bloom) -> bool { - let mut ret = false; - if inputs.len() == 0 { - ret = true; - } else { - for inner in inputs { - // Wildcard (None) or matching topic. - if inner.is_none() || bloom.contains_input( - BloomInput::Raw(inner.unwrap().as_ref()) - ) { - ret = true; - break; - } - } - } - ret - } + + pub fn bloom_filter<'a>( + address: &'a Option, + topics: &'a Option> + ) -> BloomFilter<'a> { + let mut blooms = BloomFilter::new(); // Address - let address_in_bloom = if let Some(address) = &filter.address { - let mut inner_addresses: Vec> = Vec::new(); + if let Some(address) = address { match address { VariadicValue::Single(address) => { - inner_addresses.push(Some(*address)) + let bloom: Bloom = BloomInput::Raw(address.as_ref()).into(); + blooms.push(Some(bloom)) }, - VariadicValue::Multiple(ref addresses) => { + VariadicValue::Multiple(addresses) => { for address in addresses.into_iter() { - inner_addresses.push(Some(*address)) + let bloom: Bloom = BloomInput::Raw(address.as_ref()).into(); + blooms.push(Some(bloom)) } }, - _ => inner_addresses.push(None) + _ => blooms.push(None) } - ret(inner_addresses, bloom) - - } else { - true - }; + } // Topics - let topic_in_bloom = if let Some(topics) = &filter.topics { - let mut inner_topics: Vec> = Vec::new(); - for flat in FilteredParams::flatten(topics) { + if let Some(topics) = topics { + for flat in topics { match flat { VariadicValue::Single(topic) => { - inner_topics.push(topic); - }, - VariadicValue::Multiple(topics) => { - for topic in topics { - inner_topics.push(topic); + if let Some(topic) = topic { + let bloom: Bloom = BloomInput::Raw(topic.as_ref()).into(); + blooms.push(Some(bloom)); + } else { + blooms.push(None); } }, - _ => inner_topics.push(None) + _ => blooms.push(None) } } - ret(inner_topics, bloom) + } + blooms + } + + /// Checks the possible existance of an address or topic(s) in a Bloom. + /// Wildcards (VariadicValue::Null) are matched as positive. + pub fn in_bloom(bloom: Bloom, bloom_input: &BloomFilter) -> bool { + if bloom_input.len() == 0 { + return true; } else { - true - }; - address_in_bloom && topic_in_bloom + for inner in bloom_input { + // Wildcard (None) or matching topic. + if match inner { + Some(input) => bloom.contains_bloom(input), + None => true + } { + return true; + } + } + } + false } /// Cartesian product for VariadicValue conditional indexed parameters. diff --git a/client/rpc/src/eth.rs b/client/rpc/src/eth.rs index 6e80340833..bff75ce1e1 100644 --- a/client/rpc/src/eth.rs +++ b/client/rpc/src/eth.rs @@ -236,6 +236,15 @@ fn filter_range_logs( let mut current_number = to; + // Pre-calculate BloomInput for reuse. + let topics_input = if let Some(_) = &filter.topics { + let filtered_params = FilteredParams::new(Some(filter.clone())); + Some(filtered_params.flat_topics) + } else { + None + }; + let bloom_filter = FilteredParams::bloom_filter(&filter.address, &topics_input); + while current_number >= from { let id = BlockId::Number(current_number); @@ -245,7 +254,7 @@ fn filter_range_logs( let block = handler.current_block(&id); if let Some(block) = block { - if FilteredParams::in_bloom(block.header.logs_bloom, filter) { + if FilteredParams::in_bloom(block.header.logs_bloom, &bloom_filter) { let statuses = handler.current_transaction_statuses(&id); if let Some(statuses) = statuses { filter_block_logs(ret, filter, block, statuses);