Skip to content

Conversation

Sjors
Copy link
Member

@Sjors Sjors commented Aug 1, 2025

The external_signer indicates that an external signer device may be called via HWI or equivalent application.

When it was initially introduced some additional constraints were placed on wallets with this flag: it had to be a descriptor wallet and watch-only. Also the flag could not be added or removed later.

The constraints aren't a problem for the main supported and documented use case of connecting a single hardware wallet and using it just like a normal single sig Bitcoin Core wallet.

But they get in the way of more advanced constructions, which are becoming increasingly practical especially once MuSig2 support lands with #29675. See Sjors#91 and bitcoin-core/HWI#794 for a collection of changes on top of that which facilitate MuSig2 with a hardware wallet. And see #24861.

This pull requests drops the following constraints:

  • disable_private_keys is no longer mandatory (but still default)
  • external_signer flag is now mutable

Additionally it does the following:

  • make the blank option for createwallet consistent with regular wallets by not importing keys from the connected signer
  • avoid going through createTransaction for external signers (otherwise the GUI breaks)
  • update external-signer.md mainly to use named arguments and point out a GUI setting

This should no noticeable effect on the default single sig use case described above.

@DrahtBot DrahtBot added the Wallet label Aug 1, 2025
@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 1, 2025

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

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33112.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK rkrux

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #30354 (doc: external-signer, example 'createwallet' RPC call requires eight argument by cobratbq)
  • #28333 (wallet: Construct ScriptPubKeyMans with all data rather than loaded progressively by achow101)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@Sjors Sjors mentioned this pull request Aug 1, 2025
@fanquake
Copy link
Member

fanquake commented Aug 1, 2025

https://cirrus-ci.com/task/6572167942373376?logs=ci#L1621:

[06:14:38.327] /ci_container_base/src/wallet/rpc/wallet.cpp: In function ‘wallet::createwallet()::<lambda(const RPCHelpMan&, const JSONRPCRequest&)>’:
[06:14:38.327] /ci_container_base/src/wallet/rpc/wallet.cpp:420:45: error: ‘*(unsigned char*)((char*)&disable_private_keys + offsetof(std::optional<bool>,std::optional<bool>::<unnamed>.std::_Optional_base<bool, true, true>::<unnamed>))’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
[06:14:38.327]   420 |     if (disable_private_keys.has_value() && *disable_private_keys) {
[06:14:38.327]       |                                             ^~~~~~~~~~~~~~~~~~~~~
[06:14:38.327] cc1plus: all warnings being treated as errors
[06:14:38.328] gmake[2]: *** [src/wallet/CMakeFiles/bitcoin_wallet.dir/build.make:370: src/wallet/CMakeFiles/bitcoin_wallet.dir/rpc/wallet.cpp.o] Error 1

#else
throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
#endif
}

if (disable_private_keys.has_value() && *disable_private_keys) {
Copy link
Member

Choose a reason for hiding this comment

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

not sure if this fixes the maybe-uninitialized false-positive from gcc, but you can try if (disable_private_keys.has_value() && disable_private_keys.value()) {, or add -Wno-error=maybe-uninitialized to the ci task config.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll try value_or(false)

@Sjors Sjors force-pushed the 2025/07/external-signer-relax branch from dee72e7 to 3909b0f Compare August 1, 2025 11:49
@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 1, 2025

🚧 At least one of the CI tasks failed.
Task previous releases, depends DEBUG: https://github.com/bitcoin/bitcoin/runs/47191506122
LLM reason (✨ experimental): The CI failed due to a compilation error caused by treating warnings as errors, specifically an uninitialized variable warning in wallet.cpp.

Hints

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

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

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

  • An intermittent issue.

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

@Sjors Sjors force-pushed the 2025/07/external-signer-relax branch from 3909b0f to 5763b82 Compare August 1, 2025 12:55
@Sjors
Copy link
Member Author

Sjors commented Aug 1, 2025

Added 7beb338 wallet: avoid createTransaction() with signer to prevent breaking GUI signing for private key enabled external signer wallets (even when they don't have other keys).

Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

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

ACK a973403

Agree with the intent to relax these constraints for external signer wallets.

Comment on lines 76 to 77
self.nodes[1].createwallet(wallet_name='not_hww', disable_private_keys=True, external_signer=False)
self.nodes[1].createwallet(wallet_name='not_hww', external_signer=False)
Copy link
Contributor

Choose a reason for hiding this comment

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

In 08f7813 "wallet: make watch-only optional for external signer"

Do you intend to add a test for an external signer wallet with private keys enabled in a later PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that'll become more relevant, and probably easier to test, after MuSig2 support lands.

- use bitcoin rpc instead of bitcoin-cli
- use named "external_signer" argument
- mention GUI setting
There's no need to treat external signer wallets different in this
regard. When the user sets the 'blank' flag, don't generate or
import keys.

For multisig setups that involve an external signer, it may be useful
to start from a blank wallet and manually import descriptors.
External signer enabled wallets should always use the process PSBT flow.
Avoid going through CreateTransaction.

This has no effect until the next commit when WALLET_FLAG_EXTERNAL_SIGNER
no longer implies WALLET_FLAG_DISABLE_PRIVATE_KEYS. Without this change
signing with the GUI would break for external signers with private keys
enabled.
Before this change the external_signer flag required the wallet to be watch-only.
This precludes multisig setups in which we hold a hot key.

Remove this as a requirement, but disable private keys by default. This leaves
the typical (and only documented) use case of a single external signer unaffected.
With the removal of legacy wallets and the relaxing of restrictions
in the previous commit, it's no longer a problem to toggle this flag.
@Sjors Sjors force-pushed the 2025/07/external-signer-relax branch from a973403 to 0397853 Compare September 1, 2025 07:34
@Sjors
Copy link
Member Author

Sjors commented Sep 1, 2025

Rebased and addressed nits.

Copy link
Contributor

@rkrux rkrux left a comment

Choose a reason for hiding this comment

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

re-ACK 0397853

git range-diff a973403...0397853

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants