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.
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.
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?
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.
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
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.
ryanofsky approved
ryanofsky
commented at 4:33 pm on June 29, 2021:
member
Code review ACKfa9ef0e8c6f379499ba7415040b76a76afdb02dc. 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).
luke-jr
commented at 6:18 pm on June 29, 2021:
member
Should we do this in transactionRemovedFromMempool too perhaps?
luke-jr referenced this in commit
c01b12dfa4
on Jun 29, 2021
luke-jr referenced this in commit
f477e1e587
on Jun 29, 2021
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 }
promag
commented at 6:10 pm on June 30, 2021:
member
wallet: Properly set fInMempool in mempool notificationsfa6fd3dd6a
MarcoFalke force-pushed
on Jul 1, 2021
MarcoFalke
commented at 8:48 am on July 1, 2021:
member
Should we do this in transactionRemovedFromMempool too perhaps?
Thx, done.
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.
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.
ryanofsky approved
ryanofsky
commented at 9:45 am on July 1, 2021:
member
Code review ACKfa6fd3dd6a4e7f30eff5963836aed43fe01af078. 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.
ryanofsky referenced this in commit
d622b28227
on Jul 1, 2021
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.
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