Skip to content

backport: bitcoin#25122, #25504, #25647, #25768, #25924, #25933, #25990, #26021, #26037, #26091, #26203, #26205, bitcoin-core/gui#598 - #7550

Open
knst wants to merge 13 commits into
dashpay:developfrom
knst:bp-v24-p15
Open

backport: bitcoin#25122, #25504, #25647, #25768, #25924, #25933, #25990, #26021, #26037, #26091, #26203, #26205, bitcoin-core/gui#598#7550
knst wants to merge 13 commits into
dashpay:developfrom
knst:bp-v24-p15

Conversation

@knst

@knst knst commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Multiple wallet-relevant backports

PR is slightly over-sized because some of them depends on each other ; other are conflicting if goes to own branch.

What was done?

Backports from bitcoin core v24, v25 with wallet-related code.

How Has This Been Tested?

Run unit & functional tests

Breaking Changes

See relevant release notes changes:

Wallet

Checklist:

Go over all the following points, and put an x in all the boxes that apply.

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@knst knst added this to the 24 milestone Aug 6, 2026
@knst knst added the RPC Some notable changes to RPC params/behaviour/descriptions label Aug 6, 2026
@thepastaclaw

thepastaclaw commented Aug 6, 2026

Copy link
Copy Markdown

⛔ Final review complete — 2 blocking finding(s) (commit c2bd65e)

…esses were found in the address book

baa3ddc doc: add release notes about `getreceivedbylabel` returning an error if the label is not in the address book. (furszy)
8897a21 rpc: getreceivedbylabel, don't loop over the entire wallet txs map if no destinations were found for the input label. (furszy)

Pull request description:

  Built on top of bitcoin#23662, coming from comment bitcoin#23662 (review).

  If `wallet.GetLabelAddresses()` returns an empty vector (the wallet does not have stored destinations with that label in the addressbook) or if none of the returned destinations are from the wallet, we can return the function right away.
  Otherwise, we are walking through all the wallet txs + outputs for no reason (`output_scripts` is empty).

ACKs for top commit:
  achow101:
    ACK baa3ddc
  theStack:
    re-ACK baa3ddc
  w0xlt:
    ACK bitcoin@baa3ddc

Tree-SHA512: 00e10365b179bf008da2f3ef8fbb3ee04a330426374020e3f2d0151b16991baba4ef2b944e4659452f3e4d6cb20f128d0918ddf0453933a25a4d9fd8414a1911

Co-authored-by: Andrew Chow <achow101-github@achow101.com>
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Potential PR merge conflicts

This is advisory only. It does not block CI, but it marks PRs that will likely need a rebase depending on merge order.

If this PR merges first

These open PRs will likely need a rebase:

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60494e9db0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/qt/overviewpage.cpp
QString strCoinJoinAmount = BitcoinUnits::formatHtmlWithUnit(m_display_bitcoin_unit, clientModel->coinJoinOptions().getAmount() * COIN, false, BitcoinUnits::SeparatorStyle::ALWAYS);

if(m_balances.balance == 0)
const auto& balances = walletModel->getCachedBalance();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refresh CoinJoin progress from uncached denominated balances

When only denominated_trusted or denominated_untrusted_pending changes, such as after denomination creation/confirmation during mixing, WalletModel::checkBalanceChanged() does not copy the new values because WalletBalances::balanceChanged() ignores those fields. Since this method now uses getCachedBalance() instead of fetching fresh balances, the advanced CoinJoin progress can remain stale until some unrelated tracked balance field changes.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Confirmed as a Dash-specific regression. Before this backport, the advanced CoinJoin path fetched wallet().getBalances() directly. The new cached path depends on WalletBalances::balanceChanged(), which does not compare denominated_trusted or denominated_untrusted_pending, so those fields can remain stale when they change independently. This needs a Dash adaptation before merge.

Comment thread src/qt/walletmodel.cpp Outdated

CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
{
return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Respect CoinJoin balance when no inputs are selected

In the mixed-funds send dialog, m_coin_control->UseCoinJoin(true) is set without selecting specific inputs, so this branch bypasses wallet().getAvailableBalance(*control), whose wallet interface special-cases CoinJoin to return the anonymized balance. Returning the overall cached balance here makes “Use available balance” and the upfront balance check treat non-mixed funds as spendable for CoinJoin sends, only failing later during transaction creation.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Confirmed. wallet().getAvailableBalance(*control) special-cases IsUsingCoinJoin() and returns GetBalanceAnonymized(), while the new no-manual-selection branch returns the total cached balance. Mixed-only sends therefore bypass their intended balance filter. This needs a Dash-specific adaptation before merge.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d00d22c-26d9-4017-8d81-bf7b773e29e4

📥 Commits

Reviewing files that changed from the base of the PR and between dc1d21e and c2bd65e.

📒 Files selected for processing (36)
  • doc/release-notes-25122.md
  • doc/release-notes-25504.md
  • src/Makefile.test.include
  • src/qt/overviewpage.cpp
  • src/qt/overviewpage.h
  • src/qt/sendcoinsdialog.cpp
  • src/qt/sendcoinsdialog.h
  • src/qt/test/wallettests.cpp
  • src/qt/walletmodel.cpp
  • src/qt/walletmodel.h
  • src/rpc/client.cpp
  • src/wallet/coinselection.cpp
  • src/wallet/coinselection.h
  • src/wallet/receive.cpp
  • src/wallet/receive.h
  • src/wallet/rpc/backup.cpp
  • src/wallet/rpc/coins.cpp
  • src/wallet/rpc/transactions.cpp
  • src/wallet/rpc/util.cpp
  • src/wallet/rpc/util.h
  • src/wallet/spend.cpp
  • src/wallet/test/coinselector_tests.cpp
  • src/wallet/test/fuzz/coinselection.cpp
  • src/wallet/test/walletload_tests.cpp
  • src/wallet/transaction.h
  • src/wallet/wallet.cpp
  • src/wallet/wallet.h
  • src/wallet/walletdb.cpp
  • src/wallet/walletdb.h
  • test/functional/mempool_expiry.py
  • test/functional/test_framework/messages.py
  • test/functional/wallet_basic.py
  • test/functional/wallet_groups.py
  • test/functional/wallet_listreceivedby.py
  • test/functional/wallet_listsinceblock.py
  • test/functional/wallet_resendwallettransactions.py
💤 Files with no reviewable changes (1)
  • src/qt/overviewpage.h
🚧 Files skipped from review as they are similar to previous changes (33)
  • src/wallet/walletdb.h
  • src/qt/sendcoinsdialog.h
  • test/functional/mempool_expiry.py
  • test/functional/wallet_listreceivedby.py
  • src/wallet/receive.h
  • doc/release-notes-25122.md
  • src/rpc/client.cpp
  • test/functional/test_framework/messages.py
  • src/wallet/transaction.h
  • src/wallet/test/fuzz/coinselection.cpp
  • src/wallet/rpc/util.cpp
  • src/wallet/rpc/util.h
  • src/wallet/test/coinselector_tests.cpp
  • src/qt/walletmodel.h
  • src/qt/sendcoinsdialog.cpp
  • src/wallet/receive.cpp
  • test/functional/wallet_listsinceblock.py
  • src/wallet/wallet.h
  • src/Makefile.test.include
  • test/functional/wallet_resendwallettransactions.py
  • test/functional/wallet_groups.py
  • src/wallet/rpc/transactions.cpp
  • src/qt/test/wallettests.cpp
  • src/qt/overviewpage.cpp
  • src/wallet/coinselection.cpp
  • src/wallet/wallet.cpp
  • doc/release-notes-25504.md
  • src/wallet/walletdb.cpp
  • src/wallet/coinselection.h
  • test/functional/wallet_basic.py
  • src/wallet/rpc/backup.cpp
  • src/qt/walletmodel.cpp
  • src/wallet/spend.cpp

Walkthrough

The PR centralizes Qt wallet balance access through WalletModel, updates coin selection for viable change and fee handling, and adds wallet transaction resubmission scheduling. Wallet RPCs can report parent descriptors and optionally include change outputs. Wallet loading reports unknown descriptors with a dedicated database error. Tests cover balance display, coin selection, descriptor metadata, change reporting, wallet imports, and chained transaction resubmission.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WalletTimer
  participant CWallet
  participant Mempool
  WalletTimer->>CWallet: check ShouldResend()
  CWallet->>CWallet: order and filter wallet transactions
  CWallet->>Mempool: ResubmitWalletTransactions(relay, force)
  CWallet->>WalletTimer: SetNextResend()
Loading
sequenceDiagram
  participant RPCClient
  participant listsinceblock
  participant ListTransactions
  participant CachedTxGetAmounts
  RPCClient->>listsinceblock: pass include_change
  listsinceblock->>ListTransactions: forward include_change
  ListTransactions->>CachedTxGetAmounts: request transaction amounts
  CachedTxGetAmounts-->>ListTransactions: include or omit change outputs
Loading

Possibly related PRs

  • dashpay/dash#7052: CoinJoin wallet balance and fully-mixed denomination handling overlap with the balance and coin-selection changes.
  • dashpay/dash#7480: Pending-observation locks and wallet coin-selection behavior overlap with the CoinJoin-aware balance and selection changes.
  • dashpay/dash#7502: Wallet transaction RPC schema documentation overlaps with the parent_descs and include_change updates.

Suggested reviewers: udjinm6

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the pull request as a backport of the listed Bitcoin Core and GUI changes.
Description check ✅ Passed The description explains the wallet-related backports, testing performed, and the primary user-visible RPC change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (5)
src/wallet/test/walletload_tests.cpp (1)

38-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the restating comments.

These comments only describe the next statements. Keep comments for non-obvious invariants or test setup rationale.

As per coding guidelines, “avoid comments that merely restate code and reserve comments for non-obvious invariants, workaround rationale, or non-local side effects.”

Also applies to: 47-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/test/walletload_tests.cpp` at line 38, Remove the restating
comments near the unknown active descriptor setup, including both referenced
locations, while leaving the test statements and behavior unchanged.

Source: Coding guidelines

src/wallet/coinselection.h (1)

351-361: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document the new only_fully_mixed parameter.

The doc block lists utxo_pool, target_value, rng, and max_weight, but not only_fully_mixed. This parameter is Dash-specific and controls whether CHANGE_LOWER is added to the target, so it is not self-explanatory to a reader coming from upstream.

♻️ Proposed doc addition
  * `@param`[in]  max_weight The maximum allowed weight for a selection result to be valid
+ * `@param`[in]  only_fully_mixed Dash-specific: when true, no change is allowed, so the target is
+ *             not increased by CHANGE_LOWER
  * `@returns` If successful, a valid SelectionResult, otherwise, util::Error
  */
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/coinselection.h` around lines 351 - 361, Update the SelectCoinsSRD
documentation to add an `@param` entry for only_fully_mixed, explaining that it is
Dash-specific and controls whether CHANGE_LOWER is added to the target. Keep the
existing parameter descriptions unchanged.
test/functional/wallet_groups.py (1)

28-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use Dash terminology in the new comment.

The fixed feerate makes the fee expectations deterministic, and the values are consistent with the maxapsfee thresholds on lines 28-29: the grouped/non-grouped difference is 5880 duffs, node 3 allows 5879, and node 4 allows 5880. The code is correct.

The comment says "20 sats/vB". Dash has no witness data and no vbytes, and the unit is the duff. Consider "20 duffs/byte".

♻️ Proposed comment change
-            args.append(f"-paytxfee={20 * 1e3 / 1e8}")  # apply feerate of 20 sats/vB across all nodes
+            args.append(f"-paytxfee={20 * 1e3 / 1e8}")  # apply feerate of 20 duffs/byte across all nodes
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/wallet_groups.py` around lines 28 - 34, Update the comment
beside the fixed paytxfee assignment in the extra_args loop to use Dash
terminology, replacing “20 sats/vB” with “20 duffs/byte”; leave the fee value
and surrounding whitelist comment unchanged.
src/wallet/test/coinselector_tests.cpp (1)

302-303: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider 34 for change_output_size to match the other Dash test parameters.

31 bytes is the upstream P2WPKH change-output size. Dash has no segwit outputs, and the other CoinSelectionParams initializations in this file use 34, which is the P2PKH change-output size (8 value + 1 script length + 25 script). The value only scales the derived m_change_fee, m_cost_of_change, and min_viable_change in this test, so behavior does not change. Alignment keeps the test parameters consistent.

If you prefer to keep the file identical to upstream Bitcoin Core, keep 31 and ignore this note.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/test/coinselector_tests.cpp` around lines 302 - 303, Update the
CoinSelectionParams initialization containing change_output_size and
change_spend_size to use 34 for change_output_size, matching the other Dash test
configurations in this file; leave change_spend_size and the surrounding test
logic unchanged.
src/wallet/spend.cpp (1)

958-962: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Restrict the change-position lookup to the case where a change output exists.

When change_amount is 0, no change output is inserted and nChangePosInOut is set to -1, but the lookup still searches for newTxOut, which is CTxOut(0, scriptChange). A match would restore a bogus change position. Today the dust check on recipients prevents a 0-value recipient output, so the lookup cannot match. A guard makes the intent explicit and protects the invariant if the dust rule changes.

♻️ Proposed guard
         // If there was a change output added before, we must update its position now
-        if (const auto it = std::find(txNew.vout.begin(), txNew.vout.end(), newTxOut); it != txNew.vout.end()) {
-            nChangePosInOut = std::distance(txNew.vout.begin(), it);
+        if (nChangePosInOut != -1) {
+            const auto it = std::find(txNew.vout.begin(), txNew.vout.end(), newTxOut);
+            assert(it != txNew.vout.end());
+            nChangePosInOut = std::distance(txNew.vout.begin(), it);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/spend.cpp` around lines 958 - 962, Guard the change-position
lookup in the surrounding transaction-output update logic with the condition
that a change output was actually created (change_amount > 0). Keep
nChangePosInOut at -1 when no change output exists, and only run the std::find
lookup for positive change amounts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@doc/release-notes-25504.md`:
- Around line 4-5: Update the release note’s RPC list to include listunspent
alongside listsinceblock, listtransactions, and gettransaction, preserving the
statement that each receive entry now contains parent_descs.

In `@src/wallet/wallet.cpp`:
- Line 2137: Update CWallet::GetDefaultNextResend() to return the current time
plus a 12-hour base delay and a random value below 24 hours, restoring the
intended 12–36 hour interval. Also update the GetDefaultNextResend declaration
comment in wallet.h to document that same interval.

In `@src/wallet/walletdb.cpp`:
- Around line 919-920: Update the diagnostic string in the wallet error-handling
path to say “might have been created” instead of “might had been created,”
leaving the surrounding message and conditional behavior unchanged.
- Around line 847-850: Update the wallet-loading flow around DBKeys::VERSION and
the WalletLogPrintf call so DBKeys::MINVERSION is read and applied before
pwallet->GetVersion() is logged. Alternatively, log the MINVERSION value read
directly from the database, ensuring the reported wallet file version reflects
persisted data rather than the default in-memory value.

---

Nitpick comments:
In `@src/wallet/coinselection.h`:
- Around line 351-361: Update the SelectCoinsSRD documentation to add an `@param`
entry for only_fully_mixed, explaining that it is Dash-specific and controls
whether CHANGE_LOWER is added to the target. Keep the existing parameter
descriptions unchanged.

In `@src/wallet/spend.cpp`:
- Around line 958-962: Guard the change-position lookup in the surrounding
transaction-output update logic with the condition that a change output was
actually created (change_amount > 0). Keep nChangePosInOut at -1 when no change
output exists, and only run the std::find lookup for positive change amounts.

In `@src/wallet/test/coinselector_tests.cpp`:
- Around line 302-303: Update the CoinSelectionParams initialization containing
change_output_size and change_spend_size to use 34 for change_output_size,
matching the other Dash test configurations in this file; leave
change_spend_size and the surrounding test logic unchanged.

In `@src/wallet/test/walletload_tests.cpp`:
- Line 38: Remove the restating comments near the unknown active descriptor
setup, including both referenced locations, while leaving the test statements
and behavior unchanged.

In `@test/functional/wallet_groups.py`:
- Around line 28-34: Update the comment beside the fixed paytxfee assignment in
the extra_args loop to use Dash terminology, replacing “20 sats/vB” with “20
duffs/byte”; leave the fee value and surrounding whitelist comment unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d072bb03-7ed9-4fbf-b435-cda2e63fa1c9

📥 Commits

Reviewing files that changed from the base of the PR and between dc1d21e and 60494e9.

📒 Files selected for processing (36)
  • doc/release-note-25122.md
  • doc/release-notes-25504.md
  • src/Makefile.test.include
  • src/qt/overviewpage.cpp
  • src/qt/overviewpage.h
  • src/qt/sendcoinsdialog.cpp
  • src/qt/sendcoinsdialog.h
  • src/qt/test/wallettests.cpp
  • src/qt/walletmodel.cpp
  • src/qt/walletmodel.h
  • src/rpc/client.cpp
  • src/wallet/coinselection.cpp
  • src/wallet/coinselection.h
  • src/wallet/receive.cpp
  • src/wallet/receive.h
  • src/wallet/rpc/backup.cpp
  • src/wallet/rpc/coins.cpp
  • src/wallet/rpc/transactions.cpp
  • src/wallet/rpc/util.cpp
  • src/wallet/rpc/util.h
  • src/wallet/spend.cpp
  • src/wallet/test/coinselector_tests.cpp
  • src/wallet/test/fuzz/coinselection.cpp
  • src/wallet/test/walletload_tests.cpp
  • src/wallet/transaction.h
  • src/wallet/wallet.cpp
  • src/wallet/wallet.h
  • src/wallet/walletdb.cpp
  • src/wallet/walletdb.h
  • test/functional/mempool_expiry.py
  • test/functional/test_framework/messages.py
  • test/functional/wallet_basic.py
  • test/functional/wallet_groups.py
  • test/functional/wallet_listreceivedby.py
  • test/functional/wallet_listsinceblock.py
  • test/functional/wallet_resendwallettransactions.py
💤 Files with no reviewable changes (1)
  • src/qt/overviewpage.h

Comment thread doc/release-notes-25504.md
Comment thread src/wallet/wallet.cpp
Comment thread src/wallet/walletdb.cpp
Comment thread src/wallet/walletdb.cpp
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/wallet/rpc/coins.cpp (1)

23-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove comments that restate adjacent code.

Lines 23, 27, and 35 describe the statements that immediately follow them. Remove these comments.

Proposed cleanup
     if (by_label) {
-        // Get the set of addresses assigned to label
         addresses = wallet.ListAddrBookAddresses(CWallet::AddrBookFilter{LabelFromValue(params[0])});
         if (addresses.empty()) throw JSONRPCError(RPC_WALLET_ERROR, "Label not found in wallet");
     } else {
-        // Get the address
         CTxDestination dest = DecodeDestination(params[0].get_str());
         if (!IsValidDestination(dest)) {
             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
         }
         addresses.emplace_back(dest);
     }
 
-    // Filter by own scripts only
     std::vector<CScript> output_scripts;

As per coding guidelines, “avoid comments that merely restate code.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/rpc/coins.cpp` around lines 23 - 35, Remove the comments
immediately preceding the address-listing, destination-decoding, and own-script
filtering logic in the surrounding RPC method, leaving the executable statements
and behavior unchanged.

Source: Coding guidelines

src/wallet/test/walletload_tests.cpp (1)

38-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove comments that restate the test phases.

Lines 38 and 47 repeat the operations in the following statements. Remove these comments.

Proposed cleanup
     std::unique_ptr<WalletDatabase> database = CreateMockWalletDatabase();
     {
-        // Write unknown active descriptor
         WalletBatch batch(*database, false);
         std::string unknown_desc = "trx(tpubD6NzVbkrYhZ4Y4S7m6Y5s9GD8FqEMBy56AGphZXuagajudVZEnYyBahZMgHNCTJc2at82YX6s8JiL1Lohu5A3v1Ur76qguNH4QVQ7qYrBQx/86'/1'/0'/0/*)`#8pn8tzdt`";
         WalletDescriptor wallet_descriptor(std::make_shared<DummyDescriptor>(unknown_desc), 0, 0, 0, 0);
         BOOST_CHECK(batch.WriteDescriptor(uint256(), wallet_descriptor));
         BOOST_CHECK(batch.WriteActiveScriptPubKeyMan(uint256(), false));
     }
 
     {
-        // Now try to load the wallet and verify the error.
         const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), /*coinjoin_loader=*/nullptr, "", m_args, std::move(database)));
         BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::UNKNOWN_DESCRIPTOR);

