From 4ddf6f80b95a1d5eed4f7ecb98b2580cc69e3498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Blummer?= Date: Fri, 9 Aug 2019 16:58:02 +0200 Subject: [PATCH] Reduce blockfilter memory (#302) * use same Error type in all methods of BlockFilter * reduce Blockfilter memory footprint * amend the example use * remove unused constant --- src/util/bip158.rs | 50 +++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/util/bip158.rs b/src/util/bip158.rs index e41257b1..68953f13 100644 --- a/src/util/bip158.rs +++ b/src/util/bip158.rs @@ -33,12 +33,12 @@ //! let filter = BlockFilter::new_script_filter (&block, get_script_for_coin)?; //! //! // or create a filter from known raw data -//! let filter = BlockFilter::new(&block_hash, filter_type, content); +//! let filter = BlockFilter::new(content); //! //! // read and evaluate a filter //! //! let query: Iterator = // .. some scripts you care about -//! if filter.match_any (&mut query.map(|s| s.as_bytes())) { +//! if filter.match_any (&block_hash, &mut query.map(|s| s.as_bytes())) { //! // get this block //! } //! @@ -60,9 +60,6 @@ use consensus::{Decodable, Encodable}; use consensus::encode::VarInt; use util::hash::BitcoinHash; -/// BIP158 base filter type 0: input and output scripts -pub const SCRIPT_FILTER: u8 = 0; - /// Golomb encoding parameter as in BIP-158, see also https://gist.github.com/sipa/576d5f09c3b86c3b1b75598d799fc845 const P: u8 = 19; const M: u64 = 784931; @@ -103,14 +100,8 @@ impl From for Error { /// a computed or read block filter pub struct BlockFilter { - /// id of the block - pub block_hash: sha256d::Hash, - /// filte type (see SCRIPT_FILTER) - pub filter_type: u8, /// Golomb encoded filter - pub content: Vec, - // a reader of the filter - filter_reader: BlockFilterReader + pub content: Vec } impl BlockFilter { @@ -124,9 +115,8 @@ impl BlockFilter { } /// create a new filter from pre-computed data - pub fn new (block_hash: &sha256d::Hash, filter_type: u8, content: &[u8]) -> BlockFilter { - let filter_reader = BlockFilterReader::new(block_hash); - BlockFilter { block_hash: block_hash.clone(), filter_type, content: content.to_vec(), filter_reader } + pub fn new (content: &[u8]) -> BlockFilter { + BlockFilter { content: content.to_vec() } } /// Compute a SCRIPT_FILTER that contains spent and output scripts @@ -139,19 +129,19 @@ impl BlockFilter { writer.add_input_scripts(script_for_coin)?; writer.finish()?; } - let block_hash = block.bitcoin_hash(); - let filter_reader = BlockFilterReader::new(&block_hash); - Ok(BlockFilter { block_hash, filter_type: SCRIPT_FILTER, content: out.into_inner(), filter_reader }) + Ok(BlockFilter { content: out.into_inner() }) } /// match any query pattern - pub fn match_any(&self, query: &mut Iterator) -> Result { - self.filter_reader.match_any(&mut Cursor::new(self.content.as_slice()), query) + pub fn match_any(&self, block_hash: &sha256d::Hash, query: &mut Iterator) -> Result { + let filter_reader = BlockFilterReader::new(block_hash); + filter_reader.match_any(&mut Cursor::new(self.content.as_slice()), query) } /// match all query pattern - pub fn match_all(&self, query: &mut Iterator) -> Result { - self.filter_reader.match_all(&mut Cursor::new(self.content.as_slice()), query) + pub fn match_all(&self, block_hash: &sha256d::Hash, query: &mut Iterator) -> Result { + let filter_reader = BlockFilterReader::new(block_hash); + filter_reader.match_all(&mut Cursor::new(self.content.as_slice()), query) } } @@ -224,12 +214,12 @@ impl BlockFilterReader { } /// match any query pattern - pub fn match_any(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { + pub fn match_any(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { self.reader.match_any(reader, query) } /// match all query pattern - pub fn match_all(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { + pub fn match_all(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { self.reader.match_all(reader, query) } } @@ -248,7 +238,7 @@ impl GCSFilterReader { } /// match any query pattern - pub fn match_any(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { + pub fn match_any(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { let mut decoder = reader; let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0)); let ref mut reader = decoder; @@ -288,7 +278,7 @@ impl GCSFilterReader { } /// match all query pattern - pub fn match_all(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { + pub fn match_all(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { let mut decoder = reader; let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0)); let ref mut reader = decoder; @@ -588,18 +578,18 @@ mod test { Err(Error::UtxoMissing(o.clone())) }).unwrap(); - let test_filter = BlockFilter::new(&block.header.bitcoin_hash(), - SCRIPT_FILTER, filter_content.as_slice()); + let test_filter = BlockFilter::new(filter_content.as_slice()); assert_eq!(test_filter.content, filter.content); - assert!(filter.match_all(&mut txmap.iter() + let block_hash = &block.header.bitcoin_hash(); + assert!(filter.match_all(&block_hash, &mut txmap.iter() .filter_map(|(_, s)| if !s.is_empty() { Some(s.as_bytes()) } else { None })).unwrap()); for (_, script) in &txmap { let query = vec![script]; if !script.is_empty () { - assert!(filter.match_any(&mut query.iter() + assert!(filter.match_any(&block_hash, &mut query.iter() .map(|s| s.as_bytes())).unwrap()); } }