Skip to content

Adds non-mempool wallet balance to overview - #952

Open
polespinasa wants to merge 6 commits into
bitcoin-core:masterfrom
polespinasa:2026-07-27-wallet_nonmempool_balance
Open

Adds non-mempool wallet balance to overview#952
polespinasa wants to merge 6 commits into
bitcoin-core:masterfrom
polespinasa:2026-07-27-wallet_nonmempool_balance

Conversation

@polespinasa

@polespinasa polespinasa commented Jul 27, 2026

Copy link
Copy Markdown
Member

Just grabbing #911

Copying the motivation from AJ's description:

The wallet can contain transactions that are not accepted into the node's mempool (eg due to containing a too large OP_RETURN output, due to too low a feerate, or due to too many unconfirmed ancestors). In the event you end up in this situation, it can appear as if funds have gone missing from your wallet due to the non-mempool balance not being reported. Correct this by reporting the non-mempool balance.

See bitcoin/bitcoin#33671 for further context.

The changes look like:

imagen

How to test

To test, start with -datacarriersize=10, and run

send '{"data": "4368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"}' null "unset" 1

from the console. "Non-mempool: " should appear in the Balances pane on the Overview window with the change from the transaction. Restarting with -datacarriersize=100000 should allow the tx to enter the mempool, and move the amount into the Available balance. (Presumably, do this on -regtest after generating 100 blocks; or perhaps signet after grabbing some funds from a faucet)

@DrahtBot

DrahtBot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

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

Reviews

See the guideline and AI policy for information on the review process.

Type Reviewers
ACK pablomartin4btc

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, 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.

polespinasa and others added 3 commits July 27, 2026 17:37
Use getBalances when testing the current balance in OverviewPage to take into account
non_mempool balances in next commits.

Co-authored-by: Anthony Towns <aj@erisian.com.au>
The assert removal is necesary for a next commit to introduce nonmempoolbalance
as that balance should always be negative thus making this assert no longer true.

Co-authored-by: Anthony Towns <aj@erisian.com.au>
@polespinasa
polespinasa force-pushed the 2026-07-27-wallet_nonmempool_balance branch from fce681b to db32a1b Compare July 27, 2026 15:38
@DrahtBot

Copy link
Copy Markdown
Contributor

🚧 At least one of the CI tasks failed.
Task riscv32 bare metal, static libbitcoin_consensus: https://github.com/bitcoin-core/gui/actions/runs/30279603397/job/90022318535
LLM reason (✨ experimental): CI failed because the Docker build’s submodule clone of newlib-cygwin.git from sourceware.org was rate-limited (HTTP 429), causing the 01_base_install.sh step to exit with code 2.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@polespinasa

Copy link
Copy Markdown
Member Author

Key differences with #911 are:

  • Changed the font color
  • Removed the padding after "-"
  • Separated some of the changes in multiple commits
  • Changed a bit the hint box and the naming of non-mempool balance

@pablomartin4btc pablomartin4btc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

I've suggested some release notes in previous attempt #911 and it'd be nice to include them here if you're up to ofc.

Suggested Qt test snippet for wallettests.cpp...

The PR touches wallettests.cpp but only to fix the existing call — worth adding a UI-level test for the new label visibility and formatting. Since there are no actual non-mempool transactions in the test wallet, calling setBalance() directly with crafted data is the right approach here rather than going through pollBalanceChanged().

// Test non-mempool balance display
interfaces::WalletBalances nonmempool_balances;
nonmempool_balances.balance = walletModel.wallet().getBalances().balance;
nonmempool_balances.nonmempool_balance = -50000;
overviewPage.setBalance(nonmempool_balances);
QVERIFY(overviewPage.findChild<QLabel*>("labelNonMempool")->isVisible());
QVERIFY(overviewPage.findChild<QLabel*>("labelNonMempoolText")->isVisible());
CompareBalance(walletModel, -50000, overviewPage.findChild<QLabel*>("labelNonMempool"));

nonmempool_balances.nonmempool_balance = 0;
overviewPage.setBalance(nonmempool_balances);
QVERIFY(!overviewPage.findChild<QLabel*>("labelNonMempool")->isVisible());
QVERIFY(!overviewPage.findChild<QLabel*>("labelNonMempoolText")->isVisible());

