Coverage Report

Created: 2026-08-05 14:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/common/bloom.h
Line
Count
Source
1
// Copyright (c) 2012-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_COMMON_BLOOM_H
6
#define BITCOIN_COMMON_BLOOM_H
7
8
#include <serialize.h>
9
10
#include <cstdint>
11
#include <span>
12
#include <vector>
13
14
class COutPoint;
15
class CTransaction;
16
17
//! 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%
18
static constexpr unsigned int MAX_BLOOM_FILTER_SIZE = 36000; // bytes
19
static constexpr unsigned int MAX_HASH_FUNCS = 50;
20
21
/**
22
 * First two bits of nFlags control how much IsRelevantAndUpdate actually updates
23
 * The remaining bits are reserved
24
 */
25
enum bloomflags
26
{
27
    BLOOM_UPDATE_NONE = 0,
28
    BLOOM_UPDATE_ALL = 1,
29
    // Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script
30
    BLOOM_UPDATE_P2PUBKEY_ONLY = 2,
31
    BLOOM_UPDATE_MASK = 3,
32
};
33
34
/**
35
 * BloomFilter is a probabilistic filter which SPV clients provide
36
 * so that we can filter the transactions we send them.
37
 *
38
 * This allows for significantly more efficient transaction and block downloads.
39
 *
40
 * Because bloom filters are probabilistic, a SPV node can increase the false-
41
 * positive rate, making us send it transactions which aren't actually its,
42
 * allowing clients to trade more bandwidth for more privacy by obfuscating which
43
 * keys are controlled by them.
44
 */
45
class CBloomFilter
46
{
47
private:
48
    std::vector<unsigned char> vData;
49
    unsigned int nHashFuncs;
50
    unsigned int nTweak;
51
    unsigned char nFlags;
52
53
    unsigned int Hash(unsigned int nHashNum, std::span<const unsigned char> vDataToHash) const;
54
55
public:
56
    /**
57
     * Creates a new bloom filter which will provide the given fp rate when filled with the given number of elements
58
     * Note that if the given parameters will result in a filter outside the bounds of the protocol limits,
59
     * the filter created will be as close to the given parameters as possible within the protocol limits.
60
     * This will apply if nFPRate is very low or nElements is unreasonably high.
61
     * nTweak is a constant which is added to the seed value passed to the hash function
62
     * It should generally always be a random value (and is largely only exposed for unit testing)
63
     * nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)
64
     */
65
    CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn);
66
10
    CBloomFilter() : nHashFuncs(0), nTweak(0), nFlags(0) {}
67
68
13
    SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
void CBloomFilter::SerializationOps<DataStream, CBloomFilter const, ActionSerialize>(CBloomFilter const&, DataStream&, ActionSerialize)
Line
Count
Source
68
3
    SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
void CBloomFilter::SerializationOps<DataStream, CBloomFilter, ActionUnserialize>(CBloomFilter&, DataStream&, ActionUnserialize)
Line
Count
Source
68
10
    SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
69
70
    void insert(std::span<const unsigned char> vKey);
71
    void insert(const COutPoint& outpoint);
72
73
    bool contains(std::span<const unsigned char> vKey) const;
74
    bool contains(const COutPoint& outpoint) const;
75
76
    //! True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS
77
    //! (catch a filter which was just deserialized which was too big)
78
    bool IsWithinSizeConstraints() const;
79
80
    //! Also adds any outputs which match the filter to the filter (to match their spending txes)
81
    bool IsRelevantAndUpdate(const CTransaction& tx);
82
};
83
84
/**
85
 * RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
86
 * Construct it with the number of items to keep track of, and a false-positive
87
 * rate. Unlike CBloomFilter, by default nTweak is set to a cryptographically
88
 * secure random value for you. Similarly rather than clear() the method
89
 * reset() is provided, which also changes nTweak to decrease the impact of
90
 * false-positives.
91
 *
92
 * contains(item) will always return true if item was one of the last N to 1.5*N
93
 * insert()'ed ... but may also return true for items that were not inserted.
94
 *
95
 * It needs around 1.8 bytes per element per factor 0.1 of false positive rate.
96
 * For example, if we want 1000 elements, we'd need:
97
 * - ~1800 bytes for a false positive rate of 0.1
98
 * - ~3600 bytes for a false positive rate of 0.01
99
 * - ~5400 bytes for a false positive rate of 0.001
100
 *
101
 * If we make these simplifying assumptions:
102
 * - logFpRate / log(0.5) doesn't get rounded or clamped in the nHashFuncs calculation
103
 * - nElements is even, so that nEntriesPerGeneration == nElements / 2
104
 *
105
 * Then we get a more accurate estimate for filter bytes:
106
 *
107
 *     3/(log(256)*log(2)) * log(1/fpRate) * nElements
108
 */
109
class CRollingBloomFilter
110
{
111
public:
112
    CRollingBloomFilter(unsigned int nElements, double nFPRate);
113
114
    void insert(std::span<const unsigned char> vKey);
115
    bool contains(std::span<const unsigned char> vKey) const;
116
117
    void reset();
118
119
private:
120
    int nEntriesPerGeneration;
121
    int nEntriesThisGeneration;
122
    int nGeneration;
123
    std::vector<uint64_t> data;
124
    unsigned int nTweak;
125
    int nHashFuncs;
126
};
127
128
#endif // BITCOIN_COMMON_BLOOM_H