Skip to content

Commit d3167ba

Browse files
committed
Handle conflicted transactions directly in ConnectTrace
1 parent 29e6e23 commit d3167ba

File tree

1 file changed

+39
-45
lines changed

1 file changed

+39
-45
lines changed

src/validation.cpp

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -154,39 +154,6 @@ namespace {
154154
std::set<int> setDirtyFileInfo;
155155
} // anon namespace
156156

157-
/* Use this class to start tracking transactions that are removed from the
158-
* mempool and pass all those transactions through SyncTransaction when the
159-
* object goes out of scope. This is currently only used to call SyncTransaction
160-
* on conflicts removed from the mempool during block connection. Applied in
161-
* ActivateBestChain around ActivateBestStep which in turn calls:
162-
* ConnectTip->removeForBlock->removeConflicts
163-
*/
164-
class MemPoolConflictRemovalTracker
165-
{
166-
private:
167-
std::vector<CTransactionRef> conflictedTxs;
168-
CTxMemPool &pool;
169-
170-
public:
171-
MemPoolConflictRemovalTracker(CTxMemPool &_pool) : pool(_pool) {
172-
pool.NotifyEntryRemoved.connect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
173-
}
174-
175-
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
176-
if (reason == MemPoolRemovalReason::CONFLICT) {
177-
conflictedTxs.push_back(txRemoved);
178-
}
179-
}
180-
181-
~MemPoolConflictRemovalTracker() {
182-
pool.NotifyEntryRemoved.disconnect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
183-
for (const auto& tx : conflictedTxs) {
184-
GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
185-
}
186-
conflictedTxs.clear();
187-
}
188-
};
189-
190157
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
191158
{
192159
// Find the first block the caller has in the main chain
@@ -2210,19 +2177,46 @@ static int64_t nTimePostConnect = 0;
22102177
/**
22112178
* Used to track blocks whose transactions were applied to the UTXO state as a
22122179
* part of a single ActivateBestChainStep call.
2180+
*
2181+
* This class also tracks transactions that are removed from the mempool as
2182+
* conflicts and can be used to pass all those transactions through
2183+
* SyncTransaction.
22132184
*/
2214-
struct ConnectTrace {
2185+
class ConnectTrace {
22152186
private:
22162187
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected;
2188+
std::vector<CTransactionRef> conflictedTxs;
2189+
CTxMemPool &pool;
22172190

22182191
public:
2192+
ConnectTrace(CTxMemPool &_pool) : pool(_pool) {
2193+
pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
2194+
}
2195+
2196+
~ConnectTrace() {
2197+
pool.NotifyEntryRemoved.disconnect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
2198+
}
2199+
22192200
void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) {
22202201
blocksConnected.emplace_back(pindex, std::move(pblock));
22212202
}
22222203

22232204
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > >& GetBlocksConnected() {
22242205
return blocksConnected;
22252206
}
2207+
2208+
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
2209+
if (reason == MemPoolRemovalReason::CONFLICT) {
2210+
conflictedTxs.push_back(txRemoved);
2211+
}
2212+
}
2213+
2214+
void CallSyncTransactionOnConflictedTransactions() {
2215+
for (const auto& tx : conflictedTxs) {
2216+
GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
2217+
}
2218+
conflictedTxs.clear();
2219+
}
22262220
};
22272221

22282222
/**
@@ -2470,18 +2464,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
24702464
break;
24712465

24722466
const CBlockIndex *pindexFork;
2473-
ConnectTrace connectTrace;
24742467
bool fInitialDownload;
24752468
{
24762469
LOCK(cs_main);
2477-
{ // TODO: Temporarily ensure that mempool removals are notified before
2478-
// connected transactions. This shouldn't matter, but the abandoned
2479-
// state of transactions in our wallet is currently cleared when we
2480-
// receive another notification and there is a race condition where
2481-
// notification of a connected conflict might cause an outside process
2482-
// to abandon a transaction and then have it inadvertently cleared by
2483-
// the notification that the conflicted transaction was evicted.
2484-
MemPoolConflictRemovalTracker mrt(mempool);
2470+
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
2471+
24852472
CBlockIndex *pindexOldTip = chainActive.Tip();
24862473
if (pindexMostWork == NULL) {
24872474
pindexMostWork = FindMostWorkChain();
@@ -2505,8 +2492,15 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
25052492
fInitialDownload = IsInitialBlockDownload();
25062493

25072494
// throw all transactions though the signal-interface
2508-
2509-
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
2495+
connectTrace.CallSyncTransactionOnConflictedTransactions();
2496+
2497+
// TODO: Temporarily ensure that mempool removals are notified before
2498+
// connected transactions. This shouldn't matter, but the abandoned
2499+
// state of transactions in our wallet is currently cleared when we
2500+
// receive another notification and there is a race condition where
2501+
// notification of a connected conflict might cause an outside process
2502+
// to abandon a transaction and then have it inadvertently cleared by
2503+
// the notification that the conflicted transaction was evicted.
25102504

25112505
// Transactions in the connected block are notified
25122506
for (const auto& pair : connectTrace.GetBlocksConnected()) {

0 commit comments

Comments
 (0)