@@ -148,6 +148,14 @@ namespace {
148
148
std::unique_ptr<CRollingBloomFilter> recentRejects GUARDED_BY (cs_main);
149
149
uint256 hashRecentRejectsChainTip GUARDED_BY (cs_main);
150
150
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
+
151
159
/* * Blocks that are in flight, and that are in the queue to be downloaded. */
152
160
struct QueuedBlock {
153
161
uint256 hash;
@@ -1116,6 +1124,16 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CS
1116
1124
// Initialize global variables that cannot be constructed at startup.
1117
1125
recentRejects.reset (new CRollingBloomFilter (120000 , 0.000001 ));
1118
1126
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
+
1119
1137
const Consensus::Params& consensusParams = Params ().GetConsensus ();
1120
1138
// Stale tip checking and peer eviction are on two different timers, but we
1121
1139
// 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
1129
1147
* Evict orphan txn pool entries (EraseOrphanTx) based on a newly connected
1130
1148
* block. Also save the time of the last tip update.
1131
1149
*/
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);
1134
1154
1135
- std::vector<uint256> vOrphanErase;
1155
+ std::vector<uint256> vOrphanErase;
1136
1156
1137
- for (const CTransactionRef& ptx : pblock->vtx ) {
1138
- const CTransaction& tx = *ptx;
1157
+ for (const CTransactionRef& ptx : pblock->vtx ) {
1158
+ const CTransaction& tx = *ptx;
1139
1159
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
+ }
1148
1169
}
1149
1170
}
1150
- }
1151
1171
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 ());
1157
1187
}
1158
- LogPrint (BCLog::MEMPOOL, " Erased %d orphan tx included or conflicted by block\n " , nErased);
1159
1188
}
1189
+ }
1160
1190
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 ();
1162
1203
}
1163
1204
1164
1205
// 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)
1311
1352
LOCK (g_cs_orphans);
1312
1353
if (mapOrphanTransactions.count (inv.hash )) return true ;
1313
1354
}
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
+ }
1315
1360
1316
1361
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 );
1320
1363
}
1321
1364
case MSG_BLOCK:
1322
1365
case MSG_WITNESS_BLOCK:
0 commit comments