bloom/
lib.rs

1//! Log bloom implementation for Ethereum
2
3extern crate bigint;
4extern crate rlp;
5#[cfg(test)]
6extern crate hexutil;
7extern crate sha3;
8
9use std::ops::BitOr;
10use bigint::H2048;
11use sha3::{Digest, Keccak256};
12use rlp::{Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};
13
14/// A log bloom for Ethereum
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct LogsBloom(H2048);
17
18impl From<H2048> for LogsBloom {
19    fn from(val: H2048) -> LogsBloom {
20        LogsBloom(val)
21    }
22}
23
24impl Into<H2048> for LogsBloom {
25    fn into(self) -> H2048 {
26        self.0
27    }
28}
29
30impl Encodable for LogsBloom {
31    fn rlp_append(&self, s: &mut RlpStream) {
32        self.0.rlp_append(s);
33    }
34}
35
36impl Decodable for LogsBloom {
37    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
38        Ok(LogsBloom(H2048::decode(rlp)?))
39    }
40}
41
42impl Default for LogsBloom {
43    fn default() -> LogsBloom {
44        LogsBloom(H2048::zero())
45    }
46}
47
48impl BitOr for LogsBloom {
49    type Output = LogsBloom;
50
51    fn bitor(self, other: LogsBloom) -> LogsBloom {
52        LogsBloom(self.0 | other.0)
53    }
54}
55
56fn single_set(arr: &[u8]) -> H2048 {
57    let mut r = H2048::zero();
58    let h = Keccak256::digest(arr);
59    for i in [0usize, 2usize, 4usize].iter() {
60        let m = (((h[*i] as usize) << 8) + (h[*i + 1] as usize)) % 2048;
61        r[m / 8] = r[m / 8] | (1 << (m % 8));
62    }
63    r
64}
65
66impl LogsBloom {
67    /// Create a new log bloom
68    pub fn new() -> LogsBloom {
69        LogsBloom::default()
70    }
71
72    /// Set respective bits in the bloom with the array
73    pub fn set(&mut self, arr: &[u8]) {
74        self.0 = self.0 | single_set(arr);
75    }
76
77    /// Check that an array is in the bloom
78    pub fn check(&self, arr: &[u8]) -> bool {
79        let s = single_set(arr);
80        self.0 & s == s
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::LogsBloom;
87    use bigint::H2048;
88    use hexutil::read_hex;
89
90    #[test]
91    fn test_bloom() {
92        let mut bloom = LogsBloom::new();
93        bloom.set(&read_hex("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap());
94        assert!(bloom.check(&read_hex("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap()));
95
96        let h: H2048 = bloom.into();
97        for i in [1323usize, 431usize, 1319usize].iter() {
98            let v = 1 << (i % 8);
99            assert!(h[i / 8] & v == v);
100        }
101    }
102}