]>
Commit | Line | Data |
---|---|---|
bd21612c MC |
1 | // Copyright (c) 2012 The Bitcoin developers |
2 | // Distributed under the MIT/X11 software license, see the accompanying | |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
4 | #include <math.h> | |
5 | #include <stdlib.h> | |
6 | ||
7 | #include "bloom.h" | |
8 | #include "main.h" | |
9 | #include "script.h" | |
10 | ||
11 | #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455 | |
12 | #define LN2 0.6931471805599453094172321214581765680755001343602552 | |
13 | ||
14 | using namespace std; | |
15 | ||
16 | static const unsigned char bit_mask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; | |
17 | ||
18 | CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate) : | |
19 | // The ideal size for a bloom filter with a given number of elements and false positive rate is: | |
20 | // - nElements * log(fp rate) / ln(2)^2 | |
21 | // We ignore filter parameters which will create a bloom filter larger than the protocol limits | |
22 | vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), | |
23 | // The ideal number of hash functions is filter size * ln(2) / number of elements | |
24 | // Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits | |
25 | // See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas | |
26 | nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)) | |
27 | { | |
28 | } | |
29 | ||
30 | inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const | |
31 | { | |
32 | // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values. | |
33 | return MurmurHash3(nHashNum * 0xFBA4C795, vDataToHash) % (vData.size() * 8); | |
34 | } | |
35 | ||
36 | void CBloomFilter::insert(const vector<unsigned char>& vKey) | |
37 | { | |
38 | for (unsigned int i = 0; i < nHashFuncs; i++) | |
39 | { | |
40 | unsigned int nIndex = Hash(i, vKey); | |
41 | // Sets bit nIndex of vData | |
42 | vData[nIndex >> 3] |= bit_mask[7 & nIndex]; | |
43 | } | |
44 | } | |
45 | ||
46 | void CBloomFilter::insert(const COutPoint& outpoint) | |
47 | { | |
48 | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | |
49 | stream << outpoint; | |
50 | vector<unsigned char> data(stream.begin(), stream.end()); | |
51 | insert(data); | |
52 | } | |
53 | ||
54 | void CBloomFilter::insert(const uint256& hash) | |
55 | { | |
56 | vector<unsigned char> data(hash.begin(), hash.end()); | |
57 | insert(data); | |
58 | } | |
59 | ||
60 | bool CBloomFilter::contains(const vector<unsigned char>& vKey) const | |
61 | { | |
62 | for (unsigned int i = 0; i < nHashFuncs; i++) | |
63 | { | |
64 | unsigned int nIndex = Hash(i, vKey); | |
65 | // Checks bit nIndex of vData | |
66 | if (!(vData[nIndex >> 3] & bit_mask[7 & nIndex])) | |
67 | return false; | |
68 | } | |
69 | return true; | |
70 | } | |
71 | ||
72 | bool CBloomFilter::contains(const COutPoint& outpoint) const | |
73 | { | |
74 | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | |
75 | stream << outpoint; | |
76 | vector<unsigned char> data(stream.begin(), stream.end()); | |
77 | return contains(data); | |
78 | } | |
79 | ||
80 | bool CBloomFilter::contains(const uint256& hash) const | |
81 | { | |
82 | vector<unsigned char> data(hash.begin(), hash.end()); | |
83 | return contains(data); | |
84 | } | |
85 | ||
86 | bool CBloomFilter::IsWithinSizeConstraints() const | |
87 | { | |
88 | return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS; | |
89 | } | |
90 | ||
91 | bool CBloomFilter::IsTransactionRelevantToFilter(const CTransaction& tx) const | |
92 | { | |
93 | // Match if the filter contains the hash of tx | |
94 | // for finding tx when they appear in a block | |
95 | if (contains(tx.GetHash())) | |
96 | return true; | |
97 | ||
98 | BOOST_FOREACH(const CTxOut& txout, tx.vout) | |
99 | { | |
100 | // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx | |
101 | CScript::const_iterator pc = txout.scriptPubKey.begin(); | |
102 | vector<unsigned char> data; | |
103 | while (pc < txout.scriptPubKey.end()) | |
104 | { | |
105 | opcodetype opcode; | |
106 | if (!txout.scriptPubKey.GetOp(pc, opcode, data)) | |
107 | break; | |
108 | if (data.size() != 0 && contains(data)) | |
109 | return true; | |
110 | } | |
111 | } | |
112 | ||
113 | BOOST_FOREACH(const CTxIn& txin, tx.vin) | |
114 | { | |
115 | // Match if the filter contains an outpoint tx spends | |
116 | if (contains(txin.prevout)) | |
117 | return true; | |
118 | ||
119 | // Match if the filter contains any arbitrary script data element in any scriptSig in tx | |
120 | CScript::const_iterator pc = txin.scriptSig.begin(); | |
121 | vector<unsigned char> data; | |
122 | while (pc < txin.scriptSig.end()) | |
123 | { | |
124 | opcodetype opcode; | |
125 | if (!txin.scriptSig.GetOp(pc, opcode, data)) | |
126 | break; | |
127 | if (data.size() != 0 && contains(data)) | |
128 | return true; | |
129 | } | |
130 | } | |
131 | ||
132 | return false; | |
133 | } |