Skip to content

Commit

Permalink
Move external signer out of wallet module
Browse files Browse the repository at this point in the history
This commit moves the ExternalSigner class and RPC methods out of the wallet module.

The enumeratesigners RPC can be used without a wallet since bitcoin#21417.
With additional modifications external signers could be used without a wallet in general, e.g. via signrawtransaction.

The signerdisplayaddress RPC is ranamed to walletdisplayaddress because it requires wallet context.
A future displayaddress RPC call without wallet context could take a descriptor argument.

This commit fixes a rpc_help.py failure when configured with --disable-wallet.
  • Loading branch information
Sjors committed Apr 8, 2021
1 parent 6664211 commit b54b2e7
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 134 deletions.
4 changes: 2 additions & 2 deletions doc/external-signer.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Display an address on the device:

```sh
$ bitcoin-cli -rpcwallet=<wallet> getnewaddress
$ bitcoin-cli -rpcwallet=<wallet> signerdisplayaddress <address>
$ bitcoin-cli -rpcwallet=<wallet> walletdisplayaddress <address>
```

Replace `<address>` with the result of `getnewaddress`.
Expand Down Expand Up @@ -166,6 +166,6 @@ The `createwallet` RPC calls:

It then imports descriptors for all support address types, in a BIP44/49/84 compatible manner.

The `displayaddress` RPC reuses some code from `getaddressinfo` on the provided address and obtains the inferred descriptor. It then calls `<cmd> --fingerprint=00000000 displayaddress --desc=<descriptor>`.
The `walletdisplayaddress` RPC reuses some code from `getaddressinfo` on the provided address and obtains the inferred descriptor. It then calls `<cmd> --fingerprint=00000000 displayaddress --desc=<descriptor>`.

`sendtoaddress` and `sendmany` check `inputs->bip32_derivs` to see if any inputs have the same `master_fingerprint` as the signer. If so, it calls `<cmd> --fingerprint=00000000 signtransaction <psbt>`. It waits for the device to return a (partially) signed psbt, tries to finalize it and broadcasts the transaction.
7 changes: 3 additions & 4 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ BITCOIN_CORE_H = \
core_memusage.h \
cuckoocache.h \
dbwrapper.h \
external_signer.h \
flatfile.h \
fs.h \
httprpc.h \
Expand Down Expand Up @@ -267,13 +268,11 @@ BITCOIN_CORE_H = \
wallet/crypter.h \
wallet/db.h \
wallet/dump.h \
wallet/external_signer.h \
wallet/external_signer_scriptpubkeyman.h \
wallet/feebumper.h \
wallet/fees.h \
wallet/ismine.h \
wallet/load.h \
wallet/rpcsigner.h \
wallet/rpcwallet.h \
wallet/salvage.h \
wallet/scriptpubkeyman.h \
Expand Down Expand Up @@ -387,13 +386,11 @@ libbitcoin_wallet_a_SOURCES = \
wallet/db.cpp \
wallet/dump.cpp \
wallet/external_signer_scriptpubkeyman.cpp \
wallet/external_signer.cpp \
wallet/feebumper.cpp \
wallet/fees.cpp \
wallet/interfaces.cpp \
wallet/load.cpp \
wallet/rpcdump.cpp \
wallet/rpcsigner.cpp \
wallet/rpcwallet.cpp \
wallet/scriptpubkeyman.cpp \
wallet/wallet.cpp \
Expand Down Expand Up @@ -520,6 +517,7 @@ libbitcoin_common_a_SOURCES = \
compressor.cpp \
core_read.cpp \
core_write.cpp \
external_signer.cpp \
key.cpp \
key_io.cpp \
merkleblock.cpp \
Expand All @@ -532,6 +530,7 @@ libbitcoin_common_a_SOURCES = \
protocol.cpp \
psbt.cpp \
rpc/rawtransaction_util.cpp \
rpc/external_signer.cpp \
rpc/util.cpp \
scheduler.cpp \
script/descriptor.cpp \
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/external_signer.cpp → src/external_signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <psbt.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <wallet/external_signer.h>
#include <external_signer.h>

ExternalSigner::ExternalSigner(const std::string& command, const std::string& fingerprint, std::string chain, std::string name): m_command(command), m_fingerprint(fingerprint), m_chain(chain), m_name(name) {}

Expand Down
10 changes: 5 additions & 5 deletions src/wallet/external_signer.h → src/external_signer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_WALLET_EXTERNAL_SIGNER_H
#define BITCOIN_WALLET_EXTERNAL_SIGNER_H
#ifndef BITCOIN_EXTERNAL_SIGNER_H
#define BITCOIN_EXTERNAL_SIGNER_H

#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -48,7 +48,7 @@ class ExternalSigner
//! @param[in] command the command which handles interaction with the external signer
//! @param[in,out] signers vector to which new signers (with a unique master key fingerprint) are added
//! @param chain "main", "test", "regtest" or "signet"
//! @param[out] success Boolean
//! @returns success
static bool Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, std::string chain, bool ignore_errors = false);

//! Display address on the device. Calls `<command> displayaddress --desc <descriptor>`.
Expand All @@ -59,7 +59,7 @@ class ExternalSigner
//! Get receive and change Descriptor(s) from device for a given account.
//! Calls `<command> getdescriptors --account <account>`
//! @param[in] account which BIP32 account to use (e.g. `m/44'/0'/account'`)
//! @param[out] UniValue see doc/external-signer.md
//! @returns see doc/external-signer.md
UniValue GetDescriptors(int account);

//! Sign PartiallySignedTransaction on the device.
Expand All @@ -70,4 +70,4 @@ class ExternalSigner
#endif
};

#endif // BITCOIN_WALLET_EXTERNAL_SIGNER_H
#endif // BITCOIN_EXTERNAL_SIGNER_H
54 changes: 8 additions & 46 deletions src/wallet/rpcsigner.cpp → src/rpc/external_signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparamsbase.h>
#include <key_io.h>
#include <external_signer.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <util/strencodings.h>
#include <wallet/rpcsigner.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <rpc/protocol.h>

#ifdef ENABLE_EXTERNAL_SIGNER

Expand All @@ -33,7 +31,7 @@ static RPCHelpMan enumeratesigners()
RPCExamples{""},
[](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
const std::string command = gArgs.GetArg("-signer", "");
if (command == "") throw JSONRPCError(RPC_WALLET_ERROR, "Error: restart bitcoind with -signer=<cmd>");
if (command == "") throw JSONRPCError(RPC_MISC_ERROR, "Error: restart bitcoind with -signer=<cmd>");
std::string chain = gArgs.GetChainName();
UniValue signers_res = UniValue::VARR;
try {
Expand All @@ -46,7 +44,7 @@ static RPCHelpMan enumeratesigners()
signers_res.push_back(signer_res);
}
} catch (const ExternalSignerException& e) {
throw JSONRPCError(RPC_WALLET_ERROR, e.what());
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
UniValue result(UniValue::VOBJ);
result.pushKV("signers", signers_res);
Expand All @@ -55,54 +53,18 @@ static RPCHelpMan enumeratesigners()
};
}

static RPCHelpMan signerdisplayaddress()
void RegisterSignerRPCCommands(CRPCTable &t)
{
return RPCHelpMan{
"signerdisplayaddress",
"Display address on an external signer for verification.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, /* default_val */ "", "bitcoin address to display"},
},
RPCResult{RPCResult::Type::NONE,"",""},
RPCExamples{""},
[](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();

LOCK(pwallet->cs_wallet);

CTxDestination dest = DecodeDestination(request.params[0].get_str());

// Make sure the destination is valid
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}

if (!pwallet->DisplayAddress(dest)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to display address");
}

UniValue result(UniValue::VOBJ);
result.pushKV("address", request.params[0].get_str());
return result;
}
};
}

Span<const CRPCCommand> GetSignerRPCCommands()
{

// clang-format off
static const CRPCCommand commands[] =
{ // category actor (function)
// --------------------- ------------------------
{ "signer", &enumeratesigners, },
{ "signer", &signerdisplayaddress, },
};
// clang-format on
return MakeSpan(commands);
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
}


