Skip to content

Conversation

@knst
Copy link
Collaborator

@knst knst commented Oct 22, 2025

What was done?

Extra backports to improve support of External signer.
This PR have mostly backports related to build system and Boost.

How Has This Been Tested?

N/A

Breaking Changes

There's no breaking changes because external signer has not been released yet. Though key changes are:

  • signing won't happen if more than 1 signer is available on the same time
  • external signer for Windows is still disabled
  • external signer for OpenBSD 7.3 expected to be working (but not tested)

Checklist:

  • 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)

@github-actions
Copy link

github-actions bot commented Oct 22, 2025

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Walkthrough

The patch enables external-signer support by default and moves runtime probing/handling of Boost.Process into configure.ac (with Windows forced to "no"). It relocates RunCommandParseJSON from util/system to src/common/run_command.{h,cpp} and introduces a new util/subprocess.hpp implementation. Wallet creation now errors when more than one external signer is found; tests and mocks are updated to exercise the multi-signer case and remove Windows-specific branches. Minor build/test and header-list updates accompany these changes.

Sequence Diagram(s)

sequenceDiagram
    %% Wallet creation and multi-signer handling
    actor User
    participant UI as Qt Wallet UI
    participant WC as WalletController
    participant SignerSys as External Signer System
    participant Dialog as CreateWalletDialog

    User->>UI: Request Create Wallet
    UI->>WC: createWallet()
    activate WC
    WC->>SignerSys: Run enumerate (RunCommandParseJSON -> subprocess)
    activate SignerSys
    SignerSys-->>WC: signers[]
    deactivate SignerSys

    alt signers.size() > 1
        WC->>WC: throw / show critical "More than one external signer found"
        WC->>Dialog: pass empty signers
    else signers.size() == 1
        WC->>Dialog: pass single signer
    else signers.size() == 0
        WC->>Dialog: pass empty signers
    end
    deactivate WC
    Dialog->>User: Show create wallet dialog
Loading
sequenceDiagram
    %% Configure-time probe for Boost.Process and macro definition
    participant Configure as configure.ac
    participant Compiler as compiler/linker probe
    participant Config as generated config.h / AM_CONDITIONAL

    Configure->>Compiler: test linking with Boost.Process (AC_LINK_IFELSE)
    activate Compiler
    alt link succeeds
        Compiler-->>Configure: OK
        Configure->>Config: set ENABLE_EXTERNAL_SIGNER defined
    else link fails
        Compiler-->>Configure: FAIL
        alt user requested --enable-external-signer=yes
            Compiler-->>Configure: configure error (Boost.Process required)
        else default/optional
            Configure->>Config: set use_external_signer="no"
        end
    end
    deactivate Compiler
Loading
sequenceDiagram
    %% RunCommandParseJSON runtime flow (new location: common/run_command.cpp)
    participant Caller as external_signer.cpp / tests
    participant RunCmd as RunCommandParseJSON
    participant Proc as util::Popen (subprocess.hpp)
    participant JSON as UniValue parser

    Caller->>RunCmd: RunCommandParseJSON(cmd, stdin)
    activate RunCmd
    RunCmd->>Proc: spawn process, provide stdin
    activate Proc
    Proc-->>RunCmd: stdout, stderr, exit code
    deactivate Proc
    alt exit code == 0
        RunCmd->>JSON: parse stdout first-line as JSON
        JSON-->>RunCmd: UniValue
        RunCmd-->>Caller: return UniValue
    else exit code != 0
        RunCmd-->>Caller: throw runtime_error with cmd, retcode, stderr
    end
    deactivate RunCmd
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing careful review:
    • src/util/subprocess.hpp: large, cross-platform process API additions — review for correctness, portability, memory and FD handling, and public API surface.
    • src/common/run_command.{h,cpp}: new RunCommandParseJSON behavior, error messages, and interaction with subprocess.
    • configure.ac: runtime probing logic, Windows handling, AC_DEFINE/AM_CONDITIONAL placement and help text.
    • src/wallet/external_signer_scriptpubkeyman.cpp and src/qt/walletcontroller.cpp: multi-signer error path and how callers handle thrown runtime_error / cleared signer lists.
    • Tests and mocks (test/functional/* and src/test/system_tests.cpp): ensure expectations, cross-platform commands, and mock scripts align with the new process API and single-signer enforcement.
    • Build/public headers (src/Makefile.am): exposure of new headers and library sources.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description is related to the changeset, explaining the purpose (backports for external signer support), scope (build system and Boost), and noting behavioral changes without breaking compatibility.
Title check ✅ Passed The title comprehensively references the backported Bitcoin pull requests and identifies the primary changes (external signer and boost-related improvements), directly matching the changeset's scope.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 21

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
test/functional/wallet_abandonconflict.py (1)

139-139: Use wallet RPC handle for consistency.

This line uses self.nodes[0].listtransactions() instead of alice.listtransactions(), which is inconsistent with the refactoring pattern applied throughout the rest of the file. While functionally equivalent (both access the default wallet), using the alice handle maintains consistency with the PR's objective to switch all wallet operations to wallet RPC handles.

Apply this diff:

-        txAB1_listtransactions = [d for d in self.nodes[0].listtransactions() if d['txid'] == txAB1]
+        txAB1_listtransactions = [d for d in alice.listtransactions() if d['txid'] == txAB1]
src/wallet/scriptpubkeyman.cpp (1)

1624-1649: Avoid pushing invalid entries when pool read fails.

Only append to result when ReadPool succeeds; otherwise you may return default-initialized CKeyPool.

-    while (it != std::end(*setKeyPool)) {
+    while (it != std::end(*setKeyPool)) {
         const int64_t& index = *(it);
         if (index > keypool_id) break; // set*KeyPool is ordered

         CKeyPool keypool;
-        if (batch.ReadPool(index, keypool)) { //TODO: This should be unnecessary
-            m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
-        }
+        if (batch.ReadPool(index, keypool)) { // TODO: Should be unnecessary
+            m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
+        }
         batch.ErasePool(index);
         WalletLogPrintf("keypool index %d removed\n", index);
         it = setKeyPool->erase(it);
-        result.push_back(std::move(keypool));
+        if (keypool.vchPubKey.IsValid()) {
+            result.push_back(std::move(keypool));
+        }
     }
src/qt/sendcoinsdialog.cpp (1)

796-809: External signer balance is always shown as 0.

You change the label but never assign a balance for this branch. Show watch-only (typical for external signer wallets) or regular balance.

-        if (model->wallet().hasExternalSigner()) {
-            ui->labelBalanceName->setText(tr("External balance:"));
+        if (model->wallet().hasExternalSigner()) {
+            balance = balances.watch_only_balance;
+            ui->labelBalanceName->setText(tr("External balance:"));
🧹 Nitpick comments (35)
test/functional/wallet_listtransactions.py (5)

21-24: num_nodes=3: OK, but keep restart args consistent.

Bumping to 3 is justified for cross‑node wallet checks. When you restart later, pass self.extra_args to preserve initial node config.

Apply this small change at the later restart:

-        self.start_nodes()
+        self.start_nodes(extra_args=self.extra_args)

113-118: Avoid hard‑coding wallet.dat paths; use RPC‑based cloning.

Directly copying wallet.dat is brittle (backend differences, walletdir layout like “wallets/”, multiwallet). Prefer RPCs:

  • dumpwallet on node 0 and importwallet on node 2 (no stop/start needed), or
  • backupwallet while running, then copy the backup file.

This removes assumptions about self.chain/default_wallet_name and survives backend changes.

Example replacement:

-        self.nodes[0].keypoolrefill(1000)
-        self.stop_nodes()
-        wallet0 = os.path.join(self.nodes[0].datadir, self.chain, self.default_wallet_name, "wallet.dat")
-        wallet2 = os.path.join(self.nodes[2].datadir, self.chain, self.default_wallet_name, "wallet.dat")
-        shutil.copyfile(wallet0, wallet2)
-        self.start_nodes()
+        self.nodes[0].keypoolrefill(1000)
+        dump_file = os.path.join(self.nodes[0].datadir, "w0_dump.txt")
+        self.nodes[0].dumpwallet(dump_file)
+        # Ensure wallet 2 is fresh and imports all keys/labels from node 0
+        self.nodes[2].importwallet(dump_file)

If you must keep file‑copy semantics, derive the wallet path via RPC or node attributes (e.g., walletdir) rather than constructing it manually.


118-123: Reconnect is fine; add sync for determinism.

After restarting/reconnecting, call sync_* to avoid races before subsequent sends/mines and comparisons.

         self.connect_nodes(0, 1)
         self.connect_nodes(1, 2)
         self.connect_nodes(2, 0)
+        self.sync_all()

128-140: Add chain syncs after mining to avoid flakiness across nodes.

generate() mines on a single node; peers may lag briefly. Sync before comparing listtransactions to ensure both nodes see the same chain.

         self.nodes[1].sendtoaddress(addr3, "0.001")
         self.generate(self.nodes[1], 1)
+        self.sync_blocks()
@@
         self.nodes[1].sendtoaddress(addr2, "0.001")
         self.generate(self.nodes[1], 1)
+        self.sync_blocks()
@@
         self.nodes[0].sendtoaddress(addr1, "0.001")
         self.generate(self.nodes[0], 1)
+        self.sync_blocks()

145-152: Strengthen normalization sort key to avoid duplicate‑txid ordering differences.

listtransactions can emit multiple entries with the same txid (e.g., send‑to‑self). Sorting only by txid may keep per‑txid order different across nodes, causing spurious mismatches. Include category and vout in the sort key.

-        def normalize_list(txs):
+        def normalize_list(txs):
             for tx in txs:
                 tx.pop('label', None)
                 tx.pop('time', None)
                 tx.pop('timereceived', None)
-            txs.sort(key=lambda x: x['txid'])
+            txs.sort(key=lambda x: (x['txid'], x.get('category', ''), x.get('vout', -1)))
src/wallet/init.cpp (1)

70-72: Hide -signer when feature is not compiled for consistent CLI UX.

Mirror existing patterns (e.g., -unsafesqlitesync) to avoid unknown-option noise.

 #ifdef ENABLE_EXTERNAL_SIGNER
-    argsman.AddArg("-signer=<cmd>", "External signing tool, see doc/external-signer.md", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+    argsman.AddArg("-signer=<cmd>", "External signing tool, see doc/external-signer.md", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+#else
+    argsman.AddHiddenArgs({"-signer"});
 #endif
src/qt/forms/createwalletdialog.ui (2)

112-121: Text/style polish and availability gating.

  • Use title case to match help/category naming: “External Signer”.
  • Ensure the checkbox is hidden/disabled when external signer is not compiled or no signers are detected.
-         <string>External signer</string>
+         <string>External Signer</string>

If not already handled in CreateWalletDialog code, I can add the visibility/enablement toggle based on signer enumeration.


155-155: Tab order looks fine; consider adding descriptor checkbox too (if missing).

If descriptor_checkbox isn’t already in tabstops elsewhere, add it for keyboard navigation consistency.

src/qt/walletmodel.h (1)

144-144: Consider passing string parameter by const reference.

The method signature takes std::string sAddress by value. For efficiency, consider using const std::string& sAddress to avoid unnecessary string copies, especially since the implementation only needs to read the value.

Apply this diff if you'd like to optimize the parameter passing:

-    bool displayAddress(std::string sAddress);
+    bool displayAddress(const std::string& sAddress);

Also update the implementation in src/qt/walletmodel.cpp accordingly.

src/qt/walletmodel.cpp (2)

582-592: Consider using this as the parent widget for the error dialog.

Passing nullptr as the parent to QMessageBox::critical can lead to suboptimal behavior: the dialog may not be modal to the wallet window, may appear on the wrong screen in multi-monitor setups, and lacks proper window ownership. Consider passing this or another appropriate parent widget instead.

Apply this diff:

-        QMessageBox::critical(nullptr, tr("Can't display address"), e.what());
+        QMessageBox::critical(/* appropriate parent widget */, tr("Can't display address"), e.what());

Note: You may need to refactor this method to accept a parent widget parameter, or use a pattern that ensures proper parent widget handling.


582-582: Parameter efficiency: pass by const reference.

The parameter sAddress is passed by value, which creates an unnecessary copy. Consider passing by const std::string& instead.

Apply this diff:

-bool WalletModel::displayAddress(std::string sAddress)
+bool WalletModel::displayAddress(const std::string& sAddress)
src/qt/walletcontroller.cpp (1)

296-306: Consider using a translatable string for the multi-signer error message.

