diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index 4e1631025..1b6ea7f74 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -25,48 +25,45 @@ using namespace std; using namespace dev; using namespace dev::shh; -bool BloomFilter::matches(AbridgedTopic const& _t) const -{ - static unsigned const c_match = ~unsigned(0); - unsigned topic = AbridgedTopic::Arith(_t).convert_to(); - unsigned matchingBits = m_filter & topic; - matchingBits |= ~topic; - return (c_match == matchingBits); -} +static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; -void SharedBloomFilter::add(AbridgedTopic const& _t) +void TopicBloomFilter::add(AbridgedTopic const& _h) { - unsigned const topic = AbridgedTopic::Arith(_t).convert_to(); - m_filter |= topic; - - unsigned nextBit = 1; - for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1) - if (topic & nextBit) - if (m_refCounter[i] != numeric_limits::max()) + *this |= _h; + unsigned count = 0; + for (unsigned i = 0; i < CounterSize; ++i) + if (isBitSet(_h, i)) + { + if (m_refCounter[i] != numeric_limits::max()) m_refCounter[i]++; //else: overflow - // in order to encounter overflow, you have to set at least 65536 filters simultaneously. - // even then, the problem will only arise after at least 65536 filters will be be removed. - // we assume, it will never happen. + // in order to encounter overflow, you have to set at least 65536 filters simultaneously. + // even then, the problem will only arise after at least 65536 filters will be be removed. + // we assume, it will never happen. + } } -void SharedBloomFilter::remove(AbridgedTopic const& _t) +void TopicBloomFilter::remove(AbridgedTopic const& _h) { - unsigned const topic = AbridgedTopic::Arith(_t).convert_to(); - - unsigned nextBit = 1; - for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1) - if (topic & nextBit) + unsigned count = 0; + for (unsigned i = 0; i < CounterSize; ++i) + if (isBitSet(_h, i)) { if (m_refCounter[i]) m_refCounter[i]--; if (!m_refCounter[i]) - m_filter &= ~nextBit; + (*this)[i/8] &= ~c_mask[i%8]; } } +bool TopicBloomFilter::isBitSet(AbridgedTopic const& _h, unsigned _index) +{ + unsigned iByte = _index / 8; + unsigned iBit = _index % 8; + return (_h[iByte] & c_mask[iBit]) != 0; +} diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index d663c994e..89529146a 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -28,44 +28,26 @@ namespace dev namespace shh { -class BloomFilter +class TopicBloomFilter: public AbridgedTopic { public: - virtual ~BloomFilter() {} - BloomFilter(): m_filter(0) {} - BloomFilter(unsigned _i): m_filter(_i) {} - BloomFilter(AbridgedTopic const& _t): m_filter(AbridgedTopic::Arith(_t).convert_to()) {} - - unsigned getUnsigned() const { return m_filter; } - AbridgedTopic getAbridgedTopic() const { return AbridgedTopic(m_filter); } - - bool matches(AbridgedTopic const& _t) const; - virtual void add(Topic const& _t) { add(abridge(_t)); } - virtual void add(Topics const& _topics) { for (Topic t : _topics) add(abridge(t)); } - virtual void add(AbridgedTopic const& _t) { m_filter |= AbridgedTopic::Arith(_t).convert_to(); } - virtual void remove(AbridgedTopic const&) {} // not implemented in this class, use derived class instead. - -protected: - unsigned m_filter; -}; - -class SharedBloomFilter: public BloomFilter -{ -public: - virtual ~SharedBloomFilter() {} - SharedBloomFilter() { init(); } - SharedBloomFilter(unsigned _i): BloomFilter(_i) { init(); } - SharedBloomFilter(AbridgedTopic const& _t): BloomFilter(_t) { init(); } - - void add(AbridgedTopic const& _t) override; - void remove(AbridgedTopic const& _t) override; + TopicBloomFilter() { init(); } + TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); } -protected: - void init() { for (unsigned i = 0; i < ArrSize; ++i) m_refCounter[i] = 0; } + void addBloom(AbridgedTopic const& _h) { add(_h.template bloom()); } + void removeBloom(AbridgedTopic const& _h) { remove(_h.template bloom()); } + void add(AbridgedTopic const& _h); + void remove(AbridgedTopic const& _h); + bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloom()); } + enum { BitsPerBloom = 3 }; + private: - enum { ArrSize = 8 * AbridgedTopic::size }; - unsigned short m_refCounter[ArrSize]; + void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; } + static bool isBitSet(AbridgedTopic const& _h, unsigned _index); + + enum { CounterSize = 8 * AbridgedTopic::size }; + std::array m_refCounter; }; } diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index f66036f89..46c41f3a2 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -87,7 +87,7 @@ private: mutable dev::Mutex m_filterLock; std::map m_filters; std::map m_watches; - SharedBloomFilter m_bloom; + TopicBloomFilter m_bloom; }; } diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index f58bf8503..d7a4c76ef 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -20,122 +20,163 @@ along with cpp-ethereum. If not, see . */ #include +#include #include using namespace std; using namespace dev; using namespace dev::shh; +void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(!_f.contains(_h)); + _f.add(_h); + BOOST_REQUIRE(_f.contains(_h)); +} + +void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(_f.contains(_h)); + _f.remove(_h); + BOOST_REQUIRE(!_f.contains(_h)); +} + +void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(!_f.containsBloom(_h)); + _f.addBloom(_h); + BOOST_REQUIRE(_f.containsBloom(_h)); +} + +void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(_f.containsBloom(_h)); + _f.removeBloom(_h); + BOOST_REQUIRE(!_f.containsBloom(_h)); +} + BOOST_AUTO_TEST_SUITE(bloomFilter) -BOOST_AUTO_TEST_CASE(match) +BOOST_AUTO_TEST_CASE(bloomFilterRandom) { VerbosityHolder setTemporaryLevel(10); cnote << "Testing Bloom Filter matching..."; - SharedBloomFilter f; - unsigned b00000001 = 0x01; - unsigned b00010000 = 0x10; - unsigned b00011000 = 0x18; - unsigned b00110000 = 0x30; - unsigned b00110010 = 0x32; - unsigned b00111000 = 0x38; - unsigned b00000110 = 0x06; - unsigned b00110110 = 0x36; - unsigned b00110111 = 0x37; - - AbridgedTopic x(b00111000); - SharedBloomFilter f1(b00111000); - SharedBloomFilter f2(x); - BOOST_REQUIRE_EQUAL(x, f1.getAbridgedTopic()); - BOOST_REQUIRE_EQUAL(x, f2.getAbridgedTopic()); - BOOST_REQUIRE_EQUAL(b00111000, f1.getUnsigned()); - BOOST_REQUIRE_EQUAL(b00111000, f2.getUnsigned()); - - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - f.add(AbridgedTopic(b00000001)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); - f.add(AbridgedTopic(b00010000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - f.add(AbridgedTopic(b00011000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); - f.add(AbridgedTopic(b00110000)); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); - f.add(AbridgedTopic(b00110010)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); - f.add(AbridgedTopic(b00000110)); - - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00000001)); - f.remove(AbridgedTopic(b00000001)); - f.remove(AbridgedTopic(b00000001)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00010000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00111000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.add(AbridgedTopic(b00000001)); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00110111)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00110111)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); + TopicBloomFilter f; + vector vec; + Topic x(0xDEADBEEF); + int const c_rounds = 4; + + for (int i = 0; i < c_rounds; ++i, x = sha3(x)) + vec.push_back(abridge(x)); + + for (int i = 0; i < c_rounds; ++i) + testAddNonExisting(f, vec[i]); + + for (int i = 0; i < c_rounds; ++i) + testRemoveExisting(f, vec[i]); + + for (int i = 0; i < c_rounds; ++i) + testAddNonExistingBloom(f, vec[i]); + + for (int i = 0; i < c_rounds; ++i) + testRemoveExistingBloom(f, vec[i]); +} + +BOOST_AUTO_TEST_CASE(bloomFilterRaw) +{ + VerbosityHolder setTemporaryLevel(10); + cnote << "Testing Raw Bloom matching..."; + + TopicBloomFilter f; + + AbridgedTopic b00000001(0x01); + AbridgedTopic b00010000(0x10); + AbridgedTopic b00011000(0x18); + AbridgedTopic b00110000(0x30); + AbridgedTopic b00110010(0x32); + AbridgedTopic b00111000(0x38); + AbridgedTopic b00000110(0x06); + AbridgedTopic b00110110(0x36); + AbridgedTopic b00110111(0x37); + + testAddNonExisting(f, b00000001); + testAddNonExisting(f, b00010000); + testAddNonExisting(f, b00011000); + testAddNonExisting(f, b00110000); + BOOST_REQUIRE(f.contains(b00111000)); + testAddNonExisting(f, b00110010); + testAddNonExisting(f, b00000110); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(f.contains(b00110111)); + + f.remove(b00000001); + f.remove(b00000001); + f.remove(b00000001); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.remove(b00010000); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.remove(b00111000); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.add(b00000001); + BOOST_REQUIRE(f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(f.contains(b00110111)); + + f.remove(b00110111); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(!f.contains(b00110000)); + BOOST_REQUIRE(!f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(!f.contains(b00000110)); + BOOST_REQUIRE(!f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.remove(b00110111); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(!f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(!f.contains(b00110000)); + BOOST_REQUIRE(!f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(!f.contains(b00000110)); + BOOST_REQUIRE(!f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file