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)
downloadbitcoin-4afbde6028708541c4da8732a1bd12fb8735fdae.tar.xz
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);