PRCYCoin  2.0.0.7rc1
P2P Digital Currency
bloom.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2014 The Bitcoin 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 #include "bloom.h"
6 
7 #include "hash.h"
9 #include "script/script.h"
10 #include "script/standard.h"
11 #include "random.h"
12 #include "streams.h"
13 
14 #include <math.h>
15 #include <stdlib.h>
16 
17 #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
18 #define LN2 0.6931471805599453094172321214581765680755001343602552
19 
20 
21 CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) :
27  vData(std::min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
33  isFull(false),
34  isEmpty(false),
35  nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
36  nTweak(nTweakIn),
37  nFlags(nFlagsIn)
38 {
39 }
40 
41 // Private constructor used by CRollingBloomFilter
42 CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn) :
43  vData((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)) / 8),
44  isFull(false),
45  isEmpty(true),
46  nHashFuncs((unsigned int)(vData.size() * 8 / nElements * LN2)),
47  nTweak(nTweakIn),
48  nFlags(BLOOM_UPDATE_NONE)
49 {
50 }
51 
52 inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
53 {
54  // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
55  return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
56 }
57 
58 void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
59 {
60  if (isFull)
61  return;
62  for (unsigned int i = 0; i < nHashFuncs; i++) {
63  unsigned int nIndex = Hash(i, vKey);
64  // Sets bit nIndex of vData
65  vData[nIndex >> 3] |= (1 << (7 & nIndex));
66  }
67  isEmpty = false;
68 }
69 
70 void CBloomFilter::insert(const COutPoint& outpoint)
71 {
72  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
73  stream << outpoint;
74  std::vector<unsigned char> data(stream.begin(), stream.end());
75  insert(data);
76 }
77 
78 void CBloomFilter::insert(const uint256& hash)
79 {
80  std::vector<unsigned char> data(hash.begin(), hash.end());
81  insert(data);
82 }
83 
84 bool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const
85 {
86  if (isFull)
87  return true;
88  if (isEmpty)
89  return false;
90  for (unsigned int i = 0; i < nHashFuncs; i++) {
91  unsigned int nIndex = Hash(i, vKey);
92  // Checks bit nIndex of vData
93  if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
94  return false;
95  }
96  return true;
97 }
98 
99 bool CBloomFilter::contains(const COutPoint& outpoint) const
100 {
101  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
102  stream << outpoint;
103  std::vector<unsigned char> data(stream.begin(), stream.end());
104  return contains(data);
105 }
106 
107 bool CBloomFilter::contains(const uint256& hash) const
108 {
109  std::vector<unsigned char> data(hash.begin(), hash.end());
110  return contains(data);
111 }
112 
114 {
115  vData.assign(vData.size(), 0);
116  isFull = false;
117  isEmpty = true;
118 }
119 
120 void CBloomFilter::reset(unsigned int nNewTweak)
121 {
122  clear();
123  nTweak = nNewTweak;
124 }
125 
127 {
128  return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
129 }
130 
132 {
133  bool fFound = false;
134  // Match if the filter contains the hash of tx
135  // for finding tx when they appear in a block
136  if (isFull)
137  return true;
138  if (isEmpty)
139  return false;
140  const uint256& hash = tx.GetHash();
141  if (contains(hash))
142  fFound = true;
143 
144  for (unsigned int i = 0; i < tx.vout.size(); i++) {
145  const CTxOut& txout = tx.vout[i];
146  // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
147  // If this matches, also add the specific output that was matched.
148  // This means clients don't have to update the filter themselves when a new relevant tx
149  // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
151  std::vector<unsigned char> data;
152  while (pc < txout.scriptPubKey.end()) {
153  opcodetype opcode;
154  if (!txout.scriptPubKey.GetOp(pc, opcode, data))
155  break;
156  if (data.size() != 0 && contains(data)) {
157  fFound = true;
159  insert(COutPoint(hash, i));
161  txnouttype type;
162  std::vector<std::vector<unsigned char> > vSolutions;
163  if (Solver(txout.scriptPubKey, type, vSolutions) &&
164  (type == TX_PUBKEY || type == TX_MULTISIG))
165  insert(COutPoint(hash, i));
166  }
167  break;
168  }
169  }
170  }
171 
172  if (fFound)
173  return true;
174 
175  for (const CTxIn& txin : tx.vin) {
176  // Match if the filter contains an outpoint tx spends
177  if (contains(txin.prevout))
178  return true;
179 
180  // Match if the filter contains any arbitrary script data element in any scriptSig in tx
182  std::vector<unsigned char> data;
183  while (pc < txin.scriptSig.end()) {
184  opcodetype opcode;
185  if (!txin.scriptSig.GetOp(pc, opcode, data))
186  break;
187  if (data.size() != 0 && contains(data))
188  return true;
189  }
190  }
191 
192  return false;
193 }
194 
196 {
197  bool full = true;
198  bool empty = true;
199  for (unsigned int i = 0; i < vData.size(); i++) {
200  full &= vData[i] == 0xff;
201  empty &= vData[i] == 0;
202  }
203  isFull = full;
204  isEmpty = empty;
205 }
206 
207 CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) :
208  b1(nElements * 2, fpRate, 0), b2(nElements * 2, fpRate, 0)
209 {
210  // Implemented using two bloom filters of 2 * nElements each.
211  // We fill them up, and clear them, staggered, every nElements
212  // inserted, so at least one always contains the last nElements
213  // inserted.
214  nInsertions = 0;
215  nBloomSize = nElements * 2;
216 
217  reset();
218 }
219 
220 void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
221 {
222  if (nInsertions == 0) {
223  b1.clear();
224  } else if (nInsertions == nBloomSize / 2) {
225  b2.clear();
226  }
227  b1.insert(vKey);
228  b2.insert(vKey);
229  if (++nInsertions == nBloomSize) {
230  nInsertions = 0;
231  }
232 }
233 
235 {
236  std::vector<unsigned char> data(hash.begin(), hash.end());
237  insert(data);
238 }
239 
240 bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
241 {
242  if (nInsertions < nBloomSize / 2) {
243  return b2.contains(vKey);
244  }
245  return b1.contains(vKey);
246 }
247 
248 bool CRollingBloomFilter::contains(const uint256& hash) const
249 {
250  std::vector<unsigned char> data(hash.begin(), hash.end());
251  return contains(data);
252 }
253 
255 {
256  unsigned int nNewTweak = GetRand(std::numeric_limits<unsigned int>::max());
257  b1.reset(nNewTweak);
258  b2.reset(nNewTweak);
259  nInsertions = 0;
260 }
CTxIn
An input of a transaction.
Definition: transaction.h:83
CRollingBloomFilter::nBloomSize
unsigned int nBloomSize
Definition: bloom.h:132
CBloomFilter::contains
bool contains(const std::vector< unsigned char > &vKey) const
Definition: bloom.cpp:84
base_uint::end
unsigned char * end()
Definition: arith_uint256.h:245
CRollingBloomFilter::nInsertions
unsigned int nInsertions
Definition: bloom.h:133
CBloomFilter::reset
void reset(unsigned int nNewTweak)
Definition: bloom.cpp:120
prevector::const_iterator
Definition: prevector.h:97
CRollingBloomFilter::insert
void insert(const std::vector< unsigned char > &vKey)
Definition: bloom.cpp:220
transaction.h
CBloomFilter::IsWithinSizeConstraints
bool IsWithinSizeConstraints() const
True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS (c...
Definition: bloom.cpp:126
streams.h
CBloomFilter::isFull
bool isFull
Definition: bloom.h:47
CDataStream::begin
const_iterator begin() const
Definition: streams.h:116
CBloomFilter::nTweak
unsigned int nTweak
Definition: bloom.h:50
base_uint::begin
unsigned char * begin()
Definition: arith_uint256.h:240
BLOOM_UPDATE_P2PUBKEY_ONLY
@ BLOOM_UPDATE_P2PUBKEY_ONLY
Definition: bloom.h:28
CBloomFilter::clear
void clear()
Definition: bloom.cpp:113
MurmurHash3
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector< unsigned char > &vDataToHash)
Definition: hash.cpp:15
CBloomFilter::Hash
unsigned int Hash(unsigned int nHashNum, const std::vector< unsigned char > &vDataToHash) const
Definition: bloom.cpp:52
SER_NETWORK
@ SER_NETWORK
Definition: serialize.h:159
CBloomFilter::vData
std::vector< unsigned char > vData
Definition: bloom.h:46
CBloomFilter::UpdateEmptyFull
void UpdateEmptyFull()
Checks for empty and full filters to avoid wasting cpu.
Definition: bloom.cpp:195
CRollingBloomFilter::contains
bool contains(const std::vector< unsigned char > &vKey) const
Definition: bloom.cpp:240
CRollingBloomFilter::b1
CBloomFilter b1
Definition: bloom.h:134
CTransaction
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:269
bloom.h
GetRand
uint64_t GetRand(uint64_t nMax)
Definition: random.cpp:351
CRollingBloomFilter::CRollingBloomFilter
CRollingBloomFilter(unsigned int nElements, double nFPRate)
Definition: bloom.cpp:207
prevector::end
iterator end()
Definition: prevector.h:292
TX_MULTISIG
@ TX_MULTISIG
Definition: standard.h:64
random.h
LN2
#define LN2
Definition: bloom.cpp:18
CTxOut
An output of a transaction.
Definition: transaction.h:164
CBloomFilter::insert
void insert(const std::vector< unsigned char > &vKey)
Definition: bloom.cpp:58
CBloomFilter::isEmpty
bool isEmpty
Definition: bloom.h:48
CTransaction::vout
std::vector< CTxOut > vout
Definition: transaction.h:286
CTxOut::scriptPubKey
CScript scriptPubKey
Definition: transaction.h:168
LN2SQUARED
#define LN2SQUARED
Definition: bloom.cpp:17
TX_PUBKEY
@ TX_PUBKEY
Definition: standard.h:61
CRollingBloomFilter::reset
void reset()
Definition: bloom.cpp:254
CDataStream::end
const_iterator end() const
Definition: streams.h:118
CScript::GetOp
bool GetOp(iterator &pc, opcodetype &opcodeRet, std::vector< unsigned char > &vchRet)
Definition: script.h:468
standard.h
CBloomFilter::CBloomFilter
CBloomFilter()
Definition: bloom.h:70
uint256
256-bit unsigned big integer.
Definition: uint256.h:38
BLOOM_UPDATE_MASK
@ BLOOM_UPDATE_MASK
Definition: bloom.h:29
CBloomFilter::nFlags
unsigned char nFlags
Definition: bloom.h:51
BLOOM_UPDATE_ALL
@ BLOOM_UPDATE_ALL
Definition: bloom.h:26
CTransaction::vin
std::vector< CTxIn > vin
Definition: transaction.h:285
Solver
bool Solver(const CKeyStore &keystore, const CScript &scriptPubKey, uint256 hash, int nHashType, CScript &scriptSigRet, txnouttype &whichTypeRet)
Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
Definition: sign.cpp:50
std
Definition: adjacency_graphs.hpp:25
CTxIn::prevout
COutPoint prevout
Definition: transaction.h:86
CTxIn::scriptSig
CScript scriptSig
Definition: transaction.h:87
prevector::begin
iterator begin()
Definition: prevector.h:290
CBloomFilter::nHashFuncs
unsigned int nHashFuncs
Definition: bloom.h:49
hash.h
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:34
script.h
CTransaction::GetHash
const uint256 & GetHash() const
Definition: transaction.h:342
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:36
txnouttype
txnouttype
Definition: standard.h:57
CRollingBloomFilter::b2
CBloomFilter b2
Definition: bloom.h:134
CBloomFilter::IsRelevantAndUpdate
bool IsRelevantAndUpdate(const CTransaction &tx)
Also adds any outputs which match the filter to the filter (to match their spending txes)
Definition: bloom.cpp:131
BLOOM_UPDATE_NONE
@ BLOOM_UPDATE_NONE
Definition: bloom.h:25
opcodetype
opcodetype
Script opcodes.
Definition: script.h:38