The error message on line 303 uses QString::fromStdString with a hardcoded English string, while other error messages in the same flow (like line 300) use Qt's tr() for translation.

Apply this diff to make the error message translatable and consistent with the rest of the codebase:

     if (signers.size() > 1) {
-        QMessageBox::critical(nullptr, tr("Too many external signers found"), QString::fromStdString("More than one external signer found. Please connect only one at a time."));
+        QMessageBox::critical(nullptr, tr("Too many external signers found"), tr("More than one external signer found. Please connect only one at a time."));
         signers.clear();
     }
src/wallet/rpc/backup.cpp (1)

2041-2047: CoinJoin detection via string search is brittle

Parsing the descriptor string to find "/'/'/4'/0'" is fragile. Prefer a structured check (e.g., store derivation purpose/path metadata in WalletDescriptor or a helper that decodes derivation steps) to avoid false positives if formatting changes or keys are reordered.

src/interfaces/node.h (1)

160-169: Make ExternalSigner interface const-correct and defaulted

getName is an accessor; mark it const. Also default the virtual destructor for clarity.

Apply:

-class ExternalSigner
+class ExternalSigner
 {
 public:
-    virtual ~ExternalSigner() {};
+    virtual ~ExternalSigner() = default;
 
     //! Get signer display name
-    virtual std::string getName() = 0;
+    virtual std::string getName() const = 0;
 };
doc/external-signer.md (1)

1-171: Tighten Markdown (fences, prompts, style) and mention build flag

  • Add language identifiers (sh, json).
  • Drop leading “$ ” prompts or include sample outputs per MD014.
  • Minor grammar: “In order to be” → “To be”, hyphenate “BIP44/49/84-compatible”.
  • Document that builds must enable external signer support (configure with --enable-external-signer) if that’s the gating.

Apply sample edits:

-```sh
-$ dashd -signer=../HWI/hwi.py
-```
+```sh
+dashd -signer=../HWI/hwi.py
+```

-```
-$ dash-cli enumeratesigners
+```json
+{
+  "signers": [
+    { "fingerprint": "c8df832a" }
+  ]
+}
+```

-```sh
-$ dash-cli createwallet "hww" true true "" true true true
-```
+```sh
+dash-cli createwallet "hww" true true "" true true true
+```

-``` 
-$ <cmd> enumerate
+```sh
+<cmd> enumerate
 [
   { "fingerprint": "00000000" }
 ]

+Note: build with --enable-external-signer to enable this feature.

Also fix “immedidately” → “immediately” if you keep that note in code comments elsewhere (see createwalletdialog.cpp).

</blockquote></details>
<details>
<summary>src/qt/createwalletdialog.cpp (2)</summary><blockquote>

`49-65`: **External signer toggle: align blank-wallet semantics and fix typo**

- You set blank_wallet_checkbox to checked when toggled on (Line 64), implying watch-only wallets should be “blank”. In setSigners() you later force it unchecked (see below), which is inconsistent. Decide the intended default and make both paths consistent.
- Typo in comment: “immedidately” → “immediately”.



Would you like me to update both spots to a single policy (e.g., blank=false because descriptors are imported immediately)?

---

`115-134`: **setSigners(): minor polish and consistency**

- Consistency: As noted above, this forces blank_wallet_checkbox unchecked even though the “toggled” path sets it checked. Pick one behavior.
- UX: When no signers are found (else branch), consider re-enabling the other checkboxes back to their defaults to avoid a partially locked UI if setSigners() is called after prior toggling.
- API: You call signers[0]->getName(); with the proposed const qualifier, this still works.


```diff
-        ui->blank_wallet_checkbox->setEnabled(false);
-        ui->blank_wallet_checkbox->setChecked(false);
+        ui->blank_wallet_checkbox->setEnabled(false);
+        ui->blank_wallet_checkbox->setChecked(true); // or false, but keep consistent with the toggle handler
@@
     } else {
         ui->external_signer_checkbox->setEnabled(false);
+        // Optionally restore defaults:
+        ui->encrypt_wallet_checkbox->setEnabled(true);
+        ui->blank_wallet_checkbox->setEnabled(true);
+        ui->disable_privkeys_checkbox->setEnabled(true);
+        ui->descriptor_checkbox->setEnabled(true);
     }

If you prefer blank=false, update the toggle handler accordingly.

src/node/interfaces.cpp (3)

530-551: Make listExternalSigners resilient (catch enumerate errors, guard empty cmd).

Avoid throwing across the Node interface. Catch exceptions from ExternalSigner::Enumerate and return an empty list; also use command.empty() for clarity.

Apply:

     std::vector<std::unique_ptr<interfaces::ExternalSigner>> listExternalSigners() override
     {
 #ifdef ENABLE_EXTERNAL_SIGNER
-        std::vector<ExternalSigner> signers = {};
-        const std::string command = gArgs.GetArg("-signer", "");
-        if (command == "") return {};
-        ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
+        std::vector<ExternalSigner> signers;
+        const std::string command = gArgs.GetArg("-signer", "");
+        if (command.empty()) return {};
+        try {
+            ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
+        } catch (const std::exception& e) {
+            // Log and degrade gracefully
+            LogPrintf("listExternalSigners: enumerate failed: %s\n", e.what());
+            return {};
+        }
         std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
-        for (auto& signer : signers) {
+        result.reserve(signers.size());
+        for (auto& signer : signers) {
             result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
         }
         return result;
 #else

17-17: Optional: include only when enabled.

Wrap the header include with ENABLE_EXTERNAL_SIGNER to avoid unnecessary coupling when the feature is off.

-#include <external_signer.h>
+#ifdef ENABLE_EXTERNAL_SIGNER
+#include <external_signer.h>
+#endif

402-411: Minor: keep adaptor minimal.

Consider storing just the name instead of copying the whole ::ExternalSigner, unless future methods are planned.

-class ExternalSignerImpl : public interfaces::ExternalSigner
-{
-public:
-    ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {}
-    std::string getName() override { return m_signer.m_name; }
-private:
-    ::ExternalSigner m_signer;
-};
+class ExternalSignerImpl : public interfaces::ExternalSigner {
+public:
+    explicit ExternalSignerImpl(std::string name) : m_name(std::move(name)) {}
+    std::string getName() override { return m_name; }
+private:
+    std::string m_name;
+};

And in the loop:

- result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
+ result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer.m_name)));
src/external_signer.h (1)

27-35: API polish for performance and const-correctness.

  • Remove top-level const on by-value return.
  • Pass chain by const reference in ctor.
  • Make GetDescriptors const.
-    const std::string NetworkArg() const;
+    std::string NetworkArg() const;
@@
-    ExternalSigner(const std::string& command, const std::string chain, const std::string& fingerprint, const std::string name);
+    ExternalSigner(const std::string& command, const std::string& chain, const std::string& fingerprint, const std::string& name);
@@
-    UniValue GetDescriptors(const int account);
+    UniValue GetDescriptors(int account) const;

Also update implementations:

-const std::string ExternalSigner::NetworkArg() const
+std::string ExternalSigner::NetworkArg() const
 {
     return " --chain " + m_chain;
 }
@@
-ExternalSigner::ExternalSigner(const std::string& command, const std::string chain, const std::string& fingerprint, const std::string name)
+ExternalSigner::ExternalSigner(const std::string& command, const std::string& chain, const std::string& fingerprint, const std::string& name)
   : m_command(command), m_chain(chain), m_fingerprint(fingerprint), m_name(name) {}
@@
-UniValue ExternalSigner::GetDescriptors(const int account)
+UniValue ExternalSigner::GetDescriptors(int account) const

Also applies to: 54-59

src/wallet/external_signer_scriptpubkeyman.cpp (1)

64-86: Use wallet logging instead of stderr on signing failure.

Direct writes to stderr bypass logging. Prefer LogPrintf/WalletLogPrintf.

-    if(!GetExternalSigner().SignTransaction(psbt, strFailReason)) {
-        tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason);
+    if (!GetExternalSigner().SignTransaction(psbt, strFailReason)) {
+        LogPrintf("%s: external signer failed: %s\n", __func__, strFailReason);
         return TransactionError::EXTERNAL_SIGNER_FAILED;
     }

Add:

+#include <logging.h>

near the includes.

test/functional/rpc_signer.py (2)

51-54: Fix Flake8 E128 under-indented continuations.

Reformat the four multi-line assert_raises_rpc_error calls.

-        assert_raises_rpc_error(-1, 'Error: restart dashd with -signer=<cmd>',
-            self.nodes[0].enumeratesigners
-        )
+        assert_raises_rpc_error(
+            -1,
+            'Error: restart dashd with -signer=<cmd>',
+            self.nodes[0].enumeratesigners,
+        )

-        assert_raises_rpc_error(-1, 'execve failed: No such file or directory',
-            self.nodes[3].enumeratesigners
-        )
+        assert_raises_rpc_error(
+            -1,
+            'execve failed: No such file or directory',
+            self.nodes[3].enumeratesigners,
+        )

-        assert_raises_rpc_error(-1, 'RunCommandParseJSON error',
-            self.nodes[1].enumeratesigners
-        )
+        assert_raises_rpc_error(
+            -1,
+            'RunCommandParseJSON error',
+            self.nodes[1].enumeratesigners,
+        )

-        assert_raises_rpc_error(-1, 'fingerprint not found',
-            self.nodes[1].enumeratesigners
-        )
+        assert_raises_rpc_error(
+            -1,
+            'fingerprint not found',
+            self.nodes[1].enumeratesigners,
+        )

Also applies to: 56-58, 62-64, 68-70


55-58: Harden missing-signer assertion across OSes.

The exact message “execve failed: No such file or directory” is Linux-specific and will differ on Windows/macOS. Match a less brittle substring or accept multiple options (e.g., “No such file or directory” or “The system cannot find the file specified.”).

src/qt/sendcoinsdialog.cpp (1)

503-518: Optional: sanitize suggested filename for PSBT saves.

Labels/addresses may contain characters invalid for filenames. Consider replacing forbidden characters (/:*?"<>| etc.) or falling back to a safe default.

src/wallet/wallet.h (1)

30-31: Guard external_signer include for non-signer builds.

Protect include behind ENABLE_EXTERNAL_SIGNER to avoid unnecessary coupling.

-#include <external_signer.h>
+#ifdef ENABLE_EXTERNAL_SIGNER
+#include <external_signer.h>
+#endif
test/functional/wallet_signer.py (5)

113-116: Fix flake8 E128/E124: align continuation and closing paren.

-        assert_raises_rpc_error(-1, 'RunCommandParseJSON error',
-            hww.walletdisplayaddress, address1
-        )
+        assert_raises_rpc_error(
+            -1,
+            'RunCommandParseJSON error',
+            hww.walletdisplayaddress,
+            address1,
+        )

128-141: Fix flake8 E122: indent the second descriptor dict.

-        result = mock_wallet.importdescriptors([{
+        result = mock_wallet.importdescriptors([
+            {
             "desc": "pkh([00000001/84'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0/*)#6k3x80k9",
             "timestamp": 0,
             "range": [0,1],
             "internal": False,
             "active": True
-        },
-        {
+            },
+            {
             "desc": "pkh([00000001/84'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/*)#tz5866xa",
             "timestamp": 0,
             "range": [0, 0],
             "internal": True,
             "active": True
-        }])
+            },
+        ])

179-180: Prefer assert_equal for clearer failures.

-        assert(hww.testmempoolaccept([mock_tx])[0]["allowed"])
+        assert_equal(hww.testmempoolaccept([mock_tx])[0]["allowed"], True)

21-26: Make signer path robust on Windows and paths with spaces.
Use sys.executable and quoting to avoid shell issues.

+import sys
+import shlex
...
-        if platform.system() == "Windows":
-            return "py " + path
-        else:
-            return path
+        if platform.system() == "Windows":
+            return f'"{sys.executable}" {shlex.quote(path)}'
+        return path

Please confirm CI on Windows still finds Python via sys.executable.

Also applies to: 29-34, 36-40


100-106: Reduce brittleness of exact address assertion.
Hardcoding the full address risks future derivation/encoding changes. Consider asserting validity and keypath properties instead.

-        assert_equal(address3, "yg8pCsowDbY7PbJMthTi4xkkmhNfcNNdHV")
+        assert_equal(address_info['hdkeypath'].startswith("m/44'/1'/0'/0/"), True)
+        assert_equal(address_info['iswitness'], False)

If the exact address is intentionally fixed by the mock, feel free to keep it.

src/wallet/scriptpubkeyman.h (1)

604-608: SetupDescriptor public hook — consider nodiscard.
Return value indicates success; marking [[nodiscard]] would prevent accidental ignore.

-    bool SetupDescriptor(std::unique_ptr<Descriptor>desc);
+    [[nodiscard]] bool SetupDescriptor(std::unique_ptr<Descriptor> desc);
src/wallet/wallet.cpp (3)

3731-3741: Avoid reusing SignatureData across SPKMs.
Stateful CanProvide() may mutate sigdata; reinitialize per iteration.

 std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script) const
 {
     std::set<ScriptPubKeyMan*> spk_mans;
-    SignatureData sigdata;
     for (const auto& spk_man_pair : m_spk_managers) {
-        if (spk_man_pair.second->CanProvide(script, sigdata)) {
+        SignatureData sigdata;
+        if (spk_man_pair.second->CanProvide(script, sigdata)) {
             spk_mans.insert(spk_man_pair.second.get());
         }
     }
     return spk_mans;
 }

3869-3897: External signer descriptor ingestion — minor hardening.
Consider logging/skipping descriptors with missing/unsupported output types; current continue silently drops them.

-                if (!desc->GetOutputType()) {
-                    continue;
-                }
+                if (!desc->GetOutputType()) {
+                    WalletLogPrintf("%s: skipping descriptor without output type: %s\n", __func__, desc_str);
+                    continue;
+                }

3965-3987: Remove unused variable and assert in IsInternalScriptPubKeyMan.
The output type is fetched but not used; trim dead code.

-    const auto& type = desc_spk_man->GetWalletDescriptor().descriptor->GetOutputType();
-    assert(type.has_value());
-
     return GetScriptPubKeyMan(/*internal=*/true) == desc_spk_man;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5ce1f0 and 08ca6d1b6a71cadc8173d5aa78c12d83bdc06c5f.

📒 Files selected for processing (80)
  • ci/dash/build_src.sh (1 hunks)
  • ci/test/00_setup_env_arm.sh (1 hunks)
  • ci/test/00_setup_env_mac.sh (1 hunks)
  • ci/test/00_setup_env_mac_native_x86_64.sh (1 hunks)
  • ci/test/00_setup_env_native_asan.sh (1 hunks)
  • ci/test/00_setup_env_native_fuzz.sh (1 hunks)
  • ci/test/00_setup_env_native_multiprocess.sh (1 hunks)
  • ci/test/00_setup_env_native_nowallet.sh (1 hunks)
  • ci/test/00_setup_env_native_qt5.sh (1 hunks)
  • ci/test/00_setup_env_native_tsan.sh (1 hunks)
  • ci/test/00_setup_env_s390x.sh (1 hunks)
  • ci/test/00_setup_env_win64.sh (1 hunks)
  • configure.ac (8 hunks)
  • doc/Doxyfile.in (1 hunks)
  • doc/build-openbsd.md (1 hunks)
  • doc/build-osx.md (1 hunks)
  • doc/dependencies.md (1 hunks)
  • doc/external-signer.md (1 hunks)
  • src/Makefile.am (5 hunks)
  • src/Makefile.test.include (1 hunks)
  • src/dummywallet.cpp (1 hunks)
  • src/external_signer.cpp (1 hunks)
  • src/external_signer.h (1 hunks)
  • src/interfaces/node.h (2 hunks)
  • src/interfaces/wallet.h (2 hunks)
  • src/node/interfaces.cpp (3 hunks)
  • src/qt/createwalletdialog.cpp (4 hunks)
  • src/qt/createwalletdialog.h (2 hunks)
  • src/qt/forms/createwalletdialog.ui (2 hunks)
  • src/qt/forms/optionsdialog.ui (1 hunks)
  • src/qt/forms/receiverequestdialog.ui (1 hunks)
  • src/qt/optionsdialog.cpp (3 hunks)
  • src/qt/optionsmodel.cpp (3 hunks)
  • src/qt/optionsmodel.h (1 hunks)
  • src/qt/receiverequestdialog.cpp (1 hunks)
  • src/qt/sendcoinsdialog.cpp (8 hunks)
  • src/qt/sendcoinsdialog.h (2 hunks)
  • src/qt/walletcontroller.cpp (4 hunks)
  • src/qt/walletmodel.cpp (2 hunks)
  • src/qt/walletmodel.h (1 hunks)
  • src/qt/walletmodeltransaction.cpp (1 hunks)
  • src/qt/walletmodeltransaction.h (1 hunks)
  • src/rpc/client.cpp (1 hunks)
  • src/rpc/external_signer.cpp (1 hunks)
  • src/rpc/register.h (2 hunks)
  • src/test/system_tests.cpp (3 hunks)
  • src/util/error.cpp (1 hunks)
  • src/util/error.h (1 hunks)
  • src/util/system.cpp (3 hunks)
  • src/util/system.h (0 hunks)
  • src/wallet/external_signer_scriptpubkeyman.cpp (1 hunks)
  • src/wallet/external_signer_scriptpubkeyman.h (1 hunks)
  • src/wallet/init.cpp (1 hunks)
  • src/wallet/interfaces.cpp (2 hunks)
  • src/wallet/rpc/addresses.cpp (2 hunks)
  • src/wallet/rpc/backup.cpp (2 hunks)
  • src/wallet/rpc/spend.cpp (8 hunks)
  • src/wallet/rpc/wallet.cpp (6 hunks)
  • src/wallet/scriptpubkeyman.cpp (5 hunks)
  • src/wallet/scriptpubkeyman.h (6 hunks)
  • src/wallet/spend.cpp (2 hunks)
  • src/wallet/wallet.cpp (13 hunks)
  • src/wallet/wallet.h (8 hunks)
  • src/wallet/walletdb.cpp (1 hunks)
  • src/wallet/walletdb.h (1 hunks)
  • src/wallet/walletutil.h (1 hunks)
  • test/config.ini.in (1 hunks)
  • test/functional/mocks/invalid_signer.py (1 hunks)
  • test/functional/mocks/multi_signers.py (1 hunks)
  • test/functional/mocks/signer.py (1 hunks)
  • test/functional/rpc_fundrawtransaction.py (1 hunks)
  • test/functional/rpc_help.py (1 hunks)
  • test/functional/rpc_signer.py (1 hunks)
  • test/functional/test_framework/test_framework.py (1 hunks)
  • test/functional/test_framework/test_node.py (1 hunks)
  • test/functional/test_runner.py (1 hunks)
  • test/functional/wallet_abandonconflict.py (5 hunks)
  • test/functional/wallet_listtransactions.py (2 hunks)
  • test/functional/wallet_signer.py (1 hunks)
  • test/lint/spelling.ignore-words.txt (1 hunks)
💤 Files with no reviewable changes (1)
  • src/util/system.h
🧰 Additional context used
📓 Path-based instructions (5)
ci/**

📄 CodeRabbit inference engine (CLAUDE.md)

Unless specifically prompted, avoid making changes to the ci directory (continuous integration)

Files:

  • ci/test/00_setup_env_native_asan.sh
  • ci/test/00_setup_env_s390x.sh
  • ci/test/00_setup_env_win64.sh
  • ci/test/00_setup_env_native_multiprocess.sh
  • ci/test/00_setup_env_mac_native_x86_64.sh
  • ci/test/00_setup_env_arm.sh
  • ci/test/00_setup_env_native_nowallet.sh
  • ci/test/00_setup_env_mac.sh
  • ci/test/00_setup_env_native_fuzz.sh
  • ci/test/00_setup_env_native_qt5.sh
  • ci/dash/build_src.sh
  • ci/test/00_setup_env_native_tsan.sh
doc/**

📄 CodeRabbit inference engine (CLAUDE.md)

Unless specifically prompted, avoid making changes to the doc directory (documentation)

Files:

  • doc/build-openbsd.md
  • doc/Doxyfile.in
  • doc/external-signer.md
  • doc/dependencies.md
  • doc/build-osx.md
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/util/error.cpp
  • src/qt/optionsmodel.h
  • src/qt/createwalletdialog.h
  • src/util/system.cpp
  • src/wallet/external_signer_scriptpubkeyman.cpp
  • src/qt/optionsmodel.cpp
  • src/wallet/walletdb.h
  • src/qt/sendcoinsdialog.cpp
  • src/qt/walletmodel.h
  • src/qt/receiverequestdialog.cpp
  • src/qt/createwalletdialog.cpp
  • src/wallet/rpc/addresses.cpp
  • src/rpc/external_signer.cpp
  • src/test/system_tests.cpp
  • src/qt/sendcoinsdialog.h
  • src/wallet/rpc/wallet.cpp
  • src/util/error.h
  • src/external_signer.h
  • src/wallet/wallet.h
  • src/qt/optionsdialog.cpp
  • src/rpc/register.h
  • src/wallet/rpc/backup.cpp
  • src/wallet/spend.cpp
  • src/qt/walletmodeltransaction.cpp
  • src/wallet/scriptpubkeyman.cpp
  • src/qt/walletmodeltransaction.h
  • src/wallet/walletutil.h
  • src/qt/walletcontroller.cpp
  • src/wallet/rpc/spend.cpp
  • src/interfaces/node.h
  • src/wallet/walletdb.cpp
  • src/wallet/scriptpubkeyman.h
  • src/dummywallet.cpp
  • src/interfaces/wallet.h
  • src/wallet/init.cpp
  • src/external_signer.cpp
  • src/wallet/interfaces.cpp
  • src/wallet/wallet.cpp
  • src/node/interfaces.cpp
  • src/rpc/client.cpp
  • src/wallet/external_signer_scriptpubkeyman.h
  • src/qt/walletmodel.cpp
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/system_tests.cpp
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/mocks/invalid_signer.py
  • test/functional/wallet_abandonconflict.py
  • test/functional/rpc_help.py
  • test/functional/rpc_signer.py
  • test/functional/test_runner.py
  • test/functional/rpc_fundrawtransaction.py
  • test/functional/test_framework/test_node.py
  • test/functional/mocks/signer.py
  • test/functional/test_framework/test_framework.py
  • test/functional/wallet_listtransactions.py
  • test/functional/wallet_signer.py
  • test/functional/mocks/multi_signers.py
🧬 Code graph analysis (39)
src/util/error.cpp (1)
src/util/translation.h (1)
  • Untranslated (48-48)
src/qt/createwalletdialog.h (2)
src/interfaces/node.h (2)
  • interfaces (48-411)
  • ExternalSigner (161-168)
src/qt/createwalletdialog.cpp (12)
  • setSigners (115-134)
  • setSigners (115-115)
  • isEncryptWalletChecked (141-144)
  • isEncryptWalletChecked (141-141)
  • isDisablePrivateKeysChecked (146-149)
  • isDisablePrivateKeysChecked (146-146)
  • isDescriptorWalletChecked (156-159)
  • isDescriptorWalletChecked (156-156)
  • isExternalSignerChecked (161-164)
  • isExternalSignerChecked (161-161)
  • CreateWalletDialog (17-108)
  • CreateWalletDialog (110-113)
src/util/system.cpp (1)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/wallet/external_signer_scriptpubkeyman.cpp (2)
src/wallet/wallet.cpp (6)
  • DisplayAddress (2533-2545)
  • DisplayAddress (2533-2533)
  • GetSolvingProvider (3751-3755)
  • GetSolvingProvider (3751-3751)
  • GetSolvingProvider (3757-3765)
  • GetSolvingProvider (3757-3757)
src/external_signer.cpp (4)
  • Enumerate (24-60)
  • Enumerate (24-24)
  • DisplayAddress (62-65)
  • DisplayAddress (62-62)
src/qt/sendcoinsdialog.cpp (2)
src/qt/guiutil.cpp (4)
  • setClipboard (1653-1660)
  • setClipboard (1653-1653)
  • getSaveFileName (521-559)
  • getSaveFileName (521-523)
src/qt/bitcoinunits.cpp (4)
  • formatWithUnit (125-128)
  • formatWithUnit (125-125)
  • format (80-114)
  • format (80-80)
src/qt/walletmodel.h (1)
src/qt/walletmodel.cpp (2)
  • displayAddress (582-592)
  • displayAddress (582-582)
src/qt/createwalletdialog.cpp (2)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/qt/createwalletdialog.h (1)
  • CreateWalletDialog (24-44)
src/wallet/rpc/addresses.cpp (3)
src/wallet/interfaces.cpp (18)
  • LOCK (249-258)
  • LOCK (259-262)
  • LOCK (290-294)
  • LOCK (295-299)
  • LOCK (352-360)
  • LOCK (478-490)
  • dest (209-213)
  • dest (209-209)
  • dest (222-225)
  • dest (222-222)
  • dest (226-229)
  • dest (226-226)
  • dest (230-248)
  • dest (230-233)
  • dest (263-267)
  • dest (263-263)
  • dest (268-272)
  • dest (268-268)
src/wallet/scriptpubkeyman.h (1)
  • wallet (28-253)
src/wallet/rpc/util.cpp (2)
  • GetWalletForJSONRPCRequest (55-77)
  • GetWalletForJSONRPCRequest (55-55)
src/rpc/external_signer.cpp (2)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/external_signer.cpp (2)
  • Enumerate (24-60)
  • Enumerate (24-24)
src/test/system_tests.cpp (2)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/util/system.cpp (2)
  • RunCommandParseJSON (1401-1438)
  • RunCommandParseJSON (1401-1401)
src/qt/sendcoinsdialog.h (1)
src/qt/sendcoinsdialog.cpp (6)
  • presentPSBT (489-533)
  • presentPSBT (489-489)
  • processSendCoinsReturn (820-859)
  • processSendCoinsReturn (820-820)
  • signWithExternalSigner (535-561)
  • signWithExternalSigner (535-535)
src/wallet/rpc/wallet.cpp (2)
src/wallet/rpc/addresses.cpp (2)
  • walletdisplayaddress (674-712)
  • walletdisplayaddress (674-674)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/external_signer.h (1)
src/external_signer.cpp (11)
  • ExternalSigner (17-17)
  • NetworkArg (19-22)
  • NetworkArg (19-19)
  • Enumerate (24-60)
  • Enumerate (24-24)
  • DisplayAddress (62-65)
  • DisplayAddress (62-62)
  • GetDescriptors (67-70)
  • GetDescriptors (67-67)
  • SignTransaction (72-117)
  • SignTransaction (72-72)
src/wallet/wallet.h (5)
src/wallet/wallet.cpp (19)
  • DisplayAddress (2533-2545)
  • DisplayAddress (2533-2533)
  • FillPSBT (2060-2109)
  • FillPSBT (2060-2060)
  • IsMine (1449-1453)
  • IsMine (1449-1449)
  • IsMine (1455-1459)
  • IsMine (1455-1455)
  • IsMine (1461-1469)
  • IsMine (1461-1461)
  • IsMine (1471-1478)
  • IsMine (1471-1471)
  • IsMine (1480-1491)
  • IsMine (1480-1480)
  • outpoint (1082-1082)
  • GetScriptPubKeyMans (3731-3741)
  • GetScriptPubKeyMans (3731-3731)
  • IsInternalScriptPubKeyMan (3965-3987)
  • IsInternalScriptPubKeyMan (3965-3965)
src/wallet/external_signer_scriptpubkeyman.cpp (4)
  • DisplayAddress (53-62)
  • DisplayAddress (53-53)
  • FillPSBT (65-86)
  • FillPSBT (65-65)
src/external_signer.cpp (2)
  • DisplayAddress (62-65)
  • DisplayAddress (62-62)
src/wallet/interfaces.cpp (21)
  • dest (209-213)
  • dest (209-209)
  • dest (222-225)
  • dest (222-222)
  • dest (226-229)
  • dest (226-226)
  • dest (230-248)
  • dest (230-233)
  • dest (263-267)
  • dest (263-263)
  • dest (268-272)
  • dest (268-268)
  • outpoint (397-397)
  • outpoint (397-397)
  • outpoint (398-398)
  • outpoint (398-398)
  • script (188-195)
  • script (188-188)
  • script (204-208)
  • script (204-204)
  • spk_man (214-221)
src/wallet/scriptpubkeyman.h (5)
  • ScriptPubKeyMan (170-233)
  • ScriptPubKeyMan (178-178)
  • bool (185-185)
  • bool (230-230)
  • bool (236-236)
src/qt/optionsdialog.cpp (1)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
test/functional/mocks/invalid_signer.py (2)
test/functional/mocks/signer.py (3)
  • perform_pre_checks (11-18)
  • enumerate (20-21)
  • getdescriptors (23-37)
test/functional/mocks/multi_signers.py (1)
  • enumerate (10-12)
test/functional/wallet_abandonconflict.py (4)
test/functional/test_framework/test_node.py (1)
  • get_wallet_rpc (363-369)
test/functional/test_framework/test_framework.py (2)
  • sync_mempools (848-874)
  • disconnect_nodes (744-778)
test/functional/test_framework/util.py (1)
  • assert_raises_rpc_error (132-148)
src/wallet/rpc/transactions.cpp (8)
  • abandontransaction (803-842)
  • abandontransaction (803-803)
  • gettransaction (694-801)
  • gettransaction (694-694)
  • listsinceblock (554-692)
  • listsinceblock (554-554)
  • listtransactions (442-552)
  • listtransactions (442-442)
src/rpc/register.h (2)
src/rpc/external_signer.cpp (2)
  • RegisterSignerRPCCommands (61-69)
  • RegisterSignerRPCCommands (61-61)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/wallet/rpc/backup.cpp (1)
src/wallet/scriptpubkeyman.h (1)
  • wallet (28-253)
src/wallet/spend.cpp (2)
src/interfaces/wallet.h (2)
  • wallet (39-46)
  • wallet (389-389)
src/node/interfaces.cpp (2)
  • coins (998-998)
  • coins (998-998)
test/functional/rpc_help.py (2)
test/functional/test_framework/test_framework.py (2)
  • is_external_signer_compiled (1115-1117)
  • is_zmq_compiled (1135-1137)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
test/functional/rpc_signer.py (4)
test/functional/test_framework/test_framework.py (1)
  • skip_if_no_external_signer (1106-1109)
test/functional/test_framework/util.py (2)
  • assert_equal (69-74)
  • assert_raises_rpc_error (132-148)
test/functional/wallet_signer.py (5)
  • mock_signer_path (21-26)
  • set_test_params (42-48)
  • skip_test_if_missing_module (50-52)
  • set_mock_result (54-56)
  • clear_mock_result (58-59)
src/rpc/external_signer.cpp (2)
  • enumeratesigners (16-59)
  • enumeratesigners (16-16)
src/qt/walletmodeltransaction.h (1)
src/qt/walletmodeltransaction.cpp (2)
  • setWtx (29-32)
  • setWtx (29-29)
test/functional/rpc_fundrawtransaction.py (2)
test/functional/test_framework/util.py (1)
  • assert_raises_rpc_error (132-148)
src/wallet/rpc/spend.cpp (2)
  • fundrawtransaction (554-644)
  • fundrawtransaction (554-554)
src/interfaces/node.h (2)
src/external_signer.cpp (1)
  • ExternalSigner (17-17)
src/external_signer.h (1)
  • ExternalSigner (18-64)
src/wallet/walletdb.cpp (1)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/wallet/scriptpubkeyman.h (3)
src/wallet/scriptpubkeyman.cpp (6)
  • MarkUnusedAddresses (305-340)
  • MarkUnusedAddresses (305-305)
  • MarkUnusedAddresses (2019-2045)
  • MarkUnusedAddresses (2019-2019)
  • MarkReserveKeysAsUsed (1624-1649)
  • MarkReserveKeysAsUsed (1624-1624)
src/wallet/walletutil.h (1)
  • WalletDescriptor (70-103)
src/wallet/external_signer_scriptpubkeyman.cpp (2)
  • SetupDescriptor (17-40)
  • SetupDescriptor (17-17)
src/interfaces/wallet.h (2)
src/qt/walletmodel.cpp (2)
  • displayAddress (582-592)
  • displayAddress (582-582)
src/wallet/interfaces.cpp (12)
  • dest (209-213)
  • dest (209-209)
  • dest (222-225)
  • dest (222-222)
  • dest (226-229)
  • dest (226-226)
  • dest (230-248)
  • dest (230-233)
  • dest (263-267)
  • dest (263-263)
  • dest (268-272)
  • dest (268-268)
src/wallet/init.cpp (2)
src/node/interfaces.cpp (1)
  • ENABLE_EXTERNAL_SIGNER (530-551)
src/dummywallet.cpp (1)
  • argsman (31-31)
test/functional/test_framework/test_node.py (1)
src/wallet/rpc/wallet.cpp (2)
  • createwallet (615-713)
  • createwallet (615-615)
src/external_signer.cpp (4)
src/external_signer.h (1)
  • ExternalSigner (18-64)
src/util/system.cpp (2)
  • RunCommandParseJSON (1401-1438)
  • RunCommandParseJSON (1401-1401)
src/wallet/wallet.cpp (6)
  • DisplayAddress (2533-2545)
  • DisplayAddress (2533-2533)
  • SignTransaction (2026-2043)
  • SignTransaction (2026-2026)
  • SignTransaction (2045-2058)
  • SignTransaction (2045-2045)
src/wallet/external_signer_scriptpubkeyman.cpp (2)
  • DisplayAddress (53-62)
  • DisplayAddress (53-53)
test/functional/mocks/signer.py (2)
test/functional/mocks/invalid_signer.py (3)
  • perform_pre_checks (11-18)
  • enumerate (20-21)
  • getdescriptors (23-39)
test/functional/mocks/multi_signers.py (1)
  • enumerate (10-12)
src/wallet/wallet.cpp (5)
src/wallet/interfaces.cpp (26)
  • txout (463-467)
  • txout (463-463)
  • txout (473-477)
  • txout (473-473)
  • dest (209-213)
  • dest (209-209)
  • dest (222-225)
  • dest (222-222)
  • dest (226-229)
  • dest (226-226)
  • dest (230-248)
  • dest (230-233)
  • dest (263-267)
  • dest (263-263)
  • dest (268-272)
  • dest (268-268)
  • script (188-195)
  • script (188-188)
  • script (204-208)
  • script (204-204)
  • LOCK (249-258)
  • LOCK (259-262)
  • LOCK (290-294)
  • LOCK (295-299)
  • LOCK (352-360)
  • LOCK (478-490)
src/wallet/scriptpubkeyman.cpp (9)
  • IsMine (165-177)
  • IsMine (165-165)
  • IsMine (179-183)
  • IsMine (179-179)
  • IsMine (1828-1835)
  • IsMine (1828-1828)
  • IsMine (1837-1841)
  • IsMine (1837-1837)
  • id (1684-1684)
src/wallet/scriptpubkeyman.h (2)
  • IsMine (180-180)
  • IsMine (181-181)
src/wallet/external_signer_scriptpubkeyman.cpp (4)
  • DisplayAddress (53-62)
  • DisplayAddress (53-53)
  • GetExternalSigner (42-51)
  • GetExternalSigner (42-42)
src/external_signer.cpp (2)
  • DisplayAddress (62-65)
  • DisplayAddress (62-62)
src/node/interfaces.cpp (1)
src/external_signer.cpp (2)
  • Enumerate (24-60)
  • Enumerate (24-24)
src/wallet/external_signer_scriptpubkeyman.h (4)
src/wallet/scriptpubkeyman.h (6)
  • wallet (28-253)
  • DescriptorScriptPubKeyMan (528-650)
  • WalletStorage (34-246)
  • bool (185-185)
  • bool (230-230)
  • bool (236-236)
src/wallet/external_signer_scriptpubkeyman.cpp (8)
  • SetupDescriptor (17-40)
  • SetupDescriptor (17-17)
  • GetExternalSigner (42-51)
  • GetExternalSigner (42-42)
  • DisplayAddress (53-62)
  • DisplayAddress (53-53)
  • FillPSBT (65-86)
  • FillPSBT (65-65)
src/wallet/wallet.cpp (4)
  • DisplayAddress (2533-2545)
  • DisplayAddress (2533-2533)
  • FillPSBT (2060-2109)
  • FillPSBT (2060-2060)
src/wallet/scriptpubkeyman.cpp (4)
  • FillPSBT (743-787)
  • FillPSBT (743-743)
  • FillPSBT (2314-2381)
  • FillPSBT (2314-2314)
test/functional/wallet_listtransactions.py (4)
test/functional/test_framework/test_framework.py (2)
  • stop_nodes (684-692)
  • start_nodes (660-678)
test/functional/test_framework/util.py (2)
  • assert_equal (69-74)
  • assert_raises_rpc_error (132-148)
src/wallet/rpc/addresses.cpp (6)
  • keypoolrefill (263-305)
  • keypoolrefill (263-263)
  • getnewaddress (17-56)
  • getnewaddress (17-17)
  • getaddressinfo (418-563)
  • getaddressinfo (418-418)
src/wallet/rpc/transactions.cpp (2)
  • listtransactions (442-552)
  • listtransactions (442-442)
test/functional/wallet_signer.py (6)
test/functional/test_framework/test_framework.py (9)
  • set_test_params (415-417)
  • set_test_params (1473-1475)
  • skip_test_if_missing_module (423-425)
  • skip_test_if_missing_module (1477-1478)
  • skip_if_no_external_signer (1106-1109)
  • run_test (494-496)
  • run_test (1480-1482)
  • restart_node (694-697)
  • is_bdb_compiled (1147-1149)
test/functional/rpc_signer.py (6)
  • mock_signer_path (21-26)
  • set_test_params (28-36)
  • skip_test_if_missing_module (38-39)
  • set_mock_result (41-43)
  • clear_mock_result (45-46)
  • run_test (48-73)
src/wallet/rpc/wallet.cpp (14)
  • res (591-591)
  • createwallet (615-713)
  • createwallet (615-615)
  • getwalletinfo (152-276)
  • getwalletinfo (152-152)
  • getnewaddress (1098-1098)
  • getaddressinfo (1097-1097)
  • result (308-308)
  • result (766-766)
  • result (1088-1088)
  • walletdisplayaddress (1108-1108)
  • walletcreatefundedpsbt (1151-1151)
  • walletprocesspsbt (1150-1150)
  • send (1149-1149)
test/functional/test_framework/test_node.py (2)
  • createwallet (884-889)
  • get_wallet_rpc (363-369)
src/wallet/rpc/addresses.cpp (10)
  • getnewaddress (17-56)
  • getnewaddress (17-17)
  • getaddressinfo (418-563)
  • getaddressinfo (418-418)
  • result (254-254)
  • result (707-707)
  • walletdisplayaddress (674-712)
  • walletdisplayaddress (674-674)
  • dest (382-382)
  • dest (382-382)
src/wallet/rpc/spend.cpp (11)
  • result (636-636)
  • result (730-730)
  • result (903-903)
  • result (998-998)
  • result (1127-1127)
  • walletcreatefundedpsbt (1009-1134)
  • walletcreatefundedpsbt (1009-1009)
  • walletprocesspsbt (930-1007)
  • walletprocesspsbt (930-930)
  • send (737-928)
  • send (737-737)
test/functional/mocks/multi_signers.py (2)
test/functional/mocks/invalid_signer.py (1)
  • enumerate (20-21)
test/functional/mocks/signer.py (1)
  • enumerate (20-21)
src/qt/walletmodel.cpp (1)
src/wallet/interfaces.cpp (28)
  • dest (209-213)
  • dest (209-209)
  • dest (222-225)
  • dest (222-222)
  • dest (226-229)
  • dest (226-226)
  • dest (230-248)
  • dest (230-233)
  • dest (263-267)
  • dest (263-263)
  • dest (268-272)
  • dest (268-268)
  • m_wallet (157-160)
  • m_wallet (165-165)
  • m_wallet (174-174)
  • m_wallet (175-175)
  • m_wallet (181-181)
  • m_wallet (182-182)
  • m_wallet (442-445)
  • m_wallet (446-449)
  • m_wallet (521-521)
  • m_wallet (522-522)
  • m_wallet (523-523)
  • m_wallet (524-524)
  • m_wallet (525-525)
  • m_wallet (526-526)
  • m_wallet (531-531)
  • m_wallet (591-591)
🪛 Flake8 (7.3.0)
test/functional/wallet_abandonconflict.py

[error] 79-79: block comment should start with '# '

(E265)


[error] 120-120: test for membership should be 'not in'

(E713)

test/functional/rpc_signer.py

[error] 52-52: continuation line under-indented for visual indent

(E128)


[error] 57-57: continuation line under-indented for visual indent

(E128)


[error] 63-63: continuation line under-indented for visual indent

(E128)


[error] 69-69: continuation line under-indented for visual indent

(E128)

test/functional/mocks/signer.py

[error] 96-96: indentation is not a multiple of 4

(E111)

test/functional/wallet_signer.py

[error] 115-115: continuation line under-indented for visual indent

(E128)


[error] 116-116: closing bracket does not match visual indentation

(E124)


[error] 135-135: continuation line missing indentation or outdented

(E122)

test/functional/mocks/multi_signers.py

[error] 12-12: continuation line under-indented for visual indent

(E128)

🪛 LanguageTool
doc/external-signer.md

[style] ~70-~70: Consider a more concise word here.
Context: ...ue, "txid": } ``` ## Signer API In order to be compatible with Dash Core any signer...

(IN_ORDER_TO_PREMIUM)


[grammar] ~167-~167: Use a hyphen to join words.
Context: ... support address types, in a BIP44/49/84 compatible manner. The `walletdisplayad...

(QB_NEW_EN_HYPHEN)

doc/build-osx.md

[grammar] ~87-~87: Ensure spelling is correct
Context: ...descriptor wallets. macOS ships with a useable sqlite package, meaning you don't nee...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
doc/external-signer.md

14-14: Dollar signs used before commands without showing output

(MD014, commands-show-output)


25-25: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


40-40: Dollar signs used before commands without showing output

(MD014, commands-show-output)


48-48: Dollar signs used before commands without showing output

(MD014, commands-show-output)


49-49: Dollar signs used before commands without showing output

(MD014, commands-show-output)


59-59: Dollar signs used before commands without showing output

(MD014, commands-show-output)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


98-98: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


115-115: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


122-122: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


141-141: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


147-147: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

doc/build-osx.md

83-83: Heading levels should only increment by one level at a time
Expected: h5; Actual: h6

(MD001, heading-increment)

🪛 Ruff (0.14.1)
test/functional/mocks/invalid_signer.py

20-20: Unused function argument: args

(ARG001)

test/functional/wallet_abandonconflict.py

120-120: Test for membership should be not in

Convert to not in

(E713)

test/functional/mocks/signer.py

20-20: Unused function argument: args

(ARG001)

test/functional/test_framework/test_framework.py

1109-1109: Avoid specifying long messages outside the exception class

(TRY003)

test/functional/mocks/multi_signers.py

10-10: Unused function argument: args

(ARG001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build container / Build container

Comment on lines 31 to 58
for (UniValue signer : result.getValues()) {
// Check for error
const UniValue& error = signer.find_value("error");
if (!error.isNull()) {
if (!error.isStr()) {
throw std::runtime_error(strprintf("'%s' error", command));
}
throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr()));
}
// Check if fingerprint is present
const UniValue& fingerprint = signer.find_value("fingerprint");
if (fingerprint.isNull()) {
throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command));
}
const std::string fingerprintStr = fingerprint.get_str();
// Skip duplicate signer
bool duplicate = false;
for (const ExternalSigner& signer : signers) {
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) break;
std::string name = "";
const UniValue& model_field = signer.find_value("model");
if (model_field.isStr() && model_field.getValStr() != "") {
name += model_field.getValStr();
}
signers.push_back(ExternalSigner(command, chain, fingerprintStr, name));
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Avoid shadowing and unnecessary copies in enumerate loop.

Use const references and distinct names for clarity.

-    for (UniValue signer : result.getValues()) {
+    for (const UniValue& entry : result.getValues()) {
@@
-        const UniValue& error = signer.find_value("error");
+        const UniValue& error = entry.find_value("error");
@@
-        const UniValue& fingerprint = signer.find_value("fingerprint");
+        const UniValue& fingerprint = entry.find_value("fingerprint");
@@
-        for (const ExternalSigner& signer : signers) {
-            if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
+        for (const ExternalSigner& existing : signers) {
+            if (existing.m_fingerprint == fingerprintStr) {
+                duplicate = true;
+                break;
+            }
         }
@@
-        const UniValue& model_field = signer.find_value("model");
+        const UniValue& model_field = entry.find_value("model");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (UniValue signer : result.getValues()) {
// Check for error
const UniValue& error = signer.find_value("error");
if (!error.isNull()) {
if (!error.isStr()) {
throw std::runtime_error(strprintf("'%s' error", command));
}
throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr()));
}
// Check if fingerprint is present
const UniValue& fingerprint = signer.find_value("fingerprint");
if (fingerprint.isNull()) {
throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command));
}
const std::string fingerprintStr = fingerprint.get_str();
// Skip duplicate signer
bool duplicate = false;
for (const ExternalSigner& signer : signers) {
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) break;
std::string name = "";
const UniValue& model_field = signer.find_value("model");
if (model_field.isStr() && model_field.getValStr() != "") {
name += model_field.getValStr();
}
signers.push_back(ExternalSigner(command, chain, fingerprintStr, name));
}
for (const UniValue& entry : result.getValues()) {
// Check for error
const UniValue& error = entry.find_value("error");
if (!error.isNull()) {
if (!error.isStr()) {
throw std::runtime_error(strprintf("'%s' error", command));
}
throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr()));
}
// Check if fingerprint is present
const UniValue& fingerprint = entry.find_value("fingerprint");
if (fingerprint.isNull()) {
throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command));
}
const std::string fingerprintStr = fingerprint.get_str();
// Skip duplicate signer
bool duplicate = false;
for (const ExternalSigner& existing : signers) {
if (existing.m_fingerprint == fingerprintStr) {
duplicate = true;
break;
}
}
if (duplicate) break;
std::string name = "";
const UniValue& model_field = entry.find_value("model");
if (model_field.isStr() && model_field.getValStr() != "") {
name += model_field.getValStr();
}
signers.push_back(ExternalSigner(command, chain, fingerprintStr, name));
}

Comment on lines 47 to 52
bool duplicate = false;
for (const ExternalSigner& signer : signers) {
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) break;
std::string name = "";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Duplicate handling aborts enumeration prematurely.

Using break on duplicate fingerprint stops processing remaining entries. Use continue to skip only the duplicate.

-        if (duplicate) break;
+        if (duplicate) continue;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool duplicate = false;
for (const ExternalSigner& signer : signers) {
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) break;
std::string name = "";
bool duplicate = false;
for (const ExternalSigner& signer : signers) {
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) continue;
std::string name = "";
🤖 Prompt for AI Agents
In src/external_signer.cpp around lines 47 to 52, the loop uses break when a
duplicate fingerprint is found which aborts the entire enumeration; change the
control flow to skip only the current entry by replacing the break with continue
so the loop keeps processing remaining signers, ensuring duplicate remains
detection stays the same and no other entries are prematurely skipped.

Comment on lines 87 to 90
if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) {
error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str());
return false;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t include full PSBT in error strings.

The current error leaks base64 PSBT, which is sensitive. Keep the message minimal.

-        error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str());
+        error = "Signer fingerprint " + m_fingerprint + " does not match any PSBT input.";
🤖 Prompt for AI Agents
In src/external_signer.cpp around lines 87 to 90, the error string currently
appends the full base64 PSBT (sensitive data); remove the
EncodeBase64(ssTx.str()) portion and replace the message with a minimal,
non-sensitive description (for example: indicate the signer fingerprint
mismatched and optionally include non-sensitive metadata such as the PSBT input
count or PSBT txid/hash if available), then return false as before.

Comment on lines 93 to 96
if not sys.stdin.isatty():
buffer = sys.stdin.read()
if buffer and buffer.rstrip() != "":
sys.argv.extend(buffer.rstrip().split(" "))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix the indentation on line 96.

Line 96 uses 3 spaces instead of a multiple of 4, violating PEP 8 style guidelines.

Apply this diff:

 if not sys.stdin.isatty():
     buffer = sys.stdin.read()
     if buffer and buffer.rstrip() != "":
-       sys.argv.extend(buffer.rstrip().split(" "))
+        sys.argv.extend(buffer.rstrip().split(" "))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not sys.stdin.isatty():
buffer = sys.stdin.read()
if buffer and buffer.rstrip() != "":
sys.argv.extend(buffer.rstrip().split(" "))
if not sys.stdin.isatty():
buffer = sys.stdin.read()
if buffer and buffer.rstrip() != "":
sys.argv.extend(buffer.rstrip().split(" "))
🧰 Tools
🪛 Flake8 (7.3.0)

[error] 96-96: indentation is not a multiple of 4

(E111)

🤖 Prompt for AI Agents
In test/functional/mocks/signer.py around lines 93 to 96, the third line in the
if-block (currently using 3-space indentation) violates PEP 8; re-indent that
line to use a multiple of 4 spaces (align it with the other block lines, i.e.,
replace the 3-space indent with 4 spaces) so the if-block uses consistent
4-space indentation.

Comment on lines 108 to 117
if self.is_external_signer_compiled():
components.append('Signer')

if self.is_zmq_compiled():
components.append('Zmq')

assert_equal(titles, components)
assert_equal(titles, sorted(components))

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make the category comparison truly order‑insensitive.

Sort titles as well, not just components.

-        assert_equal(titles, sorted(components))
+        assert_equal(sorted(titles), sorted(components))
🤖 Prompt for AI Agents
In test/functional/rpc_help.py around lines 108 to 115, the comparison only
sorts the components list but not titles, which makes the assertion
order-sensitive; update the assertion to compare both lists in a deterministic
order by sorting titles as well (e.g., assert_equal(sorted(titles),
sorted(components))) so the comparison is truly order-insensitive.

txAB1 = self.nodes[0].sendrawtransaction(signed["hex"])

# Identify the 14.99998btc output
nAB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txAB1)["details"] if tx_out["amount"] == Decimal("14.99998"))
nAB = next(tx_out["vout"] for tx_out in alice.gettransaction(txAB1)["details"] if tx_out["amount"] == Decimal("14.99998"))

#Create a child tx spending AB1 and C
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix comment formatting.

The comment should have a space after the # symbol per PEP 8.

Apply this diff:

-        #Create a child tx spending AB1 and C
+        # Create a child tx spending AB1 and C
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#Create a child tx spending AB1 and C
# Create a child tx spending AB1 and C
🧰 Tools
🪛 Flake8 (7.3.0)

[error] 79-79: block comment should start with '# '

(E265)

🤖 Prompt for AI Agents
In test/functional/wallet_abandonconflict.py around line 79, the inline comment
"#Create a child tx spending AB1 and C" does not follow PEP 8; add a space after
the '#' so it reads "# Create a child tx spending AB1 and C". Update only the
comment text to include the leading space and keep the rest of the line
unchanged.

assert_equal(balances['untrusted_pending'] + balances['trusted'], newbalance)
# Also shouldn't show up in listunspent
assert not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)]
assert not txABC2 in [utxo["txid"] for utxo in alice.listunspent(0)]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use idiomatic membership test.

Replace not txABC2 in with txABC2 not in for better readability per PEP 8.

Apply this diff:

-        assert not txABC2 in [utxo["txid"] for utxo in alice.listunspent(0)]
+        assert txABC2 not in [utxo["txid"] for utxo in alice.listunspent(0)]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert not txABC2 in [utxo["txid"] for utxo in alice.listunspent(0)]
assert txABC2 not in [utxo["txid"] for utxo in alice.listunspent(0)]
🧰 Tools
🪛 Flake8 (7.3.0)

[error] 120-120: test for membership should be 'not in'

(E713)

🪛 Ruff (0.14.1)

120-120: Test for membership should be not in

Convert to not in

(E713)

🤖 Prompt for AI Agents
In test/functional/wallet_abandonconflict.py around line 120, replace the
non-idiomatic membership test "not txABC2 in ..." with the PEP 8 preferred
"txABC2 not in ...": update the assertion to use "txABC2 not in [utxo['txid']
for utxo in alice.listunspent(0)]" so the test reads more clearly and follows
Python style guidelines.

Comment on lines 124 to 126
addr1 = self.nodes[0].getnewaddress("pizza1", 'legacy')
addr2 = self.nodes[0].getnewaddress("pizza2", 'p2sh-segwit')
addr3 = self.nodes[0].getnewaddress("pizza3", 'bech32')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Incorrect RPC usage: Dash getnewaddress does not accept address_type; bech32/p2sh‑segwit are unsupported.

Dash Core getnewaddress only takes an optional label and returns base58 addresses; there is no address_type argument (and Dash does not use bech32). This test will fail with “too many parameters” or invalid type. Update to call getnewaddress with just the label.

-        addr1 = self.nodes[0].getnewaddress("pizza1", 'legacy')
-        addr2 = self.nodes[0].getnewaddress("pizza2", 'p2sh-segwit')
-        addr3 = self.nodes[0].getnewaddress("pizza3", 'bech32')
+        addr1 = self.nodes[0].getnewaddress("pizza1")
+        addr2 = self.nodes[0].getnewaddress("pizza2")
+        addr3 = self.nodes[0].getnewaddress("pizza3")

Evidence: Dash Core wallet RPC docs list only a single label parameter and base58 result; no address_type is documented. Also, the provided src/wallet/rpc/addresses.cpp snippet shows a single parameter “label”. (docs.dash.org)


🏁 Script executed:

#!/bin/bash
# Verify Dash's RPC signature in-tree to avoid relying on assumptions.
rg -nP 'RPCHelpMan\s+getnewaddress\s*\(\)' -n -C3 --no-heading src | sed -n '1,120p'

Length of output: 1266


I need to see the full getnewaddress() function implementation to verify the parameter signature.


---

🏁 Script executed:

```shell
#!/bin/bash
# Extract the full getnewaddress() function definition to see all parameters
sed -n '17,100p' src/wallet/rpc/addresses.cpp

Length of output: 3069


Fix incorrect getnewaddress RPC calls: remove address_type parameter.

The Dash RPC getnewaddress() function definition (src/wallet/rpc/addresses.cpp:17-56) accepts only a single optional label parameter. The test code incorrectly passes a second address_type argument ('legacy', 'p2sh-segwit', 'bech32'), which Dash does not support and will cause the RPC call to fail.

-        addr1 = self.nodes[0].getnewaddress("pizza1", 'legacy')
-        addr2 = self.nodes[0].getnewaddress("pizza2", 'p2sh-segwit')
-        addr3 = self.nodes[0].getnewaddress("pizza3", 'bech32')
+        addr1 = self.nodes[0].getnewaddress("pizza1")
+        addr2 = self.nodes[0].getnewaddress("pizza2")
+        addr3 = self.nodes[0].getnewaddress("pizza3")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
addr1 = self.nodes[0].getnewaddress("pizza1", 'legacy')
addr2 = self.nodes[0].getnewaddress("pizza2", 'p2sh-segwit')
addr3 = self.nodes[0].getnewaddress("pizza3", 'bech32')
addr1 = self.nodes[0].getnewaddress("pizza1")
addr2 = self.nodes[0].getnewaddress("pizza2")
addr3 = self.nodes[0].getnewaddress("pizza3")
🤖 Prompt for AI Agents
In test/functional/wallet_listtransactions.py around lines 124 to 126, the calls
to getnewaddress pass an unsupported second address_type argument ('legacy',
'p2sh-segwit', 'bech32'); Dash's getnewaddress RPC only accepts an optional
label. Remove the second argument from each call so each invocation is just
getnewaddress("label") (e.g., getnewaddress("pizza1")), leaving label usage
intact and avoiding the invalid parameter that causes the RPC to fail.

@github-actions
Copy link

github-actions bot commented Nov 4, 2025

This pull request has conflicts, please rebase.

PastaPastaPasta added a commit that referenced this pull request Nov 25, 2025
013953b Merge bitcoin#24065: build: explicitly disable support for external signing on Windows (fanquake)
d1ce974 fix: missing changes from bitcoin#22320 for external signer (Konstantin Akimov)
2718bbd Merge bitcoin-core/gui#441: Add Create Unsigned button to SendConfirmationDialog (Hennadii Stepanov)
f6410f3 fix: dashify doc/external-signer.md (Konstantin Akimov)
6c4ba34 Merge bitcoin#25770: build: Fix help string for `--enable-external-signer` configure option (fanquake)
8fae189 Merge bitcoin#25019: parse external signer master fp as bytes in ExternalSigner::SignTransaction (Andrew Chow)
e852bdf Merge bitcoin#24401: wallet: Add external-signer-support specific error message (Andrew Chow)
a6f7e73 Merge bitcoin#24307: RPC: Return external_signer in getwalletinfo (Andrew Chow)
65bb461 Merge bitcoin#23628: Check descriptors returned by external signers (fanquake)
8c559be Merge bitcoin#23004: multiprocess: add interfaces::ExternalSigner class (W. J. van der Laan)
6a73d31 Merge bitcoin#22789: external_signer: improve fingerprint matching logic (stop on first match) (W. J. van der Laan)
8e5f624 Merge bitcoin-core/gui#396: Ensure external signer option remains disabled without signers (Hennadii Stepanov)
6d07721 Merge bitcoin#22348: build: Fix cross build for Windows with Boost Process (fanquake)
1b9b7c7 Merge bitcoin#21935: Enable external signer support by default, reduce #ifdef (fanquake)
9c30a2e Merge bitcoin#22173: wallet: Do not load external signers wallets when unsupported (Samuel Dobson)
38911c7 Merge bitcoin-core/gui#4: UI external signer support (e.g. hardware wallet) (Samuel Dobson)
2ebf7ca Merge bitcoin#21666: Miscellaneous external signer changes (fanquake)
7dbb4c1 Merge bitcoin#21467: Move external signer out of wallet module (fanquake)
6373ba7 Merge bitcoin#21417: Misc external signer improvement and HWI 2 support (fanquake)
fac568a Merge bitcoin#21292: build, doc: Fix configure script output indentation and typos (MarcoFalke)
3a3dfa3 Merge bitcoin#21285: wallet: fix doc typo in signer option (fanquake)
a33222d fix: alignment in configure.ac for debug output of options choice (Konstantin Akimov)
d49f0eb Merge bitcoin#16546: External signer support - Wallet Box edition (Wladimir J. van der Laan)
4bb4981 fix: remove nodiscard attribute as follow-up for bitcoin#18115 (Konstantin Akimov)
52f7cad fix: missing dashification of rpc/backup.cpp (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  This PR introduce support of external signers (for example, hardware signers such as Ledger) which could be used to sign transactions, using existing feature PSBT.

  ## What was done?
  Bitcoin backports from Bitcoin Core v22, v23, v24 to support hardware wallets in Dash Core.

  This PR is not the smallest possible set of backports, but it is set that provide working external signer in both CLI and GUI versions of Dash Core. Extra backports to improve user experience are to be done in the next PRs, see #6913

  ## How Has This Been Tested?
  Got successfully signed transaction using a repo https://github.com/knst/hwi/ (WIP, see also knst/HWI#1)

  ## Breaking Changes
  It introduces multiple new RPC, doesn't seems as any really breaking change

  ## Checklist:
  - [x] 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
  - [x] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  UdjinM6:
    utACK 013953b

Tree-SHA512: ec2158526d00130beef1d99c0030f5e3df4a4c62f439eb16bf31297c1ab5888af2e76ecaa2d7edfe31ba668a5ce550184e244e55ce1db85c3218fd9f53c6d118
abc057c build: Add Boost.Process usage check (Hennadii Stepanov)

Pull request description:

  This PR adds a check that Boost.Process can be used without linking any libraries (header-only).
  Disable the functionality if that is not the case.

  Fixes bitcoin#24314.

ACKs for top commit:
  fanquake:
    ACK abc057c

Tree-SHA512: ed2a32b1f751ec6f88cc7220766edd4cdab93c1d0515c892aa3094ee8d5b13ef569830d6e7a7a00c0197b117585dc526d00d943cc99a1f8c8a66ac4e20fe2061
@knst knst changed the title backport: _to-insert-list_ external signer backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #27449 (external signer, boost) Nov 25, 2025
laanwj and others added 7 commits November 26, 2025 02:07
…d older

774323e ci: Force `--enable-external-signer` to prevent future regressions (Hennadii Stepanov)
6997885 build: Fix Boost.Process check for Boost 1.73 and older (Hennadii Stepanov)
2199ef7 build: Fix a non-portable use of `test` (Hennadii Stepanov)
d436c48 build, refactor: Replace tabs with spaces (Hennadii Stepanov)

Pull request description:

  On master (5f44c5c) Boost.Process check false fails without the `-lpthread` flag.

  ```
  $ grep -C 2 pthread_detach config.log
  /usr/bin/ld: /tmp/cczCQfQv.o: in function `boost::asio::detail::posix_global_impl<boost::asio::system_context>::~posix_global_impl()':
  conftest.cpp:(.text._ZN5boost4asio6detail17posix_global_implINS0_14system_contextEED2Ev[_ZN5boost4asio6detail17posix_global_implINS0_14system_contextEED5Ev]+0xa3): undefined reference to `pthread_join'
  /usr/bin/ld: conftest.cpp:(.text._ZN5boost4asio6detail17posix_global_implINS0_14system_contextEED2Ev[_ZN5boost4asio6detail17posix_global_implINS0_14system_contextEED5Ev]+0xc4): undefined reference to `pthread_detach'
  collect2: error: ld returned 1 exit status
  configure:26674: $? = 1
  ```

  Not required for Boost 1.74+.

ACKs for top commit:
  laanwj:
    Code review ACK 774323e, is a bugfix/workaround, seems fine to merge last minute for 23.0.

Tree-SHA512: 2a9d4b67fd8910e107af972d8c223286b7c933bc310616f86c8b6d8c903438916980fc76bd7e37f2698f6ce5361dc706cbf2933d1ac2c081bcabe1b83ca7d6b6
1d4157a build: Fix Boost.Process detection on macOS arm64 (Hennadii Stepanov)

Pull request description:

  Could be tested as follows:
  ```
  % brew install [email protected]
  % ./autogen.sh
  % ./configure --with-boost='/opt/homebrew/opt/[email protected]'
  ```

ACKs for top commit:
  promag:
    Tested ACK on 1d4157a with boost 1.76 on macOS arm64. bitcoin#24523 is required for boost 1.78.

Tree-SHA512: 7abd39a78e970ecc051e53b5923dfc31d3f0576cf4ff7fcfb9c8708c857c46a7a595ec36238def83f41158970eeee209980da4b8b70f0ff68f940a38ac9a0471
532c64a build: Fix Boost.Process test for Boost 1.78 (Hennadii Stepanov)

Pull request description:

  Rebased bitcoin#24415 with Luke's suggestion.

  Fixes bitcoin#24413.

ACKs for top commit:
  hebasto:
    ACK 532c64a, tested on Mac mini (M1, 2020) + macOS Monterey 12.3 (21E230).

Tree-SHA512: 74f779695f6bbc45a2b7341a1402f747cc0d433d74825c7196cb9f156db0c0299895365f01665bd0bff12a8ebb5ea33a29b9a52f5eac0007ec35d1dca6544705
ba9a8e6 test: Drop unused boost workaround (Hennadii Stepanov)

Pull request description:

  This PR is a follow up of bitcoin#24065 and removes the workaround which has already been removed in other [places](https://github.com/bitcoin/bitcoin/pull/24065/files#diff-19427b0dd1a791adc728c82e88f267751ba4f1c751e19262cac03cccd2822216).

  Moreover, this workaround won't be required even if bitcoin#25696 is ever merged.

ACKs for top commit:
  fanquake:
    ACK ba9a8e6

Tree-SHA512: db19fc1550252d7a82a08f388ff6078c78452365e74b41e7bc36cbbc4d0fed9342636e8f2371bb8e78c9d11ee721d6363bcc21d11787f3aac967a6c4a9cc346f
…e found

292b1a3 GetExternalSigner(): fail if multiple signers are found (amadeuszpawlik)

Pull request description:

  If there are multiple external signers, `GetExternalSigner()` will
  just pick the first one in the list. If the user has two or more
  hardware wallets connected at the same time, he might not notice this.

  This PR adds a check and fails with suitable message, forcing the user to disconnect all but one external signer, so that there is no ambiguity as to which external signer was used.

ACKs for top commit:
  Sjors:
    tACK 292b1a3
  achow101:
    ACK 292b1a3

Tree-SHA512: e2a41d3eecc607d4f94e708614bed0f3545f7abba85f300c5a5f0d3d17d72c815259734accc5ca370953eacd290f27894ba2c18016f5e9584cd50fa1ec2fbb0b
1a0d8e1 build: Re-enable external signer on Windows (Hennadii Stepanov)
989451d configure: Detect compatibility of Boost.Process rather than hardcode non-Windows (Luke Dashjr)

Pull request description:

  As boostorg/process#207 has been resolved, it is possible now to re-enable external signer on Windows when cross-compiling.

  Guix build hashes:
  ```
  78f69ea7e0dbc8338981a92c0352220ccd7c2272d8cbff6a3b082a1412a935c5  guix-build-1a0d8e178c7b/output/aarch64-linux-gnu/SHA256SUMS.part
  ee17456ec818ddf5a175182508966e622573ccb518807cca43a40fa1dceda092  guix-build-1a0d8e178c7b/output/aarch64-linux-gnu/bitcoin-1a0d8e178c7b-aarch64-linux-gnu-debug.tar.gz
  5080551bde379c746cc67b10429aef33b9f9e49d2d4e21ee1c3bfd9c1c845d46  guix-build-1a0d8e178c7b/output/aarch64-linux-gnu/bitcoin-1a0d8e178c7b-aarch64-linux-gnu.tar.gz
  dfab220ce76a40bf7dcf07aab352a616a91b516503639455fe7e1b137bad3e85  guix-build-1a0d8e178c7b/output/arm-linux-gnueabihf/SHA256SUMS.part
  516ceb822571a8bd88fe107dca434ef596b1e4328ccbda1d51e1d482d3050396  guix-build-1a0d8e178c7b/output/arm-linux-gnueabihf/bitcoin-1a0d8e178c7b-arm-linux-gnueabihf-debug.tar.gz
  21325380638f817107c203b9a1aedb808d1a4a2b4041493753ca4cbf19aa4f2c  guix-build-1a0d8e178c7b/output/arm-linux-gnueabihf/bitcoin-1a0d8e178c7b-arm-linux-gnueabihf.tar.gz
  cf48ed78fcfceaeb3610ccf22326d735a129dcbf9d50b557b3de359169aefdfd  guix-build-1a0d8e178c7b/output/arm64-apple-darwin/SHA256SUMS.part
  d4d51e136148bac6a20bb3adb402c499967647736acb420bfdeb71603aba57da  guix-build-1a0d8e178c7b/output/arm64-apple-darwin/bitcoin-1a0d8e178c7b-arm64-apple-darwin-unsigned.dmg
  95bb62d24f860e08a392ddb74d5860ccf27e8baa183e6749af877d26a3bd6b0b  guix-build-1a0d8e178c7b/output/arm64-apple-darwin/bitcoin-1a0d8e178c7b-arm64-apple-darwin-unsigned.tar.gz
  68da4c92f37bb802df37141af194f47c16da1d84f77a0fbb1016013ae0338502  guix-build-1a0d8e178c7b/output/arm64-apple-darwin/bitcoin-1a0d8e178c7b-arm64-apple-darwin.tar.gz
  6704e38c2d3f11321403797598d05f062648fec6f2d76900ba250dab481e29da  guix-build-1a0d8e178c7b/output/dist-archive/bitcoin-1a0d8e178c7b.tar.gz
  64b936bc90d1e01fe8f276511edc9bb945dcebe70332aa37d3a786348443b8e7  guix-build-1a0d8e178c7b/output/powerpc64-linux-gnu/SHA256SUMS.part
  3d03532e54b6e42498ea240c86b8567e94fd462f56087b869c3d6f09e2dde878  guix-build-1a0d8e178c7b/output/powerpc64-linux-gnu/bitcoin-1a0d8e178c7b-powerpc64-linux-gnu-debug.tar.gz
  c5843d79a58b0a864fe723458dab4eee54ad11f4b1f7960975b086eeedc0d541  guix-build-1a0d8e178c7b/output/powerpc64-linux-gnu/bitcoin-1a0d8e178c7b-powerpc64-linux-gnu.tar.gz
  f861ff519bd5e3d6d5ce1646ee0a06bcef1288ddb804a4a600e4dbfe5d5be521  guix-build-1a0d8e178c7b/output/powerpc64le-linux-gnu/SHA256SUMS.part
  5f477da21980dbcf9696081903dc1ba8a3f79ce3579641d208e69a6f598c8eb9  guix-build-1a0d8e178c7b/output/powerpc64le-linux-gnu/bitcoin-1a0d8e178c7b-powerpc64le-linux-gnu-debug.tar.gz
  b3757b11c614136934158acea5139e8abd0c5c9cdfda72ae44db436f21716b33  guix-build-1a0d8e178c7b/output/powerpc64le-linux-gnu/bitcoin-1a0d8e178c7b-powerpc64le-linux-gnu.tar.gz
  1c21bdb17fe3436e685e88c62423e630fe2b3c41dd00025a99fd80d97817ac2f  guix-build-1a0d8e178c7b/output/riscv64-linux-gnu/SHA256SUMS.part
  f36ae98473f086ae8f0dc66223b5ec407d57dc4d8d45ae284401520ff5c0b273  guix-build-1a0d8e178c7b/output/riscv64-linux-gnu/bitcoin-1a0d8e178c7b-riscv64-linux-gnu-debug.tar.gz
  1603e4d0e869eb47a1dc2d26b67772d0016d90f7ba5e50d2009365cc02cb8169  guix-build-1a0d8e178c7b/output/riscv64-linux-gnu/bitcoin-1a0d8e178c7b-riscv64-linux-gnu.tar.gz
  f86ef652102f022827b70477bffa0a44008c6300cf62ca7b3595146cf2ed91ba  guix-build-1a0d8e178c7b/output/x86_64-apple-darwin/SHA256SUMS.part
  f84d435d8e4709bf29bc7ac7ed8dc6b8af4077cef05e520b468b2896ce10876a  guix-build-1a0d8e178c7b/output/x86_64-apple-darwin/bitcoin-1a0d8e178c7b-x86_64-apple-darwin-unsigned.dmg
  af2aab969b7ed7aeea0e02adbcc9e3b438086bf76b6bfc36146c53e05a27bd57  guix-build-1a0d8e178c7b/output/x86_64-apple-darwin/bitcoin-1a0d8e178c7b-x86_64-apple-darwin-unsigned.tar.gz
  32a5109ba28ab74ff66238e6a8f8a04e455ebce382a3be287df92a227818fe72  guix-build-1a0d8e178c7b/output/x86_64-apple-darwin/bitcoin-1a0d8e178c7b-x86_64-apple-darwin.tar.gz
  377462e9a96f4aba72c915dd5df5159a4301a1fa8ed0ee48faa6c71573de80c3  guix-build-1a0d8e178c7b/output/x86_64-linux-gnu/SHA256SUMS.part
  a3bf62e828d2350a483b2d16205014f66e8884597b0b72e178042a958c548336  guix-build-1a0d8e178c7b/output/x86_64-linux-gnu/bitcoin-1a0d8e178c7b-x86_64-linux-gnu-debug.tar.gz
  66cda980188ea1941a7d66c8b03c447580af33db55abe3bbe3581823ae0534a3  guix-build-1a0d8e178c7b/output/x86_64-linux-gnu/bitcoin-1a0d8e178c7b-x86_64-linux-gnu.tar.gz
  2117f0dd9baeb4d585f841592e94c088f4487bf2008b8f281d0c3ceee92ff6cc  guix-build-1a0d8e178c7b/output/x86_64-w64-mingw32/SHA256SUMS.part
  d40d5dec3287f467c42232c05d82f7fb538cda34bd2e63ff7e1876f471c3a790  guix-build-1a0d8e178c7b/output/x86_64-w64-mingw32/bitcoin-1a0d8e178c7b-win64-debug.zip
  92dcc92765fbc07b1cc8258bfa69280541e1b4553cc41fed18672c2c6931d5c0  guix-build-1a0d8e178c7b/output/x86_64-w64-mingw32/bitcoin-1a0d8e178c7b-win64-setup-unsigned.exe
  a6dd9b4d29f21d3a18cf64556cb03446ef17bf801eb6ac257b65d27cbd95080f  guix-build-1a0d8e178c7b/output/x86_64-w64-mingw32/bitcoin-1a0d8e178c7b-win64-unsigned.tar.gz
  a4022e595d955198f73530473ef8e90a708746089ee2dd27de794176873330c1  guix-build-1a0d8e178c7b/output/x86_64-w64-mingw32/bitcoin-1a0d8e178c7b-win64.zip
  ```

ACKs for top commit:
  Sjors:
    tACK 1a0d8e1
  achow101:
    ACK 1a0d8e1

Tree-SHA512: db7319259b1e1571cfab4bb3b99ae10a2f744e62757cae5059fd6f4dd6d5586eb09feb63a0c4bb07f7128b283f1dc281ed435224bc8e40da577fd4f04cde489a
… signer support available)

6b17994 doc: update OpenBSD build docs for 7.3 (external signer support available) (Sebastian Falbesoner)

Pull request description:

  With OpenBSD 7.3, the waitid(2) system call is implemented (see openbsd/src@8112871, first mentioned kernel improvement at https://www.openbsd.org/73.html).

  This means Boost.Process finally doesn't fail to compile anymore and we can remove the build hint about missing external signer support. Tested on my amd64 machine by reconfiguring / rebuilding master branch and successfully running the functional test wallet_signer.py. ✔️

ACKs for top commit:
  fanquake:
    ACK 6b17994 - haven't tested, but looks good to me.

Tree-SHA512: 5bbcecce4ced38d8221f2c906a54667e50317e9ded182554cf73bb7f2fce55a38e53730eca25f813cff1d2d65c94141eb158d40f83228d12dcf859c16a1798b9
@knst knst added this to the 23.1 milestone Nov 25, 2025
@DashCoreAutoGuix
Copy link

Guix Automation has began to build this PR tagged as v23.0.0-devpr6913.e8888d78. A new comment will be made when the image is pushed.

@UdjinM6
Copy link

UdjinM6 commented Nov 25, 2025

win64 build is failing

308aec3 build: disable external-signer for Windows (fanquake)
3553731 ci: remove --enable-external-signer from win64 job (fanquake)

Pull request description:

  It's come to light that Boost ASIO (a Boost Process sub dep) has in some
  instances, been quietly  initialising our network stack on Windows (see
  PR bitcoin#28486 and discussion in bitcoin#28940).

  This has been shielding a bug in our own code, but the larger issue
  is that Boost Process/ASIO is running code before main, and doing things
  like setting up networking. This undermines our own assumptions about
  how our binary works, happens before we run any sanity checks,
  and before we call our own code to setup networking. Note that ASIO also
  calls WSAStartup with version `2.0`, whereas we call with `2.2`.

  It's also not clear why a feature like external signer would have a
  dependency that would be doing anything network/socket related,
  given it only exists to spawn a local process.

  See also the discussion in bitcoin#24907. Note that the maintaince of Boost Process in general,
  has not really improved. For example, rather than fixing bugs like boostorg/process#111,
  i.e, boostorg/process#317, the maintainer chooses to just wrap exception causing overflows
  in try-catch blocks: boostorg/process@0c42a58. These changes get merged in large,
  unreviewed PRs, i.e boostorg/process#319.

  This PR disables external-signer on Windows for now. If, in future, someone
  changes how Boost Process works, or replaces it entirely with some
  properly reviewed and maintained code, we could reenable this feature on
  Windows.

ACKs for top commit:
  hebasto:
    re-ACK 308aec3.
  TheCharlatan:
    ACK 308aec3

Tree-SHA512: 7405f7fc9833eeaacd6836c4e5b1c1a7845a40c1fdd55c1060152f8d8189e4777464fde650e11eb1539556a75dddf49667105987078b1457493ee772945da66e
…tests/run_command`

51bc1c7 test: Remove Windows-specific code from `system_tests/run_command` (Hennadii Stepanov)

Pull request description:

  The removed code has been dead since bitcoin#28967.

  Required as a precondition for replacing Boost.Process with [cpp-subprocess](bitcoin#28981) to make diff for this code meaningful and reviewable.

  The plan is to reintroduce Windows-specific code in this test simultaneously with enabling Windows support in cpp-subprocess.

ACKs for top commit:
  Sjors:
    utACK 51bc1c7
  theStack:
    Code-review ACK 51bc1c7

Tree-SHA512: 0e3875c4dc20564332555633daf2227223b10dc3d052557635eced2734575d1e0252fb19e46ea6e6c47a15c51c345f70b6d437e33435abcd0e4fcf29edb50887
@knst
Copy link
Collaborator Author

knst commented Nov 25, 2025

win64 build is failing

Not anymore https://github.com/dashpay/dash/actions/runs/19684944908/job/56389784464?pr=6913

@knst knst changed the title backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #27449 (external signer, boost) backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #27449, #28967, #29489 (external signer, boost) Nov 25, 2025
@DashCoreAutoGuix
Copy link

Guix Automation has completed; a release should be present here: https://github.com/dashpay/dash-dev-branches/releases/tag/v23.0.0-devpr6913.e8888d78. The image should be on dockerhub soon.

@DashCoreAutoGuix
Copy link

Guix Automation has began to build this PR tagged as v23.0.0-devpr6913.81f21fde. A new comment will be made when the image is pushed.

@DashCoreAutoGuix
Copy link

Guix Automation has completed; a release should be present here: https://github.com/dashpay/dash-dev-branches/releases/tag/v23.0.0-devpr6913.81f21fde. The image should be on dockerhub soon.

43b8777 refactor: move run_command from util to common (Cory Fields)
192325a kernel: move RunCommandParseJSON to its own file (Cory Fields)

Pull request description:

  Because libbitcoinkernel does not include this new object, this has the side-effect of eliminating its unnecessary `boost::process` dependency.

  This leaves libbitcoinkernel with 3 remaining boost dependencies:
  - `boost::date_time` for `util/time.cpp`, which I'll separate out next. Exactly like this PR.
  - `boost::signals2` for which I have a POC re-implementation here: https://github.com/theuni/bitcoin/commits/replace-boost-signals
  - `boost::multi_index` which I'm not sure about yet.

ACKs for top commit:
  ryanofsky:
    Code review ACK 43b8777. Could consider squashing the two commits, so the code just moves once instead of twice.
  fanquake:
    ACK 43b8777

Tree-SHA512: f2a46cac34aaadfb8a1442316152ad354f6990021b82c78d80cae9fd43cd026209ffd62132eaa99d5d0f8cf34e996b6737d318a9d9a3f1d2ff8d17d697abf26d
3210f22 refactor: remove in-code warning suppression (fanquake)

Pull request description:

  Should no-longer be needed post bitcoin#27872. If it is, then suppress-external-warnings should be fixed.

ACKs for top commit:
  hebasto:
    ACK 3210f22

Tree-SHA512: 2405250b7308779d576f13ce9144944abd5b2293499a0c0fe940398dae951cb871246a55c0e644a038ee238f9510b5845c3e39f9658d9f10225a076d8122f078
d5a7155 build: remove boost::process dependency for building external signer support (Sebastian Falbesoner)
70434b1 external_signer: replace boost::process with cpp-subprocess (Sebastian Falbesoner)
cc8b987 Add `cpp-subprocess` header-only library (Hennadii Stepanov)

Pull request description:

  Closes bitcoin#24907.

  This PR is based on **theStack**'s [work](bitcoin#24907 (comment)).

  The `subprocess.hpp` header has been sourced from the [upstream repo](https://github.com/arun11299/cpp-subprocess) with the only modification being the removal of convenience functions, which are not utilized in our codebase.

  Windows-related changes will be addressed in subsequent follow-ups.

ACKs for top commit:
  achow101:
    reACK d5a7155
  Sjors:
    re-tACK d5a7155
  theStack:
    Light re-ACK d5a7155
  fanquake:
    ACK d5a7155 - with the expectation that this code is going to be maintained as our own. Next PRs should:

Tree-SHA512: d7fb6fecc3f5792496204190afb7d85b3e207b858fb1a75efe483c05260843b81b27d14b299323bb667c990e87a07197059afea3796cf218ed8b614086bd3611
@DashCoreAutoGuix
Copy link

Guix Automation has began to build this PR tagged as v23.0.0-devpr6913.b7fe8671. A new comment will be made when the image is pushed.

@DashCoreAutoGuix
Copy link

Guix Automation has completed; a release should be present here: https://github.com/dashpay/dash-dev-branches/releases/tag/v23.0.0-devpr6913.b7fe8671. The image should be on dockerhub soon.

@knst
Copy link
Collaborator Author

knst commented Nov 27, 2025

Guix build succeed:

d28f945e9e82820a668f9dd681e92c7604db3de13d8f5b306fda23b4952557a2 aarch64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-aarch64-linux-gnu-debug.tar.gz
e33741e945a13156b49539cbb39cc91deb031ce3e3f91f02bdaba546d083b774 aarch64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-aarch64-linux-gnu.tar.gz
21cf19583978ba3a30f96efae5fc99c93a7e0511a06f9e85773dd67f883c4c65 arm64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-arm64-apple-darwin-debug.tar.gz
7375adc1f1a67c4e087eff1634d230af373470ccffe89c27d7ed9e7343029e76 arm64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-arm64-apple-darwin.tar.gz
96e17062c397348b1c073718c3a2f148f18e66b627456c826c9e5b23ab877b9c arm64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-arm64-apple-darwin-unsigned.tar.gz
a9798550c1a9c6493691040ff8cc1d67a4a82a59604878d1cc759d19babe254d arm64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-arm64-apple-darwin-unsigned.zip
d2a0753bf2983180562e19931c59b6c0ee5ee24315d804ad66a715b7d5c99363 arm-linux-gnueabihf/dashcore-23.0.0-rc.3-597-gb7fe86717743-arm-linux-gnueabihf-debug.tar.gz
2d5974e3b1225db8838e4a522cde374fe017e67924e39e6e44c40c7926a0bd03 arm-linux-gnueabihf/dashcore-23.0.0-rc.3-597-gb7fe86717743-arm-linux-gnueabihf.tar.gz
465cfa15b357a13338d527c974cf314215f119fe8509423a31d45b45678bce3b dist-archive/dashcore-23.0.0-rc.3-597-gb7fe86717743.tar.gz
3342ffde100745844b03180ef26c2028ada4d57680984aae4815848e309fa83b powerpc64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-powerpc64-linux-gnu-debug.tar.gz
541d8178e945305457dfb40ed46e7d702c10c9bcaa2b6daa062355c3f694e700 powerpc64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-powerpc64-linux-gnu.tar.gz
9756d8c1a5e6a5ed8c396a0d0adfe6cd914ebcee2e1a98c0e84e53161bdf1f56 riscv64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-riscv64-linux-gnu-debug.tar.gz
7357b02e6432e8cc28bd78bfd8f6b0a86f3501c03349a5c9b29b2a34ebbe6527 riscv64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-riscv64-linux-gnu.tar.gz
c0b4f6a7aa81c0da0d5ec2c9604bfb30e01421ab1bd1c4c62b40649d3c778301 x86_64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-x86_64-apple-darwin-debug.tar.gz
8e5c802f79d9caf95d4883dc66a6d93ad1ac08078cf066b0478ced476c2bf667 x86_64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-x86_64-apple-darwin.tar.gz
adf6c6d874f27c444518c20e47e735fae9e562037963e17d352545b8540fe327 x86_64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-x86_64-apple-darwin-unsigned.tar.gz
2c568b306e58d87d3235a77a4957358de5c2784209ea7dbddf2d011eca65fc3d x86_64-apple-darwin/dashcore-23.0.0-rc.3-597-gb7fe86717743-x86_64-apple-darwin-unsigned.zip
4f973ac11240a867d174b3ca943bd10ce1bf86c0b6237a2496003812f67b332d x86_64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-x86_64-linux-gnu-debug.tar.gz
488a0917097db123a749c29a31a33c910e565d71ef48cf060f80f41a1cb0dca0 x86_64-linux-gnu/dashcore-23.0.0-rc.3-597-gb7fe86717743-x86_64-linux-gnu.tar.gz
be2fc6ccbe26cb6c2d15108bd8440344e9ab0ad9b37ac1a37f4a3c8704b57347 x86_64-w64-mingw32/dashcore-23.0.0-rc.3-597-gb7fe86717743-win64-debug.zip
4b40ce3cd0a7bf6a818e9c8b8296e134621f8156eb177818404229828a7e93c7 x86_64-w64-mingw32/dashcore-23.0.0-rc.3-597-gb7fe86717743-win64-setup-unsigned.exe
f76068bea58f7b442def99e4938c18f13afb2ad1e8d133cae23a7a80c3f100f3 x86_64-w64-mingw32/dashcore-23.0.0-rc.3-597-gb7fe86717743-win64-unsigned.tar.gz
8b3d48aee93c252b382988b335f2604cf176a23be3372218ce64bf22733edc3f x86_64-w64-mingw32/dashcore-23.0.0-rc.3-597-gb7fe86717743-win64.zip

@knst knst changed the title backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #27449, #28967, #29489 (external signer, boost) backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #27449, #28967, #29489, #26196, #28002, #28981 (external signer, boost) Nov 27, 2025
Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

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

utACK b7fe867

@knst knst changed the title backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #27449, #28967, #29489, #26196, #28002, #28981 (external signer, boost) backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #26196, #27449, #28002, #28967, #2898, #29489 (external signer, boost) Nov 27, 2025
@knst knst changed the title backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #26196, #27449, #28002, #28967, #2898, #29489 (external signer, boost) backport: bitcoin#24254, #24397, #24521, #24523, #25235, #25696, #25723, #26196, #27449, #28002, #28967, #28981, #29489 (external signer, boost) Nov 27, 2025
Copy link
Collaborator

@kwvg kwvg left a comment

Choose a reason for hiding this comment

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

utACK b7fe867

@PastaPastaPasta PastaPastaPasta merged commit 7ba3f42 into dashpay:develop Nov 28, 2025
32 of 33 checks passed
@knst knst deleted the bp-hwi-2 branch December 1, 2025 15:33
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.

8 participants