Branch data Line data Source code
1 : : // Copyright (c) 2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2022 The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 : :
6 : : #include <bitcoin-build-config.h> // IWYU pragma: keep
7 : :
8 : : #include <core_io.h>
9 : : #include <key_io.h>
10 : : #include <rpc/server.h>
11 : : #include <rpc/util.h>
12 : : #include <util/translation.h>
13 : : #include <wallet/context.h>
14 : : #include <wallet/receive.h>
15 : : #include <wallet/rpc/wallet.h>
16 : : #include <wallet/rpc/util.h>
17 : : #include <wallet/wallet.h>
18 : : #include <wallet/walletutil.h>
19 : :
20 : : #include <optional>
21 : :
22 : : #include <univalue.h>
23 : :
24 : :
25 : : namespace wallet {
26 : :
27 : : static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
28 : : {WALLET_FLAG_AVOID_REUSE,
29 : : "You need to rescan the blockchain in order to correctly mark used "
30 : : "destinations in the past. Until this is done, some destinations may "
31 : : "be considered unused, even if the opposite is the case."},
32 : : };
33 : :
34 : : /** Checks if a CKey is in the given CWallet compressed or otherwise*/
35 : 0 : bool HaveKey(const SigningProvider& wallet, const CKey& key)
36 : : {
37 : 0 : CKey key2;
38 [ # # # # : 0 : key2.Set(key.begin(), key.end(), !key.IsCompressed());
# # ]
39 [ # # # # : 0 : return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
# # # # #
# # # # #
# # ]
40 : 0 : }
41 : :
42 : 1368 : static RPCHelpMan getwalletinfo()
43 : : {
44 : 1368 : return RPCHelpMan{"getwalletinfo",
45 : : "Returns an object containing various wallet state info.\n",
46 : : {},
47 : 0 : RPCResult{
48 : : RPCResult::Type::OBJ, "", "",
49 : : {
50 : : {
51 : : {RPCResult::Type::STR, "walletname", "the wallet name"},
52 : : {RPCResult::Type::NUM, "walletversion", "the wallet version"},
53 : : {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"},
54 : : {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
55 : : {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
56 : : {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
57 : : {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
58 [ + - ]: 2736 : {RPCResult::Type::NUM_TIME, "keypoololdest", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
59 : : {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
60 : : {RPCResult::Type::NUM, "keypoolsize_hd_internal", /*optional=*/true, "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
61 [ + - ]: 2736 : {RPCResult::Type::NUM_TIME, "unlocked_until", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
62 [ + - ]: 2736 : {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"},
63 : : {RPCResult::Type::STR_HEX, "hdseedid", /*optional=*/true, "the Hash160 of the HD seed (only present when HD is enabled)"},
64 : : {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
65 : : {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
66 : : {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
67 : : {
68 : : {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
69 : : {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
70 : : }, /*skip_type_check=*/true},
71 : : {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for output script management"},
72 : : {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
73 : : {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
74 : : {RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
75 : : RESULT_LAST_PROCESSED_BLOCK,
76 : : }},
77 [ + - + - : 45144 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ + + + -
- - - ]
78 : 1368 : RPCExamples{
79 [ + - + - : 2736 : HelpExampleCli("getwalletinfo", "")
+ - ]
80 [ + - + - : 5472 : + HelpExampleRpc("getwalletinfo", "")
+ - + - ]
81 [ + - ]: 1368 : },
82 : 582 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
83 : : {
84 [ - + ]: 582 : const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
85 [ - + ]: 560 : if (!pwallet) return UniValue::VNULL;
86 : :
87 : : // Make sure the results are valid at least up to the most recent block
88 : : // the user could have gotten from another RPC command prior to now
89 [ + - ]: 560 : pwallet->BlockUntilSyncedToCurrentChain();
90 : :
91 [ + - ]: 560 : LOCK(pwallet->cs_wallet);
92 : :
93 : 560 : UniValue obj(UniValue::VOBJ);
94 : :
95 [ + - ]: 560 : size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
96 [ + - ]: 560 : const auto bal = GetBalance(*pwallet);
97 [ + - + - : 1120 : obj.pushKV("walletname", pwallet->GetName());
+ - ]
98 [ + - + - : 1120 : obj.pushKV("walletversion", pwallet->GetVersion());
+ - + - ]
99 [ + - + - : 1120 : obj.pushKV("format", pwallet->GetDatabase().Format());
+ - + - ]
100 [ + - + - : 1120 : obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
+ - ]
101 [ + - + - : 1120 : obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
+ - ]
102 [ + - + - : 1120 : obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
+ - ]
103 [ + - + - : 1120 : obj.pushKV("txcount", (int)pwallet->mapWallet.size());
+ - ]
104 [ + - ]: 560 : const auto kp_oldest = pwallet->GetOldestKeyPoolTime();
105 [ - + ]: 560 : if (kp_oldest.has_value()) {
106 [ # # # # : 0 : obj.pushKV("keypoololdest", kp_oldest.value());
# # ]
107 : : }
108 [ + - + - : 1120 : obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
+ - ]
109 : :
110 [ + - ]: 560 : LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
111 [ - + ]: 560 : if (spk_man) {
112 : 0 : CKeyID seed_id = spk_man->GetHDChain().seed_id;
113 [ # # ]: 0 : if (!seed_id.IsNull()) {
114 [ # # # # : 0 : obj.pushKV("hdseedid", seed_id.GetHex());
# # # # ]
115 : : }
116 : : }
117 : :
118 [ + - + - ]: 560 : if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
119 [ + - + - : 1120 : obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
+ - + - ]
120 : : }
121 [ + - + + ]: 560 : if (pwallet->IsCrypted()) {
122 [ + - + - : 48 : obj.pushKV("unlocked_until", pwallet->nRelockTime);
+ - ]
123 : : }
124 [ + - + - : 1120 : obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
+ - ]
125 [ + - + - : 1120 : obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ - + - ]
126 [ + - + - : 1120 : obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
+ - + - ]
127 [ - + ]: 560 : if (pwallet->IsScanning()) {
128 : 0 : UniValue scanning(UniValue::VOBJ);
129 [ # # # # : 0 : scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
# # ]
130 [ # # # # : 0 : scanning.pushKV("progress", pwallet->ScanningProgress());
# # ]
131 [ # # # # ]: 0 : obj.pushKV("scanning", std::move(scanning));
132 : 0 : } else {
133 [ + - + - : 1120 : obj.pushKV("scanning", false);
+ - ]
134 : : }
135 [ + - + - : 1120 : obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
+ - + - ]
136 [ + - + - : 1120 : obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
+ - + - ]
137 [ + - + - : 1120 : obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
+ - + - ]
138 [ + + ]: 560 : if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {
139 [ + - + - : 1018 : obj.pushKV("birthtime", birthtime);
+ - ]
140 : : }
141 : :
142 [ + - ]: 560 : AppendLastProcessedBlock(obj, *pwallet);
143 : 560 : return obj;
144 [ + - ]: 1680 : },
145 [ + - + - : 8208 : };
+ - + - ]
146 [ + - + - : 31464 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - -
- - - ]
147 : :
148 : 796 : static RPCHelpMan listwalletdir()
149 : : {
150 : 796 : return RPCHelpMan{"listwalletdir",
151 : : "Returns a list of wallets in the wallet directory.\n",
152 : : {},
153 : 0 : RPCResult{
154 : : RPCResult::Type::OBJ, "", "",
155 : : {
156 : : {RPCResult::Type::ARR, "wallets", "",
157 : : {
158 : : {RPCResult::Type::OBJ, "", "",
159 : : {
160 : : {RPCResult::Type::STR, "name", "The wallet name"},
161 : : }},
162 : : }},
163 : : }
164 [ + - + - : 5572 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + + +
+ + + - -
- - - - ]
165 : 796 : RPCExamples{
166 [ + - + - : 1592 : HelpExampleCli("listwalletdir", "")
+ - ]
167 [ + - + - : 3184 : + HelpExampleRpc("listwalletdir", "")
+ - + - ]
168 [ + - ]: 796 : },
169 : 10 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
170 : : {
171 : 10 : UniValue wallets(UniValue::VARR);
172 [ + - + - : 87 : for (const auto& [path, _] : ListDatabases(GetWalletDir())) {
+ + ]
173 : 67 : UniValue wallet(UniValue::VOBJ);
174 [ + - + - : 134 : wallet.pushKV("name", path.utf8string());
+ - + - ]
175 [ + - ]: 67 : wallets.push_back(std::move(wallet));
176 : 77 : }
177 : :
178 : 10 : UniValue result(UniValue::VOBJ);
179 [ + - + - ]: 20 : result.pushKV("wallets", std::move(wallets));
180 : 10 : return result;
181 : 10 : },
182 [ + - + - : 4776 : };
+ - + - ]
183 [ + - + - : 3184 : }
+ - + - ]
184 : :
185 : 863 : static RPCHelpMan listwallets()
186 : : {
187 : 863 : return RPCHelpMan{"listwallets",
188 : : "Returns a list of currently loaded wallets.\n"
189 : : "For full information on the wallet, use \"getwalletinfo\"\n",
190 : : {},
191 : 0 : RPCResult{
192 : : RPCResult::Type::ARR, "", "",
193 : : {
194 : : {RPCResult::Type::STR, "walletname", "the wallet name"},
195 : : }
196 [ + - + - : 2589 : },
+ - + - +
- + - + -
+ + - - ]
197 : 863 : RPCExamples{
198 [ + - + - : 1726 : HelpExampleCli("listwallets", "")
+ - ]
199 [ + - + - : 3452 : + HelpExampleRpc("listwallets", "")
+ - + - ]
200 [ + - ]: 863 : },
201 : 77 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
202 : : {
203 : 77 : UniValue obj(UniValue::VARR);
204 : :
205 [ + - ]: 77 : WalletContext& context = EnsureWalletContext(request.context);
206 [ + - + + ]: 526 : for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
207 [ + - ]: 449 : LOCK(wallet->cs_wallet);
208 [ + - + - : 449 : obj.push_back(wallet->GetName());
+ - ]
209 : 526 : }
210 : :
211 : 77 : return obj;
212 : 0 : },
213 [ + - + - : 5178 : };
+ - + - ]
214 [ + - + - ]: 1726 : }
215 : :
216 : 941 : static RPCHelpMan loadwallet()
217 : : {
218 : 941 : return RPCHelpMan{"loadwallet",
219 : : "\nLoads a wallet from a wallet file or directory."
220 : : "\nNote that all wallet command-line options used when starting bitcoind will be"
221 : : "\napplied to the new wallet.\n",
222 : : {
223 [ + - ]: 941 : {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The path to the directory of the wallet to be loaded, either absolute or relative to the \"wallets\" directory. The \"wallets\" directory is set by the -walletdir option and defaults to the \"wallets\" folder within the data directory."},
224 [ + - ]: 941 : {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
225 : : },
226 : 0 : RPCResult{
227 : : RPCResult::Type::OBJ, "", "",
228 : : {
229 : : {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
230 : : {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
231 : : {
232 : : {RPCResult::Type::STR, "", ""},
233 : : }},
234 : : }
235 [ + - + - : 5646 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + + +
+ - - -
- ]
236 : 941 : RPCExamples{
237 : : "\nLoad wallet from the wallet dir:\n"
238 [ + - + - : 1882 : + HelpExampleCli("loadwallet", "\"walletname\"")
+ - + - ]
239 [ + - + - : 3764 : + HelpExampleRpc("loadwallet", "\"walletname\"")
+ - + - ]
240 : 941 : + "\nLoad wallet using absolute path (Unix):\n"
241 [ + - + - : 3764 : + HelpExampleCli("loadwallet", "\"/path/to/walletname/\"")
+ - + - ]
242 [ + - + - : 3764 : + HelpExampleRpc("loadwallet", "\"/path/to/walletname/\"")
+ - + - ]
243 : 941 : + "\nLoad wallet using absolute path (Windows):\n"
244 [ + - + - : 3764 : + HelpExampleCli("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
+ - + - ]
245 [ + - + - : 3764 : + HelpExampleRpc("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
+ - + - ]
246 [ + - ]: 941 : },
247 : 155 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
248 : : {
249 : 155 : WalletContext& context = EnsureWalletContext(request.context);
250 : 155 : const std::string name(request.params[0].get_str());
251 : :
252 [ + - ]: 155 : DatabaseOptions options;
253 : 155 : DatabaseStatus status;
254 [ + - ]: 155 : ReadDatabaseArgs(*context.args, options);
255 : 155 : options.require_existing = true;
256 [ + - ]: 155 : bilingual_str error;
257 : 155 : std::vector<bilingual_str> warnings;
258 [ + - + + : 155 : std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
+ - + - ]
259 : :
260 : 155 : {
261 [ + - ]: 155 : LOCK(context.wallets_mutex);
262 [ + + - + : 474 : if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
- + - + -
+ - + - +
+ + ]
263 [ + - + - ]: 6 : throw JSONRPCError(RPC_WALLET_ALREADY_LOADED, "Wallet \"" + name + "\" is already loaded.");
264 : : }
265 : 2 : }
266 : :
267 [ + - ]: 153 : std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
268 : :
269 [ + + + + ]: 306 : HandleWalletError(wallet, status, error);
270 : :
271 : 134 : UniValue obj(UniValue::VOBJ);
272 [ + - + - : 268 : obj.pushKV("name", wallet->GetName());
+ - ]
273 [ + - ]: 134 : PushWarnings(warnings, obj);
274 : :
275 [ + - ]: 134 : return obj;
276 : 331 : },
277 [ + - + - : 11292 : };
+ - + - +
- + - + -
+ - + + -
- ]
278 [ + - + - : 8469 : }
+ - + - +
- + - + -
- - - - ]
279 : :
280 : 794 : static RPCHelpMan setwalletflag()
281 : : {
282 : 794 : std::string flags;
283 [ + + ]: 6352 : for (auto& it : WALLET_FLAG_MAP)
284 [ + + ]: 5558 : if (it.second & MUTABLE_WALLET_FLAGS)
285 [ - + + - ]: 1588 : flags += (flags == "" ? "" : ", ") + it.first;
286 : :
287 [ + - ]: 794 : return RPCHelpMan{"setwalletflag",
288 : : "\nChange the state of the given wallet flag for a wallet.\n",
289 : : {
290 [ + - ]: 1588 : {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
291 [ + - ]: 1588 : {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
292 : : },
293 : 0 : RPCResult{
294 : : RPCResult::Type::OBJ, "", "",
295 : : {
296 : : {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
297 : : {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
298 : : {RPCResult::Type::STR, "warnings", /*optional=*/true, "Any warnings associated with the change"},
299 : : }
300 [ + - + - : 3970 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + + -
- ]
301 : 794 : RPCExamples{
302 [ + - + - : 1588 : HelpExampleCli("setwalletflag", "avoid_reuse")
+ - ]
303 [ + - + - : 3176 : + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
+ - + - ]
304 [ + - ]: 794 : },
305 : 8 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
306 : : {
307 : 8 : std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
308 [ - + ]: 8 : if (!pwallet) return UniValue::VNULL;
309 : :
310 [ + - + - : 8 : std::string flag_str = request.params[0].get_str();
+ - ]
311 [ + - + + : 8 : bool value = request.params[1].isNull() || request.params[1].get_bool();
+ - + - +
+ ]
312 : :
313 [ + + ]: 8 : if (!WALLET_FLAG_MAP.count(flag_str)) {
314 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
315 : : }
316 : :
317 [ + - ]: 7 : auto flag = WALLET_FLAG_MAP.at(flag_str);
318 : :
319 [ + + ]: 7 : if (!(flag & MUTABLE_WALLET_FLAGS)) {
320 [ + - + - ]: 6 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
321 : : }
322 : :
323 : 4 : UniValue res(UniValue::VOBJ);
324 : :
325 [ + - + + ]: 4 : if (pwallet->IsWalletFlagSet(flag) == value) {
326 [ + + + - : 5 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
+ - ]
327 : : }
328 : :
329 [ + - + - : 4 : res.pushKV("flag_name", flag_str);
+ - ]
330 [ + - + - : 4 : res.pushKV("flag_state", value);
+ - ]
331 : :
332 [ + + ]: 2 : if (value) {
333 [ + - ]: 1 : pwallet->SetWalletFlag(flag);
334 : : } else {
335 [ + - ]: 1 : pwallet->UnsetWalletFlag(flag);
336 : : }
337 : :
338 [ + - + + : 2 : if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
+ - ]
339 [ + - + - : 2 : res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
+ - + - ]
340 : : }
341 : :
342 : 2 : return res;
343 : 12 : },
344 [ + - + - : 11116 : };
+ - + - +
- + - + -
+ - + - +
+ - - ]
345 [ + - + - : 7940 : }
+ - + - +
- + - + -
- - - - ]
346 : :
347 : 1289 : static RPCHelpMan createwallet()
348 : : {
349 : 1289 : return RPCHelpMan{
350 : : "createwallet",
351 : : "\nCreates and loads a new wallet.\n",
352 : : {
353 [ + - ]: 1289 : {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
354 [ + - ]: 2578 : {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
355 [ + - ]: 2578 : {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
356 [ + - ]: 1289 : {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
357 [ + - ]: 2578 : {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
358 [ + - ]: 2578 : {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
359 : : " Setting to \"false\" will create a legacy wallet; This is only possible with the -deprecatedrpc=create_bdb setting because, the legacy wallet type is being deprecated and"
360 : : " support for creating and opening legacy wallets will be removed in the future."},
361 [ + - ]: 1289 : {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
362 [ + - ]: 2578 : {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
363 : : },
364 : 0 : RPCResult{
365 : : RPCResult::Type::OBJ, "", "",
366 : : {
367 : : {RPCResult::Type::STR, "name", "The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
368 : : {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
369 : : {
370 : : {RPCResult::Type::STR, "", ""},
371 : : }},
372 : : }
373 [ + - + - : 7734 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + + +
+ - - -
- ]
374 : 1289 : RPCExamples{
375 [ + - + - : 2578 : HelpExampleCli("createwallet", "\"testwallet\"")
+ - ]
376 [ + - + - : 5156 : + HelpExampleRpc("createwallet", "\"testwallet\"")
+ - + - ]
377 [ + - + - : 10312 : + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
+ - + - +
+ - - ]
378 [ + - + - : 10312 : + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
+ - + - +
+ - - ]
379 [ + - ]: 1289 : },
380 : 503 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
381 : : {
382 : 503 : WalletContext& context = EnsureWalletContext(request.context);
383 : 503 : uint64_t flags = 0;
384 [ + + + + ]: 503 : if (!request.params[1].isNull() && request.params[1].get_bool()) {
385 : : flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
386 : : }
387 : :
388 [ + + + + ]: 503 : if (!request.params[2].isNull() && request.params[2].get_bool()) {
389 : 163 : flags |= WALLET_FLAG_BLANK_WALLET;
390 : : }
391 [ + - ]: 503 : SecureString passphrase;
392 [ + - ]: 503 : passphrase.reserve(100);
393 : 503 : std::vector<bilingual_str> warnings;
394 [ + - + - ]: 503 : if (!request.params[3].isNull()) {
395 [ + - + - : 503 : passphrase = std::string_view{request.params[3].get_str()};
+ - ]
396 [ + + ]: 503 : if (passphrase.empty()) {
397 : : // Empty string means unencrypted
398 [ + - + - : 982 : warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
+ - ]
399 : : }
400 : : }
401 : :
402 [ + - + + : 503 : if (!request.params[4].isNull() && request.params[4].get_bool()) {
+ - + - +
+ ]
403 : 3 : flags |= WALLET_FLAG_AVOID_REUSE;
404 : : }
405 [ + - + + ]: 503 : if (self.Arg<bool>("descriptors")) {
406 : : #ifndef USE_SQLITE
407 : : throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
408 : : #endif
409 : 502 : flags |= WALLET_FLAG_DESCRIPTORS;
410 : : } else {
411 [ + - + - : 1 : if (!context.chain->rpcEnableDeprecated("create_bdb")) {
- + ]
412 [ # # ]: 0 : throw JSONRPCError(RPC_WALLET_ERROR, "BDB wallet creation is deprecated and will be removed in a future release."
413 [ # # # # ]: 0 : " In this release it can be re-enabled temporarily with the -deprecatedrpc=create_bdb setting.");
414 : : }
415 : : }
416 [ + - + + : 503 : if (!request.params[7].isNull() && request.params[7].get_bool()) {
+ - + - +
+ ]
417 : : #ifdef ENABLE_EXTERNAL_SIGNER
418 : 5 : flags |= WALLET_FLAG_EXTERNAL_SIGNER;
419 : : #else
420 : : throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
421 : : #endif
422 : : }
423 : :
424 : : #ifndef USE_BDB
425 [ + + ]: 503 : if (!(flags & WALLET_FLAG_DESCRIPTORS)) {
426 [ + - + - ]: 2 : throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)");
427 : : }
428 : : #endif
429 : :
430 [ + - ]: 502 : DatabaseOptions options;
431 : 502 : DatabaseStatus status;
432 [ + - ]: 502 : ReadDatabaseArgs(*context.args, options);
433 : 502 : options.require_create = true;
434 : 502 : options.create_flags = flags;
435 [ + - ]: 502 : options.create_passphrase = passphrase;
436 [ + - ]: 502 : bilingual_str error;
437 [ + - + + : 502 : std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
+ - + - ]
438 [ + - + - : 502 : const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
+ + ]
439 [ + + ]: 500 : if (!wallet) {
440 [ + - ]: 9 : RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
441 [ + - ]: 9 : throw JSONRPCError(code, error.original);
442 : : }
443 : :
444 : 491 : UniValue obj(UniValue::VOBJ);
445 [ + - + - : 982 : obj.pushKV("name", wallet->GetName());
+ - ]
446 [ + - ]: 491 : PushWarnings(warnings, obj);
447 : :
448 [ + - ]: 491 : return obj;
449 : 1014 : },
450 [ + - + - : 51560 : };
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + + -
- ]
451 [ + - + - : 29647 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - - -
- - - - -
- ]
452 : :
453 : 1067 : static RPCHelpMan unloadwallet()
454 : : {
455 : 1067 : return RPCHelpMan{"unloadwallet",
456 : : "Unloads the wallet referenced by the request endpoint, otherwise unloads the wallet specified in the argument.\n"
457 : : "Specifying the wallet name on a wallet endpoint is invalid.",
458 : : {
459 [ + - ]: 2134 : {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
460 [ + - ]: 1067 : {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
461 : : },
462 : 0 : RPCResult{RPCResult::Type::OBJ, "", "", {
463 : : {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
464 : : {
465 : : {RPCResult::Type::STR, "", ""},
466 : : }},
467 [ + - + - : 5335 : }},
+ - + - +
- + - + -
+ - + - +
- + + + +
- - - - ]
468 : 1067 : RPCExamples{
469 [ + - + - : 2134 : HelpExampleCli("unloadwallet", "wallet_name")
+ - ]
470 [ + - + - : 4268 : + HelpExampleRpc("unloadwallet", "wallet_name")
+ - + - ]
471 [ + - ]: 1067 : },
472 : 281 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
473 : : {
474 [ + - ]: 281 : std::string wallet_name;
475 [ + - + + ]: 281 : if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
476 [ + - + + : 181 : if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
+ - + - +
+ ]
477 [ + - + - ]: 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
478 : : }
479 : : } else {
480 [ + - + + : 100 : wallet_name = request.params[0].get_str();
+ - ]
481 : : }
482 : :
483 [ + - ]: 277 : WalletContext& context = EnsureWalletContext(request.context);
484 [ + - ]: 277 : std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
485 [ + + ]: 277 : if (!wallet) {
486 [ + - + - ]: 8 : throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
487 : : }
488 : :
489 : 273 : std::vector<bilingual_str> warnings;
490 : 273 : {
491 : 273 : WalletRescanReserver reserver(*wallet);
492 [ - + ]: 273 : if (!reserver.reserve()) {
493 [ # # # # ]: 0 : throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
494 : : }
495 : :
496 : : // Release the "main" shared pointer and prevent further notifications.
497 : : // Note that any attempt to load the same wallet would fail until the wallet
498 : : // is destroyed (see CheckUniqueFileid).
499 [ + - ]: 273 : std::optional<bool> load_on_start{self.MaybeArg<bool>("load_on_startup")};
500 [ + - - + ]: 273 : if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
501 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
502 : : }
503 : 273 : }
504 : :
505 [ + - ]: 273 : WaitForDeleteWallet(std::move(wallet));
506 : :
507 : 273 : UniValue result(UniValue::VOBJ);
508 [ + - ]: 273 : PushWarnings(warnings, result);
509 : :
510 : 546 : return result;
511 [ - + ]: 277 : },
512 [ + - + - : 14938 : };
+ - + - +
- + - + -
+ - + + -
- ]
513 [ + - + - : 8536 : }
+ - + - +
- + - -
- ]
514 : :
515 : 787 : static RPCHelpMan sethdseed()
516 : : {
517 : 787 : return RPCHelpMan{"sethdseed",
518 : : "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
519 : : "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
520 [ + - ]: 1574 : "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE +
521 : 787 : "Note: This command is only compatible with legacy wallets.\n",
522 : : {
523 [ + - ]: 1574 : {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
524 : : "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
525 : : "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
526 : : "keypool will be used until it has been depleted."},
527 [ + - ]: 1574 : {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
528 : : "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
529 : : },
530 [ + - + - : 1574 : RPCResult{RPCResult::Type::NONE, "", ""},
+ - ]
531 : 787 : RPCExamples{
532 [ + - + - : 1574 : HelpExampleCli("sethdseed", "")
+ - ]
533 [ + - + - : 3148 : + HelpExampleCli("sethdseed", "false")
+ - + - ]
534 [ + - + - : 3148 : + HelpExampleCli("sethdseed", "true \"wifkey\"")
+ - + - ]
535 [ + - + - : 3148 : + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
+ - + - ]
536 [ + - ]: 787 : },
537 : 1 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
538 : : {
539 : 1 : std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
540 [ - + ]: 1 : if (!pwallet) return UniValue::VNULL;
541 : :
542 [ - + ]: 1 : LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
543 : :
544 [ # # # # ]: 0 : if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
545 [ # # # # ]: 0 : throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
546 : : }
547 : :
548 [ # # # # ]: 0 : LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
549 : :
550 : : // Do not do anything to non-HD wallets
551 [ # # # # ]: 0 : if (!pwallet->CanSupportFeature(FEATURE_HD)) {
552 [ # # # # ]: 0 : throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set an HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
553 : : }
554 : :
555 [ # # ]: 0 : EnsureWalletIsUnlocked(*pwallet);
556 : :
557 : 0 : bool flush_key_pool = true;
558 [ # # # # ]: 0 : if (!request.params[0].isNull()) {
559 [ # # # # ]: 0 : flush_key_pool = request.params[0].get_bool();
560 : : }
561 : :
562 [ # # ]: 0 : CPubKey master_pub_key;
563 [ # # # # ]: 0 : if (request.params[1].isNull()) {
564 [ # # ]: 0 : master_pub_key = spk_man.GenerateNewSeed();
565 : : } else {
566 [ # # # # : 0 : CKey key = DecodeSecret(request.params[1].get_str());
# # ]
567 [ # # ]: 0 : if (!key.IsValid()) {
568 [ # # # # ]: 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
569 : : }
570 : :
571 [ # # # # ]: 0 : if (HaveKey(spk_man, key)) {
572 [ # # # # ]: 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
573 : : }
574 : :
575 [ # # ]: 0 : master_pub_key = spk_man.DeriveNewSeed(key);
576 : 0 : }
577 : :
578 [ # # ]: 0 : spk_man.SetHDSeed(master_pub_key);
579 [ # # # # ]: 0 : if (flush_key_pool) spk_man.NewKeyPool();
580 : :
581 [ # # ]: 0 : return UniValue::VNULL;
582 [ # # ]: 0 : },
583 [ + - + - : 14166 : };
+ - + - +
- + - + -
+ + - - ]
584 [ + - + - : 3935 : }
+ - - - ]
585 : :
586 : 786 : static RPCHelpMan upgradewallet()
587 : : {
588 : 786 : return RPCHelpMan{"upgradewallet",
589 : : "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
590 : : "New keys may be generated and a new wallet backup will need to be made.",
591 : : {
592 [ + - ]: 1572 : {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
593 : : },
594 : 0 : RPCResult{
595 : : RPCResult::Type::OBJ, "", "",
596 : : {
597 : : {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
598 : : {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"},
599 : : {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"},
600 : : {RPCResult::Type::STR, "result", /*optional=*/true, "Description of result, if no error"},
601 : : {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"}
602 : : },
603 [ + - + - : 5502 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
+ - - ]
604 : 786 : RPCExamples{
605 [ + - + - : 1572 : HelpExampleCli("upgradewallet", "169900")
+ - ]
606 [ + - + - : 3144 : + HelpExampleRpc("upgradewallet", "169900")
+ - + - ]
607 [ + - ]: 786 : },
608 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
609 : : {
610 : 0 : std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
611 [ # # ]: 0 : if (!pwallet) return UniValue::VNULL;
612 : :
613 [ # # ]: 0 : EnsureWalletIsUnlocked(*pwallet);
614 : :
615 : 0 : int version = 0;
616 [ # # # # ]: 0 : if (!request.params[0].isNull()) {
617 [ # # # # ]: 0 : version = request.params[0].getInt<int>();
618 : : }
619 [ # # ]: 0 : bilingual_str error;
620 [ # # ]: 0 : const int previous_version{pwallet->GetVersion()};
621 [ # # ]: 0 : const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)};
622 [ # # ]: 0 : const int current_version{pwallet->GetVersion()};
623 [ # # ]: 0 : std::string result;
624 : :
625 [ # # ]: 0 : if (wallet_upgraded) {
626 [ # # ]: 0 : if (previous_version == current_version) {
627 [ # # ]: 0 : result = "Already at latest version. Wallet version unchanged.";
628 : : } else {
629 [ # # ]: 0 : result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version);
630 : : }
631 : : }
632 : :
633 : 0 : UniValue obj(UniValue::VOBJ);
634 [ # # # # : 0 : obj.pushKV("wallet_name", pwallet->GetName());
# # ]
635 [ # # # # : 0 : obj.pushKV("previous_version", previous_version);
# # ]
636 [ # # # # : 0 : obj.pushKV("current_version", current_version);
# # ]
637 [ # # ]: 0 : if (!result.empty()) {
638 [ # # # # : 0 : obj.pushKV("result", result);
# # ]
639 : : } else {
640 [ # # ]: 0 : CHECK_NONFATAL(!error.empty());
641 [ # # # # : 0 : obj.pushKV("error", error.original);
# # ]
642 : : }
643 : 0 : return obj;
644 : 0 : },
645 [ + - + - : 8646 : };
+ - + - +
- + - + +
- - ]
646 [ + - + - : 7074 : }
+ - + - +
- + - + -
+ - - - ]
647 : :
648 : 812 : RPCHelpMan simulaterawtransaction()
649 : : {
650 : 812 : return RPCHelpMan{"simulaterawtransaction",
651 : : "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
652 : : {
653 [ + - ]: 812 : {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of hex strings of raw transactions.\n",
654 : : {
655 [ + - ]: 812 : {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
656 : : },
657 : : },
658 [ + - ]: 812 : {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
659 : : {
660 [ + - ]: 1624 : {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
661 : : },
662 : : },
663 : : },
664 : 0 : RPCResult{
665 : : RPCResult::Type::OBJ, "", "",
666 : : {
667 : : {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
668 : : }
669 [ + - + - : 2436 : },
+ - + - +
- + - + -
+ + - - ]
670 : 812 : RPCExamples{
671 [ + - + - : 1624 : HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
+ - ]
672 [ + - + - : 3248 : + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
+ - + - ]
673 [ + - ]: 812 : },
674 : 26 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
675 : : {
676 [ - + ]: 26 : const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
677 [ - + ]: 26 : if (!rpc_wallet) return UniValue::VNULL;
678 [ + - ]: 26 : const CWallet& wallet = *rpc_wallet;
679 : :
680 [ + - ]: 26 : LOCK(wallet.cs_wallet);
681 : :
682 : 26 : UniValue include_watchonly(UniValue::VNULL);
683 [ + - - + ]: 26 : if (request.params[1].isObject()) {
684 [ # # # # ]: 0 : UniValue options = request.params[1];
685 [ # # # # : 0 : RPCTypeCheckObj(options,
# # ]
686 : : {
687 [ # # ]: 0 : {"include_watchonly", UniValueType(UniValue::VBOOL)},
688 : : },
689 : : true, true);
690 : :
691 [ # # # # : 0 : include_watchonly = options["include_watchonly"];
# # ]
692 : 0 : }
693 : :
694 : 26 : isminefilter filter = ISMINE_SPENDABLE;
695 [ + - + + ]: 26 : if (ParseIncludeWatchonly(include_watchonly, wallet)) {
696 : 5 : filter |= ISMINE_WATCH_ONLY;
697 : : }
698 : :
699 [ + - + - ]: 26 : const auto& txs = request.params[0].get_array();
700 : 26 : CAmount changes{0};
701 : 26 : std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
702 : 26 : std::set<COutPoint> spent;
703 : :
704 [ + + ]: 54 : for (size_t i = 0; i < txs.size(); ++i) {
705 [ + - ]: 38 : CMutableTransaction mtx;
706 [ + - + - : 38 : if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
+ - - + ]
707 [ # # # # ]: 0 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
708 : : }
709 : :
710 : : // Fetch previous transactions (inputs)
711 : 38 : std::map<COutPoint, Coin> coins;
712 [ + + ]: 67 : for (const CTxIn& txin : mtx.vin) {
713 [ + - ]: 29 : coins[txin.prevout]; // Create empty map entry keyed by prevout.
714 : : }
715 [ + - ]: 38 : wallet.chain().findCoins(coins);
716 : :
717 : : // Fetch debit; we are *spending* these; if the transaction is signed and
718 : : // broadcast, we will lose everything in these
719 [ + + ]: 57 : for (const auto& txin : mtx.vin) {
720 : 29 : const auto& outpoint = txin.prevout;
721 [ + + ]: 29 : if (spent.count(outpoint)) {
722 [ + - + - ]: 6 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
723 : : }
724 [ + + ]: 26 : if (new_utxos.count(outpoint)) {
725 [ + - ]: 6 : changes -= new_utxos.at(outpoint);
726 : 6 : new_utxos.erase(outpoint);
727 : : } else {
728 [ + - + + ]: 20 : if (coins.at(outpoint).IsSpent()) {
729 [ + - + - ]: 14 : throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
730 : : }
731 [ + - ]: 13 : changes -= wallet.GetDebit(txin, filter);
732 : : }
733 [ + - ]: 19 : spent.insert(outpoint);
734 : : }
735 : :
736 : : // Iterate over outputs; we are *receiving* these, if the wallet considers
737 : : // them "mine"; if the transaction is signed and broadcast, we will receive
738 : : // everything in these
739 : : // Also populate new_utxos in case these are spent in later transactions
740 : :
741 [ + - ]: 28 : const auto& hash = mtx.GetHash();
742 [ + + ]: 69 : for (size_t i = 0; i < mtx.vout.size(); ++i) {
743 [ + - ]: 41 : const auto& txout = mtx.vout[i];
744 [ + - ]: 41 : bool is_mine = 0 < (wallet.IsMine(txout) & filter);
745 [ + + + - ]: 41 : changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
746 : : }
747 : 76 : }
748 : :
749 : 16 : UniValue result(UniValue::VOBJ);
750 [ + - + - : 32 : result.pushKV("balance_change", ValueFromAmount(changes));
+ - ]
751 : :
752 : 16 : return result;
753 [ - - - - : 78 : }
+ - ]
754 [ + - + - : 16240 : };
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
+ + + + +
- - - - -
- ]
755 [ + - + - : 8932 : }
+ - + - +
- + - + -
- - ]
756 : :
757 : 823 : static RPCHelpMan migratewallet()
758 : : {
759 : 823 : return RPCHelpMan{"migratewallet",
760 : : "\nMigrate the wallet to a descriptor wallet.\n"
761 : : "A new wallet backup will need to be made.\n"
762 : : "\nThe migration process will create a backup of the wallet before migrating. This backup\n"
763 : : "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"
764 : : "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."
765 : : "\nEncrypted wallets must have the passphrase provided as an argument to this call.\n"
766 : : "\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",
767 : : {
768 [ + - ]: 1646 : {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},
769 [ + - ]: 823 : {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
770 : : },
771 : 0 : RPCResult{
772 : : RPCResult::Type::OBJ, "", "",
773 : : {
774 : : {RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},
775 : : {RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},
776 : : {RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},
777 : : {RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},
778 : : }
779 [ + - + - : 4938 : },
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + +
- - ]
780 : 823 : RPCExamples{
781 [ + - + - : 1646 : HelpExampleCli("migratewallet", "")
+ - ]
782 [ + - + - : 3292 : + HelpExampleRpc("migratewallet", "")
+ - + - ]
783 [ + - ]: 823 : },
784 : 37 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
785 : : {
786 [ + - ]: 37 : std::string wallet_name;
787 [ + - + + ]: 37 : if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
788 [ + - + + : 2 : if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
+ - + - +
- ]
789 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
790 : : }
791 : : } else {
792 [ + - + + ]: 35 : if (request.params[0].isNull()) {
793 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Either RPC endpoint wallet or wallet_name parameter must be provided");
794 : : }
795 [ + - + - : 34 : wallet_name = request.params[0].get_str();
+ - ]
796 : : }
797 : :
798 [ + - ]: 35 : SecureString wallet_pass;
799 [ + - ]: 35 : wallet_pass.reserve(100);
800 [ + - + + ]: 35 : if (!request.params[1].isNull()) {
801 [ + - + - : 3 : wallet_pass = std::string_view{request.params[1].get_str()};
+ - ]
802 : : }
803 : :
804 [ + - ]: 35 : WalletContext& context = EnsureWalletContext(request.context);
805 [ + - ]: 35 : util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
806 [ + + ]: 35 : if (!res) {
807 [ + - + - ]: 14 : throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
808 : : }
809 : :
810 : 28 : UniValue r{UniValue::VOBJ};
811 [ + - + - : 56 : r.pushKV("wallet_name", res->wallet_name);
+ - ]
812 [ + + ]: 28 : if (res->watchonly_wallet) {
813 [ + - + - : 20 : r.pushKV("watchonly_name", res->watchonly_wallet->GetName());
+ - ]
814 : : }
815 [ + + ]: 28 : if (res->solvables_wallet) {
816 [ + - + - : 10 : r.pushKV("solvables_name", res->solvables_wallet->GetName());
+ - ]
817 : : }
818 [ + - + - : 56 : r.pushKV("backup_path", res->backup_path.utf8string());
+ - + - ]
819 : :
820 : 28 : return r;
821 : 42 : },
822 [ + - + - : 11522 : };
+ - + - +
- + - + -
+ - + + -
- ]
823 [ + - + - : 8230 : }
+ - + - +
- + - + -
+ - - - -
- ]
824 : :
825 : 819 : RPCHelpMan gethdkeys()
826 : : {
827 : 819 : return RPCHelpMan{
828 : : "gethdkeys",
829 : : "\nList all BIP 32 HD keys in the wallet and which descriptors use them.\n",
830 : : {
831 [ + - ]: 819 : {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", {
832 [ + - ]: 1638 : {"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},
833 [ + - ]: 1638 : {"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}
834 : : }},
835 : : },
836 : 0 : RPCResult{RPCResult::Type::ARR, "", "", {
837 : : {
838 : : {RPCResult::Type::OBJ, "", "", {
839 : : {RPCResult::Type::STR, "xpub", "The extended public key"},
840 : : {RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},
841 : : {RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},
842 : : {RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",
843 : : {
844 : : {RPCResult::Type::OBJ, "", "", {
845 : : {RPCResult::Type::STR, "desc", "Descriptor string representation"},
846 : : {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
847 : : }},
848 : : }},
849 : : }},
850 : : }
851 [ + - + - : 10647 : }},
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + + +
+ + + + +
- - - - -
- - - ]
852 : 819 : RPCExamples{
853 [ + - + - : 1638 : HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")
+ - + - +
- + - +
- ]
854 [ + - + - : 8190 : + HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})
+ - + - +
- + - + -
+ - + + +
+ - - -
- ]
855 [ + - ]: 819 : },
856 : 33 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
857 : : {
858 [ - + ]: 33 : const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
859 [ - + ]: 33 : if (!wallet) return UniValue::VNULL;
860 : :
861 [ + - - + ]: 33 : if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
862 [ # # # # ]: 0 : throw JSONRPCError(RPC_WALLET_ERROR, "gethdkeys is not available for non-descriptor wallets");
863 : : }
864 : :
865 [ + - ]: 33 : LOCK(wallet->cs_wallet);
866 : :
867 [ + - + + : 33 : UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};
+ - + - ]
868 [ + - + + : 66 : const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};
+ - + - +
- ]
869 [ + - + + : 66 : const bool priv{options.exists("private") ? options["private"].get_bool() : false};
+ - + - +
- ]
870 [ + + ]: 33 : if (priv) {
871 [ + + ]: 9 : EnsureWalletIsUnlocked(*wallet);
872 : : }
873 : :
874 : :
875 [ + + ]: 32 : std::set<ScriptPubKeyMan*> spkms;
876 [ + + ]: 32 : if (active_only) {
877 [ + - ]: 12 : spkms = wallet->GetActiveScriptPubKeyMans();
878 : : } else {
879 [ + - ]: 52 : spkms = wallet->GetAllScriptPubKeyMans();
880 : : }
881 : :
882 : 32 : std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
883 : 32 : std::map<CExtPubKey, CExtKey> wallet_xprvs;
884 [ + + ]: 264 : for (auto* spkm : spkms) {
885 [ + - ]: 232 : auto* desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
886 [ + - ]: 232 : CHECK_NONFATAL(desc_spkm);
887 [ + - ]: 232 : LOCK(desc_spkm->cs_desc_man);
888 [ + - ]: 232 : WalletDescriptor w_desc = desc_spkm->GetWalletDescriptor();
889 : :
890 : : // Retrieve the pubkeys from the descriptor
891 [ + - ]: 232 : std::set<CPubKey> desc_pubkeys;
892 : 232 : std::set<CExtPubKey> desc_xpubs;
893 [ + - ]: 232 : w_desc.descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
894 [ + + ]: 457 : for (const CExtPubKey& xpub : desc_xpubs) {
895 [ + - ]: 225 : std::string desc_str;
896 [ + - ]: 225 : bool ok = desc_spkm->GetDescriptorString(desc_str, false);
897 [ + - ]: 225 : CHECK_NONFATAL(ok);
898 [ + - + - : 225 : wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
+ - + - +
- ]
899 [ + + + - : 225 : if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
+ - + + ]
900 [ + - + - ]: 64 : wallet_xprvs[xpub] = CExtKey(xpub, *key);
901 : 225 : }
902 : 225 : }
903 [ + - ]: 464 : }
904 : :
905 : 32 : UniValue response(UniValue::VARR);
906 [ + + ]: 66 : for (const auto& [xpub, descs] : wallet_xpubs) {
907 : 34 : bool has_xprv = false;
908 : 34 : UniValue descriptors(UniValue::VARR);
909 [ + + ]: 259 : for (const auto& [desc, active, has_priv] : descs) {
910 : 225 : UniValue d(UniValue::VOBJ);
911 [ + - + - : 450 : d.pushKV("desc", desc);
+ - ]
912 [ + - + - : 450 : d.pushKV("active", active);
+ - ]
913 : 225 : has_xprv |= has_priv;
914 : :
915 [ + - ]: 225 : descriptors.push_back(std::move(d));
916 : 225 : }
917 : 34 : UniValue xpub_info(UniValue::VOBJ);
918 [ + - + - : 68 : xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));
+ - + - ]
919 [ + - + - : 68 : xpub_info.pushKV("has_private", has_xprv);
+ - ]
920 [ + + ]: 34 : if (priv) {
921 [ + - + - : 16 : xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));
+ - + - +
- ]
922 : : }
923 [ + - + - ]: 68 : xpub_info.pushKV("descriptors", std::move(descriptors));
924 : :
925 [ + - ]: 34 : response.push_back(std::move(xpub_info));
926 : 34 : }
927 : :
928 : 32 : return response;
929 [ + - ]: 98 : },
930 [ + - + - : 15561 : };
+ - + - +
- + - + -
+ - + - +
- + - + +
+ + - - -
- ]
931 [ + - + - : 14742 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
- - - - -
- - - -
- ]
932 : :
933 : 799 : static RPCHelpMan createwalletdescriptor()
934 : : {
935 : 799 : return RPCHelpMan{"createwalletdescriptor",
936 : : "Creates the wallet's descriptor for the given address type. "
937 : : "The address type must be one that the wallet does not already have a descriptor for."
938 [ + - ]: 1598 : + HELP_REQUIRING_PASSPHRASE,
939 : : {
940 [ + - ]: 799 : {"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
941 [ + - ]: 799 : {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", {
942 [ + - ]: 1598 : {"internal", RPCArg::Type::BOOL, RPCArg::DefaultHint{"Both external and internal will be generated unless this parameter is specified"}, "Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)"},
943 [ + - ]: 1598 : {"hdkey", RPCArg::Type::STR, RPCArg::DefaultHint{"The HD key used by all other active descriptors"}, "The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for this descriptor's key"},
944 : : }},
945 : : },
946 : 0 : RPCResult{
947 : : RPCResult::Type::OBJ, "", "",
948 : : {
949 : : {RPCResult::Type::ARR, "descs", "The public descriptors that were added to the wallet",
950 : : {{RPCResult::Type::STR, "", ""}}
951 : : }
952 : : },
953 [ + - + - : 3995 : },
+ - + - +
- + - + -
+ - + - +
- + + + +
- - - - ]
954 : 799 : RPCExamples{
955 [ + - + - : 1598 : HelpExampleCli("createwalletdescriptor", "bech32m")
+ - ]
956 [ + - + - : 3196 : + HelpExampleRpc("createwalletdescriptor", "bech32m")
+ - + - ]
957 [ + - ]: 799 : },
958 : 13 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
959 : : {
960 : 13 : std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
961 [ - + ]: 13 : if (!pwallet) return UniValue::VNULL;
962 : :
963 : : // Make sure wallet is a descriptor wallet
964 [ + - - + ]: 13 : if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
965 [ # # # # ]: 0 : throw JSONRPCError(RPC_WALLET_ERROR, "createwalletdescriptor is not available for non-descriptor wallets");
966 : : }
967 : :
968 [ + - + - : 13 : std::optional<OutputType> output_type = ParseOutputType(request.params[0].get_str());
+ - ]
969 [ + + ]: 13 : if (!output_type) {
970 [ + - + - : 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
+ - + - ]
971 : : }
972 : :
973 [ + - + + : 12 : UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
+ - + - ]
974 [ + - + - : 12 : UniValue internal_only{options["internal"]};
+ - ]
975 [ + - + - : 12 : UniValue hdkey{options["hdkey"]};
+ - ]
976 : :
977 : 12 : std::vector<bool> internals;
978 [ + + ]: 12 : if (internal_only.isNull()) {
979 [ + - ]: 10 : internals.push_back(false);
980 [ + - ]: 10 : internals.push_back(true);
981 : : } else {
982 [ + - + - ]: 2 : internals.push_back(internal_only.get_bool());
983 : : }
984 : :
985 [ + - ]: 12 : LOCK(pwallet->cs_wallet);
986 [ + + ]: 12 : EnsureWalletIsUnlocked(*pwallet);
987 : :
988 [ + + ]: 11 : CExtPubKey xpub;
989 [ + + ]: 11 : if (hdkey.isNull()) {
990 [ + - ]: 7 : std::set<CExtPubKey> active_xpubs = pwallet->GetActiveHDPubKeys();
991 [ + + ]: 7 : if (active_xpubs.size() != 1) {
992 [ + - + - ]: 4 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to determine which HD key to use from active descriptors. Please specify with 'hdkey'");
993 : : }
994 : 5 : xpub = *active_xpubs.begin();
995 : 7 : } else {
996 [ + - + - ]: 4 : xpub = DecodeExtPubKey(hdkey.get_str());
997 [ + + ]: 4 : if (!xpub.pubkey.IsValid()) {
998 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to parse HD key. Please provide a valid xpub");
999 : : }
1000 : : }
1001 : :
1002 [ + - + - ]: 8 : std::optional<CKey> key = pwallet->GetKey(xpub.pubkey.GetID());
1003 [ + + ]: 8 : if (!key) {
1004 [ + - + - : 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Private key for %s is not known", EncodeExtPubKey(xpub)));
+ - ]
1005 : : }
1006 [ + - ]: 7 : CExtKey active_hdkey(xpub, *key);
1007 : :
1008 : 7 : std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
1009 [ + - ]: 7 : WalletBatch batch{pwallet->GetDatabase()};
1010 [ + - - + ]: 43 : for (bool internal : internals) {
1011 [ + - ]: 12 : WalletDescriptor w_desc = GenerateWalletDescriptor(xpub, *output_type, internal);
1012 [ + - ]: 12 : uint256 w_id = DescriptorID(*w_desc.descriptor);
1013 [ + - + + ]: 12 : if (!pwallet->GetScriptPubKeyMan(w_id)) {
1014 [ + - + - ]: 10 : spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type, internal));
1015 : : }
1016 : 12 : }
1017 [ + + ]: 7 : if (spkms.empty()) {
1018 [ + - + - ]: 2 : throw JSONRPCError(RPC_WALLET_ERROR, "Descriptor already exists");
1019 : : }
1020 : :
1021 : : // Fetch each descspkm from the wallet in order to get the descriptor strings
1022 : 6 : UniValue descs{UniValue::VARR};
1023 [ + + ]: 16 : for (const auto& spkm : spkms) {
1024 [ + - ]: 10 : std::string desc_str;
1025 [ + - ]: 10 : bool ok = spkm.get().GetDescriptorString(desc_str, false);
1026 [ + - ]: 10 : CHECK_NONFATAL(ok);
1027 [ + - + - ]: 10 : descs.push_back(desc_str);
1028 : 10 : }
1029 : 6 : UniValue out{UniValue::VOBJ};
1030 [ + - + - ]: 12 : out.pushKV("descs", std::move(descs));
1031 : 6 : return out;
1032 [ + - ]: 53 : }
1033 [ + - + - : 19176 : };
+ - + - +
- + - + -
+ - + - +
- + - + -
+ + + + -
- - - ]
1034 [ + - + - : 9588 : }
+ - + - +
- + - + -
+ - - - -
- ]
1035 : :
1036 : : // addresses
1037 : : RPCHelpMan getaddressinfo();
1038 : : RPCHelpMan getnewaddress();
1039 : : RPCHelpMan getrawchangeaddress();
1040 : : RPCHelpMan setlabel();
1041 : : RPCHelpMan listaddressgroupings();
1042 : : RPCHelpMan addmultisigaddress();
1043 : : RPCHelpMan keypoolrefill();
1044 : : RPCHelpMan newkeypool();
1045 : : RPCHelpMan getaddressesbylabel();
1046 : : RPCHelpMan listlabels();
1047 : : #ifdef ENABLE_EXTERNAL_SIGNER
1048 : : RPCHelpMan walletdisplayaddress();
1049 : : #endif // ENABLE_EXTERNAL_SIGNER
1050 : :
1051 : : // backup
1052 : : RPCHelpMan dumpprivkey();
1053 : : RPCHelpMan importprivkey();
1054 : : RPCHelpMan importaddress();
1055 : : RPCHelpMan importpubkey();
1056 : : RPCHelpMan dumpwallet();
1057 : : RPCHelpMan importwallet();
1058 : : RPCHelpMan importprunedfunds();
1059 : : RPCHelpMan removeprunedfunds();
1060 : : RPCHelpMan importmulti();
1061 : : RPCHelpMan importdescriptors();
1062 : : RPCHelpMan listdescriptors();
1063 : : RPCHelpMan backupwallet();
1064 : : RPCHelpMan restorewallet();
1065 : :
1066 : : // coins
1067 : : RPCHelpMan getreceivedbyaddress();
1068 : : RPCHelpMan getreceivedbylabel();
1069 : : RPCHelpMan getbalance();
1070 : : RPCHelpMan getunconfirmedbalance();
1071 : : RPCHelpMan lockunspent();
1072 : : RPCHelpMan listlockunspent();
1073 : : RPCHelpMan getbalances();
1074 : : RPCHelpMan listunspent();
1075 : :
1076 : : // encryption
1077 : : RPCHelpMan walletpassphrase();
1078 : : RPCHelpMan walletpassphrasechange();
1079 : : RPCHelpMan walletlock();
1080 : : RPCHelpMan encryptwallet();
1081 : :
1082 : : // spend
1083 : : RPCHelpMan sendtoaddress();
1084 : : RPCHelpMan sendmany();
1085 : : RPCHelpMan settxfee();
1086 : : RPCHelpMan fundrawtransaction();
1087 : : RPCHelpMan bumpfee();
1088 : : RPCHelpMan psbtbumpfee();
1089 : : RPCHelpMan send();
1090 : : RPCHelpMan sendall();
1091 : : RPCHelpMan walletprocesspsbt();
1092 : : RPCHelpMan walletcreatefundedpsbt();
1093 : : RPCHelpMan signrawtransactionwithwallet();
1094 : :
1095 : : // signmessage
1096 : : RPCHelpMan signmessage();
1097 : :
1098 : : // transactions
1099 : : RPCHelpMan listreceivedbyaddress();
1100 : : RPCHelpMan listreceivedbylabel();
1101 : : RPCHelpMan listtransactions();
1102 : : RPCHelpMan listsinceblock();
1103 : : RPCHelpMan gettransaction();
1104 : : RPCHelpMan abandontransaction();
1105 : : RPCHelpMan rescanblockchain();
1106 : : RPCHelpMan abortrescan();
1107 : :
1108 : 404 : Span<const CRPCCommand> GetWalletRPCCommands()
1109 : : {
1110 : 404 : static const CRPCCommand commands[]{
1111 : : {"rawtransactions", &fundrawtransaction},
1112 : : {"wallet", &abandontransaction},
1113 : : {"wallet", &abortrescan},
1114 : : {"wallet", &addmultisigaddress},
1115 : : {"wallet", &backupwallet},
1116 : : {"wallet", &bumpfee},
1117 : : {"wallet", &psbtbumpfee},
1118 : : {"wallet", &createwallet},
1119 : : {"wallet", &createwalletdescriptor},
1120 : : {"wallet", &restorewallet},
1121 : : {"wallet", &dumpprivkey},
1122 : : {"wallet", &dumpwallet},
1123 : : {"wallet", &encryptwallet},
1124 : : {"wallet", &getaddressesbylabel},
1125 : : {"wallet", &getaddressinfo},
1126 : : {"wallet", &getbalance},
1127 : : {"wallet", &gethdkeys},
1128 : : {"wallet", &getnewaddress},
1129 : : {"wallet", &getrawchangeaddress},
1130 : : {"wallet", &getreceivedbyaddress},
1131 : : {"wallet", &getreceivedbylabel},
1132 : : {"wallet", &gettransaction},
1133 : : {"wallet", &getunconfirmedbalance},
1134 : : {"wallet", &getbalances},
1135 : : {"wallet", &getwalletinfo},
1136 : : {"wallet", &importaddress},
1137 : : {"wallet", &importdescriptors},
1138 : : {"wallet", &importmulti},
1139 : : {"wallet", &importprivkey},
1140 : : {"wallet", &importprunedfunds},
1141 : : {"wallet", &importpubkey},
1142 : : {"wallet", &importwallet},
1143 : : {"wallet", &keypoolrefill},
1144 : : {"wallet", &listaddressgroupings},
1145 : : {"wallet", &listdescriptors},
1146 : : {"wallet", &listlabels},
1147 : : {"wallet", &listlockunspent},
1148 : : {"wallet", &listreceivedbyaddress},
1149 : : {"wallet", &listreceivedbylabel},
1150 : : {"wallet", &listsinceblock},
1151 : : {"wallet", &listtransactions},
1152 : : {"wallet", &listunspent},
1153 : : {"wallet", &listwalletdir},
1154 : : {"wallet", &listwallets},
1155 : : {"wallet", &loadwallet},
1156 : : {"wallet", &lockunspent},
1157 : : {"wallet", &migratewallet},
1158 : : {"wallet", &newkeypool},
1159 : : {"wallet", &removeprunedfunds},
1160 : : {"wallet", &rescanblockchain},
1161 : : {"wallet", &send},
1162 : : {"wallet", &sendmany},
1163 : : {"wallet", &sendtoaddress},
1164 : : {"wallet", &sethdseed},
1165 : : {"wallet", &setlabel},
1166 : : {"wallet", &settxfee},
1167 : : {"wallet", &setwalletflag},
1168 : : {"wallet", &signmessage},
1169 : : {"wallet", &signrawtransactionwithwallet},
1170 : : {"wallet", &simulaterawtransaction},
1171 : : {"wallet", &sendall},
1172 : : {"wallet", &unloadwallet},
1173 : : {"wallet", &upgradewallet},
1174 : : {"wallet", &walletcreatefundedpsbt},
1175 : : #ifdef ENABLE_EXTERNAL_SIGNER
1176 : : {"wallet", &walletdisplayaddress},
1177 : : #endif // ENABLE_EXTERNAL_SIGNER
1178 : : {"wallet", &walletlock},
1179 : : {"wallet", &walletpassphrase},
1180 : : {"wallet", &walletpassphrasechange},
1181 : : {"wallet", &walletprocesspsbt},
1182 [ + + + - : 404 : };
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- - - ]
1183 : 404 : return commands;
1184 : : }
1185 : : } // namespace wallet
|