Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/wallet/rpc/util.cpp
Line
Count
Source
1
// Copyright (c) 2011-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#include <wallet/rpc/util.h>
6
7
#include <common/url.h>
8
#include <rpc/util.h>
9
#include <util/any.h>
10
#include <util/translation.h>
11
#include <wallet/context.h>
12
#include <wallet/wallet.h>
13
14
#include <optional>
15
#include <string_view>
16
#include <univalue.h>
17
18
namespace wallet {
19
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
20
const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
21
22
0
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
23
0
    bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
24
0
    bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
25
26
0
    if (avoid_reuse && !can_avoid_reuse) {
27
0
        throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
28
0
    }
29
30
0
    return avoid_reuse;
31
0
}
32
33
std::string EnsureUniqueWalletName(const JSONRPCRequest& request, std::optional<std::string_view> wallet_name)
34
0
{
35
0
    std::string endpoint_wallet;
36
0
    if (GetWalletNameFromJSONRPCRequest(request, endpoint_wallet)) {
37
        // wallet endpoint was used
38
0
        if (wallet_name && *wallet_name != endpoint_wallet) {
39
0
            throw JSONRPCError(RPC_INVALID_PARAMETER,
40
0
                "The RPC endpoint wallet and the wallet name parameter specify different wallets");
41
0
        }
42
0
        return endpoint_wallet;
43
0
    }
44
45
    // Not a wallet endpoint; parameter must be provided
46
0
    if (!wallet_name) {
47
0
        throw JSONRPCError(RPC_INVALID_PARAMETER,
48
0
            "Either the RPC endpoint wallet or the wallet name parameter must be provided");
49
0
    }
50
51
0
    return std::string{*wallet_name};
52
0
}
53
54
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
55
0
{
56
0
    if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
57
        // wallet endpoint was used
58
0
        wallet_name = UrlDecode(std::string_view{request.URI}.substr(WALLET_ENDPOINT_BASE.size()));
59
0
        return true;
60
0
    }
61
0
    return false;
62
0
}
63
64
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
65
0
{
66
0
    CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
Line
Count
Source
110
0
    inline_check_non_fatal(condition, std::source_location::current(), #condition)
67
0
    WalletContext& context = EnsureWalletContext(request.context);
68
69
0
    std::string wallet_name;
70
0
    if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
71
0
        std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
72
0
        if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
73
0
        return pwallet;
74
0
    }
75
76
0
    size_t count{0};
77
0
    auto wallet = GetDefaultWallet(context, count);
78
0
    if (wallet) return wallet;
79
80
0
    if (count == 0) {
81
0
        throw JSONRPCError(
82
0
            RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
83
0
    }
84
0
    throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
85
0
        "Multiple wallets are loaded. Please select which wallet to use by requesting the RPC through the /wallet/<walletname> URI path.");
86
0
}
87
88
void EnsureWalletIsUnlocked(const CWallet& wallet)
89
0
{
90
0
    if (wallet.IsLocked()) {
91
0
        throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
92
0
    }
93
0
}
94
95
WalletContext& EnsureWalletContext(const std::any& context)
96
0
{
97
0
    auto wallet_context = util::AnyPtr<WalletContext>(context);
98
0
    if (!wallet_context) {
99
0
        throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
100
0
    }
101
0
    return *wallet_context;
102
0
}
103
104
std::string LabelFromValue(const UniValue& value)
105
0
{
106
0
    static const std::string empty_string;
107
0
    if (value.isNull()) return empty_string;
108
109
0
    const std::string& label{value.get_str()};
110
0
    if (label == "*")
111
0
        throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
112
0
    return label;
113
0
}
114
115
void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry)
116
0
{
117
0
    UniValue parent_descs(UniValue::VARR);
118
0
    for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) {
119
0
        std::string desc_str;
120
0
        FlatSigningProvider dummy_provider;
121
0
        if (!CHECK_NONFATAL(desc.descriptor->ToNormalizedString(dummy_provider, desc_str, &desc.cache))) continue;
Line
Count
Source
110
0
    inline_check_non_fatal(condition, std::source_location::current(), #condition)
122
0
        parent_descs.push_back(desc_str);
123
0
    }
124
0
    entry.pushKV("parent_descs", std::move(parent_descs));
125
0
}
126
127
void HandleWalletError(const std::shared_ptr<CWallet>& wallet, DatabaseStatus& status, bilingual_str& error)
128
0
{
129
0
    if (!wallet) {
130
        // Map bad format to not found, since bad format is returned when the
131
        // wallet directory exists, but doesn't contain a data file.
132
0
        RPCErrorCode code = RPC_WALLET_ERROR;
133
0
        switch (status) {
134
0
            case DatabaseStatus::FAILED_NOT_FOUND:
135
0
            case DatabaseStatus::FAILED_BAD_FORMAT:
136
0
            case DatabaseStatus::FAILED_LEGACY_DISABLED:
137
0
                code = RPC_WALLET_NOT_FOUND;
138
0
                break;
139
0
            case DatabaseStatus::FAILED_ALREADY_LOADED:
140
0
                code = RPC_WALLET_ALREADY_LOADED;
141
0
                break;
142
0
            case DatabaseStatus::FAILED_ALREADY_EXISTS:
143
0
                code = RPC_WALLET_ALREADY_EXISTS;
144
0
                break;
145
0
            case DatabaseStatus::FAILED_NEW_UNNAMED:
146
0
            case DatabaseStatus::FAILED_INVALID_BACKUP_FILE:
147
0
                code = RPC_INVALID_PARAMETER;
148
0
                break;
149
0
            case DatabaseStatus::FAILED_ENCRYPT:
150
0
                code = RPC_WALLET_ENCRYPTION_FAILED;
151
0
                break;
152
0
            default: // RPC_WALLET_ERROR is returned for all other cases.
153
0
                break;
154
0
        }
155
0
        throw JSONRPCError(code, error.original);
156
0
    }
157
0
}
158
159
void AppendLastProcessedBlock(UniValue& entry, const CWallet& wallet)
160
0
{
161
0
    AssertLockHeld(wallet.cs_wallet);
Line
Count
Source
142
0
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
162
0
    UniValue lastprocessedblock{UniValue::VOBJ};
163
0
    lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());
164
0
    lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());
165
0
    entry.pushKV("lastprocessedblock", std::move(lastprocessedblock));
166
0
}
167
168
} // namespace wallet