@@ -148,6 +148,14 @@ namespace {
148148 std::unique_ptr<CRollingBloomFilter> recentRejects GUARDED_BY (cs_main);
149149 uint256 hashRecentRejectsChainTip GUARDED_BY (cs_main);
150150
151+ /*
152+ * Filter for transactions that have been recently confirmed.
153+ * We use this to avoid requesting transactions that have already been
154+ * confirnmed.
155+ */
156+ RecursiveMutex g_cs_recent_confirmed_transactions;
157+ std::unique_ptr<CRollingBloomFilter> g_recent_confirmed_transactions GUARDED_BY (g_cs_recent_confirmed_transactions);
158+
151159 /* * Blocks that are in flight, and that are in the queue to be downloaded. */
152160 struct QueuedBlock {
153161 uint256 hash;
@@ -1116,6 +1124,16 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CS
11161124 // Initialize global variables that cannot be constructed at startup.
11171125 recentRejects.reset (new CRollingBloomFilter (120000 , 0.000001 ));
11181126
1127+ // Blocks don't typically have more than 4000 transactions, so this should
1128+ // be at least six blocks (~1 hr) worth of transactions that we can store.
1129+ // If the number of transactions appearing in a block goes up, or if we are
1130+ // seeing getdata requests more than an hour after initial announcement, we
1131+ // can increase this number.
1132+ // The false positive rate of 1/1M should come out to less than 1
1133+ // transaction per day that would be inadvertently ignored (which is the
1134+ // same probability that we have in the reject filter).
1135+ g_recent_confirmed_transactions.reset (new CRollingBloomFilter (24000 , 0.000001 ));
1136+
11191137 const Consensus::Params& consensusParams = Params ().GetConsensus ();
11201138 // Stale tip checking and peer eviction are on two different timers, but we
11211139 // don't want them to get out of sync due to drift in the scheduler, so we
@@ -1129,36 +1147,59 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CS
11291147 * Evict orphan txn pool entries (EraseOrphanTx) based on a newly connected
11301148 * block. Also save the time of the last tip update.
11311149 */
1132- void PeerLogicValidation::BlockConnected (const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted) {
1133- LOCK (g_cs_orphans);
1150+ void PeerLogicValidation::BlockConnected (const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted)
1151+ {
1152+ {
1153+ LOCK (g_cs_orphans);
11341154
1135- std::vector<uint256> vOrphanErase;
1155+ std::vector<uint256> vOrphanErase;
11361156
1137- for (const CTransactionRef& ptx : pblock->vtx ) {
1138- const CTransaction& tx = *ptx;
1157+ for (const CTransactionRef& ptx : pblock->vtx ) {
1158+ const CTransaction& tx = *ptx;
11391159
1140- // Which orphan pool entries must we evict?
1141- for (const auto & txin : tx.vin ) {
1142- auto itByPrev = mapOrphanTransactionsByPrev.find (txin.prevout );
1143- if (itByPrev == mapOrphanTransactionsByPrev.end ()) continue ;
1144- for (auto mi = itByPrev->second .begin (); mi != itByPrev->second .end (); ++mi) {
1145- const CTransaction& orphanTx = *(*mi)->second .tx ;
1146- const uint256& orphanHash = orphanTx.GetHash ();
1147- vOrphanErase.push_back (orphanHash);
1160+ // Which orphan pool entries must we evict?
1161+ for (const auto & txin : tx.vin ) {
1162+ auto itByPrev = mapOrphanTransactionsByPrev.find (txin.prevout );
1163+ if (itByPrev == mapOrphanTransactionsByPrev.end ()) continue ;
1164+ for (auto mi = itByPrev->second .begin (); mi != itByPrev->second .end (); ++mi) {
1165+ const CTransaction& orphanTx = *(*mi)->second .tx ;
1166+ const uint256& orphanHash = orphanTx.GetHash ();
1167+ vOrphanErase.push_back (orphanHash);
1168+ }
11481169 }
11491170 }
1150- }
11511171
1152- // Erase orphan transactions included or precluded by this block
1153- if (vOrphanErase.size ()) {
1154- int nErased = 0 ;
1155- for (const uint256& orphanHash : vOrphanErase) {
1156- nErased += EraseOrphanTx (orphanHash);
1172+ // Erase orphan transactions included or precluded by this block
1173+ if (vOrphanErase.size ()) {
1174+ int nErased = 0 ;
1175+ for (const uint256& orphanHash : vOrphanErase) {
1176+ nErased += EraseOrphanTx (orphanHash);
1177+ }
1178+ LogPrint (BCLog::MEMPOOL, " Erased %d orphan tx included or conflicted by block\n " , nErased);
1179+ }
1180+
1181+ g_last_tip_update = GetTime ();
1182+ }
1183+ {
1184+ LOCK (g_cs_recent_confirmed_transactions);
1185+ for (const auto ptx : pblock->vtx ) {
1186+ g_recent_confirmed_transactions->insert (ptx->GetHash ());
11571187 }
1158- LogPrint (BCLog::MEMPOOL, " Erased %d orphan tx included or conflicted by block\n " , nErased);
11591188 }
1189+ }
11601190
1161- g_last_tip_update = GetTime ();
1191+ void PeerLogicValidation::BlockDisconnected (const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)
1192+ {
1193+ // To avoid relay problems with transactions that were previously
1194+ // confirmed, clear our filter of recently confirmed transactions whenever
1195+ // there's a reorg.
1196+ // This means that in a 1-block reorg (where 1 block is disconnected and
1197+ // then another block reconnected), our filter will drop to having only one
1198+ // block's worth of transactions in it, but that should be fine, since
1199+ // presumably the most common case of relaying a confirmed transaction
1200+ // should be just after a new block containing it is found.
1201+ LOCK (g_cs_recent_confirmed_transactions);
1202+ g_recent_confirmed_transactions->reset ();
11621203}
11631204
11641205// All of the following cache a recent block, and are protected by cs_most_recent_block
@@ -1311,12 +1352,14 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
13111352 LOCK (g_cs_orphans);
13121353 if (mapOrphanTransactions.count (inv.hash )) return true ;
13131354 }
1314- const CCoinsViewCache& coins_cache = ::ChainstateActive ().CoinsTip ();
1355+
1356+ {
1357+ LOCK (g_cs_recent_confirmed_transactions);
1358+ if (g_recent_confirmed_transactions->contains (inv.hash )) return true ;
1359+ }
13151360
13161361 return recentRejects->contains (inv.hash ) ||
1317- mempool.exists (inv.hash ) ||
1318- coins_cache.HaveCoinInCache (COutPoint (inv.hash , 0 )) || // Best effort: only try output 0 and 1
1319- coins_cache.HaveCoinInCache (COutPoint (inv.hash , 1 ));
1362+ mempool.exists (inv.hash );
13201363 }
13211364 case MSG_BLOCK:
13221365 case MSG_WITNESS_BLOCK:
0 commit comments