Skip to content

Commit 4afbde6

Browse files
committed
Introduce MemPoolConflictRemovalTracker
Analogue to ConnectTrace that tracks transactions that have been removed from the mempool due to conflicts and then passes them through SyncTransaction at the end of its scope.
1 parent ff25c32 commit 4afbde6

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

src/validation.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,39 @@ namespace {
157157
set<int> setDirtyFileInfo;
158158
} // anon namespace
159159

160+
/* Use this class to start tracking transactions that are removed from the
161+
* mempool and pass all those transactions through SyncTransaction when the
162+
* object goes out of scope. This is currently only used to call SyncTransaction
163+
* on conflicts removed from the mempool during block connection. Applied in
164+
* ActivateBestChain around ActivateBestStep which in turn calls:
165+
* ConnectTip->removeForBlock->removeConflicts
166+
*/
167+
class MemPoolConflictRemovalTracker
168+
{
169+
private:
170+
std::vector<CTransactionRef> conflictedTxs;
171+
CTxMemPool &pool;
172+
173+
public:
174+
MemPoolConflictRemovalTracker(CTxMemPool &_pool) : pool(_pool) {
175+
pool.NotifyEntryRemoved.connect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
176+
}
177+
178+
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
179+
if (reason == MemPoolRemovalReason::CONFLICT) {
180+
conflictedTxs.push_back(txRemoved);
181+
}
182+
}
183+
184+
~MemPoolConflictRemovalTracker() {
185+
pool.NotifyEntryRemoved.disconnect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
186+
for (const auto& tx : conflictedTxs) {
187+
GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
188+
}
189+
conflictedTxs.clear();
190+
}
191+
};
192+
160193
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
161194
{
162195
// Find the first block the caller has in the main chain
@@ -2453,6 +2486,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
24532486
bool fInitialDownload;
24542487
{
24552488
LOCK(cs_main);
2489+
{ // TODO: Tempoarily ensure that mempool removals are notified before
2490+
// connected transactions. This shouldn't matter, but the abandoned
2491+
// state of transactions in our wallet is currently cleared when we
2492+
// receive another notification and there is a race condition where
2493+
// notification of a connected conflict might cause an outside process
2494+
// to abandon a transaction and then have it inadvertantly cleared by
2495+
// the notification that the conflicted transaction was evicted.
2496+
MemPoolConflictRemovalTracker mrt(mempool);
24562497
CBlockIndex *pindexOldTip = chainActive.Tip();
24572498
if (pindexMostWork == NULL) {
24582499
pindexMostWork = FindMostWorkChain();
@@ -2476,6 +2517,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
24762517
fInitialDownload = IsInitialBlockDownload();
24772518

24782519
// throw all transactions though the signal-interface
2520+
2521+
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
2522+
2523+
// Transactions in the connnected block are notified
24792524
for (const auto& pair : connectTrace.blocksConnected) {
24802525
assert(pair.second);
24812526
const CBlock& block = *(pair.second);

0 commit comments

Comments
 (0)