@polespinasa

Copy link
Copy Markdown
Member Author

Added the tests with you as a co-author and added some release notes.
For some reason I forgot to add the release notes before.

@polespinasa
polespinasa force-pushed the 2026-07-27-wallet_nonmempool_balance branch from eee7f87 to 1907923 Compare July 27, 2026 17:57

@pablomartin4btc pablomartin4btc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 1907923

@hebasto

hebasto commented Jul 29, 2026

Copy link
Copy Markdown
Member

@GBKS

Could you please weigh in on the UI/UX design choices in this PR?

@GBKS

GBKS commented Jul 30, 2026

Copy link
Copy Markdown

Yes, I'd be happy to.

Overall, I think a label like "On hold" or "Needs attention" would be a more clear than "Not in mempool" and go better with "Available" and "Pending". Users have mental models for those.

Not sure if this is done already, and maybe not part of this PR, but carrying this state through the rest of the UI is likely also a good idea. So a transaction in the payment history should also indicate this state. And the transaction details view can ideally let the user know why the transaction is "on hold", and provide information or options on how to either cancel it or fix the respective problem.

Hope that's helpful.

@polespinasa

polespinasa commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

Thanks for the feedback Christoph!

Overall, I think a label like "On hold" or "Needs attention" would be a more clear than "Not in mempool" and go better with "Available" and "Pending". Users have mental models for those.

I will go with "On hold", "needs attention" is a bit misleading as it doesn't really means that the user need to pay attention to it or do something specific other than wait.

Not sure if this is done already, and maybe not part of this PR, but carrying this state through the rest of the UI is likely also a good idea. So a transaction in the payment history should also indicate this state. And the transaction details view can ideally let the user know why the transaction is "on hold", and provide information or options on how to either cancel it or fix the respective problem.

I think this is a bit out of the scope of this PR, but I like the idea. I will keep this PR as is and I will try to think, as a follow-up, on how to add it to the payment history and tx details, it will mainly depend on the wallet interface giving that specific information.

Edit: Just did some checking on this last point, the transaction does appear in the transaction history, and the tx details says that is not in the mempool, probably the phrasing could be better:

imagen imagen

Any suggestion on how could it be more explicit in the "recent transactions", an "transaction list"?
This is "transaction list"
imagen

@polespinasa
polespinasa force-pushed the 2026-07-27-wallet_nonmempool_balance branch from 1907923 to 4894a79 Compare July 30, 2026 14:39

@pablomartin4btc pablomartin4btc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the label choice: I think "On hold" implies something or someone intentionally paused the transaction — but could be that the network doesn't even know it exists. For the policy-rejection cases, it's closer to a draft: created, saved locally, but rejected or never submitted. Nothing is on hold. "Pending" is already taken mentally by "in mempool, waiting for confirmation." And "Unbroadcast" isn't accurate either — the tx may have been broadcast and rejected by policy.

The Core RPC in bitcoin/bitcoin#33671 uses nonmempool — so I think the GUI label should mirror that for consistency, it matches what users would see in getbalances RPC.

The nonmempool state actually covers a wider range of situations than the PR description suggests:

Case Duration Voluntary? Tx fate
Private broadcast in-flight ~1 second Yes Will enter mempool
walletbroadcast=0 Indefinite Yes User controls
Low feerate / too many ancestors Indefinite No May enter if conditions change
Too large OP_RETURN Indefinite No Will never enter standard mempool
Mempool eviction Indefinite No May re-enter if feerate improves

Perhaps this also means the tooltip needs updating. "Balance for wallet transactions that currently don't fit node's mempool policies" is not completely right, for the first two rows — a private broadcast tx fits mempool policies fine, it's just being relayed privately via Tor/I2P. Notably, the nonmempool balance was needed as a next step once private broadcast was implemented — without it, I think funds would silently disappear during the ~1 second broadcast window.

The tooltip is also misleading on the accounting side: per Core's #33671 description, inputs consumed by non-mempool txs are added back into trusted (Available) as if the transaction doesn't exist, with nonmempool as the offsetting debit — keeping the total balance unchanged. It's not a separate pool of frozen funds.

