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.
This commit is contained in:
Alex Morcos 2016-12-16 11:34:39 -05:00
parent ff25c32392
commit 4afbde6028

View File

@ -157,6 +157,39 @@ namespace {
set<int> setDirtyFileInfo; set<int> setDirtyFileInfo;
} // anon namespace } // anon namespace
/* Use this class to start tracking transactions that are removed from the
* mempool and pass all those transactions through SyncTransaction when the
* object goes out of scope. This is currently only used to call SyncTransaction
* on conflicts removed from the mempool during block connection. Applied in
* ActivateBestChain around ActivateBestStep which in turn calls:
* ConnectTip->removeForBlock->removeConflicts
*/
class MemPoolConflictRemovalTracker
{
private:
std::vector<CTransactionRef> conflictedTxs;
CTxMemPool &pool;
public:
MemPoolConflictRemovalTracker(CTxMemPool &_pool) : pool(_pool) {
pool.NotifyEntryRemoved.connect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
}
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
if (reason == MemPoolRemovalReason::CONFLICT) {
conflictedTxs.push_back(txRemoved);
}
}
~MemPoolConflictRemovalTracker() {
pool.NotifyEntryRemoved.disconnect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
for (const auto& tx : conflictedTxs) {
GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
conflictedTxs.clear();
}
};
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{ {
// Find the first block the caller has in the main chain // Find the first block the caller has in the main chain
@ -2453,6 +2486,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
bool fInitialDownload; bool fInitialDownload;
{ {
LOCK(cs_main); LOCK(cs_main);
{ // TODO: Tempoarily ensure that mempool removals are notified before
// connected transactions. This shouldn't matter, but the abandoned
// state of transactions in our wallet is currently cleared when we
// receive another notification and there is a race condition where
// notification of a connected conflict might cause an outside process
// to abandon a transaction and then have it inadvertantly cleared by
// the notification that the conflicted transaction was evicted.
MemPoolConflictRemovalTracker mrt(mempool);
CBlockIndex *pindexOldTip = chainActive.Tip(); CBlockIndex *pindexOldTip = chainActive.Tip();
if (pindexMostWork == NULL) { if (pindexMostWork == NULL) {
pindexMostWork = FindMostWorkChain(); pindexMostWork = FindMostWorkChain();
@ -2476,6 +2517,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
fInitialDownload = IsInitialBlockDownload(); fInitialDownload = IsInitialBlockDownload();
// throw all transactions though the signal-interface // throw all transactions though the signal-interface
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
// Transactions in the connnected block are notified
for (const auto& pair : connectTrace.blocksConnected) { for (const auto& pair : connectTrace.blocksConnected) {
assert(pair.second); assert(pair.second);
const CBlock& block = *(pair.second); const CBlock& block = *(pair.second);