aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorSjors Provoost <sjors@sprovoost.nl>2021-03-18 14:17:39 +0100
committerSjors Provoost <sjors@sprovoost.nl>2021-04-08 17:56:00 +0200
commitb54b2e7b1a171203404bd41853372c73f2c64532 (patch)
treef6d0854fa8a582e536bf8cdd8c0cf51ab51e8250 /src/wallet
parent6664211be2b664dd471d7aeea12fcf2859dba860 (diff)
downloadbitcoin-b54b2e7b1a171203404bd41853372c73f2c64532.tar.xz
Move external signer out of wallet module
This commit moves the ExternalSigner class and RPC methods out of the wallet module. The enumeratesigners RPC can be used without a wallet since #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.
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/external_signer.cpp119
-rw-r--r--src/wallet/external_signer.h73
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp2
-rw-r--r--src/wallet/interfaces.cpp12
-rw-r--r--src/wallet/rpcsigner.cpp108
-rw-r--r--src/wallet/rpcsigner.h25
-rw-r--r--src/wallet/rpcwallet.cpp45
-rw-r--r--src/wallet/scriptpubkeyman.cpp2
-rw-r--r--src/wallet/wallet.h2
9 files changed, 48 insertions, 340 deletions
diff --git a/src/wallet/external_signer.cpp b/src/wallet/external_signer.cpp
deleted file mode 100644
index 3396111760..0000000000
--- a/src/wallet/external_signer.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <chainparams.h>
-#include <core_io.h>
-#include <psbt.h>
-#include <util/strencodings.h>
-#include <util/system.h>
-#include <wallet/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) {}
-
-const std::string ExternalSigner::NetworkArg() const
-{
- return " --chain " + m_chain;
-}
-
-#ifdef ENABLE_EXTERNAL_SIGNER
-
-bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, std::string chain, bool ignore_errors)
-{
- // Call <command> enumerate
- const UniValue result = RunCommandParseJSON(command + " enumerate");
- if (!result.isArray()) {
- if (ignore_errors) return false;
- throw ExternalSignerException(strprintf("'%s' received invalid response, expected array of signers", command));
- }
- for (UniValue signer : result.getValues()) {
- // Check for error
- const UniValue& error = find_value(signer, "error");
- if (!error.isNull()) {
- if (ignore_errors) return false;
- if (!error.isStr()) {
- throw ExternalSignerException(strprintf("'%s' error", command));
- }
- throw ExternalSignerException(strprintf("'%s' error: %s", command, error.getValStr()));
- }
- // Check if fingerprint is present
- const UniValue& fingerprint = find_value(signer, "fingerprint");
- if (fingerprint.isNull()) {
- if (ignore_errors) return false;
- throw ExternalSignerException(strprintf("'%s' received invalid response, missing signer fingerprint", command));
- }
- std::string fingerprintStr = fingerprint.get_str();
- // Skip duplicate signer
- bool duplicate = false;
- for (ExternalSigner signer : signers) {
- if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
- }
- if (duplicate) break;
- std::string name = "";
- const UniValue& model_field = find_value(signer, "model");
- if (model_field.isStr() && model_field.getValStr() != "") {
- name += model_field.getValStr();
- }
- signers.push_back(ExternalSigner(command, fingerprintStr, chain, name));
- }
- return true;
-}
-
-UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const
-{
- return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " displayaddress --desc \"" + descriptor + "\"");
-}
-
-UniValue ExternalSigner::GetDescriptors(int account)
-{
- return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " getdescriptors --account " + strprintf("%d", account));
-}
-
-bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::string& error)
-{
- // Serialize the PSBT
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
- ssTx << psbtx;
-
- // Check if signer fingerprint matches any input master key fingerprint
- bool match = false;
- for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
- const PSBTInput& input = psbtx.inputs[i];
- for (auto entry : input.hd_keypaths) {
- if (m_fingerprint == strprintf("%08x", ReadBE32(entry.second.fingerprint))) match = true;
- }
- }
-
- if (!match) {
- error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str());
- return false;
- }
-
- std::string command = m_command + " --stdin --fingerprint \"" + m_fingerprint + "\"" + NetworkArg();
- std::string stdinStr = "signtx \"" + EncodeBase64(ssTx.str()) + "\"";
-
- const UniValue signer_result = RunCommandParseJSON(command, stdinStr);
-
- if (find_value(signer_result, "error").isStr()) {
- error = find_value(signer_result, "error").get_str();
- return false;
- }
-
- if (!find_value(signer_result, "psbt").isStr()) {
- error = "Unexpected result from signer";
- return false;
- }
-
- PartiallySignedTransaction signer_psbtx;
- std::string signer_psbt_error;
- if (!DecodeBase64PSBT(signer_psbtx, find_value(signer_result, "psbt").get_str(), signer_psbt_error)) {
- error = strprintf("TX decode failed %s", signer_psbt_error);
- return false;
- }
-
- psbtx = signer_psbtx;
-
- return true;
-}
-
-#endif
diff --git a/src/wallet/external_signer.h b/src/wallet/external_signer.h
deleted file mode 100644
index 4b9711107b..0000000000
--- a/src/wallet/external_signer.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
-// 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
-
-#include <stdexcept>
-#include <string>
-#include <univalue.h>
-#include <util/system.h>
-
-struct PartiallySignedTransaction;
-
-class ExternalSignerException : public std::runtime_error {
-public:
- using std::runtime_error::runtime_error;
-};
-
-//! Enables interaction with an external signing device or service, such as
-//! a hardware wallet. See doc/external-signer.md
-class ExternalSigner
-{
-private:
- //! The command which handles interaction with the external signer.
- std::string m_command;
-
-public:
- //! @param[in] command the command which handles interaction with the external signer
- //! @param[in] fingerprint master key fingerprint of the signer
- //! @param[in] chain "main", "test", "regtest" or "signet"
- //! @param[in] name device name
- ExternalSigner(const std::string& command, const std::string& fingerprint, std::string chain, std::string name);
-
- //! Master key fingerprint of the signer
- std::string m_fingerprint;
-
- //! Bitcoin mainnet, testnet, etc
- std::string m_chain;
-
- //! Name of signer
- std::string m_name;
-
- const std::string NetworkArg() const;
-
-#ifdef ENABLE_EXTERNAL_SIGNER
- //! Obtain a list of signers. Calls `<command> enumerate`.
- //! @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
- 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>`.
- //! @param[in] descriptor Descriptor specifying which address to display.
- //! Must include a public key or xpub, as well as key origin.
- UniValue DisplayAddress(const std::string& descriptor) const;
-
- //! 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
- UniValue GetDescriptors(int account);
-
- //! Sign PartiallySignedTransaction on the device.
- //! Calls `<command> signtransaction` and passes the PSBT via stdin.
- //! @param[in,out] psbt PartiallySignedTransaction to be signed
- bool SignTransaction(PartiallySignedTransaction& psbt, std::string& error);
-
-#endif
-};
-
-#endif // BITCOIN_WALLET_EXTERNAL_SIGNER_H
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index a2071e521a..a113c128d7 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -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
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 23bdaa671a..64ce09d1d1 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -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>
@@ -520,17 +519,6 @@ public:
}, 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); }
diff --git a/src/wallet/rpcsigner.cpp b/src/wallet/rpcsigner.cpp
deleted file mode 100644
index 696c74d665..0000000000
--- a/src/wallet/rpcsigner.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <chainparamsbase.h>
-#include <key_io.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>
-
-#ifdef ENABLE_EXTERNAL_SIGNER
-
-static RPCHelpMan enumeratesigners()
-{
- return RPCHelpMan{
- "enumeratesigners",
- "Returns a list of external signers from -signer.",
- {},
- RPCResult{
- RPCResult::Type::OBJ, "", "",
- {
- {RPCResult::Type::ARR, "signers", /* optional */ false, "",
- {
- {RPCResult::Type::STR_HEX, "masterkeyfingerprint", "Master key fingerprint"},
- {RPCResult::Type::STR, "name", "Device name"},
- },
- }
- }
- },
- 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>");
- std::string chain = gArgs.GetChainName();
- UniValue signers_res = UniValue::VARR;
- try {
- std::vector<ExternalSigner> signers;
- ExternalSigner::Enumerate(command, signers, chain);
- for (ExternalSigner signer : signers) {
- UniValue signer_res = UniValue::VOBJ;
- signer_res.pushKV("fingerprint", signer.m_fingerprint);
- signer_res.pushKV("name", signer.m_name);
- signers_res.push_back(signer_res);
- }
- } catch (const ExternalSignerException& e) {
- throw JSONRPCError(RPC_WALLET_ERROR, e.what());
- }
- UniValue result(UniValue::VOBJ);
- result.pushKV("signers", signers_res);
- return result;
- }
- };
-}
-
-static RPCHelpMan signerdisplayaddress()
-{
- 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);
-}
-
-
-#endif // ENABLE_EXTERNAL_SIGNER
diff --git a/src/wallet/rpcsigner.h b/src/wallet/rpcsigner.h
deleted file mode 100644
index f3ab83c428..0000000000
--- a/src/wallet/rpcsigner.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2018-2021 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_WALLET_RPCSIGNER_H
-#define BITCOIN_WALLET_RPCSIGNER_H
-
-#include <span.h>
-#include <util/system.h>
-#include <vector>
-
-#ifdef ENABLE_EXTERNAL_SIGNER
-
-class CRPCCommand;
-
-namespace interfaces {
-class Chain;
-class Handler;
-}
-
-Span<const CRPCCommand> GetSignerRPCCommands();
-
-#endif // ENABLE_EXTERNAL_SIGNER
-
-#endif //BITCOIN_WALLET_RPCSIGNER_H
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 672ee3e7a4..dc821dc06d 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -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();
@@ -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, },
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 9a75002b6c..149549410c 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -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>
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 192fd60dc2..5bf3c91bec 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -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>