Bitcoin Core 31.99.0
P2P Digital Currency
util.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <wallet/rpc/util.h>
6
7#include <common/url.h>
8#include <rpc/util.h>
9#include <util/any.h>
10#include <util/translation.h>
11#include <wallet/context.h>
12#include <wallet/wallet.h>
13
14#include <optional>
15#include <string_view>
16#include <univalue.h>
17
18namespace wallet {
19static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
20const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
21
22bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
23 bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
24 bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
25
26 if (avoid_reuse && !can_avoid_reuse) {
27 throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
28 }
29
30 return avoid_reuse;
31}
32
33std::string EnsureUniqueWalletName(const JSONRPCRequest& request, std::optional<std::string_view> wallet_name)
34{
35 if (auto endpoint_wallet{GetWalletNameFromJSONRPCRequest(request)}) {
36 // wallet endpoint was used
37 if (wallet_name && *wallet_name != *endpoint_wallet) {
39 "The RPC endpoint wallet and the wallet name parameter specify different wallets");
40 }
41 return *endpoint_wallet;
42 }
43
44 // Not a wallet endpoint; parameter must be provided
45 if (!wallet_name) {
47 "Either the RPC endpoint wallet or the wallet name parameter must be provided");
48 }
49
50 return std::string{*wallet_name};
51}
52
53std::optional<std::string> GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request)
54{
55 if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
56 // wallet endpoint was used
57 return UrlDecode(std::string_view{request.URI}.substr(WALLET_ENDPOINT_BASE.size()));
58 }
59 return std::nullopt;
60}
61
62std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
63{
65 WalletContext& context = EnsureWalletContext(request.context);
66
67 if (auto wallet_name{GetWalletNameFromJSONRPCRequest(request)}) {
68 std::shared_ptr<CWallet> pwallet{GetWallet(context, *wallet_name)};
69 if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
70 return pwallet;
71 }
72
73 size_t count{0};
74 auto wallet = GetDefaultWallet(context, count);
75 if (wallet) return wallet;
76
77 if (count == 0) {
78 throw JSONRPCError(
79 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)");
80 }
82 "Multiple wallets are loaded. Please select which wallet to use by requesting the RPC through the /wallet/<walletname> URI path.");
83}
84
86{
87 if (wallet.IsLocked()) {
88 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
89 }
90}
91
92WalletContext& EnsureWalletContext(const std::any& context)
93{
94 auto wallet_context = util::AnyPtr<WalletContext>(context);
95 if (!wallet_context) {
96 throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
97 }
98 return *wallet_context;
99}
100
101std::string LabelFromValue(const UniValue& value)
102{
103 static const std::string empty_string;
104 if (value.isNull()) return empty_string;
105
106 const std::string& label{value.get_str()};
107 if (label == "*")
108 throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
109 return label;
110}
111
112void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry)
113{
114 UniValue parent_descs(UniValue::VARR);
115 for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) {
116 std::string desc_str;
117 FlatSigningProvider dummy_provider;
118 if (!CHECK_NONFATAL(desc.descriptor->ToNormalizedString(dummy_provider, desc_str, &desc.cache))) continue;
119 parent_descs.push_back(desc_str);
120 }
121 entry.pushKV("parent_descs", std::move(parent_descs));
122}
123
124void HandleWalletError(const std::shared_ptr<CWallet>& wallet, DatabaseStatus& status, bilingual_str& error)
125{
126 if (!wallet) {
127 // Map bad format to not found, since bad format is returned when the
128 // wallet directory exists, but doesn't contain a data file.
130 switch (status) {
135 break;
138 break;
141 break;
145 break;
148 break;
149 default: // RPC_WALLET_ERROR is returned for all other cases.
150 break;
151 }
152 throw JSONRPCError(code, error.original);
153 }
154}
155
157{
158 AssertLockHeld(wallet.cs_wallet);
159 UniValue lastprocessedblock{UniValue::VOBJ};
160 lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());
161 lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());
162 entry.pushKV("lastprocessedblock", std::move(lastprocessedblock));
163}
164
165} // namespace wallet
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:109
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:405
enum JSONRPCRequest::Mode mode
std::string URI
Definition: request.h:59
std::any context
Definition: request.h:62
void push_back(UniValue val)
Definition: univalue.cpp:103
const std::string & get_str() const
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:81
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:125
bool get_bool() const
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:310
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:62
void HandleWalletError(const std::shared_ptr< CWallet > &wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:124
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:85
std::string EnsureUniqueWalletName(const JSONRPCRequest &request, std::optional< std::string_view > wallet_name)
Ensures that a wallet name is specified across the endpoint and wallet_name.
Definition: util.cpp:33
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:20
void PushParentDescriptors(const CWallet &wallet, const CScript &script_pubkey, UniValue &entry)
Fetch parent descriptors of this scriptPubKey.
Definition: util.cpp:112
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:92
std::string LabelFromValue(const UniValue &value)
Definition: util.cpp:101
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:156
bool GetAvoidReuseFlag(const CWallet &wallet, const UniValue &param)
Definition: util.cpp:22
std::optional< std::string > GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request)
Definition: util.cpp:53
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:21
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:207
static const std::string WALLET_ENDPOINT_BASE
Definition: util.cpp:19
DatabaseStatus
Definition: db.h:186
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
Definition: wallet.cpp:200
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
RPCErrorCode
Bitcoin RPC error codes.
Definition: protocol.h:25
@ RPC_WALLET_NOT_SPECIFIED
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:81
@ RPC_WALLET_INVALID_LABEL_NAME
Invalid label name.
Definition: protocol.h:73
@ RPC_WALLET_UNLOCK_NEEDED
Enter the wallet passphrase with walletpassphrase first.
Definition: protocol.h:75
@ RPC_WALLET_ALREADY_EXISTS
There is already a wallet with the same name.
Definition: protocol.h:83
@ RPC_WALLET_ENCRYPTION_FAILED
Failed to encrypt the wallet.
Definition: protocol.h:78
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:71
@ RPC_WALLET_ALREADY_LOADED
This same wallet is already loaded.
Definition: protocol.h:82
@ RPC_WALLET_NOT_FOUND
Invalid wallet specified.
Definition: protocol.h:80
@ RPC_INTERNAL_ERROR
Definition: protocol.h:36
Bilingual messages:
Definition: translation.h:24
std::string original
Definition: translation.h:25
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:36
static int count
std::string UrlDecode(std::string_view url_encoded)
Definition: url.cpp:12
AssertLockHeld(pool.cs)