A more accurate tooltip I think, could be something like: "Wallet transactions not currently in the mempool — due to policy rejection, pending private broadcast, or deliberate delay."

@polespinasa
polespinasa force-pushed the 2026-07-27-wallet_nonmempool_balance branch from 4894a79 to 0351124 Compare August 3, 2026 09:18
@polespinasa

Copy link
Copy Markdown
Member Author

so I think the GUI label should mirror that for consistency, it matches what users would see in getbalances RPC

Although I like the mirroring for consistency, I don't think the RPC is though for users, the GUI is. Imho mirroring should be the first option as long as the naming is user friendly, and here I agree with Christoph that nonmempool is not really user friendly, because users might not know what that is or means.

Perhaps this also means the tooltip needs updating. "Balance for wallet transactions that currently don't fit node's mempool policies" is not completely right, for the first two rows
Wallet transactions not currently in the mempool — due to policy rejection, pending private broadcast, or deliberate delay.

Force pushed your tool-tip suggestion.
Regarding the label naming, I am not sure at all tbh, as said I understand your point, but also what Christoph is saying.
@GBKS care to jump in? :)

@GBKS

GBKS commented Aug 3, 2026

Copy link
Copy Markdown

Sure thing.

RPC mirroring: The existing Available and Pending labels don't match the RPC either (AFAICT), so I don't think there is a precedent for consistency.

Label precision: I'd propose that it is more important that labels are understood than precise. 1-2 word combos can only carry so much meaning. Pending also has a lot of underlying complexity that we have come to accept. Personally, when I see On hold, I directionally understand what is happening and can dig into the details (I want my transaction to go through, but this one is not, let me take a look and see what is happening). When I see Not in mempool, I don't have a starting point. I have to think about mempool mechanics, what it means that a transaction is not in it, etc, and derive what this means for me and my transaction.

Target audience: People like me will 1000x prefer a GUI and do everything to avoid the command line. It feels like an outdated and unnecessarily complicated way to do things that super hackers use (exaggerating slightly to make a point). I think if this application was built for coders, it would look very different, much more like a dashboard with a prominent console, transaction inspection, etc. But I think it is meant for a broader non/less technical audience that just wants to store/send/receive bitcoin, and those are not CLI/RPC first (unless I am mistaken) where the GUI should match that existing knowledge.


For another approach, here's how I resolved it in Arké. There's a Pending balance that I can tap to expand that gives me the full breakdown of everything that is in-flight (note that there is no visual indicator for the expansion because I added that more for my own use/insight). A simple default, with the option to see more complexity for those interested.

arke-expand-pending

YMMV

@pablomartin4btc pablomartin4btc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 0351124.


Fair points from @GBKS, I agree.

My earlier thinking actually started from a similar place: should this fold under Pending? After thinking through it I leaned toward accuracy, but I think the right frame is honest-but-readable rather than technically precise. One reason I moved away from it is that Pending is positive (incoming, unconfirmed receipts), while this amount is always negative — funds tied up on the outgoing side. Mixing them arithmetically would be confusing without a more elaborate breakdown like the Arké design.

I ended up thinking through a few alternatives along honest-but-readable lines:

  • Stalled — movement stopped, no guarantee it restarts; handles the policy-rejection cases well but sounds harsh;
  • Delayed — friendlier, but leans toward "will happen eventually," which isn't always true.

None of these are clearly better. "On hold" is fine — my only mild concern was that it implies something intentionally paused that will eventually release, while some cases just sit until the user acts. But that's a subtle edge case and not worth over-engineering the label for.

Thanks @GBKS for your help here.

Comment thread src/qt/forms/overviewpage.ui Outdated
polespinasa and others added 3 commits August 3, 2026 17:51
The assert in formatWithPrivacy is removed because m_mine_nonmempool is always negative, making this assert
no longer true.

Co-authored-by: Anthony Towns <aj@erisian.com.au>
Co-authored-by: Pablo Martin <pablomartin4btc@gmail.com>
@polespinasa
polespinasa force-pushed the 2026-07-27-wallet_nonmempool_balance branch from 0351124 to 4d5c099 Compare August 3, 2026 15:52

@pablomartin4btc pablomartin4btc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 4d5c099

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants