Skip to content

fix: stop fish completion from re-running the typed dash-cli command - #7783

Merged
PastaPastaPasta merged 2 commits into
dashpay:developfrom
PastaPastaPasta:fix/stop-fish-completion-from-re-running-the-typed-d
Oct 4, 2026
Merged

PastaPastaPasta merged 2 commits into
dashpay:developfrom
PastaPastaPasta:fix/stop-fish-completion-from-re-running-the-typed-d

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

The fish completion for dash-cli (contrib/completions/fish/dash-cli.fish, imported from bitcoin#24611) builds its suggestions by running the command line the user has typed so far, with help or -help appended. Once an RPC command has been typed, everything after it is passed to the node as RPC parameters, so the appended help does not ask for help: it becomes one more parameter of the typed command, and the command runs.

For anyone who has installed this completion, pressing Tab after a complete line such as dash-cli sendtoaddress <address> 1 sends the coins before Enter is pressed, with help as the wallet comment. Each Tab runs the line several times, because every complete rule's --condition calls the helper again. Pressing Enter afterwards sends once more. The same applies to any RPC that accepts a trailing string parameter. A leading -generate reserves a new wallet address on each Tab.

Why this is a real problem

Code path at c14104b:

  • dash-cli.fish#L5 takes every completed token with commandline -oc. L13-L16 strip only a bare help and -stdin*, and L19 runs $cmd help. L63 and L65 run $cmd -help the same way.
  • All three rules (L75-L99) call the helper from --condition, which fish evaluates on every Tab.
  • src/util/system.cpp#L262-L276: the first non-dash argument is the command. All later argv entries, including help and -help, are copied into the command arguments without being parsed. src/bitcoin-cli.cpp#L1207-L1212 sends args[0] as the method.
  • src/wallet/rpc/spend.cpp#L238: the third sendtoaddress parameter is an optional string comment, so help is accepted and the send goes ahead.

Reproduction against the unfixed tree. A fresh regtest dashd is built from this branch, wallet w1 is funded, and w2 provides the destination address. One Tab is simulated with fish 4.9.3 complete -C '<line>', which evaluates the completion rules exactly as an interactive Tab does. Enter is never pressed. Script: regtest-repro.sh (included below).

Unfixed: one Tab after a typed sendtoaddress line sends 5 DASH
$ git rev-parse --short HEAD
c14104b172a2
$ regtest-repro.sh $PWD
== completion output ==
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 getblockc':
    getblockchaininfo
    getblockcount
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoa':
    sendtoaddress	"address" amount ( "comment" "comment_to" subt
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -rpcw':
    -rpcwait
    -rpcwaittimeout=
    -rpcwallet=
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 help getblockc':
    getblockchaininfo
    getblockcount
== sendtoaddress ==
w1 txs before Tab: 0 sends
w2 balance before Tab (minconf 0): 0.00000000
$ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoaddress yYY9kJyUeiJJRU9nAEsx5Nu2wXZEjK4CnD 1 '"   # one Tab press, Enter never pressed
w1 txs after Tab:  5 sends
w2 balance after Tab (minconf 0): 5.00000000
mempool size:   "size": 5,
comments on the w1 sends:
   2     "comment": "-help",
   3     "comment": "help",
== -generate ==
w1 before Tab:   "keypoolsize": 1000,, blocks: 110
$ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -generate '"   # one Tab press, Enter never pressed
w1 after Tab:    "keypoolsize": 999,, blocks: 110

To show exactly what the completion executes, the same line was also completed with a stand-in dash-cli on PATH that only logs its arguments:

Unfixed: commands run by the completion for one Tab
$ git rev-parse --short HEAD
c14104b172a2
$ stub-repro.sh $PWD
### Tab after: 'dash-cli -regtest '
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest -help
  ran: dash-cli -regtest -help
### Tab after: 'dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 '
  ran: dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 help
  ran: dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 help
### Tab after: 'dash-cli -regtest -generate '
  ran: dash-cli -regtest -generate help
  ran: dash-cli -regtest -generate help
  ran: dash-cli -regtest -generate help
  ran: dash-cli -regtest -generate -help
  ran: dash-cli -regtest -generate -help
### Tab after: 'dash-cli -regtest -stdin '
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest -stdin -help
  ran: dash-cli -regtest -stdin -help
regtest-repro.sh
#!/bin/sh
# Usage: regtest-repro.sh <worktree>
# Starts a fresh regtest dashd from <worktree>/src, funds wallet w1, then asks
# fish for completions (exactly what one Tab press does) of a fully typed but
# not yet submitted `sendtoaddress` line and of `-generate `, and reports what
# changed on the node. Enter is never pressed.
WT=$1
P=$(cd "$(dirname "$0")" && pwd)
FISH=fish
D=$P/regtest-datadir
rm -rf "$D"; mkdir -p "$D"
export PATH=$WT/src:$PATH
CLI="dash-cli -regtest -datadir=$D -rpcport=19876"
"$WT/src/dashd" -regtest -datadir="$D" -rpcport=19876 -port=19877 -listen=0 -fallbackfee=0.0001 -daemon >/dev/null
$CLI -rpcwait getblockcount >/dev/null
$CLI createwallet w1 >/dev/null
$CLI createwallet w2 >/dev/null
$CLI -rpcwallet=w1 generatetoaddress 110 "$($CLI -rpcwallet=w1 getnewaddress)" >/dev/null
ADDR=$($CLI -rpcwallet=w2 getnewaddress)

tab() {
  echo "\$ fish -c \"source dash-cli.fish; complete -C '$1'\"   # one Tab press, Enter never pressed"
  "$FISH" --no-config -c "source $WT/contrib/completions/fish/dash-cli.fish; complete -C '$1' >/dev/null"
}

echo "== completion output =="
for l in "$CLI getblockc" "$CLI -rpcwallet=w1 sendtoa" "$CLI -rpcwallet=w1 -rpcw" "$CLI help getblockc"; do
  echo "Tab after '$(echo "$l" | sed "s|$D|DATADIR|")':"
  "$FISH" --no-config -c "source $WT/contrib/completions/fish/dash-cli.fish; complete -C '$l'" | cut -c1-60 | sed 's/^/    /'
done

echo "== sendtoaddress =="
echo "w1 txs before Tab: $($CLI -rpcwallet=w1 listtransactions '*' 1000 | grep -c '"category": "send"') sends"
echo "w2 balance before Tab (minconf 0): $($CLI -rpcwallet=w2 getreceivedbyaddress $ADDR 0)"
tab "$CLI -rpcwallet=w1 sendtoaddress $ADDR 1 "
echo "w1 txs after Tab:  $($CLI -rpcwallet=w1 listtransactions '*' 1000 | grep -c '"category": "send"') sends"
echo "w2 balance after Tab (minconf 0): $($CLI -rpcwallet=w2 getreceivedbyaddress $ADDR 0)"
echo "mempool size: $($CLI getmempoolinfo | grep '"size"')"
echo "comments on the w1 sends:"
$CLI -rpcwallet=w1 listtransactions '*' 1000 | grep '"comment"' | sort | uniq -c

echo "== -generate =="
echo "w1 before Tab: $($CLI -rpcwallet=w1 getwalletinfo | grep '"keypoolsize"'), blocks: $($CLI getblockcount)"
tab "$CLI -rpcwallet=w1 -generate "
echo "w1 after Tab:  $($CLI -rpcwallet=w1 getwalletinfo | grep '"keypoolsize"'), blocks: $($CLI getblockcount)"

$CLI stop >/dev/null
sleep 3

Why it matters

Pressing Tab is expected to be harmless. With this completion installed, Tab can broadcast a payment the user has not confirmed. It does so several times per keypress, so a later Enter produces a duplicate payment. Any other state-changing RPC that tolerates the extra parameter runs early in the same way. The scope is limited: the completion is opt-in and not installed by the build, it needs working RPC credentials and an unlocked wallet, and the user must already have typed the full command. Nothing is reachable remotely. The effect is still an unintended spend of the user's own funds.

What was done?

Only contrib/completions/fish/dash-cli.fish changes. The first commit is the fix; the second replaces the explicit option list with prefix matching.

  • __fish_dash_cli_get_commands_helper now runs help with only the executable and the connection options typed before the RPC command, matched by prefix: -conf, -datadir, -testnet, -regtest, -devnet, -chain, and every -rpc* option except -rpcwait* (which would make Tab hang while the node is down). This is the same prefix approach as the dash-cli bash completion, so new -rpc* connection options need no edits here. It stops at the first non-dash token, so the RPC command and its arguments are never passed on. Other leading options are dropped, including -generate, -getinfo, -netinfo, -addrinfo, -named, -rpcwait* and -stdin*. This replaces the old ad hoc stripping of help and -stdin*, which the allowlist covers.
  • __fish_dash_cli_get_options runs -help on the bare executable ($cmd[1]). The option list does not depend on the rest of the line, and the other Dash completion scripts (dash-tx.fish, dash-wallet.fish, dash-util.fish, dashd.fish) already do this.

Why this is the correct minimal fix

The root cause is that the completion re-executes user input. The fix stops passing that input on, and keeps only what is needed to reach the same node and wallet (datadir, conf, network, RPC endpoint and credentials, wallet). An allowlist is used because a denylist would have to keep up with every dash-cli option that changes what gets executed. Some leading options are themselves commands: -generate calls getnewaddress before it validates its arguments. Stripping only help would not help, because any typed RPC still runs. Excluding specific RPCs would always miss some.

Left unchanged on purpose: the completion rules, the output parsing, and the -help/-? early returns. The helper is still called once per rule on each Tab, which now only issues the read-only help RPC. Caching it, or adding a default client timeout, would be separate improvements. Bitcoin Core's bitcoin-cli.fish has the same pattern.

How Has This Been Tested?

No automated test was added. The repository has no harness for shell completion scripts, and the behaviour was checked end to end against a real node instead. Environment: macOS arm64, dashd/dash-cli built from this branch, fish 4.9.3.

  • regtest-repro.sh before the fix: one Tab after sendtoaddress <w2 address> 1 produced 5 sends from w1 (5 DASH received by w2, 5 transactions in the mempool, comments help ×3 and -help ×2). The -generate Tab reduced the keypool from 1000 to 999. Output is above.
  • regtest-repro.sh after the fix: no sends, w2 balance 0, empty mempool, keypool unchanged. Command, help <command> and option completion return the same suggestions as before.
Fixed: same script
$ git diff --stat
 contrib/completions/fish/dash-cli.fish | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
$ regtest-repro.sh $PWD
== completion output ==
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 getblockc':
    getblockchaininfo
    getblockcount
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoa':
    sendtoaddress	"address" amount ( "comment" "comment_to" subt
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -rpcw':
    -rpcwait
    -rpcwaittimeout=
    -rpcwallet=
Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 help getblockc':
    getblockchaininfo
    getblockcount
== sendtoaddress ==
w1 txs before Tab: 0 sends
w2 balance before Tab (minconf 0): 0.00000000
$ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoaddress ya4Gcphm7nFvTRuHjLqnmqh6W6tkhjmvfL 1 '"   # one Tab press, Enter never pressed
w1 txs after Tab:  0 sends
w2 balance after Tab (minconf 0): 0.00000000
mempool size:   "size": 0,
comments on the w1 sends:
== -generate ==
w1 before Tab:   "keypoolsize": 1000,, blocks: 110
$ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -generate '"   # one Tab press, Enter never pressed
w1 after Tab:    "keypoolsize": 1000,, blocks: 110
Fixed: commands run by the completion for one Tab (logging stand-in)
$ git diff --stat
 contrib/completions/fish/dash-cli.fish | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
$ stub-repro.sh $PWD
### Tab after: 'dash-cli -regtest '
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -help
  ran: dash-cli -help
### Tab after: 'dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 '
  ran: dash-cli -regtest -rpcwallet=w1 help
  ran: dash-cli -regtest -rpcwallet=w1 help
### Tab after: 'dash-cli -regtest -generate '
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -help
  ran: dash-cli -help
### Tab after: 'dash-cli -regtest -stdin '
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -regtest help
  ran: dash-cli -help
  ran: dash-cli -help
  • After switching to prefix matching (second commit), the regtest check was repeated: command, help <command>, option and -rpcwait line completions return the expected suggestions; Tab after the sendtoaddress line and after -generate leaves w1 with 0 sends, keypool 1000 and an empty mempool; with the node stopped, Tab after -rpcwait getblockc returns immediately. A logging stand-in confirmed that every connection option (-conf, -datadir, -testnet, -regtest, -devnet, -chain, -rpcconnect, -rpcport, -rpcuser, -rpcpassword, -rpccookiefile, -rpcwallet, -rpcclienttimeout) is passed on and -rpcwait, -rpcwaittimeout, -stdin*, -named, -generate, -getinfo, -netinfo are not.
  • fish --no-execute contrib/completions/fish/dash-cli.fish succeeds (syntax check). fish_indent reports no changes in the edited hunks.
  • test/lint/lint-whitespace.py passes.

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

@thepastaclaw

thepastaclaw commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

🕓 Review not started yet because the new head is waiting for the 30-minute push debounce.

  • Request normal review — click when the PR is ready for review.
  • Request priority review — click to move this review to the front of the queue.

Commit 5339d4f. Normal review starts when eligible; priority review starts as soon as a slot is available.

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b40cf4a8-ecb0-4390-9af4-ef4fe8b9f10a
📥 Commits

Reviewing files that changed from the base of the PR and between ff98899 and 5339d4f.

📒 Files selected for processing (1)
  • contrib/completions/fish/dash-cli.fish

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.


Walkthrough

The Fish completion helper builds command-help arguments from the first command-line token and recognized connection options that appear before the first non-option argument. Option completion invokes -help on the first command-line token. Existing filters for options ending in = remain.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 5339d

The completion change avoids rerunning typed RPC commands while preserving supported connection options; no actionable merge risk is established.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 5339d

The change substantially reduces accidental command execution during completion. A limited uncertainty remains: removing explicit safety overrides could allow configuration-enabled stateful behavior during command-help lookup.

Retained concerns

  • Low · security · inferred: Command-help construction drops explicit safety overrides such as -nogenerate while still loading configuration. If generation is enabled through accepted configuration, completion may allocate a wallet address despite the user's disabling flag. The general configuration-driven path predates this PR; loss of the explicit override is the potential regression.
Security review details

Security Blast Radius

  • inferred — The relevant exposure is an installed completion invoking the selected node and wallet under the local user's existing RPC credentials. The inspected change does not introduce a new credential identity or broader server authority.

Security Findings and Attack Paths

  • inferred — The conditional concern requires configuration enabling a stateful CLI mode and an explicit disabling option that the new filter discards. No remote unauthenticated attack path was established. Ordinary typed state-changing RPC methods and their parameters are excluded by the new construction.

Trust Boundaries and Controls

  • observed — Option lookup now has a strong local control: executable-only -help returns before configuration loading, stdin handling, or RPC dispatch. Command lookup instead relies on token filtering before entering the existing authenticated RPC path.

Resilience and Maintainability Implications

  • inferred — If generation mode is effective, dispatch requests a new wallet address before subsequent argument processing. A later failure does not imply that allocation was undone, and repeated completion evaluations can repeat the request. This ordering predates the PR but matters to the conditional override regression.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
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.
Title check ✅ Passed The title clearly summarizes the main change: preventing fish completion from re-running the typed dash-cli command.
Description check ✅ Passed The description explains the completion bug, the fix, its impact, and the reported test results. It is directly related to the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Phase 2 only (queue backlog)

Static verification at head 6442f5c confirms that the completion no longer forwards the typed RPC or execution-changing options, addressing the unintended-command execution. One non-blocking compatibility regression remains: supported double-dash connection options are discarded. The supplied CI snapshot reports successful lint and several builds, with additional jobs pending and PR-title validation failing; no local builds or tests were run.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: dash-core-commit-history); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: low by gpt-6.1-sol (effort low) — The diff is a small, contained fish-completion fix that filters arguments used for help queries without changing funds-movement implementation or other critical surfaces.
  • Phase 1 reviewers: not run (skipped for throughput: 22 PRs queued, above the 10 limit)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort medium); agent phase2-reviewer, gpt-6.1-sol — dash-core-commit-history (completed, effort medium); agent phase2-reviewer
🤖 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 `contrib/completions/fish/dash-cli.fish`:
- [SUGGESTION] contrib/completions/fish/dash-cli.fish:18: Preserve supported double-dash connection options
  ArgsManager::ParseParameters explicitly normalizes `--foo` to `-foo` in src/util/system.cpp:279–281, so double-dash connection options are valid dash-cli input. This new allowlist silently drops those spellings. For example, completing `dash-cli --regtest --datadir=/path/to/regtest getblockc` now requests help using the default configuration and network instead of the selected regtest node; `--rpcwallet=w1` is likewise discarded rather than selecting that wallet's endpoint. This can return suggestions from the wrong node or no RPC suggestions when the default connection fails. Accept either dash spelling for the same allowlisted names; this preserves connection selection without forwarding the typed RPC or execution-changing options.

Comment thread contrib/completions/fish/dash-cli.fish Outdated
set --local base $cmd[1]
for arg in $cmd[2..-1]
string match --quiet --regex -- '^-' $arg; or break
if string match --quiet --regex -- '^-(conf|datadir|testnet|regtest|devnet|chain|rpcconnect|rpcport|rpcuser|rpcpassword|rpccookiefile|rpcwallet|rpcclienttimeout)(=|$)' $arg

@thepastaclaw thepastaclaw Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

✅ Resolved at ff98899d; see the replies below.

🟡 Suggestion: Preserve supported double-dash connection options

ArgsManager::ParseParameters explicitly normalizes --foo to -foo in src/util/system.cpp:279–281, so double-dash connection options are valid dash-cli input. This new allowlist silently drops those spellings. For example, completing dash-cli --regtest --datadir=/path/to/regtest getblockc now requests help using the default configuration and network instead of the selected regtest node; --rpcwallet=w1 is likewise discarded rather than selecting that wallet's endpoint. This can return suggestions from the wrong node or no RPC suggestions when the default connection fails. Accept either dash spelling for the same allowlisted names; this preserves connection selection without forwarding the typed RPC or execution-changing options.

Suggested change
if string match --quiet --regex -- '^-(conf|datadir|testnet|regtest|devnet|chain|rpcconnect|rpcport|rpcuser|rpcpassword|rpccookiefile|rpcwallet|rpcclienttimeout)(=|$)' $arg
if string match --quiet --regex -- '^--?(conf|datadir|testnet|regtest|devnet|chain|rpcconnect|rpcport|rpcuser|rpcpassword|rpccookiefile|rpcwallet|rpcclienttimeout)(=|$)' $arg

source: gpt-6.1-sol (phase2-reviewer: general)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Valid, thanks. Fixed in ff98899: the allowlist pattern is now ^--?(conf|datadir|...), so --regtest, --datadir=… and --rpcwallet=… are passed on just like their single-dash forms. Rechecked with fish: dash-cli --regtest --datadir=/tmp/x getblockc<Tab> now runs dash-cli --regtest --datadir=/tmp/x help, and --stdin is still dropped.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Resolved (re-reviewed at ff98899d): Confirmed your fix at ff98899: line 18 now uses ^--?, preserving both supported dash spellings for the allowlisted connection options, consistent with ArgsManager's normalization. The allowlist still excludes --stdin and execution-changing options, and the loop stops before the typed RPC and its arguments.

@thepastaclaw thepastaclaw added the pastaclaw:commented thepastaclaw's latest review was comment-only label Oct 4, 2026
@PastaPastaPasta PastaPastaPasta changed the title fix(contrib): stop fish completion from re-running the typed dash-cli command fix: stop fish completion from re-running the typed dash-cli command Oct 4, 2026
… command

The dash-cli fish completion fetched the RPC command list by running the
whole typed command line with `help` appended, and the option list by
running it with `-help` appended. Everything after the first non-dash
token is passed to the RPC as a parameter, so pressing Tab after a
complete line such as `sendtoaddress <address> <amount>` executed it,
several times per Tab, with "help" as the comment. A leading `-generate`
likewise reserved a new address on each Tab.

Fetch the command list using only the executable and the connection
options typed before the RPC command, and fetch the option list from
the bare executable, which does not depend on the rest of the line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@PastaPastaPasta
PastaPastaPasta force-pushed the fix/stop-fish-completion-from-re-running-the-typed-d branch from 6442f5c to ff98899 Compare October 4, 2026 15:04
@thepastaclaw thepastaclaw removed the pastaclaw:commented thepastaclaw's latest review was comment-only label Oct 4, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review — Final validation — Phase 1 + Phase 2

Independently reviewed the complete diff at ff98899 and the surrounding CLI parsing and RPC dispatch paths; no actionable in-scope defects were found. Completion now excludes the typed RPC and execution-changing CLI options, and the prior double-dash connection-option finding is fixed. Validation was static only: the supplied CI snapshot shows successful container builds and ClangFormat, with lint and the full-container manifest job still pending; the author's completion reproductions were not independently rerun.

🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)

