-
Notifications
You must be signed in to change notification settings - Fork 38.6k
wallet: Add separate balance info for non-mempool wallet txs #33671
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
base: master
Are you sure you want to change the base?
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33671. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. LLM Linter (✨ experimental)Possible places where comparison-specific test macros should replace generic comparisons:
2026-01-07 |
|
Relevant for #29415 -- private relay of our wallet transactions would create spends that weren't in the mempool and would thus disappear mysteriously from the wallet balance which seems unacceptable. I think I've seen similar behaviour when doing lots of consolidations of my signet wallet, which has also been disturbing. Perhaps see #11020 for a similar previous attempt.
|
5d85ab9 to
9d9a0a6
Compare
vasild
left a comment
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.
Concept ACK
This extends the getbalances RPC. Would be good to also update the GUI (not necessary in this PR).
The new type of transactions would have somehow to be fed to the wallet so that they would be returned by wallet.GetTXOs(), called by GetBalance(). How would that be done?
|
Concept ACK |
9d9a0a6 to
5209273
Compare
Okay, I have a patch for that opened as draft at bitcoin-core/gui#911
I don't think there's a way to do this for arbitrary txs that originate outside of the wallet, even if they involve a wallet address. Maybe there should be? (ie, an RPC that lets you pass raw tx to But for txs that are created by the wallet, eg You can create non-mempool txs by limiting I've added a test to wallet_send.py that exercises this behaviour. |
|
Concept NACK-ish There's a lot of reasons that an unconfirmed transaction might be in the wallet but not the mempool, and I think giving an accurate balance of those transactions will be hard to get right. We absolutely do not want to mislead users into thinking they have more coins than they actually do, so I am hesitant to add something like this. From a cursory glance at the code, I think 2 transactions that conflict with each other but aren't in the mempool would both get counted towards the |
We currently mislead users into thinking they have less coins than they actually do (due to transactions in the wallet with long mempool chains, eg), which is very scary, and (IMO) very bad from an accounting POV. So I don't think the current state is acceptable either. The underlying problem (IMO) is that the accounting is unbalanced: if we see two transactions (A,B) in the wallet, where B spends A (via
That's accurate: ie spending a single 50 rBTC output twice suddenly gets reported as ~100 rBTC ex fees. I don't think there's an easy way to avoid that with the "don't ignore B's funds" approach: if you have confirmed utxos A (1 BTC), B (2 BTC), C (3 BTC), you could have non-mempool txs D spending A,B (3 BTC out, 2.9 BTC change) and E spending A,C (4 BTC 3.8 BTC change). You subtract 6 BTC from your balance because each of A,B,C have non-abandoned, non-block/mempool-conflicted spends in the wallet, but if D were to confirm you should add 5.9 BTC (D+C), if E were to confirm you should add 5.8 BTC (E+B), and if you pretended both were to confirm you'd add 6.7 BTC (D+E). The other approach, then, is to say "D and E aren't in the mempool, so A B and C aren't -really- spent", and not remove the 6 BTC from A,B,C from your balance; though IMO it still makes sense to separate those out into "possibly-spent-by-nonmempool-txs". I believe that easily avoids the double counting if you have conflicting possible spends. With that approach, if I spend an immature coinbase, that changes my balances from: Double spending the same tx at that point doesn't change the result. If I do the "A,B,C" (50 rBTC each) spent by conflicting "D,E", I get: That approach is still "misleading" in the sense that those nonmempool txs are reported as how much money you're spending, rather than how much you're potentially keeping as change if those spends go through. Another approach would be to report it as: ie "your balance is this, but you have X funds that are currently not in your mempool that you might lose some/all of" Could also perhaps do it more fine-grained as: [EDIT: You could perhaps also account for locked coins similarly to non-mempool spends, which might be logical if you're locking coins because you're spending them elsewhere in ways you don't expect will make it to your mempool] Happy to switch to one of those approaches, or something else, if that seems more acceptable. |
I would prefer this approach and docs just need to be clear that some of that amount may come back as change. |
7af1215 to
e720037
Compare
|
Okay, so when a "transfer to self" tx paying 1310 sats in fees from 100 BTC of inputs doesn't hit the mempool, it currently looks like: {
"mine": {
"trusted": 5949.99999220,
"untrusted_pending": 0.00000000,
"immature": 3200.00000780
}
}vs when the tx does hit the mempool: {
"mine": {
"trusted": 6049.99997910,
"untrusted_pending": 0.00000000,
"immature": 3200.00000780
}
}That is, there's 99.9999869 BTC missing from your balance while the transaction is in the wallet but not in the mempool. With the current version of this PR, it now looks like this when the tx is not in the mempool: {
"mine": {
"trusted": 6049.99999220,
"untrusted_pending": 0.00000000,
"immature": 3200.00000780,
"nonmempool": -100.00000000
}
}So if you add those figures up, you're still 100 BTC down, but at least you have a clue as to what's going on. When it does hit the mempool (or gets mined), it becomes: {
"mine": {
"trusted": 6049.99997910,
"untrusted_pending": 0.00000000,
"immature": 3200.00000780,
"nonmempool": 0.00000000
}
}which is the same as previously (with the addtion of nonmempool=0). I also refactored it to calculate the "used" value directly (ie funds held in coins with addresses that are already spent from, for wallets that care about that), since I couldn't figure out how to get the nonmempool figure correct otherwise, but I think that's an improvement anyway. I believe there was a "bug" in the |
e720037 to
815a1fc
Compare
|
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
815a1fc to
e720037
Compare
| } | ||
| if (bucket) { | ||
| // Get the amounts for mine | ||
| CAmount credit_mine = txo.GetTxOut().nValue; |
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.
In 81e763f "wallet: Have GetBalance report used amount directly without two calls"
This could be brought inline with *bucket += credit_mine; below as credit_mine is only ever used there.
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.
The value is used twice, once for *bucket += and once for ...nonmempool -= ? EDIT: ah, I guess that only happens in the following commit. Seems fine to leave though?
e720037 to
7a05458
Compare
Uses send rpc to create a tx with oversized OP_RETURN output, verifies that it doesn't enter the mempool, and that getbalance rpc returns a nonmempool value.
7a05458 to
f77bf4c
Compare
Changes
getbalancesto report the sum of txos spent by transactions that aren't confirmed nor in the mempool (eg due to being part of too long a mempool chain, or spending non-standard outputs, or having a datacarrier output that exceeds-datacarriersize, etc). Those values are added to the trusted/untrusted_pending/immature/used fields as appropriate (where previously they were skipped), and subtracted from the new nonmempool field, so that the sum of all fields remains the same.For example:
Closes #11887