As per coding guidelines, “avoid comments that merely restate code.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/test/walletload_tests.cpp` around lines 38 - 47, Remove the
phase-description comments in the test blocks surrounding WalletBatch setup and
wallet loading, including the comments before writing the descriptor and loading
the wallet. Leave the test operations and assertions unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/functional/wallet_resendwallettransactions.py`:
- Around line 91-96: Bound the wallet reload loop around listreceivedbyaddress
by tracking reload attempts and stopping after a finite limit. If the expected
order [child_txid, txid] is not observed, raise an assertion that includes the
final observed txids; retain the existing unloadwallet/loadwallet retry behavior
while attempts remain.

---

Nitpick comments:
In `@src/wallet/rpc/coins.cpp`:
- Around line 23-35: Remove the comments immediately preceding the
address-listing, destination-decoding, and own-script filtering logic in the
surrounding RPC method, leaving the executable statements and behavior
unchanged.

In `@src/wallet/test/walletload_tests.cpp`:
- Around line 38-47: Remove the phase-description comments in the test blocks
surrounding WalletBatch setup and wallet loading, including the comments before
writing the descriptor and loading the wallet. Leave the test operations and
assertions unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 33fdc6e7-2c48-4afb-89a9-e2f556f45be0

📥 Commits

Reviewing files that changed from the base of the PR and between dc1d21e and 8171fd3.

📒 Files selected for processing (36)
  • doc/release-notes-25122.md
  • doc/release-notes-25504.md
  • src/Makefile.test.include
  • src/qt/overviewpage.cpp
  • src/qt/overviewpage.h
  • src/qt/sendcoinsdialog.cpp
  • src/qt/sendcoinsdialog.h
  • src/qt/test/wallettests.cpp
  • src/qt/walletmodel.cpp
  • src/qt/walletmodel.h
  • src/rpc/client.cpp
  • src/wallet/coinselection.cpp
  • src/wallet/coinselection.h
  • src/wallet/receive.cpp
  • src/wallet/receive.h
  • src/wallet/rpc/backup.cpp
  • src/wallet/rpc/coins.cpp
  • src/wallet/rpc/transactions.cpp
  • src/wallet/rpc/util.cpp
  • src/wallet/rpc/util.h
  • src/wallet/spend.cpp
  • src/wallet/test/coinselector_tests.cpp
  • src/wallet/test/fuzz/coinselection.cpp
  • src/wallet/test/walletload_tests.cpp
  • src/wallet/transaction.h
  • src/wallet/wallet.cpp
  • src/wallet/wallet.h
  • src/wallet/walletdb.cpp
  • src/wallet/walletdb.h
  • test/functional/mempool_expiry.py
  • test/functional/test_framework/messages.py
  • test/functional/wallet_basic.py
  • test/functional/wallet_groups.py
  • test/functional/wallet_listreceivedby.py
  • test/functional/wallet_listsinceblock.py
  • test/functional/wallet_resendwallettransactions.py
💤 Files with no reviewable changes (1)
  • src/qt/overviewpage.h
🚧 Files skipped from review as they are similar to previous changes (30)
  • doc/release-notes-25504.md
  • src/rpc/client.cpp
  • src/Makefile.test.include
  • src/qt/sendcoinsdialog.h
  • src/wallet/walletdb.h
  • test/functional/mempool_expiry.py
  • test/functional/wallet_listreceivedby.py
  • src/qt/walletmodel.h
  • test/functional/test_framework/messages.py
  • test/functional/wallet_basic.py
  • src/wallet/transaction.h
  • src/wallet/test/fuzz/coinselection.cpp
  • src/qt/sendcoinsdialog.cpp
  • src/qt/test/wallettests.cpp
  • test/functional/wallet_listsinceblock.py
  • src/wallet/walletdb.cpp
  • test/functional/wallet_groups.py
  • src/wallet/rpc/util.h
  • src/qt/walletmodel.cpp
  • src/wallet/test/coinselector_tests.cpp
  • src/wallet/wallet.h
  • src/wallet/coinselection.cpp
  • src/wallet/wallet.cpp
  • src/wallet/rpc/transactions.cpp
  • src/wallet/receive.h
  • src/wallet/coinselection.h
  • src/wallet/rpc/util.cpp
  • src/wallet/rpc/backup.cpp
  • src/qt/overviewpage.cpp
  • src/wallet/spend.cpp

Comment thread test/functional/wallet_resendwallettransactions.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8171fd3f5e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/qt/walletmodel.cpp Outdated

CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
{
return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Honor watch-only coin control without manual inputs

For private-keys-disabled watch-only wallets, SendCoinsDialog::updateCoinControlState() sets fAllowWatchOnly before prepareTransaction(), and useAvailableBalance() does the same before asking for the available amount. If the user has not manually selected UTXOs, this helper now returns getCachedBalance().balance, which is the spendable balance and excludes watch_only_balance, instead of calling wallet().getAvailableBalance(*control) with fAllowWatchOnly. As a result, a watch-only wallet with funds but no selected inputs reports zero available balance and fails the upfront AmountExceedsBalance check, even though transaction creation can spend solvable watch-only coins when the control flag is honored.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Confirmed. fAllowWatchOnly changes AvailableCoins spendability filtering, but the new no-manual-selection cache path ignores that flag and returns balances.balance rather than the solvable watch-only amount. Private-keys-disabled watch-only wallets can fail the upfront balance check incorrectly. This needs a Dash-specific adaptation before merge.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Preliminary review — Codex only

The backport introduces one Dash-specific regression: the GUI balance cache bypasses the CoinJoin-filtered balance when no inputs are manually selected, causing mixed-send actions and prechecks to use the wallet's full balance. The rebroadcast timing observation is a pre-existing test defect, and the commit-history suggestion targets the already-merged base rather than this wallet backport.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed), gpt-5.6-sol — backport-reviewer (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Opus: not run (deferred by blocker gate)

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/qt/walletmodel.cpp`:
- [BLOCKING] src/qt/walletmodel.cpp:648-651: Use the CoinJoin balance for unselected CoinJoin controls
  The CoinJoin send dialog calls `UseCoinJoin(true)` but normally has no manually selected inputs. The current `HasSelected()` check therefore returns `getCachedBalance().balance`, which includes unmixed funds, instead of the available fully mixed amount. As a result, “Use available balance” and `prepareTransaction()` can accept an amount greater than the mixed balance before transaction creation fails with insufficient mixed funds. Use the cached anonymized balance when CoinJoin is active, while retaining the wallet calculation for manually selected inputs.

Comment thread src/qt/walletmodel.cpp
Comment on lines +648 to +651
CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
{
return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Blocking: Use the CoinJoin balance for unselected CoinJoin controls

The CoinJoin send dialog calls UseCoinJoin(true) but normally has no manually selected inputs. The current HasSelected() check therefore returns getCachedBalance().balance, which includes unmixed funds, instead of the available fully mixed amount. As a result, “Use available balance” and prepareTransaction() can accept an amount greater than the mixed balance before transaction creation fails with insufficient mixed funds. Use the cached anonymized balance when CoinJoin is active, while retaining the wallet calculation for manually selected inputs.

Suggested change
CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
{
return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance;
}
CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
{
if (control && control->HasSelected()) {
return wallet().getAvailableBalance(*control);
}
if (control && control->IsUsingCoinJoin()) {
return getCachedBalance().anonymized_balance;
}
return getCachedBalance().balance;
}

source: ['codex']

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Resolved in this update — Use the CoinJoin balance for unselected CoinJoin controls no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

knst and others added 12 commits August 6, 2026 22:30
…use model cache

4584d30 GUI: remove now unneeded 'm_balances' field from overviewpage (furszy)
050e8b1 GUI: 'getAvailableBalance', use cached balance if the user did not select UTXO manually (furszy)
96e3264 GUI: use cached balance in overviewpage and sendcoinsdialog (furszy)
321335b GUI: add getter for WalletModel::m_cached_balances field (furszy)
e62958d GUI: sendCoinsDialog, remove duplicate wallet().getBalances() call (furszy)

Pull request description:

  As per the title says, we are recalculating the entire wallet balance on different situations calling to `wallet().getBalances()`, when should instead make use of the wallet model cached balance.

  This has the benefits of (1) not spending resources calculating a balance that we already have cached, and (2) avoid blocking the main thread for a long time, in case of big wallets, walking through the entire wallet's tx map more than what it's really needed.

  Changes:

  1) Fix: `SendCoinsDialog` was calling `wallet().getBalances()` twice during `setModel`.
  2) Use the cached balance if the user did not select any UTXO manually inside the wallet model `getAvailableBalance` call.

  -----------------------
  As an extra note, this work born in [bitcoin#25005](bitcoin#25005) but grew out of scope of it.

ACKs for top commit:
  jarolrod:
    ACK 4584d30
  hebasto:
    re-ACK 4584d30, only suggested changes and commit message formatting since my [recent](bitcoin-core/gui#598 (review)) review.

Tree-SHA512: 6633ce7f9a82a3e46e75aa7295df46c80a4cd4a9f3305427af203c9bc8670573fa8a1927f14a279260c488cc975a08d238faba2e9751588086fea1dcf8ea2b28

Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
a6b0c1f doc: add releases notes for 25504 (listsinceblock updates) (Antoine Poinsot)
0fd2d14 rpc: add an include_change parameter to listsinceblock (Antoine Poinsot)
55f98d0 rpc: output parent wallet descriptors for coins in listunspent (Antoine Poinsot)
b724476 rpc: output wallet descriptors for received entries in listsinceblock (Antoine Poinsot)
55a82ea wallet: allow to fetch the wallet descriptors for a given Script (Antoine Poinsot)

Pull request description:

  Wallet descriptors are useful for applications using the Bitcoin Core wallet as a backend for tracking coins, as they allow to track coins for multiple descriptors in a single wallet. However there is no information currently given for such applications to link a coin with an imported descriptor, severely limiting the possibilities for such applications of using multiple descriptors in a single wallet. This PR outputs the matching imported descriptor(s) for a given received coin in `listsinceblock` (and friends).

  It comes from a need for an application i'm working on, but i think it's something any software using `bitcoind` to track multiple descriptors in a single wallet would have eventually. For instance i'm thinking about the BDK project. Currently, the way to achieve this is to import raw addresses with labels and to have your application be responsible for wallet things like the gap limit.

  I'll add this to the output of `listunspent` too if this gets a few Concept ACKs.

ACKs for top commit:
  instagibbs:
    ACK bitcoin@a6b0c1f
  achow101:
    re-ACK a6b0c1f

Tree-SHA512: 7a5850e8de98b439ddede2cb72de0208944f8cda67272e8b8037678738d55b7a5272375be808b0f7d15def4904430e089dafdcc037436858ff3292c5f8b75e37

Co-authored-by: Andrew Chow <achow101-github@achow101.com>
4fef534 wallet: use GetChange() when computing waste (S3RK)
87e0ef9 wallet: use GetChange() in tx building (S3RK)
15e97a6 wallet: add SelectionResult::GetChange (S3RK)
72cad28 wallet: calculate and store min_viable_change (S3RK)
e3210a7 wallet: account for preselected inputs in target (S3RK)
f8e7963 wallet: add SelectionResult::Merge (S3RK)
06f558e wallet: accurate SelectionResult::m_target (S3RK)
c8cf08e wallet: ensure m_min_change_target always covers change fee (S3RK)

Pull request description:

  Benefits:
  1. more accurate waste calculation for knapsack. Waste calculation is now consistent with tx building code. Before we always assumed change for knapsack even when the solution is changeless4.
  2. simpler tx building code. Only create change output when it's needed
  3. makes it easier to correctly account for fees for CPFP inputs (should be done in a follow up)

  In the first three commits we fix the code to accurately track selection target in `SelectionResult::m_target`
  Then we introduce new variable `min_change` that represents the minimum viable change amount
  Then we introduce `SelectionResult::GetChange()` which incapsulates dropping change for fee logic and uses correct values of `SelectionResult::m_target`
  Then we use `SelectionResult::GetChange()` in both tx building and waste calculation code

  This PR is a refactoring and shouldn't change the behaviour.
  There is only one known small change (arguably a bug fix). Before we dropped change output if it's smaller than `cost_of_change` after paying change fees. This is incorrect as `cost_of_change` already includes `change_fee`.

ACKs for top commit:
  achow101:
    ACK 4fef534
  Xekyo:
    crACK 4fef534
  furszy:
    Code review ACK 4fef534
  w0xlt:
    ACK bitcoin@4fef534

Tree-SHA512: 31a7455d4129bc39a444da0f16ad478d690d4d9627b2b8fdb5605facc6488171926bf02f5d7d9a545b2b59efafcf5bb3d404005e4da15c7b44b3f7d441afb941

Co-authored-by: Andrew Chow <github@achow101.com>
…nwallet/rescanblockchain/)

e90a445 scripted-diff: rpc: fix rescan RPC name (s/rescanwallet/rescanblockchain/) (Sebastian Falbesoner)

Pull request description:

  There is no RPC call named `rescanwallet`, i.e. fix this by renaming to the actual RPC called `rescanblockchain`.

ACKs for top commit:
  achow101:
    ACK e90a445
  aureleoules:
    ACK e90a445.
  promag:
    ACK e90a445

Tree-SHA512: abf1d1c18de32d87c29e4ff2b782dfb0e4a46dc2c2cc51ab616d12674a0f4a5d22214e00955663ae897cbb88f4f6ced913850f28ea3f5c1b3a54577a25fbf399

Co-authored-by: Andrew Chow <achow101-github@achow101.com>
…tion chains

3405f3e test: Test that an unconfirmed not-in-mempool chain is rebroadcast (Andrew Chow)
10d91c5 wallet: Deduplicate Resend and ReacceptWalletTransactions (Andrew Chow)

Pull request description:

  Currently `ResendWalletTransactions` (used for normal rebroadcasts) will attempt to rebroadcast all of the transactions in the wallet in the order they are stored in `mapWallet`. This ends up being random as `mapWallet` is a `std::unordered_map`. However `ReacceptWalletTransactions` (used for adding to the mempool on loading) first sorts the txs by wallet insertion order, then submits them. The result is that `ResendWalletTranactions` will fail to rebroadcast child transactions if their txids happen to be lexicographically less than their parent's txid. This PR resolves this issue by combining `ReacceptWalletTransactions` and `ResendWalletTransactions` into a new `ResubmitWalletTransactions` so that the iteration code and basic checks are shared.

  A test has also been added that checks that such transaction chains are rebroadcast correctly.

ACKs for top commit:
  naumenkogs:
    utACK 3405f3e
  1440000bytes:
    reACK bitcoin@3405f3e
  furszy:
    Late code review ACK 3405f3e
  stickies-v:
    ACK 3405f3e

Tree-SHA512: 1240d9690ecc2ae8d476286b79e2386f537a90c41dd2b8b8a5a9c2a917aa3af85d6aee019fbbb05e772985a2b197e2788305586d9d5dac78ccba1ee5aa31d77a

Co-authored-by: glozow <gloriajzhao@gmail.com>
fa1ce96 test: Add missing syncwithvalidationinterfacequeue (MacroFake)
faa4916 test/doc: Remove unused syncwithvalidationinterfacequeue (MacroFake)

Pull request description:

  Fixes bitcoin#26071

ACKs for top commit:
  achow101:
    ACK fa1ce96
  glozow:
    ACK fa1ce96
  w0xlt:
    ACK bitcoin@fa1ce96

Tree-SHA512: d1e101b55477360ead2b99ade5d42b922aabe293ec84fb26764e29161c5be6c534aef6f22d2cc5ea63a4bd6b6e77b701f1a7a2283b8e7e815d343a604cd77656

Co-authored-by: Andrew Chow <github@achow101.com>
… BDB-only wallets

9f3a315 test: Fix `wallet_listsinceblock.py` for BDB-only wallets (Hennadii Stepanov)
1941ce6 test: Fix `wallet_basic.py` for BDB-only wallets (Hennadii Stepanov)

Pull request description:

  Fixes bitcoin#26029.

ACKs for top commit:
  brunoerg:
    crACK 9f3a315

Tree-SHA512: d31c76e558dedea689ff487644e9f2d2f1df1cc2bb9bb041ede4b272884871167fdb19ccc717394c6ba6af8b8c70e9575b344988e0ce55b241a3a4922d0b7f73

Co-authored-by: MacroFake <falke.marco@gmail.com>
…mic fees in wallet_groups.py

BACKPORT NOTE:
This backport pinned every node to 20 duffs/byte via `-paytxfee`, but the
`maxapsfee` expectations were left at their dynamic-fee values. Upstream had
already recomputed them for 20 sat/vB before that commit landed, so it carried
no such update and the mismatch was invisible in the diff.

The expected debug lines still spelled out the transaction sizes (225/372 and
519/813 bytes) rather than the fees the wallet now logs, and the `maxapsfee`
thresholds still bracketed the un-pinned grouped/non-grouped delta of 294
duffs instead of 5880, so node 3 picked the non-grouped solution where the test
expects the grouped one.

------------

2186608 test: apply fixed feerate to avoid variable dynamic fees (stickies-v)

Pull request description:

  Without specifying a feerate, we let the wallet decide on an appropriate feerate, which can be influenced by various factors
  such as what's in the mempool. Since wallet_groups.py fails when feerates are unstable, we should use a fixed feerate across all nodes. The assumed feerate was 20 sats/vbyte, so this PR adopts that.

  Closes bitcoin#25940. I'm not 100% sure, but I think the increased tx relay speed introduced by bitcoin#25865 caused the transactions to more quickly and often enter the other nodes' mempools, affecting their feerate calculation done in [`wallet:GetMinimumFeeRate()`](https://github.com/bitcoin/bitcoin/blob/ea67232cdb80c4bc3f16fcd823f6f811fd8903e1/src/wallet/fees.cpp#L68-L72) and thus deviating slightly from the expected 20 sats/vbyte.

  Ran `wallet_groups.py` over 400 times without failure.

ACKs for top commit:
  aureleoules:
    ACK 2186608.
  glozow:
    Approach ACK 2186608

Tree-SHA512: 0ea467a67747e6f27369ccd0adacfb21cc36ef0ae728fb28b8ea18e409aab5bd3ede559d6cebb82da0b9703c0c8b2709d686feb3ae009ddf525aa253f44d5816

Co-authored-by: MacroFake <falke.marco@gmail.com>
…rrupt descriptor causes a fatal error

e066763 wallet: coverage for loading an unknown descriptor (furszy)
d26c3cc wallet: bugfix, load wallet with an unknown descriptor cause fatal error (furszy)

Pull request description:

  Fixes bitcoin#26015

  If the descriptor entry is unrecognized (due a soft downgrade) or corrupt, the
  unserialization fails and `LoadWallet`, instead of stop there and return the error,
  continues reading all the db records. As other records tied to the unrecognized
  or corrupt descriptor are scanned, a fatal error is being thrown.

  This fixes it by catching the descriptor parse failure and return which wallet failed.
  Logging its name/path, so the user can remove it from the settings file, to prevent
  its load at startup.

  Note: added the test in a separate file intentionally.
  Will continue adding coverage for the wallet load process in follow-up PRs.

ACKs for top commit:
  achow101:
    ACK e066763
  Sjors:
    re-utACK e066763

Tree-SHA512: d1f1a5d7e944c89c97a33b25b4411a36a11edae172c22f8524f69c84a035f84c570b284679f901fe60f1300f781b76a6c17b015a8e7ad44ebd25a0c295ef260f

Co-authored-by: Andrew Chow <github@achow101.com>
b01682a refactor: revert m_next_resend to not be std::atomic (stickies-v)
9245f45 wallet: only update m_next_resend when actually resending (stickies-v)
7fbde8a refactor: carve out tx resend timer logic into ShouldResend (stickies-v)
01f3534 refactor: remove unused locks for ResubmitWalletTransactions (stickies-v)
c6e8e11 wallet: fix capitalization in docstring (stickies-v)

Pull request description:

  This PR addresses the outstanding comments/issues from bitcoin#25768:

  - capitalization [typo](bitcoin#25768 (comment)) in docstring
  - remove [unused locks](bitcoin@01f3534) that we previously needed for `ReacceptWalletTransactions()`
  - before bitcoin#25768, only `ResendWalletTransactions()` would reset `m_next_resend` (formerly called `nNextResend`). By unifying it with `ReacceptWalletTransactions()` into `ResubmitWalletTransactions()`, the number of callsites that would reset the `m_next_resend` timer increased
    - since `m_next_resend` is only used in case of `relay=true` (formerly `ResendWalletTransactions()`), this is unintuitive
    - it leads to [unexpected behaviour](bitcoin#25768 (comment)) such as transactions potentially never being rebroadcasted.
    - it makes the ResubmitWalletTransactions()` logic [more complicated than strictly necessary](bitcoin#25768 (comment))
    - since bitcoin#25768, we relied on an earlier call of `ResubmitWalletTransactions(relay=false, force=true)` to initialize `m_next_resend()`, I think we can more elegantly do that by just providing `m_next_resend` with a default value
    - just to highlight: this commit introduces behaviour change

  Note: the `if (!fBroadcastTransactions)` in `CWallet:ShouldResend()` is duplicated on purpose, since it potentially avoids the slightly more expensive `if (!chain().isReadyToBroadcast())` check afterwards. I don't have a strong view on it, so happy to remove that additional check to reduce the diff, too.

ACKs for top commit:
  aureleoules:
    ACK b01682a
  achow101:
    ACK b01682a

Tree-SHA512: ac5f1d8858f8dd736dd1480f385984d660c1916b62a42562317020e8f9fd6a30bd8f23d973d47e4c9480d744c5ba39fdbefd69568a5eb0589a8422d7e5971c1c

Co-authored-by: fanquake <fanquake@gmail.com>
…g target

BACKPORT NOTE to Dash Core
Kept upstream's numbers even though Dash reads `SetInputWeight()` through
`GetVirtualTransactionSize(nSize, 0, 0)`, which is the identity here rather than
upstream's weight-to-vsize division: the input costs 148 bytes instead of 37, so
the coin's effective value is 99556 rather than 99889. Either way it stays below
the 99900 target, which is what the test needs.

----

d0d9cf7 test: Check external coin effective value is used in CoinSelection (Aurèle Oulès)
76b79c1 wallet: Use correct effective value when checking target (Aurèle Oulès)

Pull request description:

  Fixes bitcoin#26185. The following assert failed because it was not checked in the parent function.

  https://github.com/bitcoin/bitcoin/blob/2bd9aa5a44b88c866c4d98f8a7bf7154049cba31/src/wallet/coinselection.cpp#L391

ACKs for top commit:
  glozow:
    reACK d0d9cf7
  furszy:
    ACK d0d9cf7

Tree-SHA512: e126daba1115e9d143f2a582c6953e7ea55e96853b6e819c7744fd7a23668f7d9854681d43ef55d8774655bc54e7e87c1c9fccd746d9e30fbf3caa82ef808ae9

Co-authored-by: glozow <gloriajzhao@gmail.com>
…ype acquisition

Dash BACKPORT NOTE:
- upstream's `is_from_p2sh` flag feeds `GetOutputType(type, is_from_p2sh)` to
  tell P2SH-P2WPKH/P2SH-P2WSH apart from plain P2SH, and `CoinsResult::Add()`
  only exists on the `std::map<OutputType, ...>` shape introduced by
  bitcoin#25734. Dash has neither segwit nor that shape (see `partial
  bitcoin#24584`), so the flag is dropped and the existing `switch (type)` over
  `result.legacy` / `result.other` is kept as is.
- the `if (!ExtractDestination(...)) continue;` early-out disappears, matching
  upstream: `Solver` already yields the script hash for `TxoutType::SCRIPTHASH`
  and cannot fail for it.

58b7df3 wallet: AvailableCoins, simplify output script type acquisition (furszy)

Pull request description:

  There is an unnecessary `ExtractDestination()` call and subsequent result parse into an `CScriptID`.

  The `Solver()` call, which we are already doing below anyway, retrieves the script type and, in the P2SH case, the program id.

ACKs for top commit:
  achow101:
    ACK 58b7df3
  aureleoules:
    re-ACK 58b7df3
  rajarshimaitra:
    ACK 58b7df3
  w0xlt:
    ACK bitcoin@58b7df3

Tree-SHA512: 51080766877c34cb2232ee3a1cb6b6a62b829c9297c67b99577742b94854a737a74d248015a4603ca9b6cd0a3c9e1d6d78673ff3cc9fc65dd82deea72dc537fd

Co-authored-by: Andrew Chow <github@achow101.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@knst
knst requested review from PastaPastaPasta and UdjinM6 August 6, 2026 15:31
@thepastaclaw

Copy link
Copy Markdown

Rechecked the force-pushed head c2bd65e791acb793b15506f8913328cc939d12d0 after the latest CodeRabbit full review.

  • The unselected CoinJoin balance blocker is now addressed: WalletModel::getAvailableBalance() returns the cached anonymized balance when IsUsingCoinJoin() is set.
  • Two previously validated Dash-specific issues remain:
    • WalletBalances::balanceChanged() still does not compare denominated_trusted or denominated_untrusted_pending, so the advanced CoinJoin progress cache can retain stale denomination values.
    • The no-selection fallback still returns getCachedBalance().balance when fAllowWatchOnly is set, so private-keys-disabled watch-only sends can fail the upfront balance check instead of using their solvable watch-only amount.

CodeRabbit's latest run reported no new actionable comments, but it skipped the relevant files as similar to previously reviewed changes, so that result does not clear these existing threads.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Final validation — Codex + Sonnet

Carried-forward prior findings: the sole blocking finding, "Use the CoinJoin balance for unselected CoinJoin controls," is FIXED at the current head because unselected CoinJoin controls now use the cached anonymized balance. New latest-delta findings: none; the cumulative backport review found no remaining in-scope correctness, Dash-integration, test-adaptation, or prerequisite issues.

Source: reviewers gpt-5.6-sol (general, dash-core-commit-history, backport-reviewer) and claude-sonnet-5 (dash-core-commit-history, backport-reviewer, plus a fresh general retry after the initial general attempt failed the raw-JSON contract); final verifier gpt-5.6-sol (codex). The openclaw-agent coordinator is orchestration-only.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed), gpt-5.6-sol — backport-reviewer (completed)
  • Verifier: gpt-5.6-sol — final-verifier (Sol fallback after Sonnet verifier contract failures)
  • Sonnet reviewers: claude-sonnet-5 — general (failed), claude-sonnet-5 — dash-core-commit-history (completed), claude-sonnet-5 — backport-reviewer (completed), claude-sonnet-5 — general (completed)

@thepastaclaw

Copy link
Copy Markdown

Follow-up on the automated final validation at c2bd65e791acb793b15506f8913328cc939d12d0: it correctly confirms that the unselected CoinJoin balance blocker is fixed, but it does not clear two earlier validated Dash-specific issues that are still present at this same head:

The latest CodeRabbit full review produced no new actionable comments. These two existing findings still need an author-side Dash adaptation before merge.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Final validation — Codex + Sonnet

Carried-forward prior context: the previously indexed blocker, "Use the CoinJoin balance for unselected CoinJoin controls," is FIXED, while the two previously omitted external threads remain valid blockers because advanced CoinJoin progress can retain stale denominated balances and unselected watch-only controls still use the spendable-key cache. New latest-delta findings: none; both active blockers arise from cumulative behavior introduced by the GUI balance-cache backport rather than the latest eight-line CoinJoin fix. Source: reviewers gpt-5.6-sol (general, dash-core-commit-history, backport-reviewer) and claude-sonnet-5 (dash-core-commit-history, backport-reviewer, plus a fresh general retry after the initial general attempt failed the raw-JSON contract); final verifier gpt-5.6-sol (codex). The openclaw-agent coordinator is orchestration-only.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed), gpt-5.6-sol — backport-reviewer (completed)
  • Verifier: gpt-5.6-sol — final-verifier (Sol fallback after Sonnet verifier contract failures)
  • Sonnet reviewers: claude-sonnet-5 — general (failed), claude-sonnet-5 — dash-core-commit-history (completed), claude-sonnet-5 — backport-reviewer (completed), claude-sonnet-5 — general (completed)

