Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: Merge bitcoin#23712 , 23346, 23120, 23640, 22008, 22100 #6308

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ BITCOIN_CORE_H = \
wallet/ismine.h \
wallet/load.h \
wallet/rpcwallet.h \
wallet/rpc/util.h \
wallet/salvage.h \
wallet/scriptpubkeyman.h \
wallet/sqlite.h \
Expand Down Expand Up @@ -595,8 +596,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/hdchain.cpp \
wallet/interfaces.cpp \
wallet/load.cpp \
wallet/rpc/util.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/scriptpubkeyman.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \
Expand Down
7 changes: 7 additions & 0 deletions src/bitcoin-wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@
#include <compat/compat.h>
#include <logging.h>
#include <util/strencodings.h>
#include <clientversion.h>
#include <key.h>
#include <pubkey.h>
#include <tinyformat.h>
#include <util/system.h>
#include <util/translation.h>
#include <util/url.h>
#include <wallet/wallettool.h>

#include <exception>
#include <string>
#include <tuple>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = nullptr;

Expand Down
1 change: 1 addition & 0 deletions src/rpc/coinjoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <coinjoin/options.h>
#include <interfaces/coinjoin.h>
#include <wallet/rpcwallet.h>
#include <wallet/rpc/util.h>
#endif // ENABLE_WALLET

#include <univalue.h>
Expand Down
1 change: 1 addition & 0 deletions src/rpc/evo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <wallet/coincontrol.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/rpc/util.h>
#endif//ENABLE_WALLET

#ifdef ENABLE_WALLET
Expand Down
1 change: 1 addition & 0 deletions src/rpc/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <wallet/rpcwallet.h>
#ifdef ENABLE_WALLET
#include <wallet/wallet.h>
#include <wallet/rpc/util.h>
#endif // ENABLE_WALLET

#include <fstream>
Expand Down
122 changes: 122 additions & 0 deletions src/wallet/rpc/util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// 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 <wallet/rpc/util.h>

#include <rpc/util.h>
#include <util/url.h>
#include <wallet/context.h>
#include <wallet/wallet.h>

#include <univalue.h>

static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};

bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();

if (avoid_reuse && !can_avoid_reuse) {
throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
}

return avoid_reuse;
}

/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn't
* explicitly set.
*/
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
{
if (include_watchonly.isNull()) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}

// otherwise return whatever include_watchonly was set to
return include_watchonly.get_bool();
}

bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
return true;
}
return false;
}

std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
WalletContext& context = EnsureWalletContext(request.context);

std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}

std::vector<std::shared_ptr<CWallet>> wallets = GetWallets(context);
if (wallets.size() == 1) {
return wallets[0];
}

if (wallets.empty()) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}
throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}

void EnsureWalletIsUnlocked(const CWallet& wallet)
{
if (wallet.IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
}

WalletContext& EnsureWalletContext(const std::any& context)
{
auto wallet_context = util::AnyPtr<WalletContext>(context);
if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
return *wallet_context;
}

// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}

const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet)
{
const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}

std::string LabelFromValue(const UniValue& value)
{
std::string label = value.get_str();
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}
38 changes: 38 additions & 0 deletions src/wallet/rpc/util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2017-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_RPC_UTIL_H
#define BITCOIN_WALLET_RPC_UTIL_H

#include <any>
#include <memory>
#include <string>

class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
class UniValue;
struct WalletContext;

extern const std::string HELP_REQUIRING_PASSPHRASE;

/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name);

void EnsureWalletIsUnlocked(const CWallet&);
WalletContext& EnsureWalletContext(const std::any& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet);

bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
std::string LabelFromValue(const UniValue& value);

#endif // BITCOIN_WALLET_RPC_UTIL_H
1 change: 1 addition & 0 deletions src/wallet/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <validation.h>
#include <wallet/wallet.h>
#include <wallet/rpcwallet.h>
#include <wallet/rpc/util.h>

#include <cstdint>
#include <fstream>
Expand Down
101 changes: 1 addition & 100 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <wallet/load.h>
#include <wallet/rpcwallet.h>
#include <wallet/scriptpubkeyman.h>
#include <wallet/rpc/util.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
Expand All @@ -49,35 +50,6 @@

using interfaces::FoundBlock;

static const std::string WALLET_ENDPOINT_BASE = "/wallet/";

static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();

if (avoid_reuse && !can_avoid_reuse) {
throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
}

return avoid_reuse;
}


/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn't
* explicitly set.
*/
static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
{
if (include_watchonly.isNull()) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}

// otherwise return whatever include_watchonly was set to
return include_watchonly.get_bool();
}


/** Checks if a CKey is in the given CWallet compressed or otherwise*/
bool HaveKey(const SigningProvider& wallet, const CKey& key)
Expand All @@ -87,69 +59,6 @@ bool HaveKey(const SigningProvider& wallet, const CKey& key)
return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
}

bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
return true;
}
return false;
}

std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);

std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}

std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
if (wallets.size() == 1) {
return wallets[0];
}

if (wallets.empty()) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}
throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}

void EnsureWalletIsUnlocked(const CWallet& wallet)
{
if (wallet.IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
}

// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}

WalletContext& EnsureWalletContext(const CoreContext& context)
{
auto* wallet_context = GetContext<WalletContext>(context);
if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
return *wallet_context;
}

static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
{
int confirms = wtx.GetDepthInMainChain();
Expand Down Expand Up @@ -191,14 +100,6 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
}


static std::string LabelFromValue(const UniValue& value)
{
std::string label = value.get_str();
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}

/**
* Update coin control with fee estimation based on the given parameters
*
Expand Down
25 changes: 0 additions & 25 deletions src/wallet/rpcwallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,10 @@
#include <context.h>
#include <span.h>

#include <memory>
#include <string>
#include <vector>

class CRPCCommand;
class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
class UniValue;
class CTransaction;
struct PartiallySignedTransaction;
struct WalletContext;

static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};

Span<const CRPCCommand> GetWalletRPCCommands();

/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);

void EnsureWalletIsUnlocked(const CWallet&);
WalletContext& EnsureWalletContext(const CoreContext& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);

RPCHelpMan getaddressinfo();
RPCHelpMan getrawchangeaddress();
RPCHelpMan addmultisigaddress();
Expand Down
Loading
Loading