aboutsummaryrefslogtreecommitdiff
path: root/src/validation.cpp
diff options
context:
space:
mode:
authorMatt Corallo <git@bluematt.me>2017-03-06 17:19:22 -0500
committerMatt Corallo <git@bluematt.me>2017-04-07 11:53:42 +0200
commitd3167ba9bbefc2e5b7062f81c481547f21c5e44b (patch)
tree5a0ce816036736bb70b875f7516d4ca59496186f /src/validation.cpp
parent29e6e231c88904d0e17187b116db5a958d952bcf (diff)
Handle conflicted transactions directly in ConnectTrace
Diffstat (limited to 'src/validation.cpp')
-rw-r--r--src/validation.cpp84
1 files changed, 39 insertions, 45 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index f2c90e028b..d91afbb714 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -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()) {