|
|
@ -154,39 +154,6 @@ namespace { |
|
|
|
std::set<int> setDirtyFileInfo; |
|
|
|
std::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
|
|
|
@ -2210,12 +2177,26 @@ static int64_t nTimePostConnect = 0; |
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Used to track blocks whose transactions were applied to the UTXO state as a |
|
|
|
* Used to track blocks whose transactions were applied to the UTXO state as a |
|
|
|
* part of a single ActivateBestChainStep call. |
|
|
|
* part of a single ActivateBestChainStep call. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* This class also tracks transactions that are removed from the mempool as |
|
|
|
|
|
|
|
* conflicts and can be used to pass all those transactions through |
|
|
|
|
|
|
|
* SyncTransaction. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
struct ConnectTrace { |
|
|
|
class ConnectTrace { |
|
|
|
private: |
|
|
|
private: |
|
|
|
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected; |
|
|
|
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected; |
|
|
|
|
|
|
|
std::vector<CTransactionRef> conflictedTxs; |
|
|
|
|
|
|
|
CTxMemPool &pool; |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
public: |
|
|
|
|
|
|
|
ConnectTrace(CTxMemPool &_pool) : pool(_pool) { |
|
|
|
|
|
|
|
pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~ConnectTrace() { |
|
|
|
|
|
|
|
pool.NotifyEntryRemoved.disconnect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) { |
|
|
|
void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) { |
|
|
|
blocksConnected.emplace_back(pindex, std::move(pblock)); |
|
|
|
blocksConnected.emplace_back(pindex, std::move(pblock)); |
|
|
|
} |
|
|
|
} |
|
|
@ -2223,6 +2204,19 @@ public: |
|
|
|
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > >& GetBlocksConnected() { |
|
|
|
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > >& GetBlocksConnected() { |
|
|
|
return blocksConnected; |
|
|
|
return blocksConnected; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) { |
|
|
|
|
|
|
|
if (reason == MemPoolRemovalReason::CONFLICT) { |
|
|
|
|
|
|
|
conflictedTxs.push_back(txRemoved); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CallSyncTransactionOnConflictedTransactions() { |
|
|
|
|
|
|
|
for (const auto& tx : conflictedTxs) { |
|
|
|
|
|
|
|
GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
conflictedTxs.clear(); |
|
|
|
|
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2470,18 +2464,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
const CBlockIndex *pindexFork; |
|
|
|
const CBlockIndex *pindexFork; |
|
|
|
ConnectTrace connectTrace; |
|
|
|
|
|
|
|
bool fInitialDownload; |
|
|
|
bool fInitialDownload; |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(cs_main); |
|
|
|
LOCK(cs_main); |
|
|
|
{ // TODO: Temporarily ensure that mempool removals are notified before
|
|
|
|
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
|
|
|
|
// 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 inadvertently 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(); |
|
|
@ -2505,8 +2492,15 @@ 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
|
|
|
|
|
|
|
|
connectTrace.CallSyncTransactionOnConflictedTransactions(); |
|
|
|
|
|
|
|
|
|
|
|
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
|
|
|
|
// TODO: Temporarily 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 inadvertently cleared by
|
|
|
|
|
|
|
|
// the notification that the conflicted transaction was evicted.
|
|
|
|
|
|
|
|
|
|
|
|
// Transactions in the connected block are notified
|
|
|
|
// Transactions in the connected block are notified
|
|
|
|
for (const auto& pair : connectTrace.GetBlocksConnected()) { |
|
|
|
for (const auto& pair : connectTrace.GetBlocksConnected()) { |
|
|
|