#endif // ENABLE_EXTERNAL_SIGNER
5 changes: 5 additions & 0 deletions src/rpc/register.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ void RegisterMiscRPCCommands(CRPCTable &tableRPC);
void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterSignerRPCCommands(CRPCTable &tableRPC);

static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{
Expand All @@ -27,6 +29,9 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
RegisterMiscRPCCommands(t);
RegisterMiningRPCCommands(t);
RegisterRawTransactionRPCCommands(t);
#ifdef ENABLE_EXTERNAL_SIGNER
RegisterSignerRPCCommands(t);
#endif // ENABLE_EXTERNAL_SIGNER
}

#endif // BITCOIN_RPC_REGISTER_H
2 changes: 1 addition & 1 deletion src/wallet/external_signer_scriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <wallet/external_signer.h>
#include <external_signer.h>
#include <wallet/external_signer_scriptpubkeyman.h>

#ifdef ENABLE_EXTERNAL_SIGNER
Expand Down
12 changes: 0 additions & 12 deletions src/wallet/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <wallet/fees.h>
#include <wallet/ismine.h>
#include <wallet/load.h>
#include <wallet/rpcsigner.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>

Expand Down Expand Up @@ -520,17 +519,6 @@ class WalletClientImpl : public WalletClient
}, command.argNames, command.unique_id);
m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back()));
}

#ifdef ENABLE_EXTERNAL_SIGNER
for (const CRPCCommand& command : GetSignerRPCCommands()) {
m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
JSONRPCRequest wallet_request = request;
wallet_request.context = &m_context;
return command.actor(wallet_request, result, last_handler);
}, command.argNames, command.unique_id);
m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back()));
}
#endif
}
bool verify() override { return VerifyWallets(*m_context.chain); }
bool load() override { return LoadWallets(*m_context.chain); }
Expand Down
25 changes: 0 additions & 25 deletions src/wallet/rpcsigner.h

This file was deleted.

45 changes: 45 additions & 0 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4526,6 +4526,48 @@ static RPCHelpMan upgradewallet()
};
}

#ifdef ENABLE_EXTERNAL_SIGNER
static RPCHelpMan walletdisplayaddress()
{
return RPCHelpMan{
"walletdisplayaddress",
"Display address on an external signer for verification.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, /* default_val */ "", "bitcoin address to display"},
},
RPCResult{
RPCResult::Type::OBJ,"","",
{
{RPCResult::Type::STR, "address", "The address as confirmed by the signer"},
}
},
RPCExamples{""},
[](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();

LOCK(pwallet->cs_wallet);

CTxDestination dest = DecodeDestination(request.params[0].get_str());

// Make sure the destination is valid
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}

if (!pwallet->DisplayAddress(dest)) {
throw JSONRPCError(RPC_MISC_ERROR, "Failed to display address");
}

UniValue result(UniValue::VOBJ);
result.pushKV("address", request.params[0].get_str());
return result;
}
};
}
#endif // ENABLE_EXTERNAL_SIGNER

RPCHelpMan abortrescan();
RPCHelpMan dumpprivkey();
RPCHelpMan importprivkey();
Expand Down Expand Up @@ -4602,6 +4644,9 @@ static const CRPCCommand commands[] =
{ "wallet", &unloadwallet, },
{ "wallet", &upgradewallet, },
{ "wallet", &walletcreatefundedpsbt, },
#ifdef ENABLE_EXTERNAL_SIGNER
{ "wallet", &walletdisplayaddress, },
#endif // ENABLE_EXTERNAL_SIGNER
{ "wallet", &walletlock, },
{ "wallet", &walletpassphrase, },
{ "wallet", &walletpassphrasechange, },
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/scriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
#include <wallet/external_signer.h>
#include <external_signer.h>
#include <wallet/scriptpubkeyman.h>

#include <optional>
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <wallet/coinselection.h>
#include <wallet/crypter.h>
#include <wallet/scriptpubkeyman.h>
#include <wallet/external_signer.h>
#include <external_signer.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>

Expand Down
Loading

0 comments on commit b54b2e7

Please sign in to comment.