🔴 2 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/qt/overviewpage.cpp`:
- [BLOCKING] src/qt/overviewpage.cpp:404: Refresh CoinJoin progress from uncached denominated balances
  The backport replaces the advanced CoinJoin view's direct `wallet().getBalances()` call with `getCachedBalance()`, but `WalletBalances::balanceChanged()` does not compare `denominated_trusted` or `denominated_untrusted_pending`. These fields can change without any compared field changing: while CoinJoin is disabled, `GetBalance()` leaves both denominated fields at zero; after CoinJoin is re-enabled, a wallet containing denominated but not fully mixed outputs repopulates them while its total, pending, immature, and anonymized balances remain unchanged. `checkBalanceChanged()` then declines to assign the new value, and the advanced progress calculation continues using stale zero denominated balances. Include both denominated fields in cache invalidation, or retain an uncached balance query for the advanced CoinJoin calculation.

In `src/qt/walletmodel.cpp`:
- [BLOCKING] src/qt/walletmodel.cpp:648-656: Honor watch-only coin control without manual inputs
  `SendCoinsDialog` sets `fAllowWatchOnly` for private-keys-disabled wallets before both "Use available balance" and `prepareTransaction()`. When no inputs are manually selected, this method nevertheless returns `getCachedBalance().balance`, which contains spendable-key funds and excludes the separately cached watch-only balance. The wallet-level `getAvailableBalance(*control)` path applies `fAllowWatchOnly`, filters for solvable watch-only outputs, and was used before this backport. As a result, a watch-only wallet can display funds but receive `AmountExceedsBalance` before it can create its unsigned PSBT. Delegate to the wallet calculation whenever `fAllowWatchOnly` is set.

Comment thread src/qt/overviewpage.cpp
QString strCoinJoinAmount = BitcoinUnits::formatHtmlWithUnit(m_display_bitcoin_unit, clientModel->coinJoinOptions().getAmount() * COIN, false, BitcoinUnits::SeparatorStyle::ALWAYS);

if(m_balances.balance == 0)
const auto& balances = walletModel->getCachedBalance();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Blocking: Refresh CoinJoin progress from uncached denominated balances

The backport replaces the advanced CoinJoin view's direct wallet().getBalances() call with getCachedBalance(), but WalletBalances::balanceChanged() does not compare denominated_trusted or denominated_untrusted_pending. These fields can change without any compared field changing: while CoinJoin is disabled, GetBalance() leaves both denominated fields at zero; after CoinJoin is re-enabled, a wallet containing denominated but not fully mixed outputs repopulates them while its total, pending, immature, and anonymized balances remain unchanged. checkBalanceChanged() then declines to assign the new value, and the advanced progress calculation continues using stale zero denominated balances. Include both denominated fields in cache invalidation, or retain an uncached balance query for the advanced CoinJoin calculation.

source: ['codex']

Comment thread src/qt/walletmodel.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RPC Some notable changes to RPC params/behaviour/descriptions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants