aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Morcos <morcos@chaincode.com>2016-12-16 11:34:39 -0500
committerAlex Morcos <morcos@chaincode.com>2017-01-23 15:43:22 -0500
commit4afbde6028708541c4da8732a1bd12fb8735fdae (patch)
treeb609405705274e9f07f9df6e419df9a78599d592
parentff25c32392596883c13623eed6018fabb7877ed7 (diff)
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.
-rw-r--r--src/validation.cpp45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index d382e121bc..b882416961 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -157,6 +157,39 @@ namespace {
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
@@ -2453,6 +2486,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
bool fInitialDownload;
{
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();
if (pindexMostWork == NULL) {
pindexMostWork = FindMostWorkChain();
@@ -2476,6 +2517,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
fInitialDownload = IsInitialBlockDownload();
// 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) {
assert(pair.second);
const CBlock& block = *(pair.second);