Browse Source

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.
0.14
Alex Morcos 8 years ago
parent
commit
4afbde6028
  1. 45
      src/validation.cpp

45
src/validation.cpp

@ -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);

Loading…
Cancel
Save