diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -26,6 +26,7 @@ receive.cpp rpcdump.cpp rpcwallet.cpp + rpc/signmessage.cpp salvage.cpp scriptpubkeyman.cpp spend.cpp diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp new file mode 100644 --- /dev/null +++ b/src/wallet/rpc/signmessage.cpp @@ -0,0 +1,82 @@ +// Copyright (c) 2011-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 <key_io.h> +#include <rpc/util.h> +#include <util/message.h> +#include <wallet/rpcwallet.h> +#include <wallet/wallet.h> + +#include <univalue.h> + +RPCHelpMan signmessage() { + return RPCHelpMan{ + "signmessage", + "Sign a message with the private key of an address" + + HELP_REQUIRING_PASSPHRASE, + { + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, + "The bitcoin address to use for the private key."}, + {"message", RPCArg::Type::STR, RPCArg::Optional::NO, + "The message to create a signature of."}, + }, + RPCResult{RPCResult::Type::STR, "signature", + "The signature of the message encoded in base 64"}, + RPCExamples{ + "\nUnlock the wallet for 30 seconds\n" + + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + + "\nCreate the signature\n" + + HelpExampleCli( + "signmessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + + "\nVerify the signature\n" + + HelpExampleCli("verifymessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" " + "\"signature\" \"my message\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc( + "signmessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")}, + [&](const RPCHelpMan &self, const Config &config, + const JSONRPCRequest &request) -> UniValue { + std::shared_ptr<CWallet> const wallet = + GetWalletForJSONRPCRequest(request); + if (!wallet) { + return NullUniValue; + } + const CWallet *const pwallet = wallet.get(); + + LOCK(pwallet->cs_wallet); + + EnsureWalletIsUnlocked(pwallet); + + std::string strAddress = request.params[0].get_str(); + std::string strMessage = request.params[1].get_str(); + + CTxDestination dest = + DecodeDestination(strAddress, wallet->GetChainParams()); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + } + + const PKHash *pkhash = boost::get<PKHash>(&dest); + if (!pkhash) { + throw JSONRPCError(RPC_TYPE_ERROR, + "Address does not refer to key"); + } + + std::string signature; + SigningResult err = + pwallet->SignMessage(strMessage, *pkhash, signature); + if (err == SigningResult::SIGNING_FAILED) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + SigningResultString(err)); + } else if (err != SigningResult::OK) { + throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err)); + } + + return signature; + }, + }; +} diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -22,6 +22,8 @@ class RPCHelpMan; struct WalletContext; +extern const std::string HELP_REQUIRING_PASSPHRASE; + Span<const CRPCCommand> GetWalletRPCCommands(); /** diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -21,7 +21,6 @@ #include <script/descriptor.h> #include <util/bip32.h> #include <util/error.h> -#include <util/message.h> // For MessageSign() #include <util/moneystr.h> #include <util/string.h> #include <util/system.h> @@ -45,7 +44,7 @@ using interfaces::FoundBlock; static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; -static const std::string HELP_REQUIRING_PASSPHRASE{ +const std::string HELP_REQUIRING_PASSPHRASE{ "\nRequires wallet passphrase to be set with walletpassphrase call if " "wallet is encrypted.\n"}; @@ -599,77 +598,6 @@ }; } -static RPCHelpMan signmessage() { - return RPCHelpMan{ - "signmessage", - "Sign a message with the private key of an address" + - HELP_REQUIRING_PASSPHRASE, - { - {"address", RPCArg::Type::STR, RPCArg::Optional::NO, - "The bitcoin address to use for the private key."}, - {"message", RPCArg::Type::STR, RPCArg::Optional::NO, - "The message to create a signature of."}, - }, - RPCResult{RPCResult::Type::STR, "signature", - "The signature of the message encoded in base 64"}, - RPCExamples{ - "\nUnlock the wallet for 30 seconds\n" + - HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + - "\nCreate the signature\n" + - HelpExampleCli( - "signmessage", - "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + - "\nVerify the signature\n" + - HelpExampleCli("verifymessage", - "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" " - "\"signature\" \"my message\"") + - "\nAs a JSON-RPC call\n" + - HelpExampleRpc( - "signmessage", - "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")}, - [&](const RPCHelpMan &self, const Config &config, - const JSONRPCRequest &request) -> UniValue { - std::shared_ptr<CWallet> const wallet = - GetWalletForJSONRPCRequest(request); - if (!wallet) { - return NullUniValue; - } - const CWallet *const pwallet = wallet.get(); - - LOCK(pwallet->cs_wallet); - - EnsureWalletIsUnlocked(pwallet); - - std::string strAddress = request.params[0].get_str(); - std::string strMessage = request.params[1].get_str(); - - CTxDestination dest = - DecodeDestination(strAddress, wallet->GetChainParams()); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); - } - - const PKHash *pkhash = boost::get<PKHash>(&dest); - if (!pkhash) { - throw JSONRPCError(RPC_TYPE_ERROR, - "Address does not refer to key"); - } - - std::string signature; - SigningResult err = - pwallet->SignMessage(strMessage, *pkhash, signature); - if (err == SigningResult::SIGNING_FAILED) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - SigningResultString(err)); - } else if (err != SigningResult::OK) { - throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err)); - } - - return signature; - }, - }; -} - static Amount GetReceived(const CWallet &wallet, const UniValue ¶ms, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { @@ -5414,6 +5342,8 @@ }; } +RPCHelpMan signmessage(); + Span<const CRPCCommand> GetWalletRPCCommands() { // clang-format off static const CRPCCommand commands[] = {