]>
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 | ||
e1a4f377 | 18 | CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) : |
bd21612c MC |
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 | |
b1f99bed | 26 | nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), |
e1a4f377 MC |
27 | nTweak(nTweakIn), |
28 | nFlags(nFlagsIn) | |
bd21612c MC |
29 | { |
30 | } | |
31 | ||
32 | inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const | |
33 | { | |
34 | // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values. | |
b1f99bed | 35 | return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8); |
bd21612c MC |
36 | } |
37 | ||
38 | void CBloomFilter::insert(const vector<unsigned char>& vKey) | |
39 | { | |
40 | for (unsigned int i = 0; i < nHashFuncs; i++) | |
41 | { | |
42 | unsigned int nIndex = Hash(i, vKey); | |
43 | // Sets bit nIndex of vData | |
44 | vData[nIndex >> 3] |= bit_mask[7 & nIndex]; | |
45 | } | |
46 | } | |
47 | ||
48 | void CBloomFilter::insert(const COutPoint& outpoint) | |
49 | { | |
50 | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | |
51 | stream << outpoint; | |
52 | vector<unsigned char> data(stream.begin(), stream.end()); | |
53 | insert(data); | |
54 | } | |
55 | ||
56 | void CBloomFilter::insert(const uint256& hash) | |
57 | { | |
58 | vector<unsigned char> data(hash.begin(), hash.end()); | |
59 | insert(data); | |
60 | } | |
61 | ||
62 | bool CBloomFilter::contains(const vector<unsigned char>& vKey) const | |
63 | { | |
64 | for (unsigned int i = 0; i < nHashFuncs; i++) | |
65 | { | |
66 | unsigned int nIndex = Hash(i, vKey); | |
67 | // Checks bit nIndex of vData | |
68 | if (!(vData[nIndex >> 3] & bit_mask[7 & nIndex])) | |
69 | return false; | |
70 | } | |
71 | return true; | |
72 | } | |
73 | ||
74 | bool CBloomFilter::contains(const COutPoint& outpoint) const | |
75 | { | |
76 | CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | |
77 | stream << outpoint; | |
78 | vector<unsigned char> data(stream.begin(), stream.end()); | |
79 | return contains(data); | |
80 | } | |
81 | ||
82 | bool CBloomFilter::contains(const uint256& hash) const | |
83 | { | |
84 | vector<unsigned char> data(hash.begin(), hash.end()); | |
85 | return contains(data); | |
86 | } | |
87 | ||
88 | bool CBloomFilter::IsWithinSizeConstraints() const | |
89 | { | |
90 | return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS; | |
91 | } | |
92 | ||
d3b26f70 | 93 | bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash) |
bd21612c | 94 | { |
d3b26f70 | 95 | bool fFound = false; |
bd21612c MC |
96 | // Match if the filter contains the hash of tx |
97 | // for finding tx when they appear in a block | |
269d9c64 | 98 | if (contains(hash)) |
d3b26f70 | 99 | fFound = true; |
bd21612c | 100 | |
d3b26f70 | 101 | for (unsigned int i = 0; i < tx.vout.size(); i++) |
bd21612c | 102 | { |
d3b26f70 | 103 | const CTxOut& txout = tx.vout[i]; |
bd21612c | 104 | // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx |
d3b26f70 MC |
105 | // If this matches, also add the specific output that was matched. |
106 | // This means clients don't have to update the filter themselves when a new relevant tx | |
107 | // is discovered in order to find spending transactions, which avoids round-tripping and race conditions. | |
bd21612c MC |
108 | CScript::const_iterator pc = txout.scriptPubKey.begin(); |
109 | vector<unsigned char> data; | |
110 | while (pc < txout.scriptPubKey.end()) | |
111 | { | |
112 | opcodetype opcode; | |
113 | if (!txout.scriptPubKey.GetOp(pc, opcode, data)) | |
114 | break; | |
115 | if (data.size() != 0 && contains(data)) | |
d3b26f70 MC |
116 | { |
117 | fFound = true; | |
e1a4f377 MC |
118 | if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL) |
119 | insert(COutPoint(hash, i)); | |
120 | else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY) | |
121 | { | |
122 | txnouttype type; | |
123 | vector<vector<unsigned char> > vSolutions; | |
124 | if (Solver(txout.scriptPubKey, type, vSolutions) && | |
125 | (type == TX_PUBKEY || type == TX_MULTISIG)) | |
126 | insert(COutPoint(hash, i)); | |
127 | } | |
d3b26f70 MC |
128 | break; |
129 | } | |
bd21612c MC |
130 | } |
131 | } | |
132 | ||
d3b26f70 MC |
133 | if (fFound) |
134 | return true; | |
135 | ||
bd21612c MC |
136 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
137 | { | |
138 | // Match if the filter contains an outpoint tx spends | |
139 | if (contains(txin.prevout)) | |
140 | return true; | |
141 | ||
142 | // Match if the filter contains any arbitrary script data element in any scriptSig in tx | |
143 | CScript::const_iterator pc = txin.scriptSig.begin(); | |
144 | vector<unsigned char> data; | |
145 | while (pc < txin.scriptSig.end()) | |
146 | { | |
147 | opcodetype opcode; | |
148 | if (!txin.scriptSig.GetOp(pc, opcode, data)) | |
149 | break; | |
150 | if (data.size() != 0 && contains(data)) | |
151 | return true; | |
152 | } | |
153 | } | |
154 | ||
155 | return false; | |
156 | } |