Review provenance

Source: reviewer 1: glm-5.3-flash (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: dash-core-commit-history); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: dash-core-commit-history); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: low by gpt-6.1-sol (effort low) — The diff is a small, contained fish-completion fix that filters arguments passed to help queries rather than changing funds-movement logic or another critical surface.
  • Phase 1 reviewers: glm-5.3-flash — general (completed, effort high); agent phase1-reviewer
  • Phase 1 model: glm-5.3-flash — zai quota: 5h 99% left, weekly 67% left; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 15% left, 5h 100% left)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort medium); agent phase2-reviewer, gpt-6.1-sol — dash-core-commit-history (completed, effort medium); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort medium); agent phase2-reviewer, gpt-6.1-sol — dash-core-commit-history (completed, effort medium); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.

No unresolved findings remain from the prior review on this head.

@thepastaclaw thepastaclaw added the pastaclaw:approved thepastaclaw's latest review approved this PR label Oct 4, 2026
…h completion

Keep -conf, -datadir, the network selectors and every -rpc* option except
-rpcwait*, the same prefix approach the dash-cli bash completion uses.
This drops the per-option list, so new -rpc* connection options are kept
without further edits, while -rpcwait* stays excluded so Tab does not
block while the node is down.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@thepastaclaw thepastaclaw removed the pastaclaw:approved thepastaclaw's latest review approved this PR label Oct 4, 2026

