]> Git Repo - VerusCoin.git/blob - src/bloom.cpp
Merge pull request #5237
[VerusCoin.git] / src / bloom.cpp
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
5 #include "bloom.h"
6
7 #include "core/transaction.h"
8 #include "hash.h"
9 #include "script/script.h"
10 #include "script/standard.h"
11 #include "streams.h"
12
13 #include <math.h>
14 #include <stdlib.h>
15
16 #include <boost/foreach.hpp>
17
18 #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
19 #define LN2 0.6931471805599453094172321214581765680755001343602552
20
21 using namespace std;
22
23 CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) :
24 // The ideal size for a bloom filter with a given number of elements and false positive rate is:
25 // - nElements * log(fp rate) / ln(2)^2
26 // We ignore filter parameters which will create a bloom filter larger than the protocol limits
27 vData(min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
28 // The ideal number of hash functions is filter size * ln(2) / number of elements
29 // Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
30 // See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
31 isFull(false),
32 isEmpty(false),
33 nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
34 nTweak(nTweakIn),
35 nFlags(nFlagsIn)
36 {
37 }
38
39 inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
40 {
41     // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
42     return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
43 }
44
45 void CBloomFilter::insert(const vector<unsigned char>& vKey)
46 {
47     if (isFull)
48         return;
49     for (unsigned int i = 0; i < nHashFuncs; i++)
50     {
51         unsigned int nIndex = Hash(i, vKey);
52         // Sets bit nIndex of vData
53         vData[nIndex >> 3] |= (1 << (7 & nIndex));
54     }
55     isEmpty = false;
56 }
57
58 void CBloomFilter::insert(const COutPoint& outpoint)
59 {
60     CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
61     stream << outpoint;
62     vector<unsigned char> data(stream.begin(), stream.end());
63     insert(data);
64 }
65
66 void CBloomFilter::insert(const uint256& hash)
67 {
68     vector<unsigned char> data(hash.begin(), hash.end());
69     insert(data);
70 }
71
72 bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
73 {
74     if (isFull)
75         return true;
76     if (isEmpty)
77         return false;
78     for (unsigned int i = 0; i < nHashFuncs; i++)
79     {
80         unsigned int nIndex = Hash(i, vKey);
81         // Checks bit nIndex of vData
82         if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
83             return false;
84     }
85     return true;
86 }
87
88 bool CBloomFilter::contains(const COutPoint& outpoint) const
89 {
90     CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
91     stream << outpoint;
92     vector<unsigned char> data(stream.begin(), stream.end());
93     return contains(data);
94 }
95
96 bool CBloomFilter::contains(const uint256& hash) const
97 {
98     vector<unsigned char> data(hash.begin(), hash.end());
99     return contains(data);
100 }
101
102 void CBloomFilter::clear()
103 {
104     vData.assign(vData.size(),0);
105     isFull = false;
106     isEmpty = true;
107 }
108
109 bool CBloomFilter::IsWithinSizeConstraints() const
110 {
111     return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
112 }
113
114 bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
115 {
116     bool fFound = false;
117     // Match if the filter contains the hash of tx
118     //  for finding tx when they appear in a block
119     if (isFull)
120         return true;
121     if (isEmpty)
122         return false;
123     const uint256& hash = tx.GetHash();
124     if (contains(hash))
125         fFound = true;
126
127     for (unsigned int i = 0; i < tx.vout.size(); i++)
128     {
129         const CTxOut& txout = tx.vout[i];
130         // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
131         // If this matches, also add the specific output that was matched.
132         // This means clients don't have to update the filter themselves when a new relevant tx 
133         // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
134         CScript::const_iterator pc = txout.scriptPubKey.begin();
135         vector<unsigned char> data;
136         while (pc < txout.scriptPubKey.end())
137         {
138             opcodetype opcode;
139             if (!txout.scriptPubKey.GetOp(pc, opcode, data))
140                 break;
141             if (data.size() != 0 && contains(data))
142             {
143                 fFound = true;
144                 if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
145                     insert(COutPoint(hash, i));
146                 else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
147                 {
148                     txnouttype type;
149                     vector<vector<unsigned char> > vSolutions;
150                     if (Solver(txout.scriptPubKey, type, vSolutions) &&
151                             (type == TX_PUBKEY || type == TX_MULTISIG))
152                         insert(COutPoint(hash, i));
153                 }
154                 break;
155             }
156         }
157     }
158
159     if (fFound)
160         return true;
161
162     BOOST_FOREACH(const CTxIn& txin, tx.vin)
163     {
164         // Match if the filter contains an outpoint tx spends
165         if (contains(txin.prevout))
166             return true;
167
168         // Match if the filter contains any arbitrary script data element in any scriptSig in tx
169         CScript::const_iterator pc = txin.scriptSig.begin();
170         vector<unsigned char> data;
171         while (pc < txin.scriptSig.end())
172         {
173             opcodetype opcode;
174             if (!txin.scriptSig.GetOp(pc, opcode, data))
175                 break;
176             if (data.size() != 0 && contains(data))
177                 return true;
178         }
179     }
180
181     return false;
182 }
183
184 void CBloomFilter::UpdateEmptyFull()
185 {
186     bool full = true;
187     bool empty = true;
188     for (unsigned int i = 0; i < vData.size(); i++)
189     {
190         full &= vData[i] == 0xff;
191         empty &= vData[i] == 0;
192     }
193     isFull = full;
194     isEmpty = empty;
195 }
This page took 0.03486 seconds and 4 git commands to generate.