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)
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>