bloomfilters connected to blockchain (but without reversion)

This commit is contained in:
debris 2016-02-12 00:40:45 +01:00
parent 2cf0f1b5f3
commit 160c52a14b
4 changed files with 90 additions and 13 deletions

View File

@ -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<BlockNumber>;
}
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
@ -167,6 +174,17 @@ pub struct BlockChain {
blocks_db: DB,
cache_man: RwLock<CacheManager>,
// blooms config
bloom_index_size: usize,
bloom_levels: u8
}
impl FilterDataSource for BlockChain {
fn bloom_at_index(&self, bloom_index: &BloomIndex) -> Option<H2048> {
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<TransactionAddress> {
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<BlockNumber> {
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<H2048> = 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<BlockLogBlooms> {
fn log_blooms(&self, hash: &H256) -> Option<BlockLogBlooms> {
self.query_extras(hash, &self.block_logs)
}
/// Get block blooms.
fn blocks_blooms(&self, hash: &H256) -> Option<BlocksBlooms> {
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<K, T>(&self, hash: &K, cache: &RwLock<HashMap<K, T>>) -> Option<T> 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();

View File

@ -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<H2048>;
}
/// 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<H2048> {
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);

View File

@ -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 {

View File

@ -302,6 +302,10 @@ mod tests {
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
self.numbers.get(&index).cloned()
}
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber> {
unimplemented!()
}
}
fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> {