Handle conflicted transactions directly in ConnectTrace
This commit is contained in:
parent
29e6e231c8
commit
d3167ba9bb
1 changed files with 38 additions and 44 deletions
|
@ -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()) {
|
||||||
|
|
Loading…
Reference in a new issue