Skip to content

Commit a55b9f9

Browse files
mempool: guard removeProTxKeyChangedConflicts against already-removed entries
The eviction loop dereferenced mapTx.find(txHash) without checking for end(). If two stale provider updates for one masternode form a parent/child chain, removeRecursive() on the parent also evicts the child, so the child's saved hash then resolves to mapTx.end() and dereferencing it can crash the node. This is a pre-existing hazard in the conflict-eviction path (surfaced while reviewing the shared-masternode changes to this function); guard the lookup and skip entries already gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 5495e02 commit a55b9f9

1 file changed

Lines changed: 8 additions & 2 deletions

File tree

src/txmempool.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,8 +1065,14 @@ void CTxMemPool::removeProTxKeyChangedConflicts(const CTransaction &tx, const ui
10651065
}
10661066
}
10671067
for (const auto& txHash : conflictingTxs) {
1068-
auto& tx = mapTx.find(txHash)->GetTx();
1069-
removeRecursive(tx, MemPoolRemovalReason::CONFLICT);
1068+
// An earlier removeRecursive() may have already evicted this entry as a descendant of a
1069+
// previously-processed conflict, so it can be absent here; dereferencing mapTx.end() would
1070+
// crash. (Pre-existing hazard; guarded here to be safe.)
1071+
auto it = mapTx.find(txHash);
1072+
if (it == mapTx.end()) {
1073+
continue;
1074+
}
1075+
removeRecursive(it->GetTx(), MemPoolRemovalReason::CONFLICT);
10701076
}
10711077
}
10721078

0 commit comments

Comments
 (0)