Skip to content

Commit

Permalink
Performance optimization for bloom filters.
Browse files Browse the repository at this point in the history
This reduces a peer's ability to attack network resources by
 using a full bloom filter, but without reducing the usability
 of bloom filters.  It sets a default match everything filter
 for peers and it generalizes a prior optimization to
 cover more cases.
  • Loading branch information
gmaxwell committed Aug 20, 2013
1 parent 4bc9a19 commit 37c6389
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 7 deletions.
26 changes: 24 additions & 2 deletions src/bloom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM
// The ideal number of hash functions is filter size * ln(2) / number of elements
// Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
// See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
isFull(false),
isEmpty(false),
nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn)
Expand All @@ -37,14 +39,15 @@ inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<

void CBloomFilter::insert(const vector<unsigned char>& vKey)
{
if (vData.size() == 1 && vData[0] == 0xff)
if (isFull)
return;
for (unsigned int i = 0; i < nHashFuncs; i++)
{
unsigned int nIndex = Hash(i, vKey);
// Sets bit nIndex of vData
vData[nIndex >> 3] |= bit_mask[7 & nIndex];
}
isEmpty = false;
}

void CBloomFilter::insert(const COutPoint& outpoint)
Expand All @@ -63,8 +66,10 @@ void CBloomFilter::insert(const uint256& hash)

bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
{
if (vData.size() == 1 && vData[0] == 0xff)
if (isFull)
return true;
if (isEmpty)
return false;
for (unsigned int i = 0; i < nHashFuncs; i++)
{
unsigned int nIndex = Hash(i, vKey);
Expand Down Expand Up @@ -99,6 +104,10 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha
bool fFound = false;
// Match if the filter contains the hash of tx
// for finding tx when they appear in a block
if (isFull)
return true;
if (isEmpty)
return false;
if (contains(hash))
fFound = true;

Expand Down Expand Up @@ -158,3 +167,16 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha

return false;
}

void CBloomFilter::UpdateEmptyFull()
{
bool full = true;
bool empty = true;
for (unsigned int i = 0; i < vData.size(); i++)
{
full &= vData[i] == 0xff;
empty &= vData[i] == 0;
}
isFull = full;
isEmpty = empty;
}
9 changes: 6 additions & 3 deletions src/bloom.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class CBloomFilter
{
private:
std::vector<unsigned char> vData;
bool isFull;
bool isEmpty;
unsigned int nHashFuncs;
unsigned int nTweak;
unsigned char nFlags;
Expand All @@ -57,9 +59,7 @@ class CBloomFilter
// It should generally always be a random value (and is largely only exposed for unit testing)
// nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)
CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn);
// Using a filter initialized with this results in undefined behavior
// Should only be used for deserialization
CBloomFilter() {}
CBloomFilter() : isFull(true) {}

IMPLEMENT_SERIALIZE
(
Expand All @@ -83,6 +83,9 @@ class CBloomFilter

// Also adds any outputs which match the filter to the filter (to match their spending txes)
bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash);

// Checks for empty and full filters to avoid wasting cpu
void UpdateEmptyFull();
};

#endif /* BITCOIN_BLOOM_H */
3 changes: 2 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3893,6 +3893,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
filter.UpdateEmptyFull();
}
pfrom->fRelayTxes = true;
}
Expand Down Expand Up @@ -3922,7 +3923,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = NULL;
pfrom->pfilter = new CBloomFilter();
pfrom->fRelayTxes = true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class CNode
nMisbehavior = 0;
fRelayTxes = false;
setInventoryKnown.max_size(SendBufferSize() / 1000);
pfilter = NULL;
pfilter = new CBloomFilter();

// Be shy and don't send version until we hear
if (hSocket != INVALID_SOCKET && !fInbound)
Expand Down

0 comments on commit 37c6389

Please sign in to comment.