ethbloom crate
This commit is contained in:
parent
36f0ab750c
commit
0e8144ca78
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["uint", "fixed-hash", "ethereum-types", "tests"]
|
||||
members = ["uint", "fixed-hash", "ethereum-types", "tests", "ethbloom"]
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "ethbloom"
|
||||
version = "0.3.0"
|
||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||
description = "Ethereum bloom filter"
|
||||
license = "MIT"
|
||||
documentation = "https://docs.rs/ethbloom"
|
||||
homepage = "https://github.com/debris/ethbloom"
|
||||
repository = "https://github.com/debris/ethbloom"
|
||||
|
||||
[dependencies]
|
||||
tiny-keccak = "1.4"
|
||||
crunchy = { version = "0.1.6", features = ["limit_256"] }
|
||||
fixed-hash = { version = "0.1.1", path = "../fixed-hash" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.4"
|
||||
rustc-hex = "1.0"
|
||||
|
||||
[features]
|
||||
default = ["std", "heapsizeof"]
|
||||
std = ["fixed-hash/std"]
|
||||
heapsizeof = ["fixed-hash/heapsizeof"]
|
|
@ -0,0 +1,108 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rustc_hex;
|
||||
extern crate tiny_keccak;
|
||||
extern crate ethbloom;
|
||||
|
||||
use test::Bencher;
|
||||
use rustc_hex::FromHex;
|
||||
use tiny_keccak::keccak256;
|
||||
use ethbloom::{Bloom, Input};
|
||||
|
||||
fn test_bloom() -> Bloom {
|
||||
"00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into()
|
||||
}
|
||||
|
||||
fn test_topic() -> Vec<u8> {
|
||||
"02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc".from_hex().unwrap()
|
||||
}
|
||||
|
||||
fn test_address() -> Vec<u8> {
|
||||
"ef2d6d194084c2de36e0dabfce45d046b37d1106".from_hex().unwrap()
|
||||
}
|
||||
|
||||
fn test_dummy() -> Vec<u8> {
|
||||
b"123456".to_vec()
|
||||
}
|
||||
|
||||
fn test_dummy2() -> Vec<u8> {
|
||||
b"654321".to_vec()
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn accrue_raw(b: &mut Bencher) {
|
||||
let mut bloom = Bloom::default();
|
||||
let topic = test_topic();
|
||||
let address = test_address();
|
||||
b.iter(|| {
|
||||
bloom.accrue(Input::Raw(&topic));
|
||||
bloom.accrue(Input::Raw(&address));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn accrue_hash(b: &mut Bencher) {
|
||||
let mut bloom = Bloom::default();
|
||||
let topic = keccak256(&test_topic());
|
||||
let address = keccak256(&test_address());
|
||||
b.iter(|| {
|
||||
bloom.accrue(Input::Hash(&topic));
|
||||
bloom.accrue(Input::Hash(&address));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn contains_input_raw(b: &mut Bencher) {
|
||||
let bloom = test_bloom();
|
||||
let topic = test_topic();
|
||||
let address = test_address();
|
||||
b.iter(|| {
|
||||
assert!(bloom.contains_input(Input::Raw(&topic)));
|
||||
assert!(bloom.contains_input(Input::Raw(&address)));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn does_not_contain_raw(b: &mut Bencher) {
|
||||
let bloom = test_bloom();
|
||||
let dummy = test_dummy();
|
||||
let dummy2 = test_dummy2();
|
||||
b.iter(|| {
|
||||
assert!(!bloom.contains_input(Input::Raw(&dummy)));
|
||||
assert!(!bloom.contains_input(Input::Raw(&dummy2)));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn contains_input_hash(b: &mut Bencher) {
|
||||
let bloom = test_bloom();
|
||||
let topic = keccak256(&test_topic());
|
||||
let address = keccak256(&test_address());
|
||||
b.iter(|| {
|
||||
assert!(bloom.contains_input(Input::Hash(&topic)));
|
||||
assert!(bloom.contains_input(Input::Hash(&address)));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn does_not_contain_hash(b: &mut Bencher) {
|
||||
let bloom = test_bloom();
|
||||
let dummy = keccak256(&test_dummy());
|
||||
let dummy2 = keccak256(&test_dummy2());
|
||||
b.iter(|| {
|
||||
assert!(!bloom.contains_input(Input::Hash(&dummy)));
|
||||
assert!(!bloom.contains_input(Input::Hash(&dummy2)));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn does_not_contain_random_hash(b: &mut Bencher) {
|
||||
let bloom = test_bloom();
|
||||
let dummy: Vec<_> = (0..255u8).into_iter().map(|i| keccak256(&[i])).collect();
|
||||
b.iter(|| {
|
||||
for d in &dummy {
|
||||
assert!(!bloom.contains_input(Input::Hash(d)));
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
#[macro_use]
|
||||
extern crate crunchy;
|
||||
|
||||
use test::{Bencher, black_box};
|
||||
use rand::Rng;
|
||||
|
||||
fn random_data() -> [u8; 256] {
|
||||
let mut res = [0u8; 256];
|
||||
rand::thread_rng().fill_bytes(&mut res);
|
||||
res
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn forwards_with_crunchy(b: &mut Bencher) {
|
||||
let mut data = random_data();
|
||||
b.iter(|| {
|
||||
let other_data = random_data();
|
||||
unroll! {
|
||||
for i in 0..255 {
|
||||
data[i] |= other_data[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
black_box(data);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn backwards_with_crunchy(b: &mut Bencher) {
|
||||
let mut data = random_data();
|
||||
b.iter(|| {
|
||||
let other_data = random_data();
|
||||
unroll! {
|
||||
for i in 0..255 {
|
||||
data[255-i] |= other_data[255-i];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
black_box(data);
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn forwards_without_crunchy(b: &mut Bencher) {
|
||||
let mut data = random_data();
|
||||
b.iter(|| {
|
||||
let other_data = random_data();
|
||||
for i in 0..255 {
|
||||
data[i] |= other_data[i];
|
||||
}
|
||||
});
|
||||
|
||||
black_box(data);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn backwards_without_crunchy(b: &mut Bencher) {
|
||||
let mut data = random_data();
|
||||
b.iter(|| {
|
||||
let other_data = random_data();
|
||||
for i in 0..255 {
|
||||
data[255-i] |= other_data[255-i];
|
||||
}
|
||||
});
|
||||
|
||||
black_box(data);
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
//!
|
||||
//! ```rust
|
||||
//! extern crate ethbloom;
|
||||
//! extern crate rustc_hex;
|
||||
//! use rustc_hex::FromHex;
|
||||
//! use ethbloom::{Bloom, Input};
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let bloom: Bloom = "00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
||||
//! let address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".from_hex().unwrap();
|
||||
//! let topic = "02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc".from_hex().unwrap();
|
||||
//!
|
||||
//! let mut my_bloom = Bloom::default();
|
||||
//! assert!(!my_bloom.contains_input(Input::Raw(&address)));
|
||||
//! assert!(!my_bloom.contains_input(Input::Raw(&topic)));
|
||||
//!
|
||||
//! my_bloom.accrue(Input::Raw(&address));
|
||||
//! assert!(my_bloom.contains_input(Input::Raw(&address)));
|
||||
//! assert!(!my_bloom.contains_input(Input::Raw(&topic)));
|
||||
//!
|
||||
//! my_bloom.accrue(Input::Raw(&topic));
|
||||
//! assert!(my_bloom.contains_input(Input::Raw(&address)));
|
||||
//! assert!(my_bloom.contains_input(Input::Raw(&topic)));
|
||||
//! assert_eq!(my_bloom, bloom);
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
||||
#![cfg_attr(not(feature="std"), no_std)]
|
||||
|
||||
#![cfg_attr(asm_available, feature(asm))]
|
||||
|
||||
#[cfg(feature="std")]
|
||||
extern crate core;
|
||||
|
||||
extern crate tiny_keccak;
|
||||
#[macro_use]
|
||||
extern crate crunchy;
|
||||
|
||||
#[macro_use]
|
||||
extern crate fixed_hash;
|
||||
|
||||
use core::{ops, mem, str};
|
||||
use tiny_keccak::keccak256;
|
||||
|
||||
// 3 according to yellowpaper
|
||||
const BLOOM_BITS: u32 = 3;
|
||||
|
||||
construct_hash!(Bloom, 256);
|
||||
|
||||
/// Returns log2.
|
||||
fn log2(x: usize) -> u32 {
|
||||
if x <= 1 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let n = x.leading_zeros();
|
||||
mem::size_of::<usize>() as u32 * 8 - n
|
||||
}
|
||||
|
||||
pub enum Input<'a> {
|
||||
Raw(&'a [u8]),
|
||||
Hash(&'a [u8; 32]),
|
||||
}
|
||||
|
||||
enum Hash<'a> {
|
||||
Ref(&'a [u8; 32]),
|
||||
Owned([u8; 32]),
|
||||
}
|
||||
|
||||
impl<'a> From<Input<'a>> for Hash<'a> {
|
||||
fn from(input: Input<'a>) -> Self {
|
||||
match input {
|
||||
Input::Raw(raw) => Hash::Owned(keccak256(raw)),
|
||||
Input::Hash(hash) => Hash::Ref(hash),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Index<usize> for Hash<'a> {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: usize) -> &u8 {
|
||||
match *self {
|
||||
Hash::Ref(r) => &r[index],
|
||||
Hash::Owned(ref hash) => &hash[index],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Hash<'a> {
|
||||
fn len(&self) -> usize {
|
||||
match *self {
|
||||
Hash::Ref(r) => r.len(),
|
||||
Hash::Owned(ref hash) => hash.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<BloomRef<'a>> for Bloom {
|
||||
fn eq(&self, other: &BloomRef<'a>) -> bool {
|
||||
let s_ref: &[u8] = &self.0;
|
||||
let o_ref: &[u8] = other.0;
|
||||
s_ref.eq(o_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Input<'a>> for Bloom {
|
||||
fn from(input: Input<'a>) -> Bloom {
|
||||
let mut bloom = Bloom::default();
|
||||
bloom.accrue(input);
|
||||
bloom
|
||||
}
|
||||
}
|
||||
|
||||
impl Bloom {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.iter().all(|x| *x == 0)
|
||||
}
|
||||
|
||||
pub fn contains_input<'a>(&self, input: Input<'a>) -> bool {
|
||||
let bloom: Bloom = input.into();
|
||||
self.contains_bloom(&bloom)
|
||||
}
|
||||
|
||||
pub fn contains_bloom<'a, B>(&self, bloom: B) -> bool where BloomRef<'a>: From<B> {
|
||||
let bloom_ref: BloomRef = bloom.into();
|
||||
// workaround for https://github.com/rust-lang/rust/issues/43644
|
||||
self.contains_bloom_ref(bloom_ref)
|
||||
}
|
||||
|
||||
fn contains_bloom_ref(&self, bloom: BloomRef) -> bool {
|
||||
let self_ref: BloomRef = self.into();
|
||||
self_ref.contains_bloom(bloom)
|
||||
}
|
||||
|
||||
pub fn accrue<'a>(&mut self, input: Input<'a>) {
|
||||
let p = BLOOM_BITS;
|
||||
|
||||
let m = self.0.len();
|
||||
let bloom_bits = m * 8;
|
||||
let mask = bloom_bits - 1;
|
||||
let bloom_bytes = (log2(bloom_bits) + 7) / 8;
|
||||
|
||||
let hash: Hash = input.into();
|
||||
|
||||
// must be a power of 2
|
||||
assert_eq!(m & (m - 1), 0);
|
||||
// out of range
|
||||
assert!(p * bloom_bytes <= hash.len() as u32);
|
||||
|
||||
let mut ptr = 0;
|
||||
|
||||
assert_eq!(BLOOM_BITS, 3);
|
||||
unroll! {
|
||||
for i in 0..3 {
|
||||
let _ = i;
|
||||
let mut index = 0 as usize;
|
||||
for _ in 0..bloom_bytes {
|
||||
index = (index << 8) | hash[ptr] as usize;
|
||||
ptr += 1;
|
||||
}
|
||||
index &= mask;
|
||||
self.0[m - 1 - index / 8] |= 1 << (index % 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accrue_bloom<'a, B>(&mut self, bloom: B) where BloomRef<'a>: From<B> {
|
||||
let bloom_ref: BloomRef = bloom.into();
|
||||
assert_eq!(self.0.len(), 256);
|
||||
assert_eq!(bloom_ref.0.len(), 256);
|
||||
for i in 0..256 {
|
||||
self.0[i] |= bloom_ref.0[i];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8; 256] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BloomRef<'a>(&'a [u8; 256]);
|
||||
|
||||
impl<'a> BloomRef<'a> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.iter().all(|x| *x == 0)
|
||||
}
|
||||
|
||||
pub fn contains_input<'b>(&self, input: Input<'b>) -> bool {
|
||||
let bloom: Bloom = input.into();
|
||||
self.contains_bloom(&bloom)
|
||||
}
|
||||
|
||||
pub fn contains_bloom<'b, B>(&self, bloom: B) -> bool where BloomRef<'b>: From<B> {
|
||||
let bloom_ref: BloomRef = bloom.into();
|
||||
assert_eq!(self.0.len(), 256);
|
||||
assert_eq!(bloom_ref.0.len(), 256);
|
||||
for i in 0..256 {
|
||||
let a = self.0[i];
|
||||
let b = bloom_ref.0[i];
|
||||
if (a & b) != b {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &'a [u8; 256] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8; 256]> for BloomRef<'a> {
|
||||
fn from(data: &'a [u8; 256]) -> Self {
|
||||
BloomRef(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Bloom> for BloomRef<'a> {
|
||||
fn from(bloom: &'a Bloom) -> Self {
|
||||
BloomRef(&bloom.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate rustc_hex;
|
||||
use self::rustc_hex::FromHex;
|
||||
use {Bloom, Input};
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let bloom: Bloom = "00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into();
|
||||
let address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".from_hex().unwrap();
|
||||
let topic = "02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc".from_hex().unwrap();
|
||||
|
||||
let mut my_bloom = Bloom::default();
|
||||
assert!(!my_bloom.contains_input(Input::Raw(&address)));
|
||||
assert!(!my_bloom.contains_input(Input::Raw(&topic)));
|
||||
|
||||
my_bloom.accrue(Input::Raw(&address));
|
||||
assert!(my_bloom.contains_input(Input::Raw(&address)));
|
||||
assert!(!my_bloom.contains_input(Input::Raw(&topic)));
|
||||
|
||||
my_bloom.accrue(Input::Raw(&topic));
|
||||
assert!(my_bloom.contains_input(Input::Raw(&address)));
|
||||
assert!(my_bloom.contains_input(Input::Raw(&topic)));
|
||||
assert_eq!(my_bloom, bloom);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ethereum-types"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||
license = "MIT"
|
||||
homepage = "https://github.com/paritytech/primitives"
|
||||
|
@ -12,9 +12,10 @@ rustc_version = "0.2"
|
|||
[dependencies]
|
||||
uint = { path = "../uint", version = "0.1" }
|
||||
fixed-hash = { path = "../fixed-hash", version = "0.1.1" }
|
||||
ethbloom = { path = "../ethbloom", version = "0.3" }
|
||||
crunchy = "0.1.5"
|
||||
|
||||
[features]
|
||||
default = ["std", "heapsizeof"]
|
||||
std = ["uint/std", "fixed-hash/std"]
|
||||
heapsizeof = ["uint/heapsizeof", "fixed-hash/heapsizeof"]
|
||||
std = ["uint/std", "fixed-hash/std", "ethbloom/std"]
|
||||
heapsizeof = ["uint/heapsizeof", "fixed-hash/heapsizeof", "ethbloom/heapsizeof"]
|
||||
|
|
|
@ -9,7 +9,6 @@ construct_hash!(H264, 33);
|
|||
construct_hash!(H512, 64);
|
||||
construct_hash!(H520, 65);
|
||||
construct_hash!(H1024, 128);
|
||||
construct_hash!(H2048, 256);
|
||||
|
||||
impl From<U256> for H256 {
|
||||
fn from(value: U256) -> H256 {
|
||||
|
|
|
@ -10,16 +10,17 @@ extern crate crunchy;
|
|||
extern crate uint as uint_crate;
|
||||
#[macro_use]
|
||||
extern crate fixed_hash;
|
||||
extern crate ethbloom;
|
||||
|
||||
mod hash;
|
||||
mod uint;
|
||||
|
||||
pub use uint::{U128, U256, U512};
|
||||
pub use hash::{H32, H64, H128, H160, H256, H264, H512, H520, H1024, H2048};
|
||||
pub use hash::{H32, H64, H128, H160, H256, H264, H512, H520, H1024};
|
||||
pub use ethbloom::{Bloom, BloomRef, Input as BloomInput};
|
||||
pub use fixed_hash::clean_0x;
|
||||
|
||||
pub type Address = H160;
|
||||
pub type Secret = H256;
|
||||
pub type Public = H512;
|
||||
pub type Signature = H520;
|
||||
pub type LogBloom = H2048;
|
||||
|
|
|
@ -9,7 +9,7 @@ description = "Fixed-size hashes"
|
|||
[dependencies]
|
||||
heapsize = { version = "0.4", optional = true }
|
||||
libc = { version = "0.2", default-features = false }
|
||||
rand = { version = "0.3", optional = true }
|
||||
rand = { version = "0.4", optional = true }
|
||||
rustc-hex = { version = "1.0", optional = true }
|
||||
|
||||
[features]
|
||||
|
|
|
@ -9,5 +9,5 @@ rustc_version = "0.2"
|
|||
[dependencies]
|
||||
crunchy = "0.1.5"
|
||||
ethereum-types = { path ="../ethereum-types", features = ["std", "heapsizeof"] }
|
||||
quickcheck = "0.4"
|
||||
quickcheck = "0.6"
|
||||
uint = { path = "../uint" }
|
||||
|
|
Loading…
Reference in New Issue