Anoncoin  0.9.4
P2P Digital Currency
bloom.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012 The Bitcoin developers
2 // Copyright (c) 2013-2014 The Anoncoin Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "bloom.h"
7 
8 #include "core.h"
9 #include "script.h"
10 
11 #include <math.h>
12 #include <stdlib.h>
13 
14 #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
15 #define LN2 0.6931471805599453094172321214581765680755001343602552
16 
17 using namespace std;
18 
19 CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) :
20 // The ideal size for a bloom filter with a given number of elements and false positive rate is:
21 // - nElements * log(fp rate) / ln(2)^2
22 // We ignore filter parameters which will create a bloom filter larger than the protocol limits
23 vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
24 // The ideal number of hash functions is filter size * ln(2) / number of elements
25 // Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
26 // See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
27 isFull(false),
28 isEmpty(false),
29 nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
30 nTweak(nTweakIn),
31 nFlags(nFlagsIn)
32 {
33 }
34 
35 inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
36 {
37  // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
38  return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
39 }
40 
41 void CBloomFilter::insert(const vector<unsigned char>& vKey)
42 {
43  if (isFull)
44  return;
45  for (unsigned int i = 0; i < nHashFuncs; i++)
46  {
47  unsigned int nIndex = Hash(i, vKey);
48  // Sets bit nIndex of vData
49  vData[nIndex >> 3] |= (1 << (7 & nIndex));
50  }
51  isEmpty = false;
52 }
53 
54 void CBloomFilter::insert(const COutPoint& outpoint)
55 {
56  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
57  stream << outpoint;
58  vector<unsigned char> data(stream.begin(), stream.end());
59  insert(data);
60 }
61 
62 void CBloomFilter::insert(const uint256& hash)
63 {
64  vector<unsigned char> data(hash.begin(), hash.end());
65  insert(data);
66 }
67 
68 bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
69 {
70  if (isFull)
71  return true;
72  if (isEmpty)
73  return false;
74  for (unsigned int i = 0; i < nHashFuncs; i++)
75  {
76  unsigned int nIndex = Hash(i, vKey);
77  // Checks bit nIndex of vData
78  if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
79  return false;
80  }
81  return true;
82 }
83 
84 bool CBloomFilter::contains(const COutPoint& outpoint) const
85 {
86  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
87  stream << outpoint;
88  vector<unsigned char> data(stream.begin(), stream.end());
89  return contains(data);
90 }
91 
92 bool CBloomFilter::contains(const uint256& hash) const
93 {
94  vector<unsigned char> data(hash.begin(), hash.end());
95  return contains(data);
96 }
97 
99 {
100  return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
101 }
102 
104 {
105  bool fFound = false;
106  // Match if the filter contains the hash of tx
107  // for finding tx when they appear in a block
108  if (isFull)
109  return true;
110  if (isEmpty)
111  return false;
112  if (contains(hash))
113  fFound = true;
114 
115  for (unsigned int i = 0; i < tx.vout.size(); i++)
116  {
117  const CTxOut& txout = tx.vout[i];
118  // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
119  // If this matches, also add the specific output that was matched.
120  // This means clients don't have to update the filter themselves when a new relevant tx
121  // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
122  CScript::const_iterator pc = txout.scriptPubKey.begin();
123  vector<unsigned char> data;
124  while (pc < txout.scriptPubKey.end())
125  {
126  opcodetype opcode;
127  if (!txout.scriptPubKey.GetOp(pc, opcode, data))
128  break;
129  if (data.size() != 0 && contains(data))
130  {
131  fFound = true;
133  insert(COutPoint(hash, i));
134  else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
135  {
136  txnouttype type;
137  vector<vector<unsigned char> > vSolutions;
138  if (Solver(txout.scriptPubKey, type, vSolutions) &&
139  (type == TX_PUBKEY || type == TX_MULTISIG))
140  insert(COutPoint(hash, i));
141  }
142  break;
143  }
144  }
145  }
146 
147  if (fFound)
148  return true;
149 
150  BOOST_FOREACH(const CTxIn& txin, tx.vin)
151  {
152  // Match if the filter contains an outpoint tx spends
153  if (contains(txin.prevout))
154  return true;
155 
156  // Match if the filter contains any arbitrary script data element in any scriptSig in tx
157  CScript::const_iterator pc = txin.scriptSig.begin();
158  vector<unsigned char> data;
159  while (pc < txin.scriptSig.end())
160  {
161  opcodetype opcode;
162  if (!txin.scriptSig.GetOp(pc, opcode, data))
163  break;
164  if (data.size() != 0 && contains(data))
165  return true;
166  }
167  }
168 
169  return false;
170 }
171 
173 {
174  bool full = true;
175  bool empty = true;
176  for (unsigned int i = 0; i < vData.size(); i++)
177  {
178  full &= vData[i] == 0xff;
179  empty &= vData[i] == 0;
180  }
181  isFull = full;
182  isEmpty = empty;
183 }
const_iterator begin() const
Definition: serialize.h:933
CScript scriptPubKey
Definition: core.h:125
unsigned char * end()
Definition: uint256.h:351
unsigned int nTweak
Definition: bloom.h:50
unsigned char nFlags
Definition: bloom.h:51
unsigned char * begin()
Definition: uint256.h:346
unsigned int Hash(unsigned int nHashNum, const std::vector< unsigned char > &vDataToHash) const
Definition: bloom.cpp:35
bool isFull
Definition: bloom.h:47
std::vector< unsigned char > vData
Definition: bloom.h:46
unsigned int nHashFuncs
Definition: bloom.h:49
Double ended buffer combining vector and stream-like interfaces.
Definition: serialize.h:848
#define LN2
Definition: bloom.cpp:15
void insert(const uint256 &hash)
Definition: bloom.cpp:41
bool IsWithinSizeConstraints() const
Definition: bloom.cpp:98
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector< unsigned char > &vDataToHash)
Definition: hash.cpp:8
opcodetype
Script opcodes.
Definition: script.h:235
An input of a transaction.
Definition: core.h:72
std::vector< CTxOut > vout
Definition: core.h:187
txnouttype
Definition: script.h:207
bool contains(const std::vector< unsigned char > &vKey) const
Definition: bloom.cpp:68
std::vector< CTxIn > vin
Definition: core.h:186
CBloomFilter()
Definition: bloom.h:64
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, vector< vector< unsigned char > > &vSolutionsRet)
Definition: script.cpp:1187
An output of a transaction.
Definition: core.h:121
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: core.h:24
#define LN2SQUARED
Definition: bloom.cpp:14
CScript scriptSig
Definition: core.h:76
256-bit unsigned integer
Definition: uint256.h:532
bool IsRelevantAndUpdate(const CTransaction &tx, const uint256 &hash)
Definition: bloom.cpp:103
void UpdateEmptyFull()
Definition: bloom.cpp:172
bool GetOp(iterator &pc, opcodetype &opcodeRet, std::vector< unsigned char > &vchRet)
Definition: script.h:532
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: core.h:179
COutPoint prevout
Definition: core.h:75
bool isEmpty
Definition: bloom.h:48
const_iterator end() const
Definition: serialize.h:935