Feathercoin  0.5.0
P2P Digital Currency
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
bloom.cpp
Go to the documentation of this file.
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, unsigned int nTweakIn, unsigned char nFlagsIn) :
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 isFull(false),
27 isEmpty(false),
28 nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
29 nTweak(nTweakIn),
30 nFlags(nFlagsIn)
31 {
32 }
33 
34 inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
35 {
36  // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
37  return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
38 }
39 
40 void CBloomFilter::insert(const vector<unsigned char>& vKey)
41 {
42  if (isFull)
43  return;
44  for (unsigned int i = 0; i < nHashFuncs; i++)
45  {
46  unsigned int nIndex = Hash(i, vKey);
47  // Sets bit nIndex of vData
48  vData[nIndex >> 3] |= bit_mask[7 & nIndex];
49  }
50  isEmpty = false;
51 }
52 
53 void CBloomFilter::insert(const COutPoint& outpoint)
54 {
55  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
56  stream << outpoint;
57  vector<unsigned char> data(stream.begin(), stream.end());
58  insert(data);
59 }
60 
62 {
63  vector<unsigned char> data(hash.begin(), hash.end());
64  insert(data);
65 }
66 
67 bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
68 {
69  if (isFull)
70  return true;
71  if (isEmpty)
72  return false;
73  for (unsigned int i = 0; i < nHashFuncs; i++)
74  {
75  unsigned int nIndex = Hash(i, vKey);
76  // Checks bit nIndex of vData
77  if (!(vData[nIndex >> 3] & bit_mask[7 & nIndex]))
78  return false;
79  }
80  return true;
81 }
82 
83 bool CBloomFilter::contains(const COutPoint& outpoint) const
84 {
85  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
86  stream << outpoint;
87  vector<unsigned char> data(stream.begin(), stream.end());
88  return contains(data);
89 }
90 
91 bool CBloomFilter::contains(const uint256& hash) const
92 {
93  vector<unsigned char> data(hash.begin(), hash.end());
94  return contains(data);
95 }
96 
98 {
99  return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
100 }
101 
103 {
104  bool fFound = false;
105  // Match if the filter contains the hash of tx
106  // for finding tx when they appear in a block
107  if (isFull)
108  return true;
109  if (isEmpty)
110  return false;
111  if (contains(hash))
112  fFound = true;
113 
114  for (unsigned int i = 0; i < tx.vout.size(); i++)
115  {
116  const CTxOut& txout = tx.vout[i];
117  // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
118  // If this matches, also add the specific output that was matched.
119  // This means clients don't have to update the filter themselves when a new relevant tx
120  // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
121  CScript::const_iterator pc = txout.scriptPubKey.begin();
122  vector<unsigned char> data;
123  while (pc < txout.scriptPubKey.end())
124  {
125  opcodetype opcode;
126  if (!txout.scriptPubKey.GetOp(pc, opcode, data))
127  break;
128  if (data.size() != 0 && contains(data))
129  {
130  fFound = true;
132  insert(COutPoint(hash, i));
133  else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
134  {
135  txnouttype type;
136  vector<vector<unsigned char> > vSolutions;
137  if (Solver(txout.scriptPubKey, type, vSolutions) &&
138  (type == TX_PUBKEY || type == TX_MULTISIG))
139  insert(COutPoint(hash, i));
140  }
141  break;
142  }
143  }
144  }
145 
146  if (fFound)
147  return true;
148 
149  BOOST_FOREACH(const CTxIn& txin, tx.vin)
150  {
151  // Match if the filter contains an outpoint tx spends
152  if (contains(txin.prevout))
153  return true;
154 
155  // Match if the filter contains any arbitrary script data element in any scriptSig in tx
156  CScript::const_iterator pc = txin.scriptSig.begin();
157  vector<unsigned char> data;
158  while (pc < txin.scriptSig.end())
159  {
160  opcodetype opcode;
161  if (!txin.scriptSig.GetOp(pc, opcode, data))
162  break;
163  if (data.size() != 0 && contains(data))
164  return true;
165  }
166  }
167 
168  return false;
169 }
170 
172 {
173  bool full = true;
174  bool empty = true;
175  for (unsigned int i = 0; i < vData.size(); i++)
176  {
177  full &= vData[i] == 0xff;
178  empty &= vData[i] == 0;
179  }
180  isFull = full;
181  isEmpty = empty;
182 }
const_iterator begin() const
Definition: serialize.h:884
CScript scriptPubKey
Definition: main.h:404
unsigned char * end()
Definition: uint256.h:353
unsigned int nTweak
Definition: bloom.h:48
unsigned char nFlags
Definition: bloom.h:49
unsigned char * begin()
Definition: uint256.h:348
unsigned int Hash(unsigned int nHashNum, const std::vector< unsigned char > &vDataToHash) const
Definition: bloom.cpp:34
bool isFull
Definition: bloom.h:45
std::vector< unsigned char > vData
Definition: bloom.h:44
unsigned int nHashFuncs
Definition: bloom.h:47
Double ended buffer combining vector and stream-like interfaces.
Definition: serialize.h:799
#define LN2
Definition: bloom.cpp:12
void insert(const uint256 &hash)
Definition: bloom.cpp:40
bool IsWithinSizeConstraints() const
Definition: bloom.cpp:97
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector< unsigned char > &vDataToHash)
Definition: hash.cpp:8
opcodetype
Script opcodes.
Definition: script.h:67
An input of a transaction.
Definition: main.h:323
std::vector< CTxOut > vout
Definition: main.h:485
txnouttype
Definition: script.h:40
bool contains(const std::vector< unsigned char > &vKey) const
Definition: bloom.cpp:67
std::vector< CTxIn > vin
Definition: main.h:484
CBloomFilter()
Definition: bloom.h:62
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, vector< vector< unsigned char > > &vSolutionsRet)
Definition: script.cpp:1127
An output of a transaction.
Definition: main.h:400
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: main.h:278
#define LN2SQUARED
Definition: bloom.cpp:11
CScript scriptSig
Definition: main.h:327
256-bit unsigned integer
Definition: uint256.h:537
bool IsRelevantAndUpdate(const CTransaction &tx, const uint256 &hash)
Definition: bloom.cpp:102
void UpdateEmptyFull()
Definition: bloom.cpp:171
bool GetOp(iterator &pc, opcodetype &opcodeRet, std::vector< unsigned char > &vchRet)
Definition: script.h:399
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: main.h:477
COutPoint prevout
Definition: main.h:326
uint32_t hash
Definition: cache.cc:34
bool isEmpty
Definition: bloom.h:46
const_iterator end() const
Definition: serialize.h:886