External signer support - Wallet Box edition#16546
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
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. |
There was a problem hiding this comment.
This list-of-bools thing seems like a terrible idea...
There was a problem hiding this comment.
Indeed, I was complaining about that when blank was added :-)
There was a problem hiding this comment.
What if there are multiple wallets, with different signers?
IMO -signer needs to be replaced with either a wallet-stored path, or a path provided when the wallet is loaded...
There was a problem hiding this comment.
Storing signer in the wallet makes sense, but I also think it can wait for a later PR. In practice afaik the only tool that currently works is HWI and it can handle multiple wallets. In the long run however I do hope that wallet manufactures provide their own software that just uses the same commands / responses.
0e28746 to
7511650
Compare
7511650 to
8d88bf9
Compare
|
Can we expect this to be merged and included in 0.19? It's a really useful and requested feature! Thanks to everyone who is working on it. |
|
@Relaxo143 not a chance; this is still work in progress and there's several pull requests that need to be reviewed and merged first. There's also a feature freeze on 0.19. |
8d88bf9 to
3e991aa
Compare
|
I dropped the dependency on my new |
3e991aa to
ca42459
Compare
|
re-ACK 96f991a11a871502d1a39f684994c1e2664c3af7 |
fanquake
left a comment
There was a problem hiding this comment.
In 903f277f982ed390dc68114c9c1eb70b4a59bb19 is where we should be able to drop HAVE_BOOST_PROCESS entirely. I realise that boost process could potentially be used for other things in future, but currently, it's not, and as this is implemented, there's a bit of an awkward split between HAVE_BOOST_PROCESS & ENABLE_EXTERNAL_SIGNER for code which, as I understand it, is all essentially the same feature. So I think for now we should just replace the few usages of HAVE_BOOST_PROCESS with ENABLE_EXTERNAL_SIGNER.
There was a problem hiding this comment.
| const std::string command = gArgs.GetArg("-signer", ""); // DEFAULT_EXTERNAL_SIGNER); | |
| const std::string command = gArgs.GetArg("-signer", DEFAULT_EXTERNAL_SIGNER); |
Or if we are going to use "", we should remove the commented code.
There was a problem hiding this comment.
Not sure what was going on there, but I put DEFAULT_EXTERNAL_SIGNER back.
There was a problem hiding this comment.
Now I remember, I didn't want a circular inclusion. I just switched to "".
There was a problem hiding this comment.
From what I can see, GetExternalSigner() is only called from code that is inside ENABLE_EXTERNAL_SIGNER #idfefs. So why can't we wrap this whole function in an #ifdef, and drop the need for the throw()? I think the same goes for most of this file, and some other functions in this PR. It seems weird that when external signing is not enabled, we'd still be compiling functions that aren't called from anywhere, and who's purpose is to throw a runtime error to tell you about external signing and it's need of Boost Process.
There was a problem hiding this comment.
If turns out I can put the entire ExternalSignerScriptPubKeyMan inside #ifdef. The most important throw()s are already in wallet.cpp.
This option replaces --with-boost-process This prepares external signer support to be disabled by default. It adds a configure option to enable this feature and to check if Boost::Process is present. This also exposes ENABLE_EXTERNAL_SIGNER to the test suite via test/config.ini
|
Rebased onto CI fix. @fanquake I replaced the remaining instances of |
|
Please squash the |
|
That may be a rather big rebase hell though, because the commits make incremental changes to these files so I'd have to divide this commit in 10 pieces, squash them in the right place and then deal with rebase conflicts. Unless there's an intelligent Git incantation to rename a file across all commits? |
Something like this will rename the one file. You can extend it to rename other files or do more replacements across commits: end=f1824e7af7a8d53f9be50a6c6354511190dcb774
start=b9a262ea0a86f498959e81113522ce26299f1984
git checkout $end
git filter-branch --tree-filter '
git mv src/wallet/externalsigner.h src/wallet/external_signer.h
git grep -l externalsigner | xargs sed -i s:wallet/externalsigner.h:wallet/external_signer.h:
' --force $start^..HEAD |
|
Also git tends to be smart enough to take into account renamed files when rebasing. If you go to the first commit with |
|
@ryanofsky's thanks! That worked (with some tweaks), and despite warnings from the git, it still compiles and history looks sane. @laanwj I have indeed seen Git behave sanely when it comes to renames, so maybe my worries were not necessary. |
Create basic ExternalSigner class with contructor. A Signer(<cmd>) is added to CWallet on load if -signer=<cmd> is set.
Includes a mock to mimick the HWI interace.
|
re-ACK f75e0c1 |
| Create a wallet, this automatically imports the public keys: | ||
|
|
||
| ```sh | ||
| $ bitcoin-cli createwallet "hww" true true "" true true true |
There was a problem hiding this comment.
nit: Would be nice to use named args
| }, | ||
| RPCExamples{""}, | ||
| [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { | ||
| std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); |
There was a problem hiding this comment.
why does this rpc require a wallet?
There was a problem hiding this comment.
I might get rid of that requirement in a followup.
| @BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true | ||
| @ENABLE_FUZZ_TRUE@ENABLE_FUZZ=true | ||
| @ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true | ||
| @ENABLE_EXTERNAL_SIGNER_TRUE@ENABLE_EXTERNAL_SIGNER=true |
There was a problem hiding this comment.
It seems the @ENABLE_EXTERNAL_SIGNER_TRUE@ substitution does not work for some reasons.
Big picture overview in this gist.
This PR lets
bitcoindcall an arbitrary command-signer=<cmd>, e.g. a hardware wallet driver, where it can fetch public keys, ask to display an address, and sign a transaction (using PSBT under the hood).It's design to work with https://github.com/bitcoin-core/HWI, which supports multiple hardware wallets. Any command with the same arguments and return values will work. It simplifies the manual procedure described here.
Usage is documented in doc/external-signer.md, which also describes what protocol a different signer binary should conform to.
Use
--enable-external-signerto opt in, requires Boost::Process:It adds the following RPC methods:
enumeratesigners: asks for a list of signers (e.g. devices) and their master key fingerprintsignerdisplayaddress <address>: asks to display an addressIt enhances the following RPC methods:
createwallet: takes an additionalexternal_signerargument and fetches keys from devicesend: automatically sends transaction to device and waitsUsage TL&DR:
bitcoind -signer=../HWI/hwi.pybitcoin-cli enumeratesignersbitcoin-cli createwallet "hww" true true "" true true truebitcoin-cli signerdisplayaddress ...sendRPC and approve transaction on devicePrerequisites:
Potentially useful followups: