#33112 wallet: relax external_signer flag constraints
| Reviewability | Reviews | Agreement | Size | ||||
|---|---|---|---|---|---|---|---|
| #33112 wallet: relax external_signer flag constraints | Ready | 0 (+3) | Strong | 179 + 91 tests | |||
|
|
|
|
| |||
Reviewability: ReadyStalePaused Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs. Size: lines added or modified outside tests, then in tests; greener = smaller. | |||||||
Goal
This pull request relaxes constraints on the `external_signer` wallet flag in Bitcoin Core. It removes the requirement that external signer wallets must have private keys disabled, makes the `external_signer` flag mutable via `setwalletflag` (automatically reloading the wallet when toggled), ensures blank signer wallets do not auto-import keys, and allows the wallet to sign with internal keys before delegating remaining inputs to the external signer.
Problem: Previously, the `external_signer` flag forced a wallet to be watch-only and immutable from creation, which blocked multisig or MuSig2 setups where the node holds both a hot key and relies on an external signer device.
Reviewability
Ready
Nothing known that would invalidate a review now.
Waiting on (from the thread read):
- reviewer: review of the rebased PR 2026-09-14
- reviewer: review of latest rebase and fixes 2026-09-14
Agreement
Strong
substantive support, no open objection (rkrux, adyshimony, naiyoma, jeanpablojp, PraneethGunas, fametrano)
Thread notes: Added participant fametrano with supportive testing feedback regarding reduced signer calls. Added questions from rkrux and PraneethGunas and an interface suggestion from rkrux on error messaging. Verified existing objections were fixed and confirmed clears_with fits change for defects. / Added fametrano to participants and support after testing repeated signer call reductions; converted previous objections to clears_with=change and updated PraneethGunas's objection status to accepted; recorded
Objections, suggestions, and questions:
| Reviewer | Type | Harm, request, or question | Status | Must be | Author replied | Quote |
|---|---|---|---|---|---|---|
| rkrux (member) | question, approach | Asks whether there are plans to add a test for an external signer wallet with private keys enabled in a later PR. | answered · author replied that testing would be easier after MuSig2 lands | answered | yes | 2025-08-11: 'Do you intend to add a test for an external signer wallet with private keys enabled in a later PR?' Status from: 2025-08-15: Sjors: 'I think that'll become more relevant, and probably easier to test, after MuSig2 support lands.' |
| adyshimony (none) | suggestion, maintenance | Add a functional test explicitly enabling private keys upon external signer wallet creation. | answered · fix pushed · naiyoma seconded the suggestion and author later added test coverage | answered | by others | 2026-02-26: 'Maybe add a check that create the wallet with explicitly values upon creation?' Status from: 2026-03-08: naiyoma: '+1 on testing when `disable_private_keys=False `' |
| rkrux (member) | suggestion, interface | Update the error message so it does not state private keys are disabled when an external signer is used without private keys disabled. | fixed · fix pushed · author split the change into its own commit with an updated error message and test | changed | yes | 2026-05-04: 'After the next commit, the associated error here ("Private keys are disabled for this wallet") doesn't seem correct if it's an external signer.' Status from: 2026-05-06: Sjors: 'Indeed. I also split this change into its own commit 996064c6db85023e0f8aa4f91277ac494821292d and added a test.' |
| jeanpablojp (contributor) | objection, correctness | Toggling external_signer flag on an existing wallet leaves descriptor ScriptPubKeyMans out of sync, causing wallet operations like display address and send to fail until reloaded. | fixed · fix pushed · reloading the wallet on toggle keeps SPKMs in sync; no further objection | changed | yes | 2026-08-25: 'The SPKM subclass is chosen when it's constructed, and toggling doesn't rebuild the existing ones, so after unloadwallet/loadwallet, with nothing else changed, both work.' Status from: 2026-08-26: Sjors: 'it's actually easier to just have the RPC automatically reload the whole wallet for this flag. So I went with that.' |
| jeanpablojp (contributor) | objection, correctness | Toggling external_signer flag off leaves leftover external signer SPKMs, causing subsequent spends to abort in FillPSBT without a reload. | fixed · fix pushed · fixed by the automatic reload on flag toggle | changed | yes | 2026-08-25: 'Imported a descriptor with the flag on, turned the flag off, imported another one, and without reloading I can't spend from either.' Status from: 2026-08-26: Sjors: 'That should be fixed now, thanks to the reload.' |
| jeanpablojp (contributor) | objection, safety | Setting external_signer flag on a build without external signer support bricks the wallet from loading on that binary. | fixed · fix pushed · added compile guard for ENABLE_EXTERNAL_SIGNER; no further objection | changed | yes | 2026-08-25: 'On a build with -DENABLE_EXTERNAL_SIGNER=OFF I set the flag on an ordinary wallet and it no longer loads on that binary, not even after a restart' Status from: 2026-08-26: Sjors: 'Added a guard for completeness.' |
| PraneethGunas (none) | objection, correctness | In an external signer wallet with private keys enabled, FillPSBT attempts to sign hot key UTXOs using the hardware signer and fails. | accepted · fix pushed · reviewer confirmed the fix on Ledger Flex | changed | yes | 2026-08-27: 'a descriptor holding a hot key also gets an ExternalSignerScriptPubKeyMan here, and at LoadDescriptorScriptPubKeyMan. Its FillPSBT() goes straight to the device when sign=true and never falls back.' Status from: 2026-08-28: PraneethGunas: 'Confirmed fixed on a Ledger Flex, thanks.' |
| PraneethGunas (none) | question, approach | What is the intended wallet layout for a multisig where one cosigner is an external signer and another is a hot key, if mixing hot and cold descriptors in one wallet is discouraged? | answered · author explained the descriptor setup and key export workflow | answered | yes | 2026-08-28: 'If mixing hot and cold in one wallet isn't encouraged, what's the intended layout for a multisig where one cosigner is an external signer and another is a hot key, one wallet per key?' Status from: 2026-08-31: Sjors: 'Ideally there's a single multisig descriptor for which the wallet has one key, e.g. musig2(core_xprv, ledger_xpub).' |
Support:
- rkrux (member) (ACK, 2025-08-11) [read]: Agree with the intent to relax these constraints for external signer wallets.
- rkrux (member) (ACK, 2025-09-02): re-ACK 03978530ad8dc9124307d2ffc7d64c24b784be0e [not substantive]
- adyshimony (none) (ACK, 2026-02-26) [tested: Qt UX]: Built and ran successfully all tests. Qt UX tested on regtest with mock signer
- naiyoma (member) (Concept ACK, 2026-03-08) [both: bitcoin-qt, cli]: Reviewed commits and tested createwallet on bitcoin-qt and on cli
- achow101 (member) (Concept ACK, 2026-04-30): Concept ACK [not substantive]
- jeanpablojp (contributor) (Concept ACK, 2026-08-25) [tested: signer, wallet]: Built and ran the wallet and signer tests.
- PraneethGunas (none) (Concept ACK, 2026-08-27): This greatly helps unblock using external signers and hot keys in the same wallet for a multisig setup
- PraneethGunas (none) (ACK, 2026-08-29): ACK f4dd05644f3eada3656f619f71ab3b94fe08ec3d, 5a7c4309da24d9dd3ff5a8f7edc3d316cd9355c0 [not substantive]
- fametrano (contributor) (2026-10-22) [both: test/functional/mocks/signer.py, test/functional/wallet_signer.py, wallet_signer.py]: This PR also reduces repeated external signer calls: on master one signing can ask the device once per descriptor.
Participants:
- fanquake (member, neutral, 1 statements 2025-08-01 to 2025-08-01): reported CI build failure on maybe-uninitialized compiler warning
- maflcko (member, neutral, 2 statements 2025-08-01 to 2025-08-01): suggested fixes and nits for the CI compiler warning
- rkrux (member, support, 12 statements 2025-08-11 to 2026-05-04): ACKed the approach and implementation, reviewed test coverage, and suggested error message fix
- adyshimony (none, support, 4 statements 2026-02-26 to 2026-02-26): tested Qt UX and CLI workflows and gave ACK
- naiyoma (member, support, 2 statements 2026-03-08 to 2026-03-08): tested bitcoin-qt and CLI behavior and gave Concept ACK
- achow101 (member, support, 1 statements 2026-04-30 to 2026-04-30): Concept ACK
- jeanpablojp (contributor, objection, 4 statements 2026-08-25 to 2026-08-25): identified descriptor SPKM mismatches on flag toggling and missing compile guards
- PraneethGunas (none, objection, 4 statements 2026-08-27 to 2026-08-29): found that spending hot key UTXOs failed on external signers, verified the fix, and ACKed
- fametrano (contributor, support, 1 statements 2026-10-22 to 2026-10-22): tested signer calls and noted the PR reduces repeated external signer requests
Dependencies
Enables:
- MuSig2 multisig support with external signers
Files
132 lines under test/bench/ci.
- src/wallet/rpc/wallet.cpp +115/-46
- test/functional/wallet_signer.py +83/-36
- src/wallet/wallet.cpp +19/-17
- src/qt/createwalletdialog.cpp +8/-20
- src/wallet/external_signer_scriptpubkeyman.cpp +24/-4
- src/wallet/wallet.h +11/-7
- test/functional/rpc_signer.py +0/-5
- test/functional/test_framework/test_framework.py +5/-0
- test/functional/wallet_avoidreuse.py +3/-0
- src/qt/walletmodel.cpp +1/-1
- src/wallet/external_signer_scriptpubkeyman.h +1/-0
Card
The short text the ranking pass compares across PRs.
This PR relaxes constraints on external signer wallets in Bitcoin Core by allowing private keys to remain enabled and making the external_signer flag mutable via setwalletflag. This enables hybrid setups where a wallet contains both hot keys and external signer keys, which is a required prerequisite for MuSig2 and multisig hardware signer integration. Reviewers had previously flagged issues with SPKM construction during flag toggling and hot key PSBT signing, both of which have been resolved and verified with physical hardware testing. The PR is clean and ready for final review.
Data
thread read through 2026-10-22 (55 statements), head ac6c932e10
labels: Wallet
Categories
Wallet
P2 · new feature (ranking pass: Moved down: prerequisite value for MuSig2/hardware multisig is real but speculative relative to shipped-bug fixes.)
Enables hybrid hot-and-cold multisig and MuSig2 setups by relaxing the external signer watch-only constraint. Reviewers note this 'greatly helps unblock using external signers and hot keys in the same wallet for a multisig setup', expanding external signer functionality significantly.
Membership: Carries the Wallet label and modifies external signer wallet logic across src/wallet/.
Factors: security/stability 0, bug 0, performance 0, user value 2, leverage 2