wallet: Do not set fInMempool in transactionAddedToMempool when tx is not in the mempool #22359

pull MarcoFalke wants to merge 1 commits into bitcoin:master from MarcoFalke:2106-walletFix changing 1 files +13 −6
  1. MarcoFalke commented at 9:02 am on June 28, 2021: member

    A wallet method (like bumping the fee) might have set fInMempool to false because the transaction was removed from the mempool (See commit fa4e088cbac035b8029a10b492849540150d0622).

    Avoid setting it back to true (incorrectly) in the validation interface background thread.

    Fixes #22357

  2. fanquake added the label Wallet on Jun 28, 2021
  3. MarcoFalke force-pushed on Jun 28, 2021
  4. DrahtBot commented at 9:55 am on June 28, 2021: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    No conflicts as of last run.

  5. promag commented at 1:29 pm on June 28, 2021: member

    Not sure about this, can’t the transaction be removed from the mempool after isInMempool?

    Wouldn’t be more correct to SyncWithValidationInterfaceQueue at the end of the RPC call - in the same way it’s called at the beginning? This ensures transactionRemovedFromMempool is processed to the caller?

  6. MarcoFalke commented at 2:23 pm on June 29, 2021: member
    @promag I agree. This is also my preferred solution (see #18840). Happy to reopen that one.
  7. ryanofsky commented at 4:02 pm on June 29, 2021: member

    I could be missing something but it seems to me neither solution is clearly correct in all cases. The advantages of this solution over #18440 are that:

    • It’s more obvious what this solution is trying to do. This solution is plainly updating mempool status to reflect what’s in the mempool, where #18440 is broadening a sync that happens in a different part of the code without a specific explanation about why it’s necessary.
    • #18440 waits for extra notifications to be handled that may not be relevant, blocking longer than it needs to.
    • It’s not clear whether #18440 fixes the problem in all cases, since it’s assuming that the mempool implementation will alway queue the removedFromMempool notification before the wallet RPC tries to sync with the queue. And even if this does work now, there is no unit test or other coverage for it to make sure the sync runs at the right point in the broken case, to make sure this stays fixed in the future.

    But I do agree with the general point that a fully correct solution is probably a blocking solution. I just think the blocking should be targeted. Not more narrow or more wide than it needs to be. For example could add std::condition_variable m_mempool_cv; to CWallet and m_mempool_cv.notify_all() in transactionRemovedFromMempool() and m_mempool_cv.wait(lock, []{return !replaced_tx.fInMempool}) in bumpfee

  8. ryanofsky commented at 4:28 pm on June 29, 2021: member

    For example could add std::condition_variable m_mempool_cv; to CWallet and m_mempool_cv.notify_all() in transactionRemovedFromMempool() and m_mempool_cv.wait(lock, []{return !replaced_tx.fInMempool}) in bumpfee

    Thinking about this, in a really pathological case where a replaced transaction got added back to the mempool, this could hang. Dropping CWalletTx::fInMempool and giving transactions clear states like 730df28e00822f06c9fc11c86a74f764a2f5136c from #21206 would help here, because the replaced transaction could ambiguously transition from the in-mempool state to an intermediate in-mempool-but-replaced state to the inactive state, and the cv.wait() could just wait for the transaction to be out of the intermediate state.

    Any case, will ACK this PR. IMO, this is the best fix for we have for now, and it is straightforward and simple, even if it is not 100% right in every case and doesn’t have a fancy test.

  9. ryanofsky approved
  10. ryanofsky commented at 4:33 pm on June 29, 2021: member
    Code review ACK fa9ef0e8c6f379499ba7415040b76a76afdb02dc. This is a pretty simple fix that should make tests more reliable and the RPC more reliable in applications and should be better than status quo even if it is not 100% in every case (see previous discussion).
  11. luke-jr commented at 6:18 pm on June 29, 2021: member
    Should we do this in transactionRemovedFromMempool too perhaps?
  12. luke-jr referenced this in commit c01b12dfa4 on Jun 29, 2021
  13. luke-jr referenced this in commit f477e1e587 on Jun 29, 2021
  14. promag commented at 9:14 pm on June 29, 2021: member

    Maybe it should avoid fInMempool in some cases, like in CWallet::AbandonTransaction:

     0@@ -1078,10 +1078,11 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
     1     std::set<uint256> done;
     2
     3     // Can't mark abandoned if confirmed or in mempool
     4+    if (chain().isInMempool(hashTx)) return false;
     5     auto it = mapWallet.find(hashTx);
     6     assert(it != mapWallet.end());
     7     const CWalletTx& origtx = it->second;
     8-    if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
     9+    if (origtx.GetDepthInMainChain() != 0) {
    10         return false;
    11     }
    
  15. promag commented at 6:10 pm on June 30, 2021: member
    Code review ACK fa9ef0e8c6f379499ba7415040b76a76afdb02dc.
  16. wallet: Properly set fInMempool in mempool notifications fa6fd3dd6a
  17. MarcoFalke force-pushed on Jul 1, 2021
  18. MarcoFalke commented at 8:48 am on July 1, 2021: member

    Should we do this in transactionRemovedFromMempool too perhaps?

    Thx, done.

  19. MarcoFalke commented at 8:50 am on July 1, 2021: member

    Maybe it should avoid fInMempool in some cases, like in CWallet::AbandonTransaction:

    Maybe the mempool status should be removed and simply be queried when needed? Otherwise it just seems like applying random patches that happen to improve the situation, but don’t actually fix the underlying issue.

  20. ryanofsky commented at 9:35 am on July 1, 2021: member

    Maybe the mempool status should be removed and simply be queried when needed?

    I think there are two drawbacks to querying the mempool when needed:

    • Conceptually it seems less appealing because it means coin selection, balance checking, etc code is combining mempool and chain state from two different points in time instead of one point. Instead of using chain and mempool state from the time of last notification, it is combining data from the last notification time with data from the current time. I don’t think the consequences of this are very bad but they could make coin selection and balance checking glitchy or weird if there is a backlog of notifications.

    • At least according to 17220d6325ef8d7789373055586e4332977077b0 which introduced the cached fInMempool field, there are some reasons to think this may be worse for performance.

    Otherwise it just seems like applying random patches that happen to improve the situation, but don’t actually fix the underlying issue.

    I think if we combine transaction states (730df28e00822f06c9fc11c86a74f764a2f5136c from #21206) with the notify suggestion mentioned earlier (in #22359 (comment) and #22359 (comment)), that is a clean and robust solution that gets rid of all race conditions. But since that requires reviewing and writing more code, using tx.fInMempool = chain.isInMempool(tx.GetHash()); is at least a straighforward workaround in the meantime.

  21. ryanofsky approved
  22. ryanofsky commented at 9:45 am on July 1, 2021: member
    Code review ACK fa6fd3dd6a4e7f30eff5963836aed43fe01af078. Only change since last review is extending workaround to transactionRemovedFromMempool. Since we know this workaround is imperfect and the goal of this PR is mainly to fix CI errors, I would probably be inclined to limit the workaround to as few places as possible where we have seen actual failures, instead of adding the workaround to as many places as possible, where there is some chance it might trigger new failures. But since this workaround is so straightforward and almost looks like a real fix, probably it doesn’t matter.
  23. ryanofsky referenced this in commit d622b28227 on Jul 1, 2021
  24. ryanofsky commented at 10:23 pm on July 1, 2021: member

    I think if we combine transaction states (730df28 from #21206) with the notify suggestion mentioned earlier (in #22359 (comment) and #22359 (comment)), that is a clean and robust solution that gets rid of all race conditions.

    FWIW, I started implementing this in f54631dec3ccb4f2df1545eab86a3f9ad824c1e9 (branch). It could be cleaned up more, and doesn’t have a dedicated test, and might not be totally complete (might need one or two more cv.wait() calls), but this shows the general idea.


    EDIT: Updated d622b28227efbb4e0709e768a089e655fceecc19 -> f54631dec3ccb4f2df1545eab86a3f9ad824c1e9 (compare)

  25. ryanofsky referenced this in commit f54631dec3 on Jul 2, 2021
  26. meshcollider commented at 1:44 am on August 9, 2021: contributor
    utACK fa6fd3dd6a4e7f30eff5963836aed43fe01af078
  27. meshcollider merged this on Aug 9, 2021
  28. meshcollider closed this on Aug 9, 2021

  29. sidhujag referenced this in commit 7d26036eac on Aug 10, 2021
  30. luke-jr referenced this in commit 171ac54ea4 on Oct 10, 2021
  31. luke-jr referenced this in commit 462ebb66dc on Dec 14, 2021
  32. DrahtBot locked this on Aug 16, 2022
  33. MarcoFalke deleted the branch on Aug 22, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-18 12:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me