Bitcoin Core 28.99.0
P2P Digital Currency
addresses.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 <bitcoin-build-config.h> // IWYU pragma: keep
6
7#include <core_io.h>
8#include <key_io.h>
9#include <rpc/util.h>
10#include <script/script.h>
11#include <script/solver.h>
12#include <util/bip32.h>
13#include <util/translation.h>
14#include <wallet/receive.h>
15#include <wallet/rpc/util.h>
16#include <wallet/wallet.h>
17
18#include <univalue.h>
19
20namespace wallet {
22{
23 return RPCHelpMan{"getnewaddress",
24 "\nReturns a new Bitcoin address for receiving payments.\n"
25 "If 'label' is specified, it is added to the address book \n"
26 "so payments received with the address will be associated with 'label'.\n",
27 {
28 {"label", RPCArg::Type::STR, RPCArg::Default{""}, "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
29 {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
30 },
32 RPCResult::Type::STR, "address", "The new bitcoin address"
33 },
35 HelpExampleCli("getnewaddress", "")
36 + HelpExampleRpc("getnewaddress", "")
37 },
38 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
39{
40 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
41 if (!pwallet) return UniValue::VNULL;
42
43 LOCK(pwallet->cs_wallet);
44
45 if (!pwallet->CanGetAddresses()) {
46 throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
47 }
48
49 // Parse the label first so we don't generate a key if there's an error
50 const std::string label{LabelFromValue(request.params[0])};
51
52 OutputType output_type = pwallet->m_default_address_type;
53 if (!request.params[1].isNull()) {
54 std::optional<OutputType> parsed = ParseOutputType(request.params[1].get_str());
55 if (!parsed) {
56 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
57 } else if (parsed.value() == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
58 throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
59 }
60 output_type = parsed.value();
61 }
62
63 auto op_dest = pwallet->GetNewDestination(output_type, label);
64 if (!op_dest) {
66 }
67
68 return EncodeDestination(*op_dest);
69},
70 };
71}
72
74{
75 return RPCHelpMan{"getrawchangeaddress",
76 "\nReturns a new Bitcoin address, for receiving change.\n"
77 "This is for use with raw transactions, NOT normal use.\n",
78 {
79 {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
80 },
82 RPCResult::Type::STR, "address", "The address"
83 },
85 HelpExampleCli("getrawchangeaddress", "")
86 + HelpExampleRpc("getrawchangeaddress", "")
87 },
88 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
89{
90 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
91 if (!pwallet) return UniValue::VNULL;
92
93 LOCK(pwallet->cs_wallet);
94
95 if (!pwallet->CanGetAddresses(true)) {
96 throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
97 }
98
99 OutputType output_type = pwallet->m_default_change_type.value_or(pwallet->m_default_address_type);
100 if (!request.params[0].isNull()) {
101 std::optional<OutputType> parsed = ParseOutputType(request.params[0].get_str());
102 if (!parsed) {
103 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
104 } else if (parsed.value() == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
105 throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
106 }
107 output_type = parsed.value();
108 }
109
110 auto op_dest = pwallet->GetNewChangeDestination(output_type);
111 if (!op_dest) {
113 }
114 return EncodeDestination(*op_dest);
115},
116 };
117}
118
119
121{
122 return RPCHelpMan{"setlabel",
123 "\nSets the label associated with the given address.\n",
124 {
125 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to be associated with a label."},
126 {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."},
127 },
130 HelpExampleCli("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\" \"tabby\"")
131 + HelpExampleRpc("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\", \"tabby\"")
132 },
133 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
134{
135 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
136 if (!pwallet) return UniValue::VNULL;
137
138 LOCK(pwallet->cs_wallet);
139
140 CTxDestination dest = DecodeDestination(request.params[0].get_str());
141 if (!IsValidDestination(dest)) {
142 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
143 }
144
145 const std::string label{LabelFromValue(request.params[1])};
146
147 if (pwallet->IsMine(dest)) {
148 pwallet->SetAddressBook(dest, label, AddressPurpose::RECEIVE);
149 } else {
150 pwallet->SetAddressBook(dest, label, AddressPurpose::SEND);
151 }
152
153 return UniValue::VNULL;
154},
155 };
156}
157
159{
160 return RPCHelpMan{"listaddressgroupings",
161 "\nLists groups of addresses which have had their common ownership\n"
162 "made public by common use as inputs or as the resulting change\n"
163 "in past transactions\n",
164 {},
165 RPCResult{
166 RPCResult::Type::ARR, "", "",
167 {
168 {RPCResult::Type::ARR, "", "",
169 {
171 {
172 {RPCResult::Type::STR, "address", "The bitcoin address"},
173 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
174 {RPCResult::Type::STR, "label", /*optional=*/true, "The label"},
175 }},
176 }},
177 }
178 },
180 HelpExampleCli("listaddressgroupings", "")
181 + HelpExampleRpc("listaddressgroupings", "")
182 },
183 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
184{
185 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
186 if (!pwallet) return UniValue::VNULL;
187
188 // Make sure the results are valid at least up to the most recent block
189 // the user could have gotten from another RPC command prior to now
190 pwallet->BlockUntilSyncedToCurrentChain();
191
192 LOCK(pwallet->cs_wallet);
193
194 UniValue jsonGroupings(UniValue::VARR);
195 std::map<CTxDestination, CAmount> balances = GetAddressBalances(*pwallet);
196 for (const std::set<CTxDestination>& grouping : GetAddressGroupings(*pwallet)) {
197 UniValue jsonGrouping(UniValue::VARR);
198 for (const CTxDestination& address : grouping)
199 {
200 UniValue addressInfo(UniValue::VARR);
201 addressInfo.push_back(EncodeDestination(address));
202 addressInfo.push_back(ValueFromAmount(balances[address]));
203 {
204 const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
205 if (address_book_entry) {
206 addressInfo.push_back(address_book_entry->GetLabel());
207 }
208 }
209 jsonGrouping.push_back(std::move(addressInfo));
210 }
211 jsonGroupings.push_back(std::move(jsonGrouping));
212 }
213 return jsonGroupings;
214},
215 };
216}
217
219{
220 return RPCHelpMan{"addmultisigaddress",
221 "\nAdd an nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
222 "Each key is a Bitcoin address or hex-encoded public key.\n"
223 "This functionality is only intended for use with non-watchonly addresses.\n"
224 "See `importaddress` for watchonly p2sh address support.\n"
225 "If 'label' is specified, assign address to that label.\n"
226 "Note: This command is only compatible with legacy wallets.\n",
227 {
228 {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
229 {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The bitcoin addresses or hex-encoded public keys",
230 {
231 {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address or hex-encoded public key"},
232 },
233 },
234 {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A label to assign the addresses to."},
235 {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
236 },
237 RPCResult{
238 RPCResult::Type::OBJ, "", "",
239 {
240 {RPCResult::Type::STR, "address", "The value of the new multisig address"},
241 {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script"},
242 {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},
243 {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Any warnings resulting from the creation of this multisig",
244 {
245 {RPCResult::Type::STR, "", ""},
246 }},
247 }
248 },
250 "\nAdd a multisig address from 2 addresses\n"
251 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
252 "\nAs a JSON-RPC call\n"
253 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
254 },
255 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
256{
257 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
258 if (!pwallet) return UniValue::VNULL;
259
261
262 LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
263
264 const std::string label{LabelFromValue(request.params[2])};
265
266 int required = request.params[0].getInt<int>();
267
268 // Get the public keys
269 const UniValue& keys_or_addrs = request.params[1].get_array();
270 std::vector<CPubKey> pubkeys;
271 for (unsigned int i = 0; i < keys_or_addrs.size(); ++i) {
272 if (IsHex(keys_or_addrs[i].get_str()) && (keys_or_addrs[i].get_str().length() == 66 || keys_or_addrs[i].get_str().length() == 130)) {
273 pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
274 } else {
275 pubkeys.push_back(AddrToPubKey(spk_man, keys_or_addrs[i].get_str()));
276 }
277 }
278
279 OutputType output_type = pwallet->m_default_address_type;
280 if (!request.params[3].isNull()) {
281 std::optional<OutputType> parsed = ParseOutputType(request.params[3].get_str());
282 if (!parsed) {
283 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
284 } else if (parsed.value() == OutputType::BECH32M) {
285 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m multisig addresses cannot be created with legacy wallets");
286 }
287 output_type = parsed.value();
288 }
289
290 // Construct multisig scripts
291 FlatSigningProvider provider;
292 CScript inner;
293 CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, provider, inner);
294
295 // Import scripts into the wallet
296 for (const auto& [id, script] : provider.scripts) {
297 // Due to a bug in the legacy wallet, the p2sh maximum script size limit is also imposed on 'p2sh-segwit' and 'bech32' redeem scripts.
298 // Even when redeem scripts over MAX_SCRIPT_ELEMENT_SIZE bytes are valid for segwit output types, we don't want to
299 // enable it because:
300 // 1) It introduces a compatibility-breaking change requiring downgrade protection; older wallets would be unable to interact with these "new" legacy wallets.
301 // 2) Considering the ongoing deprecation of the legacy spkm, this issue adds another good reason to transition towards descriptors.
302 if (script.size() > MAX_SCRIPT_ELEMENT_SIZE) throw JSONRPCError(RPC_WALLET_ERROR, "Unsupported multisig script size for legacy wallet. Upgrade to descriptors to overcome this limitation for p2sh-segwit or bech32 scripts");
303
304 if (!spk_man.AddCScript(script)) {
305 if (CScript inner_script; spk_man.GetCScript(CScriptID(script), inner_script)) {
306 CHECK_NONFATAL(inner_script == script); // Nothing to add, script already contained by the wallet
307 continue;
308 }
309 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error importing script into the wallet"));
310 }
311 }
312
313 // Store destination in the addressbook
314 pwallet->SetAddressBook(dest, label, AddressPurpose::SEND);
315
316 // Make the descriptor
317 std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man);
318
319 UniValue result(UniValue::VOBJ);
320 result.pushKV("address", EncodeDestination(dest));
321 result.pushKV("redeemScript", HexStr(inner));
322 result.pushKV("descriptor", descriptor->ToString());
323
324 UniValue warnings(UniValue::VARR);
325 if (descriptor->GetOutputType() != output_type) {
326 // Only warns if the user has explicitly chosen an address type we cannot generate
327 warnings.push_back("Unable to make chosen address type, please ensure no uncompressed public keys are present.");
328 }
329 PushWarnings(warnings, result);
330
331 return result;
332},
333 };
334}
335
337{
338 return RPCHelpMan{"keypoolrefill",
339 "\nFills the keypool."+
341 {
342 {"newsize", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%u, or as set by -keypool", DEFAULT_KEYPOOL_SIZE)}, "The new keypool size"},
343 },
346 HelpExampleCli("keypoolrefill", "")
347 + HelpExampleRpc("keypoolrefill", "")
348 },
349 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
350{
351 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
352 if (!pwallet) return UniValue::VNULL;
353
354 if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
355 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
356 }
357
358 LOCK(pwallet->cs_wallet);
359
360 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
361 unsigned int kpSize = 0;
362 if (!request.params[0].isNull()) {
363 if (request.params[0].getInt<int>() < 0)
364 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
365 kpSize = (unsigned int)request.params[0].getInt<int>();
366 }
367
368 EnsureWalletIsUnlocked(*pwallet);
369 pwallet->TopUpKeyPool(kpSize);
370
371 if (pwallet->GetKeyPoolSize() < kpSize) {
372 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
373 }
374
375 return UniValue::VNULL;
376},
377 };
378}
379
381{
382 return RPCHelpMan{"newkeypool",
383 "\nEntirely clears and refills the keypool.\n"
384 "WARNING: On non-HD wallets, this will require a new backup immediately, to include the new keys.\n"
385 "When restoring a backup of an HD wallet created before the newkeypool command is run, funds received to\n"
386 "new addresses may not appear automatically. They have not been lost, but the wallet may not find them.\n"
387 "This can be fixed by running the newkeypool command on the backup and then rescanning, so the wallet\n"
388 "re-generates the required keys." +
390 {},
393 HelpExampleCli("newkeypool", "")
394 + HelpExampleRpc("newkeypool", "")
395 },
396 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
397{
398 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
399 if (!pwallet) return UniValue::VNULL;
400
401 LOCK(pwallet->cs_wallet);
402
403 LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
404 spk_man.NewKeyPool();
405
406 return UniValue::VNULL;
407},
408 };
409}
410
411
413{
414public:
416
417 // NOLINTNEXTLINE(misc-no-recursion)
418 void ProcessSubScript(const CScript& subscript, UniValue& obj) const
419 {
420 // Always present: script type and redeemscript
421 std::vector<std::vector<unsigned char>> solutions_data;
422 TxoutType which_type = Solver(subscript, solutions_data);
423 obj.pushKV("script", GetTxnOutputType(which_type));
424 obj.pushKV("hex", HexStr(subscript));
425
426 CTxDestination embedded;
427 if (ExtractDestination(subscript, embedded)) {
428 // Only when the script corresponds to an address.
429 UniValue subobj(UniValue::VOBJ);
430 UniValue detail = DescribeAddress(embedded);
431 subobj.pushKVs(std::move(detail));
432 UniValue wallet_detail = std::visit(*this, embedded);
433 subobj.pushKVs(std::move(wallet_detail));
434 subobj.pushKV("address", EncodeDestination(embedded));
435 subobj.pushKV("scriptPubKey", HexStr(subscript));
436 // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
437 if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
438 obj.pushKV("embedded", std::move(subobj));
439 } else if (which_type == TxoutType::MULTISIG) {
440 // Also report some information on multisig scripts (which do not have a corresponding address).
441 obj.pushKV("sigsrequired", solutions_data[0][0]);
442 UniValue pubkeys(UniValue::VARR);
443 for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
444 CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
445 pubkeys.push_back(HexStr(key));
446 }
447 obj.pushKV("pubkeys", std::move(pubkeys));
448 }
449 }
450
451 explicit DescribeWalletAddressVisitor(const SigningProvider* _provider) : provider(_provider) {}
452
455
456 UniValue operator()(const PKHash& pkhash) const
457 {
458 CKeyID keyID{ToKeyID(pkhash)};
460 CPubKey vchPubKey;
461 if (provider && provider->GetPubKey(keyID, vchPubKey)) {
462 obj.pushKV("pubkey", HexStr(vchPubKey));
463 obj.pushKV("iscompressed", vchPubKey.IsCompressed());
464 }
465 return obj;
466 }
467
468 // NOLINTNEXTLINE(misc-no-recursion)
469 UniValue operator()(const ScriptHash& scripthash) const
470 {
472 CScript subscript;
473 if (provider && provider->GetCScript(ToScriptID(scripthash), subscript)) {
474 ProcessSubScript(subscript, obj);
475 }
476 return obj;
477 }
478
480 {
482 CPubKey pubkey;
483 if (provider && provider->GetPubKey(ToKeyID(id), pubkey)) {
484 obj.pushKV("pubkey", HexStr(pubkey));
485 }
486 return obj;
487 }
488
489 // NOLINTNEXTLINE(misc-no-recursion)
491 {
493 CScript subscript;
494 CRIPEMD160 hasher;
495 uint160 hash;
496 hasher.Write(id.begin(), 32).Finalize(hash.begin());
497 if (provider && provider->GetCScript(CScriptID(hash), subscript)) {
498 ProcessSubScript(subscript, obj);
499 }
500 return obj;
501 }
502
506};
507
509{
513 std::unique_ptr<SigningProvider> provider = nullptr;
514 provider = wallet.GetSolvingProvider(script);
515 ret.pushKVs(std::move(detail));
516 ret.pushKVs(std::visit(DescribeWalletAddressVisitor(provider.get()), dest));
517 return ret;
518}
519
521{
522 return RPCHelpMan{"getaddressinfo",
523 "\nReturn information about the given bitcoin address.\n"
524 "Some of the information will only be present if the address is in the active wallet.\n",
525 {
526 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for which to get information."},
527 },
528 RPCResult{
529 RPCResult::Type::OBJ, "", "",
530 {
531 {RPCResult::Type::STR, "address", "The bitcoin address validated."},
532 {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded output script generated by the address."},
533 {RPCResult::Type::BOOL, "ismine", "If the address is yours."},
534 {RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
535 {RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
536 {RPCResult::Type::STR, "desc", /*optional=*/true, "A descriptor for spending coins sent to this address (only when solvable)."},
537 {RPCResult::Type::STR, "parent_desc", /*optional=*/true, "The descriptor used to derive this address if this is a descriptor wallet"},
538 {RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script."},
539 {RPCResult::Type::BOOL, "ischange", "If the address was used for change output."},
540 {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address."},
541 {RPCResult::Type::NUM, "witness_version", /*optional=*/true, "The version number of the witness program."},
542 {RPCResult::Type::STR_HEX, "witness_program", /*optional=*/true, "The hex value of the witness program."},
543 {RPCResult::Type::STR, "script", /*optional=*/true, "The output script type. Only if isscript is true and the redeemscript is known. Possible\n"
544 "types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash,\n"
545 "witness_v0_scripthash, witness_unknown."},
546 {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "The redeemscript for the p2sh address."},
547 {RPCResult::Type::ARR, "pubkeys", /*optional=*/true, "Array of pubkeys associated with the known redeemscript (only if script is multisig).",
548 {
549 {RPCResult::Type::STR, "pubkey", ""},
550 }},
551 {RPCResult::Type::NUM, "sigsrequired", /*optional=*/true, "The number of signatures required to spend multisig output (only if script is multisig)."},
552 {RPCResult::Type::STR_HEX, "pubkey", /*optional=*/true, "The hex value of the raw public key for single-key addresses (possibly embedded in P2SH or P2WSH)."},
553 {RPCResult::Type::OBJ, "embedded", /*optional=*/true, "Information about the address embedded in P2SH or P2WSH, if relevant and known.",
554 {
555 {RPCResult::Type::ELISION, "", "Includes all getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath, hdseedid)\n"
556 "and relation to the wallet (ismine, iswatchonly)."},
557 }},
558 {RPCResult::Type::BOOL, "iscompressed", /*optional=*/true, "If the pubkey is compressed."},
559 {RPCResult::Type::NUM_TIME, "timestamp", /*optional=*/true, "The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + "."},
560 {RPCResult::Type::STR, "hdkeypath", /*optional=*/true, "The HD keypath, if the key is HD and available."},
561 {RPCResult::Type::STR_HEX, "hdseedid", /*optional=*/true, "The Hash160 of the HD seed."},
562 {RPCResult::Type::STR_HEX, "hdmasterfingerprint", /*optional=*/true, "The fingerprint of the master key."},
563 {RPCResult::Type::ARR, "labels", "Array of labels associated with the address. Currently limited to one label but returned\n"
564 "as an array to keep the API stable if multiple labels are enabled in the future.",
565 {
566 {RPCResult::Type::STR, "label name", "Label name (defaults to \"\")."},
567 }},
568 }
569 },
571 HelpExampleCli("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
572 HelpExampleRpc("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"")
573 },
574 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
575{
576 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
577 if (!pwallet) return UniValue::VNULL;
578
579 LOCK(pwallet->cs_wallet);
580
581 std::string error_msg;
582 CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
583
584 // Make sure the destination is valid
585 if (!IsValidDestination(dest)) {
586 // Set generic error message in case 'DecodeDestination' didn't set it
587 if (error_msg.empty()) error_msg = "Invalid address";
588
590 }
591
593
594 std::string currentAddress = EncodeDestination(dest);
595 ret.pushKV("address", currentAddress);
596
597 CScript scriptPubKey = GetScriptForDestination(dest);
598 ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
599
600 std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
601
602 isminetype mine = pwallet->IsMine(dest);
603 ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
604
605 if (provider) {
606 auto inferred = InferDescriptor(scriptPubKey, *provider);
607 bool solvable = inferred->IsSolvable();
608 ret.pushKV("solvable", solvable);
609 if (solvable) {
610 ret.pushKV("desc", inferred->ToString());
611 }
612 } else {
613 ret.pushKV("solvable", false);
614 }
615
616 const auto& spk_mans = pwallet->GetScriptPubKeyMans(scriptPubKey);
617 // In most cases there is only one matching ScriptPubKey manager and we can't resolve ambiguity in a better way
618 ScriptPubKeyMan* spk_man{nullptr};
619 if (spk_mans.size()) spk_man = *spk_mans.begin();
620
621 DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
622 if (desc_spk_man) {
623 std::string desc_str;
624 if (desc_spk_man->GetDescriptorString(desc_str, /*priv=*/false)) {
625 ret.pushKV("parent_desc", desc_str);
626 }
627 }
628
629 ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
630
631 UniValue detail = DescribeWalletAddress(*pwallet, dest);
632 ret.pushKVs(std::move(detail));
633
634 ret.pushKV("ischange", ScriptIsChange(*pwallet, scriptPubKey));
635
636 if (spk_man) {
637 if (const std::unique_ptr<CKeyMetadata> meta = spk_man->GetMetadata(dest)) {
638 ret.pushKV("timestamp", meta->nCreateTime);
639 if (meta->has_key_origin) {
640 // In legacy wallets hdkeypath has always used an apostrophe for
641 // hardened derivation. Perhaps some external tool depends on that.
642 ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path, /*apostrophe=*/!desc_spk_man));
643 ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
644 ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));
645 }
646 }
647 }
648
649 // Return a `labels` array containing the label associated with the address,
650 // equivalent to the `label` field above. Currently only one label can be
651 // associated with an address, but we return an array so the API remains
652 // stable if we allow multiple labels to be associated with an address in
653 // the future.
654 UniValue labels(UniValue::VARR);
655 const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
656 if (address_book_entry) {
657 labels.push_back(address_book_entry->GetLabel());
658 }
659 ret.pushKV("labels", std::move(labels));
660
661 return ret;
662},
663 };
664}
665
667{
668 return RPCHelpMan{"getaddressesbylabel",
669 "\nReturns the list of addresses assigned the specified label.\n",
670 {
671 {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},
672 },
673 RPCResult{
674 RPCResult::Type::OBJ_DYN, "", "json object with addresses as keys",
675 {
676 {RPCResult::Type::OBJ, "address", "json object with information about address",
677 {
678 {RPCResult::Type::STR, "purpose", "Purpose of address (\"send\" for sending address, \"receive\" for receiving address)"},
679 }},
680 }
681 },
683 HelpExampleCli("getaddressesbylabel", "\"tabby\"")
684 + HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
685 },
686 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
687{
688 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
689 if (!pwallet) return UniValue::VNULL;
690
691 LOCK(pwallet->cs_wallet);
692
693 const std::string label{LabelFromValue(request.params[0])};
694
695 // Find all addresses that have the given label
697 std::set<std::string> addresses;
698 pwallet->ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label, bool _is_change, const std::optional<AddressPurpose>& _purpose) {
699 if (_is_change) return;
700 if (_label == label) {
701 std::string address = EncodeDestination(_dest);
702 // CWallet::m_address_book is not expected to contain duplicate
703 // address strings, but build a separate set as a precaution just in
704 // case it does.
705 bool unique = addresses.emplace(address).second;
706 CHECK_NONFATAL(unique);
707 // UniValue::pushKV checks if the key exists in O(N)
708 // and since duplicate addresses are unexpected (checked with
709 // std::set in O(log(N))), UniValue::pushKVEnd is used instead,
710 // which currently is O(1).
712 value.pushKV("purpose", _purpose ? PurposeToString(*_purpose) : "unknown");
713 ret.pushKVEnd(address, std::move(value));
714 }
715 });
716
717 if (ret.empty()) {
718 throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
719 }
720
721 return ret;
722},
723 };
724}
725
727{
728 return RPCHelpMan{"listlabels",
729 "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
730 {
731 {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
732 },
733 RPCResult{
734 RPCResult::Type::ARR, "", "",
735 {
736 {RPCResult::Type::STR, "label", "Label name"},
737 }
738 },
740 "\nList all labels\n"
741 + HelpExampleCli("listlabels", "") +
742 "\nList labels that have receiving addresses\n"
743 + HelpExampleCli("listlabels", "receive") +
744 "\nList labels that have sending addresses\n"
745 + HelpExampleCli("listlabels", "send") +
746 "\nAs a JSON-RPC call\n"
747 + HelpExampleRpc("listlabels", "receive")
748 },
749 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
750{
751 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
752 if (!pwallet) return UniValue::VNULL;
753
754 LOCK(pwallet->cs_wallet);
755
756 std::optional<AddressPurpose> purpose;
757 if (!request.params[0].isNull()) {
758 std::string purpose_str = request.params[0].get_str();
759 if (!purpose_str.empty()) {
760 purpose = PurposeFromString(purpose_str);
761 if (!purpose) {
762 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid 'purpose' argument, must be a known purpose string, typically 'send', or 'receive'.");
763 }
764 }
765 }
766
767 // Add to a set to sort by label name, then insert into Univalue array
768 std::set<std::string> label_set = pwallet->ListAddrBookLabels(purpose);
769
771 for (const std::string& name : label_set) {
772 ret.push_back(name);
773 }
774
775 return ret;
776},
777 };
778}
779
780
781#ifdef ENABLE_EXTERNAL_SIGNER
783{
784 return RPCHelpMan{
785 "walletdisplayaddress",
786 "Display address on an external signer for verification.",
787 {
788 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "bitcoin address to display"},
789 },
790 RPCResult{
792 {
793 {RPCResult::Type::STR, "address", "The address as confirmed by the signer"},
794 }
795 },
796 RPCExamples{""},
797 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
798 {
799 std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
800 if (!wallet) return UniValue::VNULL;
801 CWallet* const pwallet = wallet.get();
802
803 LOCK(pwallet->cs_wallet);
804
805 CTxDestination dest = DecodeDestination(request.params[0].get_str());
806
807 // Make sure the destination is valid
808 if (!IsValidDestination(dest)) {
809 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
810 }
811
812 util::Result<void> res = pwallet->DisplayAddress(dest);
813 if (!res) throw JSONRPCError(RPC_MISC_ERROR, util::ErrorString(res).original);
814
815 UniValue result(UniValue::VOBJ);
816 result.pushKV("address", request.params[0].get_str());
817 return result;
818 }
819 };
820}
821#endif // ENABLE_EXTERNAL_SIGNER
822} // namespace wallet
CScriptID ToScriptID(const ScriptHash &script_hash)
Definition: addresstype.cpp:39
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
Definition: addresstype.cpp:49
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
CKeyID ToKeyID(const PKHash &key_hash)
Definition: addresstype.cpp:29
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:140
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath, bool apostrophe)
Write HD keypaths as strings.
Definition: bip32.cpp:64
int ret
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:81
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:24
An encapsulated public key.
Definition: pubkey.h:34
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:204
A hasher class for RIPEMD-160.
Definition: ripemd160.h:13
CRIPEMD160 & Write(const unsigned char *data, size_t len)
Definition: ripemd160.cpp:247
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: ripemd160.cpp:273
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:415
A reference to a CScript: the Hash160 of its serialization.
Definition: script.h:602
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
RecursiveMutex cs_KeyStore
An interface to be implemented by keystores that support signing.
virtual bool GetCScript(const CScriptID &scriptid, CScript &script) const
virtual bool GetPubKey(const CKeyID &address, CPubKey &pubkey) const
void push_back(UniValue val)
Definition: univalue.cpp:104
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
void pushKVs(UniValue obj)
Definition: univalue.cpp:137
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:77
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
constexpr unsigned char * begin()
Definition: uint256.h:104
160-bit opaque blob.
Definition: uint256.h:178
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:300
RecursiveMutex cs_wallet
Main wallet lock.
Definition: wallet.h:445
UniValue operator()(const PayToAnchor &id) const
Definition: addresses.cpp:504
UniValue operator()(const PKHash &pkhash) const
Definition: addresses.cpp:456
UniValue operator()(const WitnessV0ScriptHash &id) const
Definition: addresses.cpp:490
UniValue operator()(const WitnessV1Taproot &id) const
Definition: addresses.cpp:503
const SigningProvider *const provider
Definition: addresses.cpp:415
UniValue operator()(const WitnessV0KeyHash &id) const
Definition: addresses.cpp:479
UniValue operator()(const WitnessUnknown &id) const
Definition: addresses.cpp:505
DescribeWalletAddressVisitor(const SigningProvider *_provider)
Definition: addresses.cpp:451
void ProcessSubScript(const CScript &subscript, UniValue &obj) const
Definition: addresses.cpp:418
UniValue operator()(const CNoDestination &dest) const
Definition: addresses.cpp:453
UniValue operator()(const ScriptHash &scripthash) const
Definition: addresses.cpp:469
UniValue operator()(const PubKeyDestination &dest) const
Definition: addresses.cpp:454
bool GetDescriptorString(std::string &out, const bool priv) const
bool AddCScript(const CScript &redeemScript) override
bool NewKeyPool()
Mark old keypool keys as used, and generate all new keys.
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
const std::string CURRENCY_UNIT
Definition: feerate.h:17
util::Result< void > DisplayAddress(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Display address on an external signer.
Definition: wallet.cpp:2697
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:29
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg, std::vector< int > *error_locations)
Definition: key_io.cpp:299
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:294
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:57
RPCHelpMan keypoolrefill()
Definition: addresses.cpp:336
bool ScriptIsChange(const CWallet &wallet, const CScript &script)
Definition: receive.cpp:51
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:81
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:19
RPCHelpMan walletdisplayaddress()
Definition: addresses.cpp:782
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:98
RPCHelpMan addmultisigaddress()
Definition: addresses.cpp:218
RPCHelpMan listaddressgroupings()
Definition: addresses.cpp:158
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
std::string LabelFromValue(const UniValue &value)
Definition: util.cpp:119
RPCHelpMan listlabels()
Definition: addresses.cpp:726
isminetype
IsMine() return codes, which depend on ScriptPubKeyMan implementation.
Definition: types.h:41
@ ISMINE_SPENDABLE
Definition: types.h:44
@ ISMINE_WATCH_ONLY
Definition: types.h:43
static UniValue DescribeWalletAddress(const CWallet &wallet, const CTxDestination &dest)
Definition: addresses.cpp:508
std::string PurposeToString(AddressPurpose p)
Definition: wallet.h:270
RPCHelpMan getrawchangeaddress()
Definition: addresses.cpp:73
RPCHelpMan setlabel()
Definition: addresses.cpp:120
RPCHelpMan getaddressinfo()
Definition: addresses.cpp:520
std::map< CTxDestination, CAmount > GetAddressBalances(const CWallet &wallet)
Definition: receive.cpp:322
RPCHelpMan getaddressesbylabel()
Definition: addresses.cpp:666
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:51
std::optional< AddressPurpose > PurposeFromString(std::string_view s)
Definition: wallet.h:280
RPCHelpMan getnewaddress()
Definition: addresses.cpp:21
RPCHelpMan newkeypool()
Definition: addresses.cpp:380
std::set< std::set< CTxDestination > > GetAddressGroupings(const CWallet &wallet)
Definition: receive.cpp:360
std::optional< OutputType > ParseOutputType(const std::string &type)
Definition: outputtype.cpp:24
OutputType
Definition: outputtype.h:17
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
const char * name
Definition: rest.cpp:49
@ RPC_WALLET_INVALID_LABEL_NAME
Invalid label name.
Definition: protocol.h:73
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:71
@ RPC_WALLET_KEYPOOL_RAN_OUT
Keypool ran out, call keypoolrefill first.
Definition: protocol.h:74
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:184
void PushWarnings(const UniValue &warnings, UniValue &obj)
Push warning messages to an RPC "warnings" field as a JSON array of strings.
Definition: util.cpp:1399
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:202
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:44
CPubKey HexToPubKey(const std::string &hex_in)
Definition: util.cpp:220
const std::string EXAMPLE_ADDRESS[2]
Example bech32 addresses for the RPCExamples help documentation.
Definition: util.cpp:45
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector< CPubKey > &pubkeys, OutputType type, FlatSigningProvider &keystore, CScript &script_out)
Definition: util.cpp:257
CPubKey AddrToPubKey(const FillableSigningProvider &keystore, const std::string &addr_in)
Definition: util.cpp:236
UniValue DescribeAddress(const CTxDestination &dest)
Definition: util.cpp:369
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE
Definition: script.h:28
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: solver.cpp:141
std::string GetTxnOutputType(TxoutType t)
Get the name of a TxoutType as a string.
Definition: solver.cpp:18
TxoutType
Definition: solver.h:22
std::map< CScriptID, CScript > scripts
std::string DefaultHint
Hint for default value.
Definition: util.h:217
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ ARR_FIXED
Special array that has a fixed number of entries.
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
CTxDestination subtype to encode any future Witness version.
Definition: addresstype.h:96
#define LOCK2(cs1, cs2)
Definition: sync.h:258
#define LOCK(cs)
Definition: sync.h:257
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1165
bool IsHex(std::string_view str)