From b54b2e7b1a171203404bd41853372c73f2c64532 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 18 Mar 2021 14:17:39 +0100 Subject: 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. --- doc/external-signer.md | 4 +- src/Makefile.am | 7 +- src/external_signer.cpp | 119 +++++++++++++++++++++++++ src/external_signer.h | 73 +++++++++++++++ src/rpc/external_signer.cpp | 70 +++++++++++++++ src/rpc/register.h | 5 ++ src/wallet/external_signer.cpp | 119 ------------------------- src/wallet/external_signer.h | 73 --------------- src/wallet/external_signer_scriptpubkeyman.cpp | 2 +- src/wallet/interfaces.cpp | 12 --- src/wallet/rpcsigner.cpp | 108 ---------------------- src/wallet/rpcsigner.h | 25 ------ src/wallet/rpcwallet.cpp | 45 ++++++++++ src/wallet/scriptpubkeyman.cpp | 2 +- src/wallet/wallet.h | 2 +- test/functional/rpc_signer.py | 79 ++++++++++++++++ test/functional/test_runner.py | 1 + test/functional/wallet_signer.py | 44 ++------- 18 files changed, 408 insertions(+), 382 deletions(-) create mode 100644 src/external_signer.cpp create mode 100644 src/external_signer.h create mode 100644 src/rpc/external_signer.cpp delete mode 100644 src/wallet/external_signer.cpp delete mode 100644 src/wallet/external_signer.h delete mode 100644 src/wallet/rpcsigner.cpp delete mode 100644 src/wallet/rpcsigner.h create mode 100755 test/functional/rpc_signer.py diff --git a/doc/external-signer.md b/doc/external-signer.md index 2b3b378bee..de44cdd880 100644 --- a/doc/external-signer.md +++ b/doc/external-signer.md @@ -46,7 +46,7 @@ Display an address on the device: ```sh $ bitcoin-cli -rpcwallet= getnewaddress -$ bitcoin-cli -rpcwallet= signerdisplayaddress
+$ bitcoin-cli -rpcwallet= walletdisplayaddress
``` Replace `
` with the result of `getnewaddress`. @@ -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 ` --fingerprint=00000000 displayaddress --desc=`. +The `walletdisplayaddress` RPC reuses some code from `getaddressinfo` on the provided address and obtains the inferred descriptor. It then calls ` --fingerprint=00000000 displayaddress --desc=`. `sendtoaddress` and `sendmany` check `inputs->bip32_derivs` to see if any inputs have the same `master_fingerprint` as the signer. If so, it calls ` --fingerprint=00000000 signtransaction `. It waits for the device to return a (partially) signed psbt, tries to finalize it and broadcasts the transaction. diff --git a/src/Makefile.am b/src/Makefile.am index 4e09c86ebd..3359be8a6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -144,6 +144,7 @@ BITCOIN_CORE_H = \ core_memusage.h \ cuckoocache.h \ dbwrapper.h \ + external_signer.h \ flatfile.h \ fs.h \ httprpc.h \ @@ -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 \ @@ -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 \ @@ -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 \ @@ -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 \ diff --git a/src/external_signer.cpp b/src/external_signer.cpp new file mode 100644 index 0000000000..b82dcc503d --- /dev/null +++ b/src/external_signer.cpp @@ -0,0 +1,119 @@ +// 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 +#include +#include +#include +#include +#include + +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& signers, std::string chain, bool ignore_errors) +{ + // Call 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/external_signer.h b/src/external_signer.h new file mode 100644 index 0000000000..17428ba2f9 --- /dev/null +++ b/src/external_signer.h @@ -0,0 +1,73 @@ +// 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_EXTERNAL_SIGNER_H +#define BITCOIN_EXTERNAL_SIGNER_H + +#include +#include +#include +#include + +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 ` 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" + //! @returns success + static bool Enumerate(const std::string& command, std::vector& signers, std::string chain, bool ignore_errors = false); + + //! Display address on the device. Calls ` displayaddress --desc `. + //! @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 ` getdescriptors --account ` + //! @param[in] account which BIP32 account to use (e.g. `m/44'/0'/account'`) + //! @returns see doc/external-signer.md + UniValue GetDescriptors(int account); + + //! Sign PartiallySignedTransaction on the device. + //! Calls ` 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_EXTERNAL_SIGNER_H diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp new file mode 100644 index 0000000000..628c684215 --- /dev/null +++ b/src/rpc/external_signer.cpp @@ -0,0 +1,70 @@ +// 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 +#include +#include +#include +#include +#include + +#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_MISC_ERROR, "Error: restart bitcoind with -signer="); + std::string chain = gArgs.GetChainName(); + UniValue signers_res = UniValue::VARR; + try { + std::vector 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_MISC_ERROR, e.what()); + } + UniValue result(UniValue::VOBJ); + result.pushKV("signers", signers_res); + return result; + } + }; +} + +void RegisterSignerRPCCommands(CRPCTable &t) +{ +// clang-format off +static const CRPCCommand commands[] = +{ // category actor (function) + // --------------------- ------------------------ + { "signer", &enumeratesigners, }, +}; +// clang-format on + for (const auto& c : commands) { + t.appendCommand(c.name, &c); + } +} + +#endif // ENABLE_EXTERNAL_SIGNER diff --git a/src/rpc/register.h b/src/rpc/register.h index 374a1e3db8..6724203ffe 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -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) { @@ -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 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 -#include -#include -#include -#include -#include - -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& signers, std::string chain, bool ignore_errors) -{ - // Call 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 -#include -#include -#include - -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 ` 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& signers, std::string chain, bool ignore_errors = false); - - //! Display address on the device. Calls ` displayaddress --desc `. - //! @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 ` getdescriptors --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 ` 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 -#include +#include #include #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 #include #include -#include #include #include @@ -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 -#include -#include -#include -#include -#include -#include -#include - -#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="); - std::string chain = gArgs.GetChainName(); - UniValue signers_res = UniValue::VARR; - try { - std::vector 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 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 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 -#include -#include - -#ifdef ENABLE_EXTERNAL_SIGNER - -class CRPCCommand; - -namespace interfaces { -class Chain; -class Handler; -} - -Span 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 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 #include #include -#include +#include #include #include 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 #include #include -#include +#include #include #include diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py new file mode 100755 index 0000000000..3188763f49 --- /dev/null +++ b/test/functional/rpc_signer.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017-2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test external signer. + +Verify that a bitcoind node can use an external signer command. +See also wallet_signer.py for tests that require wallet context. +""" +import os +import platform + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, +) + + +class RPCSignerTest(BitcoinTestFramework): + def mock_signer_path(self): + path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mocks', 'signer.py') + if platform.system() == "Windows": + return "py " + path + else: + return path + + def set_test_params(self): + self.num_nodes = 4 + + self.extra_args = [ + [], + [f"-signer={self.mock_signer_path()}", '-keypool=10'], + [f"-signer={self.mock_signer_path()}", '-keypool=10'], + ["-signer=fake.py"], + ] + + def skip_test_if_missing_module(self): + self.skip_if_no_external_signer() + + def set_mock_result(self, node, res): + with open(os.path.join(node.cwd, "mock_result"), "w", encoding="utf8") as f: + f.write(res) + + def clear_mock_result(self, node): + os.remove(os.path.join(node.cwd, "mock_result")) + + def run_test(self): + self.log.debug(f"-signer={self.mock_signer_path()}") + + assert_raises_rpc_error(-1, 'Error: restart bitcoind with -signer=', + self.nodes[0].enumeratesigners + ) + + # Handle script missing: + assert_raises_rpc_error(-1, 'execve failed: No such file or directory', + self.nodes[3].enumeratesigners + ) + + # Handle error thrown by script + self.set_mock_result(self.nodes[1], "2") + assert_raises_rpc_error(-1, 'RunCommandParseJSON error', + self.nodes[1].enumeratesigners + ) + self.clear_mock_result(self.nodes[1]) + + self.set_mock_result(self.nodes[1], '0 [{"type": "trezor", "model": "trezor_t", "error": "fingerprint not found"}]') + assert_raises_rpc_error(-1, 'fingerprint not found', + self.nodes[1].enumeratesigners + ) + self.clear_mock_result(self.nodes[1]) + + result = self.nodes[1].enumeratesigners() + assert_equal(len(result['signers']), 2) + assert_equal(result['signers'][0]["fingerprint"], "00000001") + assert_equal(result['signers'][0]["name"], "trezor_t") + +if __name__ == '__main__': + RPCSignerTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 001d161612..bd58f2cd51 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -111,6 +111,7 @@ BASE_SCRIPTS = [ 'wallet_listtransactions.py --legacy-wallet', 'wallet_listtransactions.py --descriptors', 'feature_taproot.py', + 'rpc_signer.py', 'wallet_signer.py --descriptors', # vv Tests less than 60s vv 'p2p_sendheaders.py', diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py index 9dd080dca9..afd4fd3691 100755 --- a/test/functional/wallet_signer.py +++ b/test/functional/wallet_signer.py @@ -5,6 +5,7 @@ """Test external signer. Verify that a bitcoind node can use an external signer command +See also rpc_signer.py for tests without wallet context. """ import os import platform @@ -16,7 +17,7 @@ from test_framework.util import ( ) -class SignerTest(BitcoinTestFramework): +class WalletSignerTest(BitcoinTestFramework): def mock_signer_path(self): path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mocks', 'signer.py') if platform.system() == "Windows": @@ -25,18 +26,16 @@ class SignerTest(BitcoinTestFramework): return path def set_test_params(self): - self.num_nodes = 4 + self.num_nodes = 2 self.extra_args = [ [], [f"-signer={self.mock_signer_path()}", '-keypool=10'], - [f"-signer={self.mock_signer_path()}", '-keypool=10'], - ["-signer=fake.py"], ] def skip_test_if_missing_module(self): - self.skip_if_no_wallet() self.skip_if_no_external_signer() + self.skip_if_no_wallet() def set_mock_result(self, node, res): with open(os.path.join(node.cwd, "mock_result"), "w", encoding="utf8") as f: @@ -48,28 +47,6 @@ class SignerTest(BitcoinTestFramework): def run_test(self): self.log.debug(f"-signer={self.mock_signer_path()}") - assert_raises_rpc_error(-4, 'Error: restart bitcoind with -signer=', - self.nodes[0].enumeratesigners - ) - - # Handle script missing: - assert_raises_rpc_error(-1, 'execve failed: No such file or directory', - self.nodes[3].enumeratesigners - ) - - # Handle error thrown by script - self.set_mock_result(self.nodes[1], "2") - assert_raises_rpc_error(-1, 'RunCommandParseJSON error', - self.nodes[1].enumeratesigners - ) - self.clear_mock_result(self.nodes[1]) - - self.set_mock_result(self.nodes[1], '0 [{"type": "trezor", "model": "trezor_t", "error": "fingerprint not found"}]') - assert_raises_rpc_error(-4, 'fingerprint not found', - self.nodes[1].enumeratesigners - ) - self.clear_mock_result(self.nodes[1]) - # Create new wallets for an external signer. # disable_private_keys and descriptors must be true: assert_raises_rpc_error(-4, "Private keys must be disabled when using an external signer", self.nodes[1].createwallet, wallet_name='not_hww', disable_private_keys=False, descriptors=True, external_signer=True) @@ -81,11 +58,6 @@ class SignerTest(BitcoinTestFramework): self.nodes[1].createwallet(wallet_name='hww', disable_private_keys=True, descriptors=True, external_signer=True) hww = self.nodes[1].get_wallet_rpc('hww') - result = hww.enumeratesigners() - assert_equal(len(result['signers']), 2) - assert_equal(result['signers'][0]["fingerprint"], "00000001") - assert_equal(result['signers'][0]["name"], "trezor_t") - # Flag can't be set afterwards (could be added later for non-blank descriptor based watch-only wallets) self.nodes[1].createwallet(wallet_name='not_hww', disable_private_keys=True, descriptors=True, external_signer=False) not_hww = self.nodes[1].get_wallet_rpc('not_hww') @@ -123,14 +95,14 @@ class SignerTest(BitcoinTestFramework): assert_equal(address_info['ismine'], True) assert_equal(address_info['hdkeypath'], "m/44'/1'/0'/0/0") - self.log.info('Test signerdisplayaddress') - result = hww.signerdisplayaddress(address1) + self.log.info('Test walletdisplayaddress') + result = hww.walletdisplayaddress(address1) assert_equal(result, {"address": address1}) # Handle error thrown by script self.set_mock_result(self.nodes[1], "2") assert_raises_rpc_error(-1, 'RunCommandParseJSON error', - hww.signerdisplayaddress, address1 + hww.walletdisplayaddress, address1 ) self.clear_mock_result(self.nodes[1]) @@ -214,4 +186,4 @@ class SignerTest(BitcoinTestFramework): # self.clear_mock_result(self.nodes[4]) if __name__ == '__main__': - SignerTest().main() + WalletSignerTest().main() -- cgit v1.2.3 From b0db187e5b30a491c9f95685430a82a1e35e921d Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 18 Mar 2021 15:11:12 +0100 Subject: ci: use --enable-external-signer instead of --with-boost-process An earlier version of #16546 used both --with-boost-process and --enable-external-signer, which was simplified to only use the latter. However I forgot to update CI, so the external signer tests were not run. --- ci/test/00_setup_env_arm.sh | 2 +- ci/test/00_setup_env_i686_centos.sh | 2 +- ci/test/00_setup_env_mac.sh | 2 +- ci/test/00_setup_env_mac_host.sh | 2 +- ci/test/00_setup_env_native_asan.sh | 2 +- ci/test/00_setup_env_native_fuzz.sh | 2 +- ci/test/00_setup_env_native_multiprocess.sh | 2 +- ci/test/00_setup_env_native_nowallet.sh | 2 +- ci/test/00_setup_env_native_qt5.sh | 2 +- ci/test/00_setup_env_native_tsan.sh | 2 +- ci/test/00_setup_env_s390x.sh | 2 +- ci/test/00_setup_env_win64.sh | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh index 42783197a9..07f099b85c 100644 --- a/ci/test/00_setup_env_arm.sh +++ b/ci/test/00_setup_env_arm.sh @@ -25,4 +25,4 @@ export RUN_FUNCTIONAL_TESTS=false export GOAL="install" # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" # This could be removed once the ABI change warning does not show up by default -export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi --with-boost-process" +export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi --enable-external-signer" diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh index 07e7c2dc27..05c724fc0b 100644 --- a/ci/test/00_setup_env_i686_centos.sh +++ b/ci/test/00_setup_env_i686_centos.sh @@ -11,6 +11,6 @@ export CONTAINER_NAME=ci_i686_centos_8 export DOCKER_NAME_TAG=centos:8 export DOCKER_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-zmq which patch lbzip2 dash rsync coreutils bison" export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --enable-external-signer" export CONFIG_SHELL="/bin/dash" export TEST_RUNNER_ENV="LC_ALL=en_US.UTF-8" diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh index 6ce3812447..f051318a58 100644 --- a/ci/test/00_setup_env_mac.sh +++ b/ci/test/00_setup_env_mac.sh @@ -15,4 +15,4 @@ export XCODE_BUILD_ID=11C505 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export GOAL="deploy" -export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --with-boost-process" +export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-external-signer" diff --git a/ci/test/00_setup_env_mac_host.sh b/ci/test/00_setup_env_mac_host.sh index 274a0d1b7c..e54e78add4 100644 --- a/ci/test/00_setup_env_mac_host.sh +++ b/ci/test/00_setup_env_mac_host.sh @@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8 export HOST=x86_64-apple-darwin18 export PIP_PACKAGES="zmq" export GOAL="install" -export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --with-boost-process" +export BITCOIN_CONFIG="--with-gui --enable-reduce-exports --enable-external-signer" export CI_OS_NAME="macos" export NO_DEPENDS=1 export OSX_SDK="" diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index e47119e6fa..6039c51018 100644 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -11,4 +11,4 @@ export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent- export DOCKER_NAME_TAG=ubuntu:20.04 export NO_DEPENDS=1 export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++ --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++ --enable-external-signer" diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh index ebb5a1cabe..bedd0cf9aa 100644 --- a/ci/test/00_setup_env_native_fuzz.sh +++ b/ci/test/00_setup_env_native_fuzz.sh @@ -14,5 +14,5 @@ export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true export GOAL="install" -export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,integer CC=clang CXX=clang++ --with-boost-process" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,integer CC=clang CXX=clang++ --enable-external-signer" export CCACHE_SIZE=200M diff --git a/ci/test/00_setup_env_native_multiprocess.sh b/ci/test/00_setup_env_native_multiprocess.sh index c5692d786a..26a3996ce2 100644 --- a/ci/test/00_setup_env_native_multiprocess.sh +++ b/ci/test/00_setup_env_native_multiprocess.sh @@ -11,6 +11,6 @@ export DOCKER_NAME_TAG=ubuntu:20.04 export PACKAGES="cmake python3" export DEP_OPTS="MULTIPROCESS=1" export GOAL="install" -export BITCOIN_CONFIG="--with-boost-process" +export BITCOIN_CONFIG="--enable-external-signer" export TEST_RUNNER_ENV="BITCOIND=bitcoin-node" export RUN_SECURITY_TESTS="true" diff --git a/ci/test/00_setup_env_native_nowallet.sh b/ci/test/00_setup_env_native_nowallet.sh index 7ff044c020..a496b5af6e 100644 --- a/ci/test/00_setup_env_native_nowallet.sh +++ b/ci/test/00_setup_env_native_nowallet.sh @@ -11,4 +11,4 @@ export DOCKER_NAME_TAG=ubuntu:18.04 # Use bionic to have one config run the tes export PACKAGES="python3-zmq clang-5.0 llvm-5.0" # Use clang-5 to test C++17 compatibility, see doc/dependencies.md export DEP_OPTS="NO_WALLET=1" export GOAL="install" -export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CC=clang-5.0 CXX=clang++-5.0 --with-boost-process" +export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CC=clang-5.0 CXX=clang++-5.0 --enable-external-signer" diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh index 4c42605e9a..61948ab221 100644 --- a/ci/test/00_setup_env_native_qt5.sh +++ b/ci/test/00_setup_env_native_qt5.sh @@ -16,4 +16,4 @@ export RUN_UNIT_TESTS="false" export GOAL="install" export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.15.2 v0.16.3 v0.17.2 v0.18.1 v0.19.1" export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports ---enable-debug --disable-fuzz-binary CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" --with-boost-process" +--enable-debug --disable-fuzz-binary CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" --enable-external-signer" diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index 182e42ee7d..d3875fc045 100644 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -11,4 +11,4 @@ export DOCKER_NAME_TAG=ubuntu:20.04 export PACKAGES="clang llvm libc++abi-dev libc++-dev python3-zmq" export DEP_OPTS="CC=clang CXX='clang++ -stdlib=libc++'" export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq --with-gui=no CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' CXXFLAGS='-g' --with-sanitizers=thread CC=clang CXX='clang++ -stdlib=libc++' --with-boost-process" +export BITCOIN_CONFIG="--enable-zmq --with-gui=no CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' CXXFLAGS='-g' --with-sanitizers=thread CC=clang CXX='clang++ -stdlib=libc++' --enable-external-signer" diff --git a/ci/test/00_setup_env_s390x.sh b/ci/test/00_setup_env_s390x.sh index accbd07e22..88b431f3c7 100644 --- a/ci/test/00_setup_env_s390x.sh +++ b/ci/test/00_setup_env_s390x.sh @@ -23,4 +23,4 @@ export RUN_UNIT_TESTS=true export TEST_RUNNER_ENV="LC_ALL=C" export RUN_FUNCTIONAL_TESTS=true export GOAL="install" -export BITCOIN_CONFIG="--enable-reduce-exports --with-incompatible-bdb --with-boost-process" +export BITCOIN_CONFIG="--enable-reduce-exports --with-incompatible-bdb --enable-external-signer" diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh index 1e68d2a61a..4d5bde13fd 100644 --- a/ci/test/00_setup_env_win64.sh +++ b/ci/test/00_setup_env_win64.sh @@ -13,7 +13,7 @@ export DPKG_ADD_ARCH="i386" export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 wine32 file" export RUN_FUNCTIONAL_TESTS=false export GOAL="deploy" -export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests --without-boost-process" +export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests --disable-external-signer" # Compiler for MinGW-w64 causes false -Wreturn-type warning. # See https://sourceforge.net/p/mingw-w64/bugs/306/ -- cgit v1.2.3 From 88d4d5ff2f5c71a9a2f4c78c2b2e2fd00568cfee Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Fri, 26 Mar 2021 10:28:37 +0100 Subject: rpc: add help for enumeratesigners and walletdisplayaddress --- src/rpc/external_signer.cpp | 11 +++++++---- src/wallet/rpcwallet.cpp | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp index 628c684215..0f8f197ad8 100644 --- a/src/rpc/external_signer.cpp +++ b/src/rpc/external_signer.cpp @@ -13,8 +13,7 @@ static RPCHelpMan enumeratesigners() { - return RPCHelpMan{ - "enumeratesigners", + return RPCHelpMan{"enumeratesigners", "Returns a list of external signers from -signer.", {}, RPCResult{ @@ -28,8 +27,12 @@ static RPCHelpMan enumeratesigners() } } }, - RPCExamples{""}, - [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + RPCExamples{ + HelpExampleCli("enumeratesigners", "") + + HelpExampleRpc("enumeratesigners", "") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { const std::string command = gArgs.GetArg("-signer", ""); if (command == "") throw JSONRPCError(RPC_MISC_ERROR, "Error: restart bitcoind with -signer="); std::string chain = gArgs.GetChainName(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index dc821dc06d..a3e42a34d9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4529,9 +4529,8 @@ static RPCHelpMan upgradewallet() #ifdef ENABLE_EXTERNAL_SIGNER static RPCHelpMan walletdisplayaddress() { - return RPCHelpMan{ - "walletdisplayaddress", - "Display address on an external signer for verification.\n", + return RPCHelpMan{"walletdisplayaddress", + "Display address on an external signer for verification.", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, /* default_val */ "", "bitcoin address to display"}, }, @@ -4542,7 +4541,8 @@ static RPCHelpMan walletdisplayaddress() } }, RPCExamples{""}, - [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); -- cgit v1.2.3