@PastaPastaPasta PastaPastaPasta left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

approved; this is technically an upstream issue; but they rarely change these files so backport conflict isn't much concern; I'll try to upstream this, but idk if it'll have any movement; let's fix it now and then complete a backport later if we can.

@PastaPastaPasta
PastaPastaPasta merged commit 3789ec0 into dashpay:develop Oct 4, 2026
43 of 44 checks passed
PastaPastaPasta added a commit that referenced this pull request Oct 7, 2026
…-cli command

5339d4f refactor(contrib): match dash-cli connection options by prefix in fish completion (pasta)
ff98899 fix(contrib): stop fish completion from re-running the typed dash-cli command (pasta)

Pull request description:

  ## Issue being fixed or feature implemented

  The fish completion for `dash-cli` (`contrib/completions/fish/dash-cli.fish`, imported from bitcoin#24611) builds its suggestions by running the command line the user has typed so far, with `help` or `-help` appended. Once an RPC command has been typed, everything after it is passed to the node as RPC parameters, so the appended `help` does not ask for help: it becomes one more parameter of the typed command, and the command runs.

  For anyone who has installed this completion, pressing Tab after a complete line such as `dash-cli sendtoaddress <address> 1 ` sends the coins before Enter is pressed, with `help` as the wallet comment. Each Tab runs the line several times, because every `complete` rule's `--condition` calls the helper again. Pressing Enter afterwards sends once more. The same applies to any RPC that accepts a trailing string parameter. A leading `-generate` reserves a new wallet address on each Tab.

  ### Why this is a real problem

  Code path at c14104b:

  - [`dash-cli.fish#L5`](https://github.com/dashpay/dash/blob/c14104b172a2/contrib/completions/fish/dash-cli.fish#L5) takes every completed token with `commandline -oc`. [L13-L16](https://github.com/dashpay/dash/blob/c14104b172a2/contrib/completions/fish/dash-cli.fish#L13-L16) strip only a bare `help` and `-stdin*`, and [L19](https://github.com/dashpay/dash/blob/c14104b172a2/contrib/completions/fish/dash-cli.fish#L19) runs `$cmd help`. [L63](https://github.com/dashpay/dash/blob/c14104b172a2/contrib/completions/fish/dash-cli.fish#L63) and [L65](https://github.com/dashpay/dash/blob/c14104b172a2/contrib/completions/fish/dash-cli.fish#L65) run `$cmd -help` the same way.
  - All three rules ([L75-L99](https://github.com/dashpay/dash/blob/c14104b172a2/contrib/completions/fish/dash-cli.fish#L75-L99)) call the helper from `--condition`, which fish evaluates on every Tab.
  - [`src/util/system.cpp#L262-L276`](https://github.com/dashpay/dash/blob/c14104b172a2/src/util/system.cpp#L262-L276): the first non-dash argument is the command. All later argv entries, including `help` and `-help`, are copied into the command arguments without being parsed. [`src/bitcoin-cli.cpp#L1207-L1212`](https://github.com/dashpay/dash/blob/c14104b172a2/src/bitcoin-cli.cpp#L1207-L1212) sends `args[0]` as the method.
  - [`src/wallet/rpc/spend.cpp#L238`](https://github.com/dashpay/dash/blob/c14104b172a2/src/wallet/rpc/spend.cpp#L238): the third `sendtoaddress` parameter is an optional string `comment`, so `help` is accepted and the send goes ahead.

  Reproduction against the unfixed tree. A fresh regtest `dashd` is built from this branch, wallet `w1` is funded, and `w2` provides the destination address. One Tab is simulated with fish 4.9.3 `complete -C '<line>'`, which evaluates the completion rules exactly as an interactive Tab does. Enter is never pressed. Script: `regtest-repro.sh` (included below).

  <details><summary>Unfixed: one Tab after a typed <code>sendtoaddress</code> line sends 5 DASH</summary>

  ```
  $ git rev-parse --short HEAD
  c14104b
  $ regtest-repro.sh $PWD
  == completion output ==
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 getblockc':
      getblockchaininfo
      getblockcount
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoa':
      sendtoaddress	"address" amount ( "comment" "comment_to" subt
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -rpcw':
      -rpcwait
      -rpcwaittimeout=
      -rpcwallet=
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 help getblockc':
      getblockchaininfo
      getblockcount
  == sendtoaddress ==
  w1 txs before Tab: 0 sends
  w2 balance before Tab (minconf 0): 0.00000000
  $ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoaddress yYY9kJyUeiJJRU9nAEsx5Nu2wXZEjK4CnD 1 '"   # one Tab press, Enter never pressed
  w1 txs after Tab:  5 sends
  w2 balance after Tab (minconf 0): 5.00000000
  mempool size:   "size": 5,
  comments on the w1 sends:
     2     "comment": "-help",
     3     "comment": "help",
  == -generate ==
  w1 before Tab:   "keypoolsize": 1000,, blocks: 110
  $ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -generate '"   # one Tab press, Enter never pressed
  w1 after Tab:    "keypoolsize": 999,, blocks: 110
  ```

  </details>

  To show exactly what the completion executes, the same line was also completed with a stand-in `dash-cli` on `PATH` that only logs its arguments:

  <details><summary>Unfixed: commands run by the completion for one Tab</summary>

  ```
  $ git rev-parse --short HEAD
  c14104b
  $ stub-repro.sh $PWD
  ### Tab after: 'dash-cli -regtest '
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest -help
    ran: dash-cli -regtest -help
  ### Tab after: 'dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 '
    ran: dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 help
    ran: dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 help
  ### Tab after: 'dash-cli -regtest -generate '
    ran: dash-cli -regtest -generate help
    ran: dash-cli -regtest -generate help
    ran: dash-cli -regtest -generate help
    ran: dash-cli -regtest -generate -help
    ran: dash-cli -regtest -generate -help
  ### Tab after: 'dash-cli -regtest -stdin '
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest -stdin -help
    ran: dash-cli -regtest -stdin -help
  ```

  </details>

  <details><summary>regtest-repro.sh</summary>

  ```sh
  #!/bin/sh
  # Usage: regtest-repro.sh <worktree>
  # Starts a fresh regtest dashd from <worktree>/src, funds wallet w1, then asks
  # fish for completions (exactly what one Tab press does) of a fully typed but
  # not yet submitted `sendtoaddress` line and of `-generate `, and reports what
  # changed on the node. Enter is never pressed.
  WT=$1
  P=$(cd "$(dirname "$0")" && pwd)
  FISH=fish
  D=$P/regtest-datadir
  rm -rf "$D"; mkdir -p "$D"
  export PATH=$WT/src:$PATH
  CLI="dash-cli -regtest -datadir=$D -rpcport=19876"
  "$WT/src/dashd" -regtest -datadir="$D" -rpcport=19876 -port=19877 -listen=0 -fallbackfee=0.0001 -daemon >/dev/null
  $CLI -rpcwait getblockcount >/dev/null
  $CLI createwallet w1 >/dev/null
  $CLI createwallet w2 >/dev/null
  $CLI -rpcwallet=w1 generatetoaddress 110 "$($CLI -rpcwallet=w1 getnewaddress)" >/dev/null
  ADDR=$($CLI -rpcwallet=w2 getnewaddress)

  tab() {
    echo "\$ fish -c \"source dash-cli.fish; complete -C '$1'\"   # one Tab press, Enter never pressed"
    "$FISH" --no-config -c "source $WT/contrib/completions/fish/dash-cli.fish; complete -C '$1' >/dev/null"
  }

  echo "== completion output =="
  for l in "$CLI getblockc" "$CLI -rpcwallet=w1 sendtoa" "$CLI -rpcwallet=w1 -rpcw" "$CLI help getblockc"; do
    echo "Tab after '$(echo "$l" | sed "s|$D|DATADIR|")':"
    "$FISH" --no-config -c "source $WT/contrib/completions/fish/dash-cli.fish; complete -C '$l'" | cut -c1-60 | sed 's/^/    /'
  done

  echo "== sendtoaddress =="
  echo "w1 txs before Tab: $($CLI -rpcwallet=w1 listtransactions '*' 1000 | grep -c '"category": "send"') sends"
  echo "w2 balance before Tab (minconf 0): $($CLI -rpcwallet=w2 getreceivedbyaddress $ADDR 0)"
  tab "$CLI -rpcwallet=w1 sendtoaddress $ADDR 1 "
  echo "w1 txs after Tab:  $($CLI -rpcwallet=w1 listtransactions '*' 1000 | grep -c '"category": "send"') sends"
  echo "w2 balance after Tab (minconf 0): $($CLI -rpcwallet=w2 getreceivedbyaddress $ADDR 0)"
  echo "mempool size: $($CLI getmempoolinfo | grep '"size"')"
  echo "comments on the w1 sends:"
  $CLI -rpcwallet=w1 listtransactions '*' 1000 | grep '"comment"' | sort | uniq -c

  echo "== -generate =="
  echo "w1 before Tab: $($CLI -rpcwallet=w1 getwalletinfo | grep '"keypoolsize"'), blocks: $($CLI getblockcount)"
  tab "$CLI -rpcwallet=w1 -generate "
  echo "w1 after Tab:  $($CLI -rpcwallet=w1 getwalletinfo | grep '"keypoolsize"'), blocks: $($CLI getblockcount)"

  $CLI stop >/dev/null
  sleep 3
  ```

  </details>

  ### Why it matters

  Pressing Tab is expected to be harmless. With this completion installed, Tab can broadcast a payment the user has not confirmed. It does so several times per keypress, so a later Enter produces a duplicate payment. Any other state-changing RPC that tolerates the extra parameter runs early in the same way. The scope is limited: the completion is opt-in and not installed by the build, it needs working RPC credentials and an unlocked wallet, and the user must already have typed the full command. Nothing is reachable remotely. The effect is still an unintended spend of the user's own funds.

  ## What was done?

  Only `contrib/completions/fish/dash-cli.fish` changes. The first commit is the fix; the second replaces the explicit option list with prefix matching.

  - `__fish_dash_cli_get_commands_helper` now runs `help` with only the executable and the connection options typed before the RPC command, matched by prefix: `-conf`, `-datadir`, `-testnet`, `-regtest`, `-devnet`, `-chain`, and every `-rpc*` option except `-rpcwait*` (which would make Tab hang while the node is down). This is the same prefix approach as the dash-cli bash completion, so new `-rpc*` connection options need no edits here. It stops at the first non-dash token, so the RPC command and its arguments are never passed on. Other leading options are dropped, including `-generate`, `-getinfo`, `-netinfo`, `-addrinfo`, `-named`, `-rpcwait*` and `-stdin*`. This replaces the old ad hoc stripping of `help` and `-stdin*`, which the allowlist covers.
  - `__fish_dash_cli_get_options` runs `-help` on the bare executable (`$cmd[1]`). The option list does not depend on the rest of the line, and the other Dash completion scripts (`dash-tx.fish`, `dash-wallet.fish`, `dash-util.fish`, `dashd.fish`) already do this.

  ### Why this is the correct minimal fix

  The root cause is that the completion re-executes user input. The fix stops passing that input on, and keeps only what is needed to reach the same node and wallet (datadir, conf, network, RPC endpoint and credentials, wallet). An allowlist is used because a denylist would have to keep up with every dash-cli option that changes what gets executed. Some leading options are themselves commands: `-generate` calls `getnewaddress` before it validates its arguments. Stripping only `help` would not help, because any typed RPC still runs. Excluding specific RPCs would always miss some.

  Left unchanged on purpose: the completion rules, the output parsing, and the `-help`/`-?` early returns. The helper is still called once per rule on each Tab, which now only issues the read-only `help` RPC. Caching it, or adding a default client timeout, would be separate improvements. Bitcoin Core's `bitcoin-cli.fish` has the same pattern.

  ## How Has This Been Tested?

  No automated test was added. The repository has no harness for shell completion scripts, and the behaviour was checked end to end against a real node instead. Environment: macOS arm64, `dashd`/`dash-cli` built from this branch, fish 4.9.3.

  - `regtest-repro.sh` before the fix: one Tab after `sendtoaddress <w2 address> 1 ` produced 5 sends from `w1` (5 DASH received by `w2`, 5 transactions in the mempool, comments `help` ×3 and `-help` ×2). The `-generate ` Tab reduced the keypool from 1000 to 999. Output is above.
  - `regtest-repro.sh` after the fix: no sends, `w2` balance 0, empty mempool, keypool unchanged. Command, `help <command>` and option completion return the same suggestions as before.

  <details><summary>Fixed: same script</summary>

  ```
  $ git diff --stat
   contrib/completions/fish/dash-cli.fish | 21 +++++++++++++--------
   1 file changed, 13 insertions(+), 8 deletions(-)
  $ regtest-repro.sh $PWD
  == completion output ==
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 getblockc':
      getblockchaininfo
      getblockcount
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoa':
      sendtoaddress	"address" amount ( "comment" "comment_to" subt
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -rpcw':
      -rpcwait
      -rpcwaittimeout=
      -rpcwallet=
  Tab after 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 help getblockc':
      getblockchaininfo
      getblockcount
  == sendtoaddress ==
  w1 txs before Tab: 0 sends
  w2 balance before Tab (minconf 0): 0.00000000
  $ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 sendtoaddress ya4Gcphm7nFvTRuHjLqnmqh6W6tkhjmvfL 1 '"   # one Tab press, Enter never pressed
  w1 txs after Tab:  0 sends
  w2 balance after Tab (minconf 0): 0.00000000
  mempool size:   "size": 0,
  comments on the w1 sends:
  == -generate ==
  w1 before Tab:   "keypoolsize": 1000,, blocks: 110
  $ fish -c "source dash-cli.fish; complete -C 'dash-cli -regtest -datadir=DATADIR -rpcport=19876 -rpcwallet=w1 -generate '"   # one Tab press, Enter never pressed
  w1 after Tab:    "keypoolsize": 1000,, blocks: 110
  ```

  </details>

  <details><summary>Fixed: commands run by the completion for one Tab (logging stand-in)</summary>

  ```
  $ git diff --stat
   contrib/completions/fish/dash-cli.fish | 21 +++++++++++++--------
   1 file changed, 13 insertions(+), 8 deletions(-)
  $ stub-repro.sh $PWD
  ### Tab after: 'dash-cli -regtest '
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -help
    ran: dash-cli -help
  ### Tab after: 'dash-cli -regtest -rpcwallet=w1 sendtoaddress yNmxLr8sgqWjj8qEcvH7bD3b4G4Bu4PZpq 1 '
    ran: dash-cli -regtest -rpcwallet=w1 help
    ran: dash-cli -regtest -rpcwallet=w1 help
  ### Tab after: 'dash-cli -regtest -generate '
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -help
    ran: dash-cli -help
  ### Tab after: 'dash-cli -regtest -stdin '
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -regtest help
    ran: dash-cli -help
    ran: dash-cli -help
  ```

  </details>

  - After switching to prefix matching (second commit), the regtest check was repeated: command, `help <command>`, option and `-rpcwait` line completions return the expected suggestions; Tab after the `sendtoaddress` line and after `-generate ` leaves w1 with 0 sends, keypool 1000 and an empty mempool; with the node stopped, Tab after `-rpcwait getblockc` returns immediately. A logging stand-in confirmed that every connection option (`-conf`, `-datadir`, `-testnet`, `-regtest`, `-devnet`, `-chain`, `-rpcconnect`, `-rpcport`, `-rpcuser`, `-rpcpassword`, `-rpccookiefile`, `-rpcwallet`, `-rpcclienttimeout`) is passed on and `-rpcwait`, `-rpcwaittimeout`, `-stdin*`, `-named`, `-generate`, `-getinfo`, `-netinfo` are not.
  - `fish --no-execute contrib/completions/fish/dash-cli.fish` succeeds (syntax check). `fish_indent` reports no changes in the edited hunks.
  - `test/lint/lint-whitespace.py` passes.

  ## Breaking Changes

  None.

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have made corresponding changes to the documentation
  - [ ] I have assigned this pull request to a milestone

  🤖 Generated with [Claude Code](https://claude.com/claude-code)

Top commit has no ACKs.

Tree-SHA512: 233c7ab06389315b9ca8aed82b36438b55f482e6fc167c4cecaaba135ff0363d84c1b593904bfdb0ac529c2f2b1722f29eeb12c6616d9da75bb1c1934adce9e9
(cherry picked from commit 3789ec0)
PastaPastaPasta added a commit that referenced this pull request Oct 7, 2026
fbe6526 Merge #7807: feat(consensus): hold EvoNode shares and multiple payouts behind a new evo_shares deployment (pasta)
57fd2d9 Merge #7776: fix: keep a pending ProUpServTx across a registrar update that keeps the operator key (pasta)
ca69801 Merge #7803: fix: return non-zero amount of accounts after sethdseed (pasta)
57a8f07 Merge #7796: backport: bitcoin#26720 (remaining), partial bitcoin#29523: weight-check the knapsack exact-match selection (pasta)
4eb82f6 Merge #7786: fix(net): keep a dedicated onion listener when -bind is given and correct the bind release note (pasta)
70626a0 Merge #7793: backport: partial bitcoin#28868 (wallet: reload wallet if migration exited early, keep mixed watchonly txs) (pasta)
250a3cd Merge #7790: fix: guard cached governance object flags with the object lock (pasta)
700c195 Merge #7787: fix: only sign EHF signals inside the deployment's start/timeout window (pasta)
a3b0f3c Merge #7785: fix: restore the txindex requirement when governance validation is enabled (pasta)
2d1735d Merge #7794: fix(wallet): floor the denomination gap threshold so rebalancing cannot oscillate (pasta)
d9f6592 Merge #7783: fix: stop fish completion from re-running the typed dash-cli command (pasta)
89d44c8 Merge #7795: backport: bitcoin#34272, partial bitcoin#31650 (pass PSBT by const reference in PSBTInputSignedAndVerified) (pasta)
a1d7411 Merge #7779: fix!: report legacy evonode Platform addresses when listdiff changes its address (pasta)
73f6ea2 Merge #7789: fix(qt): report malformed lang/font settings instead of aborting at startup (pasta)
40de493 Merge #7781: fix(rpc): use a consistent tip height in quorum dkgstatus (pasta)
7d1a90d Merge #7791: fix(net): request object votes from nPeersPerHashMax peers (pasta)
51b145c Merge #7778: test: use single-member in functional tests: feature_mnehf, feature_notifications, p2p_instantsend (pasta)

Pull request description:

  ## Issue being fixed or feature implemented

  Backports for v24.0.0-rc.3. `v24.0.x` was cut at the v24.0.0-rc.2 tag (1e239d4), and develop has since moved to 24.1.0 (#7775), so rc.3 is built from this branch instead of being tagged on develop like rc.1 and rc.2.

  ## What was done?

  Cherry-picked (`git cherry-pick -m1 -x`) every develop merge since rc.2 that carries `backport-candidate-24.0.x`, plus #7778, which #7807's test needs. They are in develop merge order:

  - #7778 test: use single-member in functional tests: feature_mnehf, feature_notifications, p2p_instantsend (test-only. Needed because #7807's `feature_evo_shares_activation.py` depends on its `mine_quorum_single_member()` fix and fails without it.)
  - #7791 fix(net): request object votes from nPeersPerHashMax peers
  - #7781 fix(rpc): use a consistent tip height in quorum dkgstatus
  - #7789 fix(qt): report malformed lang/font settings instead of aborting at startup
  - #7779 fix!: report legacy evonode Platform addresses when listdiff changes its address
  - #7795 backport: bitcoin#34272, partial bitcoin#31650 (pass PSBT by const reference in PSBTInputSignedAndVerified)
  - #7783 fix: stop fish completion from re-running the typed dash-cli command
  - #7794 fix(wallet): floor the denomination gap threshold so rebalancing cannot oscillate
  - #7785 fix: restore the txindex requirement when governance validation is enabled
  - #7787 fix: only sign EHF signals inside the deployment's start/timeout window
  - #7790 fix: guard cached governance object flags with the object lock
  - #7793 backport: partial bitcoin#28868 (wallet: reload wallet if migration exited early, keep mixed watchonly txs)
  - #7786 fix(net): keep a dedicated onion listener when -bind is given and correct the bind release note. Includes partial bitcoin#36170 (5f40d56). Upstream's dedicated-onion-bind changes to `feature_torcontrol.py` and `p2p_private_broadcast.py` are not included, because those tests depend on upstream commits (5693833, e74d54e) that Dash does not have.
  - #7796 backport: bitcoin#26720 (remaining), partial bitcoin#29523: weight-check the knapsack exact-match selection
  - #7803 fix: return non-zero amount of accounts after sethdseed
  - #7776 fix: keep a pending ProUpServTx across a registrar update that keeps the operator key
  - #7807 feat(consensus): hold EvoNode shares and multiple payouts behind a new evo_shares deployment

  One pick needed conflict resolution, in a test only, described in its commit message: #7793, `test/functional/wallet_migration.py`. `test_conflict_txs()` comes from bitcoin#28542 (#7762), which is not on this branch, so it is left out. The C++ part of #7793 is identical to develop.

  Merged since rc.2 but intentionally not included: #7775 (24.1 version bump), #7260 and #7804 (new Qt feature and its CI fix), #7584 (refactor), routine upstream backports #7257, #7759, #7762, #7768, #7788, #7801, and test/CI-only changes #7777 and #7797.

  No version change is needed. `configure.ac` is already 24.0.0 with `CLIENT_VERSION_IS_RELEASE` false, so the build takes its version string from the `v24.0.0-rc.3` tag, as it did for rc.2.

  ## How Has This Been Tested?

  Built on macOS arm64 against depends with `--enable-debug --enable-werror` (dashd, dash-qt, tests).

  - `make check`: all unit test suites pass, including `test_dash-qt`.
  - Functional tests, all passing: `feature_evo_shares_activation.py`, `feature_masternode_shares.py`, `feature_mnehf.py`, `feature_governance.py --descriptors`, `feature_governance_objects.py`, `feature_governance_txindex_devnet.py`, `feature_proxy.py`, `feature_notifications.py`, `feature_llmq_connections.py`, `feature_llmq_chainlocks_automatic.py`, `feature_llmq_singlenode.py`, `p2p_instantsend.py`, `rpc_blockchain.py` (v1 and v2 transport), `rpc_netinfo.py`, `rpc_quorum.py`, `rpc_verifychainlock.py`, `wallet_hd.py` (legacy and descriptors), `wallet_migration.py`.
  - `feature_bind_extra.py` (from #7786) only runs on Linux and was skipped locally, so CI covers it.

  Every touched file was diffed against develop. The remaining differences come only from develop PRs that are not part of this backport.

  ## Breaking Changes

  Carried over from the picked PRs:

  - #7807: consensus change behind the new `evo_shares` deployment (bit 14). Mainnet and testnet are unaffected until it activates. Devnets with `v24` already active and an EvoNode carrying several owner payouts need to check or reset. New RPC `protx shared_register_prepare_evo`.
  - #7785: outside regtest, a node with `-txindex=0` and without `-disablegovernance` refuses to start again, as before v23.1.0.
  - #7786: carries a partial bitcoin#36170. A node started with `-bind` but no specific `-bind=<addr:port>=onion` now refuses to start while `-listenonion` is enabled. That is the default when listening, even without Tor configured. A wildcard onion bind is also refused. Such nodes need `-bind=127.0.0.1:<port>=onion` or `-listenonion=0`. Nodes without `-bind`, including those using only `-whitebind`, keep the default `127.0.0.1:9996` (`19996` testnet) onion target. See `doc/release-notes-7300.md`.
  - #7779: `protx listdiff` now includes `platform_p2p` and `platform_https` for a legacy-address evonode whose core P2P address changes.

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have made corresponding changes to the documentation
  - [ ] I have assigned this pull request to a milestone

  🤖 Generated with [Claude Code](https://claude.com/claude-code)

Top commit has no ACKs.

Tree-SHA512: 8cb01bdb0234f31b5dd2c105b69673de148922991a7523627395c0e0ccfa22b94be5ffbecc842398d443bc90fd9baf2eee6a9cf6fcdbbd1626eb00b93726a55a
@UdjinM6 UdjinM6 added this to the 24 milestone Oct 16, 2026
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.

3 participants