From 160c52a14bd19fb41d1f5093e8a17eb56524a637 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 12 Feb 2016 00:40:45 +0100 Subject: [PATCH] bloomfilters connected to blockchain (but without reversion) --- ethcore/src/blockchain.rs | 73 +++++++++++++++++++++++++++++++++---- ethcore/src/chainfilter.rs | 12 +++--- ethcore/src/extras.rs | 14 +++++++ ethcore/src/verification.rs | 4 ++ 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 270dfc459..3c2fe3a37 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -23,6 +23,10 @@ use extras::*; use transaction::*; use views::*; use receipt::Receipt; +use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; + +const BLOOM_INDEX_SIZE: usize = 16; +const BLOOM_LEVELS: u8 = 3; /// Represents a tree route between `from` block and `to` block: pub struct TreeRoute { @@ -131,6 +135,9 @@ pub trait BlockProvider { fn genesis_header(&self) -> Header { self.block_header(&self.genesis_hash()).unwrap() } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec; } #[derive(Debug, Hash, Eq, PartialEq, Clone)] @@ -167,6 +174,17 @@ pub struct BlockChain { blocks_db: DB, cache_man: RwLock, + + // blooms config + bloom_index_size: usize, + bloom_levels: u8 +} + +impl FilterDataSource for BlockChain { + fn bloom_at_index(&self, bloom_index: &BloomIndex) -> Option { + let location = self.blocks_bloom_location(bloom_index); + self.blocks_blooms(&location.hash).and_then(|blooms| blooms.blooms.into_iter().nth(location.index).cloned()) + } } impl BlockProvider for BlockChain { @@ -215,6 +233,12 @@ impl BlockProvider for BlockChain { fn transaction_address(&self, hash: &H256) -> Option { self.query_extras(hash, &self.transaction_addresses) } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { + let filter = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels); + filter.blocks_with_bloom(bloom, from_block as usize, to_block as usize).into_iter().map(|b| b as BlockNumber).collect() + } } const COLLECTION_QUEUE_SIZE: usize = 8; @@ -274,6 +298,8 @@ impl BlockChain { extras_db: extras_db, blocks_db: blocks_db, cache_man: RwLock::new(cache_man), + bloom_index_size: BLOOM_INDEX_SIZE, + bloom_levels: BLOOM_LEVELS }; // load best block @@ -497,8 +523,23 @@ impl BlockChain { } // update block blooms + let blooms: Vec = receipts.iter().map(|r| r.log_bloom.clone()).collect(); + + let modified_blooms = { + let filter = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels); + let bloom = blooms.iter().fold(H2048::new(), | ref acc, b | acc | b); + filter.add_bloom(&bloom, header.number() as usize) + }; + + for (bloom_index, bloom) in modified_blooms.into_iter() { + let location = self.blocks_bloom_location(&bloom_index); + let mut blocks_blooms = self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new); + blocks_blooms.blooms[location.index] = bloom; + batch.put_extras(&location.hash, &blocks_blooms); + } + batch.put_extras(&hash, &BlockLogBlooms { - blooms: receipts.iter().map(|r| r.log_bloom.clone()).collect() + blooms: blooms }); // if it's not new best block, just return @@ -541,11 +582,6 @@ impl BlockChain { (batch, Some(best_block), details) } - /// Returns true if transaction is known. - pub fn is_known_transaction(&self, hash: &H256) -> bool { - self.query_extras_exist(hash, &self.transaction_addresses) - } - /// Get best block hash. pub fn best_block_hash(&self) -> H256 { self.best_block.read().unwrap().hash.clone() @@ -562,10 +598,32 @@ impl BlockChain { } /// Get the transactions' log blooms of a block. - pub fn log_blooms(&self, hash: &H256) -> Option { + fn log_blooms(&self, hash: &H256) -> Option { self.query_extras(hash, &self.block_logs) } + /// Get block blooms. + fn blocks_blooms(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.blocks_blooms) + } + + /// Calculates bloom's position in database. + fn blocks_bloom_location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { + use std::{mem, ptr}; + + let hash = unsafe { + let mut hash: H256 = mem::zeroed(); + ptr::copy(&[bloom_index.index / self.bloom_index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); + hash[8] = bloom_index.level; + hash + }; + + BlocksBloomLocation { + hash: hash, + index: bloom_index.index % self.bloom_index_size + } + } + fn query_extras(&self, hash: &K, cache: &RwLock>) -> Option where T: Clone + Decodable + ExtrasIndexable, K: ExtrasSliceConvertable + Eq + Hash + Clone { @@ -685,6 +743,7 @@ mod tests { assert_eq!(bc.best_block_hash(), genesis_hash.clone()); assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.block_hash(1), None); + assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); diff --git a/ethcore/src/chainfilter.rs b/ethcore/src/chainfilter.rs index 4043a1fee..dde91e18e 100644 --- a/ethcore/src/chainfilter.rs +++ b/ethcore/src/chainfilter.rs @@ -85,7 +85,7 @@ impl BloomIndex { /// Types implementing this trait should provide read access for bloom filters database. pub trait FilterDataSource { /// returns reference to log at given position if it exists - fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048>; + fn bloom_at_index(&self, index: &BloomIndex) -> Option; } /// In memory cache for blooms. @@ -110,8 +110,8 @@ impl MemoryCache { } impl FilterDataSource for MemoryCache { - fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048> { - self.blooms.get(index) + fn bloom_at_index(&self, index: &BloomIndex) -> Option { + self.blooms.get(index).cloned() } } @@ -238,7 +238,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource for level in 0..self.levels() { let bloom_index = self.bloom_index(block_number, level); let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(old_bloom) => old_bloom | bloom, + Some(old_bloom) => old_bloom | bloom.clone(), None => bloom.clone(), }; @@ -268,7 +268,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // it hasn't been modified yet if is_new_bloom { let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(old_bloom) => old_bloom | &blooms[i], + Some(ref old_bloom) => old_bloom | &blooms[i], None => blooms[i].clone(), }; result.insert(bloom_index, new_bloom); @@ -298,7 +298,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // filter existing ones .filter_map(|b| b) // BitOr all of them - .fold(H2048::new(), |acc, bloom| &acc | bloom); + .fold(H2048::new(), |acc, bloom| acc | bloom); reset_index = index.clone(); result.insert(index, &new_bloom | bloom); diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index b65d4ed7a..305b7767e 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -213,6 +213,12 @@ pub struct BlocksBlooms { pub blooms: [H2048; 16] } +impl BlocksBlooms { + pub fn new() -> Self { + BlocksBlooms { blooms: unsafe { ::std::mem::zeroed() }} + } +} + impl ExtrasIndexable for BlocksBlooms { fn extras_index() -> ExtrasIndex { ExtrasIndex::BlocksBlooms @@ -254,6 +260,14 @@ impl Encodable for BlocksBlooms { } } +/// Represents location of bloom in database. +pub struct BlocksBloomLocation { + /// Unique hash of BlocksBloom + pub hash: H256, + /// Index within BlocksBloom + pub index: usize +} + /// Represents address of certain transaction within block #[derive(Clone)] pub struct TransactionAddress { diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index c7d5e265f..0b234b00d 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -302,6 +302,10 @@ mod tests { fn block_hash(&self, index: BlockNumber) -> Option { self.numbers.get(&index).cloned() } + + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { + unimplemented!() + } } fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> {