Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
util.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2022 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 <string_view>
15#include <univalue.h>
16
17#include <boost/date_time/posix_time/posix_time.hpp>
18
19namespace wallet {
20static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
21const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
22
23int64_t ParseISO8601DateTime(const std::string& str)
24{
25 static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
26 static const std::locale loc(std::locale::classic(),
27 new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
28 std::istringstream iss(str);
29 iss.imbue(loc);
30 boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
31 iss >> ptime;
32 if (ptime.is_not_a_date_time() || epoch > ptime)
33 return 0;
34 return (ptime - epoch).total_seconds();
35}
36
37bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
38 bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
39 bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
40
41 if (avoid_reuse && !can_avoid_reuse) {
42 throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
43 }
44
45 return avoid_reuse;
46}
47
52bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
53{
54 if (include_watchonly.isNull()) {
55 // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
56 return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
57 }
58
59 // otherwise return whatever include_watchonly was set to
60 return include_watchonly.get_bool();
61}
62
63bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
64{
65 if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
66 // wallet endpoint was used
67 wallet_name = UrlDecode(std::string_view{request.URI}.substr(WALLET_ENDPOINT_BASE.size()));
68 return true;
69 }
70 return false;
71}
72
73std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
74{
76 WalletContext& context = EnsureWalletContext(request.context);
77
78 std::string wallet_name;
79 if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
80 std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
81 if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
82 return pwallet;
83 }
84
85 size_t count{0};
86 auto wallet = GetDefaultWallet(context, count);
87 if (wallet) return wallet;
88
89 if (count == 0) {
90 throw JSONRPCError(
91 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)");
92 }
94 "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
95}
96
98{
99 if (wallet.IsLocked()) {
100 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
101 }
102}
103
104WalletContext& EnsureWalletContext(const std::any& context)
105{
106 auto wallet_context = util::AnyPtr<WalletContext>(context);
107 if (!wallet_context) {
108 throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
109 }
110 return *wallet_context;
111}
112
113// 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
115{
116 LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
117 if (!spk_man && also_create) {
118 spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
119 }
120 if (!spk_man) {
121 throw JSONRPCError(RPC_WALLET_ERROR, "Only legacy wallets are supported by this command");
122 }
123 return *spk_man;
124}
125
127{
128 const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
129 if (!spk_man) {
130 throw JSONRPCError(RPC_WALLET_ERROR, "Only legacy wallets are supported by this command");
131 }
132 return *spk_man;
133}
134
135std::string LabelFromValue(const UniValue& value)
136{
137 static const std::string empty_string;
138 if (value.isNull()) return empty_string;
139
140 const std::string& label{value.get_str()};
141 if (label == "*")
142 throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
143 return label;
144}
145
146void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry)
147{
148 UniValue parent_descs(UniValue::VARR);
149 for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) {
150 parent_descs.push_back(desc.descriptor->ToString());
151 }
152 entry.pushKV("parent_descs", std::move(parent_descs));
153}
154
155void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error)
156{
157 if (!wallet) {
158 // Map bad format to not found, since bad format is returned when the
159 // wallet directory exists, but doesn't contain a data file.
161 switch (status) {
165 break;
168 break;
171 break;
174 break;
175 default: // RPC_WALLET_ERROR is returned for all other cases.
176 break;
177 }
178 throw JSONRPCError(code, error.original);
179 }
180}
181
183{
184 AssertLockHeld(wallet.cs_wallet);
185 UniValue lastprocessedblock{UniValue::VOBJ};
186 lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());
187 lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());
188 entry.pushKV("lastprocessedblock", std::move(lastprocessedblock));
189}
190
191} // namespace wallet
#define CHECK_NONFATAL(condition)
Identity function.
Definition check.h:73
Serialized script, used inside transaction inputs and outputs.
Definition script.h:414
enum JSONRPCRequest::Mode mode
std::string URI
Definition request.h:42
std::any context
Definition request.h:45
void push_back(UniValue val)
Definition univalue.cpp:104
const std::string & get_str() const
bool isNull() const
Definition univalue.h:79
void pushKV(std::string key, UniValue val)
Definition univalue.cpp:126
bool get_bool() const
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition wallet.h:300
T * AnyPtr(const std::any &any) noexcept
Helper function to access the contained object of a std::any instance.
Definition any.h:18
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition util.cpp:73
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name)
Definition util.cpp:63
void HandleWalletError(const std::shared_ptr< CWallet > wallet, DatabaseStatus &status, bilingual_str &error)
Definition util.cpp:155
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition util.cpp:97
const LegacyScriptPubKeyMan & EnsureConstLegacyScriptPubKeyMan(const CWallet &wallet)
Definition util.cpp:126
const std::string HELP_REQUIRING_PASSPHRASE
Definition util.cpp:21
void PushParentDescriptors(const CWallet &wallet, const CScript &script_pubkey, UniValue &entry)
Fetch parent descriptors of this scriptPubKey.
Definition util.cpp:146
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition util.cpp:114
WalletContext & EnsureWalletContext(const std::any &context)
Definition util.cpp:104
std::string LabelFromValue(const UniValue &value)
Definition util.cpp:135
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition util.cpp:182
bool ParseIncludeWatchonly(const UniValue &include_watchonly, const CWallet &wallet)
Used by RPC commands that have an include_watchonly parameter.
Definition util.cpp:52
int64_t ParseISO8601DateTime(const std::string &str)
Definition util.cpp:23
bool GetAvoidReuseFlag(const CWallet &wallet, const UniValue &param)
Definition util.cpp:37
@ WALLET_FLAG_AVOID_REUSE
Definition walletutil.h:42
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition wallet.cpp:204
static const std::string WALLET_ENDPOINT_BASE
Definition util.cpp:20
DatabaseStatus
Definition db.h:204
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
Definition wallet.cpp:197
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_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:18
std::string original
Definition translation.h:19
WalletContext struct containing references to state shared between CWallet instances,...
Definition context.h:36
#define AssertLockHeld(cs)
Definition sync.h:142
static int count
std::string UrlDecode(std::string_view url_encoded)
Definition url.cpp:12