-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: Mark replaced tx to not be in the mempool anymore #18842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wallet: Mark replaced tx to not be in the mempool anymore #18842
Conversation
This is an alternative to my preferred fix #18840 |
re: #18842 (comment)
fa3fdbf does seem a little fragile. I guess I was thinking of something more like: diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 0e7641ae320..8b288e62ff7 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -309,6 +309,11 @@ public:
LOCK(::mempool.cs);
return IsRBFOptIn(tx, ::mempool);
}
+ bool isInMempool(const uint256& txid) override
+ {
+ LOCK(::mempool.cs);
+ return ::mempool.exists(txid);
+ }
bool hasDescendantsInMempool(const uint256& txid) override
{
LOCK(::mempool.cs);
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index fb77c81cdcb..c76a361f261 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -185,6 +185,9 @@ public:
//! Check if transaction is RBF opt in.
virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
+ //! Check if transaction is in mempool.
+ virtual bool isInMempool(const uint256& txid) = 0;
+
//! Check if transaction has descendants in mempool.
virtual bool hasDescendantsInMempool(const uint256& txid) = 0;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 7a6deab1a8c..833414d4880 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -707,6 +707,12 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
wtx.mapValue["replaced_by_txid"] = newHash.ToString();
+ // Refresh mempool status without waiting for transactionRemovedFromMempool
+ // notification so the wallet is in an internally consistent state and
+ // immediately knows the old transaction should not be considered trusted
+ // and is eligible to be abandoned
+ wtx.fInMempool = chain().isInMempool(originalHash);
+
WalletBatch batch(*database, "r+");
bool success = true; |
Concept ACK. This looks a bug to me, a test would be nice. @ryanofsky how could I find odd that |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
Apparently the backwards compatibility test is still intermittently failing. Needs rebase. |
fa3fdbf
to
faeedff
Compare
Rebased. Not addressed any feedback, because the question by @promag hasn't been answered: "@ryanofsky how could chain().isInMempool(originalHash) be true?" |
I think it should be true because MarkReplaced should be called after the new transaction is committed and the old transaction is no longer in the mempool. As I understand it, the race happens because |
Oh sorry, I answered why the question how could it be false, not how could it be true. It could be true if MarkReplaced was called at unexpected time on a transaction that wasn't successfully replaced, or maybe restored after a replacement was abandoned. So the change was suggested to make MarkReplaced safer. An alternative to: wtx.fInMempool = chain().isInMempool(originalHash); could be: assert(!chain().isInMempool(originalHash));
wtx.fInMempool = false; and I think either of these would be more safe. Adding the comment from #18842 (comment) could also be helpful. |
Code review ACK faeedff or for any of the suggested alternatives. |
This seems fragile, as it (in theory) may crash the node. Imagine calling |
Right, that's why I suggested |
Or you could replace crashing assert with throwing CHECK. Basically #18842 (comment) is still my preferred alternative, but all alternatives discussed and current PR seem fine. |
I don't think it is possible to do a thing that is correct in all scenarios. The wallet is an async subscriber of the mempool, so if there are any mempool RPCs called concurrently (and conflicting) with wallet RPCs there is no way to "do the correct thing". The design here is that the wallet will eventually catch up with the correct data if you give it enough time to eat all previous in-flight notifications. |
Is there something not correct about |
It won't crash the node, but adding it doesn't guarantee that the in-mempool status is correct at all times. Imagine calling |
I think can you avoid problems here just holding cs_wallet throughout the bumpfee call. I haven't dug into the details of what we're doing, but clearly what we're doing now is incorrect. I'm not sure if you prefer blindly assigning |
faeedff
to
fa4e088
Compare
Thanks, force pushed your patch (needed rebased) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK fa4e088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variant has two ACKs, so I think it is good to go in |
…l anymore fa4e088 wallet: Mark replaced tx to not be in the mempool anymore (MarcoFalke) Pull request description: The wallet does not mark the replaced tx as out-of-mempool. This causes failures in user scripts, because later RPCs may depend on this state change from `bumpfee`. For example, the following might fail on current master: ``` txid = sendtoaddress(...) bumpfee(txid) abandontransaction(txid) # fails because txid is still marked as "in mempool" ``` Fixes bitcoin#18831 ACKs for top commit: meshcollider: utACK fa4e088 ryanofsky: Code review ACK fa4e088, and previous ACK faeedff is also still valid in case there's a preference for the original fix Tree-SHA512: 9858f40f5fb5a43a7b584b5c4268b6befa82e6a84583be5206fe721bcb6c255e8d35479d347d0b9aed72703df49887c02b14ab680e8efdd28b90dd6b93d9439a
Github-Pull: bitcoin#18842 Rebased-From: fa4e088
The wallet does not mark the replaced tx as out-of-mempool. This causes failures in user scripts, because later RPCs may depend on this state change from
bumpfee
.For example, the following might fail on current master:
Fixes #18831