|
|
|
@ -154,39 +154,6 @@ namespace {
|
|
|
|
|
std::set<int> setDirtyFileInfo;
|
|
|
|
|
} // 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)
|
|
|
|
|
{
|
|
|
|
|
// 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
|
|
|
|
|
* 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:
|
|
|
|
|
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected;
|
|
|
|
|
std::vector<CTransactionRef> conflictedTxs;
|
|
|
|
|
CTxMemPool &pool;
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
blocksConnected.emplace_back(pindex, std::move(pblock));
|
|
|
|
|
}
|
|
|
|
@ -2223,6 +2204,19 @@ public:
|
|
|
|
|
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > >& GetBlocksConnected() {
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
const CBlockIndex *pindexFork;
|
|
|
|
|
ConnectTrace connectTrace;
|
|
|
|
|
bool fInitialDownload;
|
|
|
|
|
{
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
{ // 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.
|
|
|
|
|
MemPoolConflictRemovalTracker mrt(mempool);
|
|
|
|
|
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
|
|
|
|
|
|
|
|
|
|
CBlockIndex *pindexOldTip = chainActive.Tip();
|
|
|
|
|
if (pindexMostWork == NULL) {
|
|
|
|
|
pindexMostWork = FindMostWorkChain();
|
|
|
|
@ -2505,8 +2492,15 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|
|
|
|
fInitialDownload = IsInitialBlockDownload();
|
|
|
|
|
|
|
|
|
|
// throw all transactions though the signal-interface
|
|
|
|
|
|
|
|
|
|
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
|
|
|
|
|
connectTrace.CallSyncTransactionOnConflictedTransactions();
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
for (const auto& pair : connectTrace.GetBlocksConnected()) {
|
|
|
|
|