1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
//! Log bloom implementation for Ethereum

extern crate bigint;
extern crate rlp;
#[cfg(test)]
extern crate hexutil;
extern crate sha3;

use std::ops::BitOr;
use bigint::H2048;
use sha3::{Digest, Keccak256};
use rlp::{Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};

/// A log bloom for Ethereum
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LogsBloom(H2048);

impl From<H2048> for LogsBloom {
    fn from(val: H2048) -> LogsBloom {
        LogsBloom(val)
    }
}

impl Into<H2048> for LogsBloom {
    fn into(self) -> H2048 {
        self.0
    }
}

impl Encodable for LogsBloom {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.0.rlp_append(s);
    }
}

impl Decodable for LogsBloom {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        Ok(LogsBloom(H2048::decode(rlp)?))
    }
}

impl Default for LogsBloom {
    fn default() -> LogsBloom {
        LogsBloom(H2048::zero())
    }
}

impl BitOr for LogsBloom {
    type Output = LogsBloom;

    fn bitor(self, other: LogsBloom) -> LogsBloom {
        LogsBloom(self.0 | other.0)
    }
}

fn single_set(arr: &[u8]) -> H2048 {
    let mut r = H2048::zero();
    let h = Keccak256::digest(arr);
    for i in [0usize, 2usize, 4usize].iter() {
        let m = (((h[*i] as usize) << 8) + (h[*i + 1] as usize)) % 2048;
        r[m / 8] = r[m / 8] | (1 << (m % 8));
    }
    r
}

impl LogsBloom {
    /// Create a new log bloom
    pub fn new() -> LogsBloom {
        LogsBloom::default()
    }

    /// Set respective bits in the bloom with the array
    pub fn set(&mut self, arr: &[u8]) {
        self.0 = self.0 | single_set(arr);
    }

    /// Check that an array is in the bloom
    pub fn check(&self, arr: &[u8]) -> bool {
        let s = single_set(arr);
        self.0 & s == s
    }
}

#[cfg(test)]
mod tests {
    use super::LogsBloom;
    use bigint::H2048;
    use hexutil::read_hex;

    #[test]
    fn test_bloom() {
        let mut bloom = LogsBloom::new();
        bloom.set(&read_hex("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap());
        assert!(bloom.check(&read_hex("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap()));

        let h: H2048 = bloom.into();
        for i in [1323usize, 431usize, 1319usize].iter() {
            let v = 1 << (i % 8);
            assert!(h[i / 8] & v == v);
        }
    }
}