From a1867a7ba64e022692b294feb276d069f8f55181 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 4 Aug 2016 15:38:16 +0200 Subject: [PATCH] bloomable trait --- ethcore/src/types/filter.rs | 1 + ethcore/src/types/log_entry.rs | 3 +- ethcore/src/types/trace_types/filter.rs | 6 +- ethcore/src/types/trace_types/trace.rs | 3 +- util/bigint/src/hash.rs | 96 +--------------- util/src/bloom.rs | 145 ++++++++++++++++++++++++ util/src/lib.rs | 1 + 7 files changed, 157 insertions(+), 98 deletions(-) create mode 100644 util/src/bloom.rs diff --git a/ethcore/src/types/filter.rs b/ethcore/src/types/filter.rs index d8d5d03bd..a5aed6ac6 100644 --- a/ethcore/src/types/filter.rs +++ b/ethcore/src/types/filter.rs @@ -18,6 +18,7 @@ use util::hash::*; use util::sha3::*; +use util::bloom::Bloomable; use client::BlockID; use log_entry::LogEntry; use ipc::binary::BinaryConvertError; diff --git a/ethcore/src/types/log_entry.rs b/ethcore/src/types/log_entry.rs index 3edbb5d0b..47600fdbb 100644 --- a/ethcore/src/types/log_entry.rs +++ b/ethcore/src/types/log_entry.rs @@ -19,8 +19,9 @@ use std::mem; use std::ops::Deref; use std::collections::VecDeque; -use util::{H256, Address, Bytes, HeapSizeOf, FixedHash, Hashable}; +use util::{H256, Address, Bytes, HeapSizeOf, Hashable}; use util::rlp::*; +use util::bloom::Bloomable; use ipc::binary::BinaryConvertError; use basic_types::LogBloom; use header::BlockNumber; diff --git a/ethcore/src/types/trace_types/filter.rs b/ethcore/src/types/trace_types/filter.rs index 27ef38e08..03100f411 100644 --- a/ethcore/src/types/trace_types/filter.rs +++ b/ethcore/src/types/trace_types/filter.rs @@ -20,8 +20,9 @@ use std::ops::Range; use std::mem; use std::collections::VecDeque; use bloomchain::{Filter as BloomFilter, Bloom, Number}; -use util::{Address, FixedHash}; +use util::Address; use util::sha3::Hashable; +use util::bloom::Bloomable; use basic_types::LogBloom; use trace::flat::FlatTrace; use types::trace_types::trace::{Action, Res}; @@ -137,8 +138,9 @@ impl Filter { #[cfg(test)] mod tests { - use util::{FixedHash, Address}; + use util::Address; use util::sha3::Hashable; + use util::bloom::Bloomable; use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide}; use trace::flat::FlatTrace; use trace::{Filter, AddressesFilter}; diff --git a/ethcore/src/types/trace_types/trace.rs b/ethcore/src/types/trace_types/trace.rs index 8d251032c..4e339d4bd 100644 --- a/ethcore/src/types/trace_types/trace.rs +++ b/ethcore/src/types/trace_types/trace.rs @@ -16,9 +16,10 @@ //! Tracing datatypes. -use util::{U256, Bytes, Address, FixedHash}; +use util::{U256, Bytes, Address}; use util::rlp::*; use util::sha3::Hashable; +use util::bloom::Bloomable; use action_params::ActionParams; use basic_types::LogBloom; use types::executed::CallType; diff --git a/util/bigint/src/hash.rs b/util/bigint/src/hash.rs index 7ef3dcae5..403fb232b 100644 --- a/util/bigint/src/hash.rs +++ b/util/bigint/src/hash.rs @@ -16,7 +16,7 @@ //! General hash types, a fixed-size raw-data type used as the output of hash functions. -use std::{ops, fmt, cmp, mem}; +use std::{ops, fmt, cmp}; use std::cmp::*; use std::ops::*; use std::hash::{Hash, Hasher, BuildHasherDefault}; @@ -28,7 +28,7 @@ use rustc_serialize::hex::{FromHex, FromHexError}; use uint::{Uint, U256}; /// Trait for a fixed-size byte array to be used as the output of hash functions. -pub trait FixedHash: Sized + FromStr + Default + DerefMut { +pub trait FixedHash: Sized { /// Create a new, zero-initialised, instance. fn new() -> Self; /// Synonym for `new()`. Prefer to new as it's more readable. @@ -45,14 +45,6 @@ pub trait FixedHash: Sized + FromStr + Default + DerefMut { fn clone_from_slice(&mut self, src: &[u8]) -> usize; /// Copy the data of this object into some mutable slice of length `len()`. fn copy_to(&self, dest: &mut [u8]); - /// When interpreting self as a bloom output, augment (bit-wise OR) with the a bloomed version of `b`. - fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash; - /// Same as `shift_bloomed` except that `self` is consumed and a new value returned. - fn with_bloomed(mut self, b: &T) -> Self where T: FixedHash { self.shift_bloomed(b); self } - /// Bloom the current value using the bloom parameter `m`. - fn bloom_part(&self, m: usize) -> T where T: FixedHash; - /// Check to see whether this hash, interpreted as a bloom, contains the value `b` when bloomed. - fn contains_bloomed(&self, b: &T) -> bool where T: FixedHash; /// Returns `true` if all bits set in `b` are also set in `self`. fn contains<'a>(&'a self, b: &'a Self) -> bool; /// Returns `true` if no bits are set. @@ -70,16 +62,6 @@ pub fn clean_0x(s: &str) -> &str { } } -/// Returns log2. -pub fn log2(x: usize) -> u32 { - if x <= 1 { - return 0; - } - - let n = x.leading_zeros(); - mem::size_of::() as u32 * 8 - n -} - macro_rules! impl_hash { ($from: ident, $size: expr) => { #[derive(Eq)] @@ -158,54 +140,6 @@ macro_rules! impl_hash { dest[..min].copy_from_slice(&self.0[..min]); } - fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash { - let bp: Self = b.bloom_part($size); - let new_self = &bp | self; - - self.0 = new_self.0; - self - } - - fn bloom_part(&self, m: usize) -> T where T: FixedHash { - // numbers of bits - // TODO: move it to some constant - let p = 3; - - let bloom_bits = m * 8; - let mask = bloom_bits - 1; - let bloom_bytes = (log2(bloom_bits) + 7) / 8; - - // must be a power of 2 - assert_eq!(m & (m - 1), 0); - // out of range - assert!(p * bloom_bytes <= $size); - - // return type - let mut ret = T::new(); - - // 'ptr' to out slice - let mut ptr = 0; - - // set p number of bits, - // p is equal 3 according to yellowpaper - for _ in 0..p { - let mut index = 0 as usize; - for _ in 0..bloom_bytes { - index = (index << 8) | self.0[ptr] as usize; - ptr += 1; - } - index &= mask; - ret[m - 1 - index / 8] |= 1 << (index % 8); - } - - ret - } - - fn contains_bloomed(&self, b: &T) -> bool where T: FixedHash { - let bp: Self = b.bloom_part($size); - self.contains(&bp) - } - fn contains<'a>(&'a self, b: &'a Self) -> bool { &(b & self) == b } @@ -415,9 +349,6 @@ macro_rules! impl_hash { pub fn hex(&self) -> String { format!("{:?}", self) } - - /// Construct new instance equal to the bloomed value of `b`. - pub fn from_bloomed(b: &T) -> Self where T: FixedHash { b.bloom_part($size) } } impl Default for $from { @@ -609,29 +540,6 @@ mod tests { assert_eq!(a | b, c); } - #[test] - #[ignore] - fn shift_bloomed() { - //use sha3::Hashable; - - //let bloom = H2048::from_str("00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); - //let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(); - //let topic = H256::from_str("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); - - //let mut my_bloom = H2048::new(); - //assert!(!my_bloom.contains_bloomed(&address.sha3())); - //assert!(!my_bloom.contains_bloomed(&topic.sha3())); - - //my_bloom.shift_bloomed(&address.sha3()); - //assert!(my_bloom.contains_bloomed(&address.sha3())); - //assert!(!my_bloom.contains_bloomed(&topic.sha3())); - - //my_bloom.shift_bloomed(&topic.sha3()); - //assert_eq!(my_bloom, bloom); - //assert!(my_bloom.contains_bloomed(&address.sha3())); - //assert!(my_bloom.contains_bloomed(&topic.sha3())); - } - #[test] fn from_and_to_address() { let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(); diff --git a/util/src/bloom.rs b/util/src/bloom.rs new file mode 100644 index 000000000..a67f8d482 --- /dev/null +++ b/util/src/bloom.rs @@ -0,0 +1,145 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Bloom operations. + +use std::mem; +use std::ops::DerefMut; +use {H64, Address, H256, H512, H520, H2048, FixedHash}; + +/// Returns log2. +pub fn log2(x: usize) -> u32 { + if x <= 1 { + return 0; + } + + let n = x.leading_zeros(); + mem::size_of::() as u32 * 8 - n +} + +/// Bloom operations. +pub trait Bloomable: Sized + Default + DerefMut { + /// When interpreting self as a bloom output, augment (bit-wise OR) with the a bloomed version of `b`. + fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: Bloomable; + + /// Same as `shift_bloomed` except that `self` is consumed and a new value returned. + fn with_bloomed(mut self, b: &T) -> Self where T: Bloomable { + self.shift_bloomed(b); + self + } + + /// Construct new instance equal to the bloomed value of `b`. + fn from_bloomed(b: &T) -> Self where T: Bloomable; + + /// Bloom the current value using the bloom parameter `m`. + fn bloom_part(&self, m: usize) -> T where T: Bloomable; + + /// Check to see whether this hash, interpreted as a bloom, contains the value `b` when bloomed. + fn contains_bloomed(&self, b: &T) -> bool where T: Bloomable; +} + +macro_rules! impl_bloomable_for_hash { + ($name: ident, $size: expr) => { + impl Bloomable for $name { + fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: Bloomable { + let bp: Self = b.bloom_part($size); + let new_self = &bp | self; + + self.0 = new_self.0; + self + } + + fn bloom_part(&self, m: usize) -> T where T: Bloomable + Default { + // numbers of bits + // TODO: move it to some constant + let p = 3; + + let bloom_bits = m * 8; + let mask = bloom_bits - 1; + let bloom_bytes = (log2(bloom_bits) + 7) / 8; + + // must be a power of 2 + assert_eq!(m & (m - 1), 0); + // out of range + assert!(p * bloom_bytes <= $size); + + // return type + let mut ret = T::default(); + + // 'ptr' to out slice + let mut ptr = 0; + + // set p number of bits, + // p is equal 3 according to yellowpaper + for _ in 0..p { + let mut index = 0 as usize; + for _ in 0..bloom_bytes { + index = (index << 8) | self.0[ptr] as usize; + ptr += 1; + } + index &= mask; + ret[m - 1 - index / 8] |= 1 << (index % 8); + } + + ret + } + + fn contains_bloomed(&self, b: &T) -> bool where T: Bloomable { + let bp: Self = b.bloom_part($size); + self.contains(&bp) + } + + fn from_bloomed(b: &T) -> Self where T: Bloomable { + b.bloom_part($size) + } + } + } +} + +impl_bloomable_for_hash!(H64, 8); +impl_bloomable_for_hash!(Address, 20); +impl_bloomable_for_hash!(H256, 32); +impl_bloomable_for_hash!(H512, 64); +impl_bloomable_for_hash!(H520, 65); +impl_bloomable_for_hash!(H2048, 256); + +#[cfg(test)] +mod tests { + use {Address, H256, H2048}; + use sha3::Hashable; + use super::Bloomable; + + #[test] + fn shift_bloomed() { + let bloom: H2048 = "00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse().unwrap(); + let address: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".parse().unwrap(); + let topic: H256 = "02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc".parse().unwrap(); + + let mut my_bloom = H2048::default(); + assert!(!my_bloom.contains_bloomed(&address.sha3())); + assert!(!my_bloom.contains_bloomed(&topic.sha3())); + + my_bloom.shift_bloomed(&address.sha3()); + assert!(my_bloom.contains_bloomed(&address.sha3())); + assert!(!my_bloom.contains_bloomed(&topic.sha3())); + + my_bloom.shift_bloomed(&topic.sha3()); + assert_eq!(my_bloom, bloom); + assert!(my_bloom.contains_bloomed(&address.sha3())); + assert!(my_bloom.contains_bloomed(&topic.sha3())); + } +} + diff --git a/util/src/lib.rs b/util/src/lib.rs index 2a35fe8fb..57ff2e6a5 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -117,6 +117,7 @@ pub extern crate using_queue; pub extern crate table; extern crate ansi_term; +pub mod bloom; pub mod standard; #[macro_use] pub mod from_json;