Automatically add any matching outputs to a filter during matching.

This commit is contained in:
Matt Corallo 2012-08-18 23:38:28 -04:00
parent 269d9c6492
commit d3b26f7077
3 changed files with 19 additions and 6 deletions

View File

@ -88,16 +88,21 @@ bool CBloomFilter::IsWithinSizeConstraints() const
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS; return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
} }
bool CBloomFilter::IsTransactionRelevantToFilter(const CTransaction& tx, const uint256& hash) const bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash)
{ {
bool fFound = false;
// Match if the filter contains the hash of tx // Match if the filter contains the hash of tx
// for finding tx when they appear in a block // for finding tx when they appear in a block
if (contains(hash)) if (contains(hash))
return true; fFound = true;
BOOST_FOREACH(const CTxOut& txout, tx.vout) for (unsigned int i = 0; i < tx.vout.size(); i++)
{ {
const CTxOut& txout = tx.vout[i];
// Match if the filter contains any arbitrary script data element in any scriptPubKey in tx // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
// If this matches, also add the specific output that was matched.
// This means clients don't have to update the filter themselves when a new relevant tx
// is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
CScript::const_iterator pc = txout.scriptPubKey.begin(); CScript::const_iterator pc = txout.scriptPubKey.begin();
vector<unsigned char> data; vector<unsigned char> data;
while (pc < txout.scriptPubKey.end()) while (pc < txout.scriptPubKey.end())
@ -106,10 +111,17 @@ bool CBloomFilter::IsTransactionRelevantToFilter(const CTransaction& tx, const u
if (!txout.scriptPubKey.GetOp(pc, opcode, data)) if (!txout.scriptPubKey.GetOp(pc, opcode, data))
break; break;
if (data.size() != 0 && contains(data)) if (data.size() != 0 && contains(data))
return true; {
fFound = true;
insert(COutPoint(hash, i));
break;
}
} }
} }
if (fFound)
return true;
BOOST_FOREACH(const CTxIn& txin, tx.vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
{ {
// Match if the filter contains an outpoint tx spends // Match if the filter contains an outpoint tx spends

View File

@ -64,7 +64,8 @@ public:
// (catch a filter which was just deserialized which was too big) // (catch a filter which was just deserialized which was too big)
bool IsWithinSizeConstraints() const; bool IsWithinSizeConstraints() const;
bool IsTransactionRelevantToFilter(const CTransaction& tx, const uint256& hash) const; // Also adds any outputs which match the filter to the filter (to match their spending txes)
bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash);
}; };
#endif /* BITCOIN_BLOOM_H */ #endif /* BITCOIN_BLOOM_H */

View File

@ -2034,7 +2034,7 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
LOCK(pnode->cs_filter); LOCK(pnode->cs_filter);
if (pnode->pfilter) if (pnode->pfilter)
{ {
if (pnode->pfilter->IsTransactionRelevantToFilter(tx, hash)) if (pnode->pfilter->IsRelevantAndUpdate(tx, hash))
pnode->PushInventory(inv); pnode->PushInventory(inv);
} else } else
pnode->PushInventory(inv); pnode->PushInventory(inv);