Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
501if (provider) {502auto inferred = InferDescriptor(scriptPubKey, *provider);503bool solvable = inferred->IsSolvable();504ret.pushKV("solvable", solvable);505if (solvable) {506ret.pushKV("desc", inferred->ToString());507}508} else {509ret.pushKV("solvable", false);510}512const auto& spk_mans = pwallet->GetScriptPubKeyMans(scriptPubKey);513// In most cases there is only one matching ScriptPubKey manager and we can't resolve ambiguity in a better way514ScriptPubKeyMan* spk_man{nullptr};515if (spk_mans.size()) spk_man = *spk_mans.begin();517DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);518if (desc_spk_man) {519std::string desc_str;520if (desc_spk_man->GetDescriptorString(desc_str, /*priv=*/false)) {521ret.pushKV("parent_desc", desc_str);522}523}525ret.pushKV("iswatchonly", false);527UniValue detail = DescribeWalletAddress(*pwallet, dest);528ret.pushKVs(std::move(detail));530ret.pushKV("ischange", ScriptIsChange(*pwallet, scriptPubKey));532if (spk_man) {533if (const std::unique_ptr<CKeyMetadata> meta = spk_man->GetMetadata(dest)) {534ret.pushKV("timestamp", meta->nCreateTime);535if (meta->has_key_origin) {536// In legacy wallets hdkeypath has always used an apostrophe for537// hardened derivation. Perhaps some external tool depends on that.538ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path, /*apostrophe=*/!desc_spk_man));539ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());540ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));541}542}543}545// Return a `labels` array containing the label associated with the address,546// equivalent to the `label` field above. Currently only one label can be547// associated with an address, but we return an array so the API remains548// stable if we allow multiple labels to be associated with an address in549// the future.550UniValue labels(UniValue::VARR);551const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);552if (address_book_entry) {553labels.push_back(address_book_entry->GetLabel());554}555ret.pushKV("labels", std::move(labels));557return ret;558},559};560}562RPCMethod getaddressesbylabel()563{564return RPCMethod{565"getaddressesbylabel",566"Returns the list of addresses assigned the specified label.\n",567{568{"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},569},570RPCResult{571RPCResult::Type::OBJ_DYN, "", "json object with addresses as keys",572{573{RPCResult::Type::OBJ, "address", "json object with information about address",574{575{RPCResult::Type::STR, "purpose", "Purpose of address (\"send\" for sending address, \"receive\" for receiving address)"},576}},577}578},579RPCExamples{580HelpExampleCli("getaddressesbylabel", "\"tabby\"")581+ HelpExampleRpc("getaddressesbylabel", "\"tabby\"")582},583[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue584{585const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);586if (!pwallet) return UniValue::VNULL;588LOCK(pwallet->cs_wallet);590const std::string label{LabelFromValue(request.params[0])};592// Find all addresses that have the given label593UniValue ret(UniValue::VOBJ);594std::set<std::string> addresses;595pwallet->ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label, bool _is_change, const std::optional<AddressPurpose>& _purpose) {596if (_is_change) return;597if (_label == label) {598std::string address = EncodeDestination(_dest);599// CWallet::m_address_book is not expected to contain duplicate600// address strings, but build a separate set as a precaution just in601// case it does.602bool unique = addresses.emplace(address).second;603CHECK_NONFATAL(unique);604// UniValue::pushKV checks if the key exists in O(N)605// and since duplicate addresses are unexpected (checked with606// std::set in O(log(N))), UniValue::pushKVEnd is used instead,607// which currently is O(1).608UniValue value(UniValue::VOBJ);609value.pushKV("purpose", _purpose ? PurposeToString(*_purpose) : "unknown");610ret.pushKVEnd(address, std::move(value));611}612});614if (ret.empty()) {615throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));616}618return ret;619},620};621}623RPCMethod listlabels()624{625return RPCMethod{626"listlabels",627"Returns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",628{629{"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."},630},631RPCResult{632RPCResult::Type::ARR, "", "",633{634{RPCResult::Type::STR, "label", "Label name"},635}636},637RPCExamples{638"\nList all labels\n"639+ HelpExampleCli("listlabels", "") +640"\nList labels that have receiving addresses\n"641+ HelpExampleCli("listlabels", "receive") +642"\nList labels that have sending addresses\n"643+ HelpExampleCli("listlabels", "send") +644"\nAs a JSON-RPC call\n"645+ HelpExampleRpc("listlabels", R"("receive")")646},647[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue648{649const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);650if (!pwallet) return UniValue::VNULL;652LOCK(pwallet->cs_wallet);654std::optional<AddressPurpose> purpose;655if (!request.params[0].isNull()) {656std::string purpose_str = request.params[0].get_str();657if (!purpose_str.empty()) {658purpose = PurposeFromString(purpose_str);659if (!purpose) {660throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid 'purpose' argument, must be a known purpose string, typically 'send', or 'receive'.");661}662}663}665// Add to a set to sort by label name, then insert into Univalue array666std::set<std::string> label_set = pwallet->ListAddrBookLabels(purpose);668UniValue ret(UniValue::VARR);669for (const std::string& name : label_set) {670ret.push_back(name);671}673return ret;674},675};676}679#ifdef ENABLE_EXTERNAL_SIGNER680RPCMethod walletdisplayaddress()681{682return RPCMethod{683"walletdisplayaddress",684"Display address on an external signer for verification.",685{686{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "bitcoin address to display"},687},688RPCResult{689RPCResult::Type::OBJ,"","",690{691{RPCResult::Type::STR, "address", "The address as confirmed by the signer"},692}693},694RPCExamples{""},695[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue696{697std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);698if (!wallet) return UniValue::VNULL;699CWallet* const pwallet = wallet.get();701LOCK(pwallet->cs_wallet);703CTxDestination dest = DecodeDestination(request.params[0].get_str());705// Make sure the destination is valid706if (!IsValidDestination(dest)) {707throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");708}710util::Result<void> res = pwallet->DisplayAddress(dest);711if (!res) throw JSONRPCError(RPC_MISC_ERROR, util::ErrorString(res).original);713UniValue result(UniValue::VOBJ);714result.pushKV("address", request.params[0].get_str());715return result;716}717};718}719#endif // ENABLE_EXTERNAL_SIGNER720} // namespace wallet