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/node/interfaces.cpp
Line
Count
Source
1
// Copyright (c) 2018-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 <addrdb.h>
6
#include <banman.h>
7
#include <blockfilter.h>
8
#include <chain.h>
9
#include <chainparams.h>
10
#include <common/args.h>
11
#include <consensus/merkle.h>
12
#include <consensus/validation.h>
13
#include <deploymentstatus.h>
14
#include <external_signer.h>
15
#include <index/blockfilterindex.h>
16
#include <init.h>
17
#include <interfaces/chain.h>
18
#include <interfaces/handler.h>
19
#include <interfaces/mining.h>
20
#include <interfaces/node.h>
21
#include <interfaces/types.h>
22
#include <interfaces/wallet.h>
23
#include <kernel/chain.h>
24
#include <kernel/context.h>
25
#include <kernel/mempool_entry.h>
26
#include <logging.h>
27
#include <mapport.h>
28
#include <net.h>
29
#include <net_processing.h>
30
#include <netaddress.h>
31
#include <netbase.h>
32
#include <node/blockstorage.h>
33
#include <node/coin.h>
34
#include <node/context.h>
35
#include <node/interface_ui.h>
36
#include <node/mini_miner.h>
37
#include <node/miner.h>
38
#include <node/kernel_notifications.h>
39
#include <node/transaction.h>
40
#include <node/types.h>
41
#include <node/warnings.h>
42
#include <policy/feerate.h>
43
#include <policy/fees/block_policy_estimator.h>
44
#include <policy/policy.h>
45
#include <policy/rbf.h>
46
#include <policy/settings.h>
47
#include <primitives/block.h>
48
#include <primitives/transaction.h>
49
#include <rpc/blockchain.h>
50
#include <rpc/protocol.h>
51
#include <rpc/server.h>
52
#include <support/allocators/secure.h>
53
#include <sync.h>
54
#include <txmempool.h>
55
#include <uint256.h>
56
#include <univalue.h>
57
#include <util/check.h>
58
#include <util/result.h>
59
#include <util/signalinterrupt.h>
60
#include <util/string.h>
61
#include <util/translation.h>
62
#include <validation.h>
63
#include <validationinterface.h>
64
65
#include <bitcoin-build-config.h> // IWYU pragma: keep
66
67
#include <any>
68
#include <memory>
69
#include <optional>
70
#include <stdexcept>
71
#include <utility>
72
73
#include <boost/signals2/signal.hpp>
74
75
using interfaces::BlockRef;
76
using interfaces::BlockTemplate;
77
using interfaces::BlockTip;
78
using interfaces::Chain;
79
using interfaces::FoundBlock;
80
using interfaces::Handler;
81
using interfaces::MakeSignalHandler;
82
using interfaces::Mining;
83
using interfaces::Node;
84
using interfaces::WalletLoader;
85
using kernel::ChainstateRole;
86
using node::BlockAssembler;
87
using node::BlockWaitOptions;
88
using node::CoinbaseTx;
89
using util::Join;
90
91
namespace node {
92
// All members of the classes in this namespace are intentionally public, as the
93
// classes themselves are private.
94
namespace {
95
#ifdef ENABLE_EXTERNAL_SIGNER
96
class ExternalSignerImpl : public interfaces::ExternalSigner
97
{
98
public:
99
    ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {}
100
    std::string getName() override { return m_signer.m_name; }
101
    ::ExternalSigner m_signer;
102
};
103
#endif
104
105
class NodeImpl : public Node
106
{
107
public:
108
0
    explicit NodeImpl(NodeContext& context) { setContext(&context); }
109
0
    void initLogging() override { InitLogging(args()); }
110
0
    void initParameterInteraction() override { InitParameterInteraction(args()); }
111
0
    bilingual_str getWarnings() override { return Join(Assert(m_context->warnings)->GetMessages(), Untranslated("<hr />")); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
112
0
    int getExitStatus() override { return Assert(m_context)->exit_status.load(); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
113
0
    BCLog::CategoryMask getLogCategories() override { return LogInstance().GetCategoryMask(); }
114
    bool baseInitialize() override
115
0
    {
116
0
        if (!AppInitBasicSetup(args(), Assert(context())->exit_status)) return false;
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
117
0
        if (!AppInitParameterInteraction(args())) return false;
118
119
0
        m_context->warnings = std::make_unique<node::Warnings>();
120
0
        m_context->kernel = std::make_unique<kernel::Context>();
121
0
        m_context->ecc_context = std::make_unique<ECC_Context>();
122
0
        if (!AppInitSanityChecks(*m_context->kernel)) return false;
123
124
0
        if (!AppInitLockDirectories()) return false;
125
0
        if (!AppInitInterfaces(*m_context)) return false;
126
127
0
        return true;
128
0
    }
129
    bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
130
0
    {
131
0
        if (AppInitMain(*m_context, tip_info)) return true;
132
        // Error during initialization, set exit status before continue
133
0
        m_context->exit_status.store(EXIT_FAILURE);
134
0
        return false;
135
0
    }
136
    void appShutdown() override
137
0
    {
138
0
        Shutdown(*m_context);
139
0
    }
140
    void startShutdown() override
141
0
    {
142
0
        NodeContext& ctx{*Assert(m_context)};
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
143
0
        if (!(Assert(ctx.shutdown_request))()) {
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
144
0
            LogError("Failed to send shutdown signal\n");
Line
Count
Source
97
0
#define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__)
Line
Count
Source
89
0
#define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__)
145
0
        }
146
0
        Interrupt(*m_context);
147
0
    }
148
0
    bool shutdownRequested() override { return ShutdownRequested(*Assert(m_context)); };
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
149
    bool isSettingIgnored(const std::string& name) override
150
0
    {
151
0
        bool ignored = false;
152
0
        args().LockSettings([&](common::Settings& settings) {
153
0
            if (auto* options = common::FindKey(settings.command_line_options, name)) {
154
0
                ignored = !options->empty();
155
0
            }
156
0
        });
157
0
        return ignored;
158
0
    }
159
0
    common::SettingsValue getPersistentSetting(const std::string& name) override { return args().GetPersistentSetting(name); }
160
    void updateRwSetting(const std::string& name, const common::SettingsValue& value) override
161
0
    {
162
0
        args().LockSettings([&](common::Settings& settings) {
163
0
            if (value.isNull()) {
164
0
                settings.rw_settings.erase(name);
165
0
            } else {
166
0
                settings.rw_settings[name] = value;
167
0
            }
168
0
        });
169
0
        args().WriteSettingsFile();
170
0
    }
171
    void forceSetting(const std::string& name, const common::SettingsValue& value) override
172
0
    {
173
0
        args().LockSettings([&](common::Settings& settings) {
174
0
            if (value.isNull()) {
175
0
                settings.forced_settings.erase(name);
176
0
            } else {
177
0
                settings.forced_settings[name] = value;
178
0
            }
179
0
        });
180
0
    }
181
    void resetSettings() override
182
0
    {
183
0
        args().WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
184
0
        args().LockSettings([&](common::Settings& settings) {
185
0
            settings.rw_settings.clear();
186
0
        });
187
0
        args().WriteSettingsFile();
188
0
    }
189
0
    void mapPort(bool enable) override { StartMapPort(enable); }
190
0
    bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); }
191
    size_t getNodeCount(ConnectionDirection flags) override
192
0
    {
193
0
        return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
194
0
    }
195
    bool getNodesStats(NodesStats& stats) override
196
0
    {
197
0
        stats.clear();
198
199
0
        if (m_context->connman) {
200
0
            std::vector<CNodeStats> stats_temp;
201
0
            m_context->connman->GetNodeStats(stats_temp);
202
203
0
            stats.reserve(stats_temp.size());
204
0
            for (auto& node_stats_temp : stats_temp) {
205
0
                stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
206
0
            }
207
208
            // Try to retrieve the CNodeStateStats for each node.
209
0
            if (m_context->peerman) {
210
0
                TRY_LOCK(::cs_main, lockMain);
Line
Count
Source
271
0
#define TRY_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs), true)
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
211
0
                if (lockMain) {
212
0
                    for (auto& node_stats : stats) {
213
0
                        std::get<1>(node_stats) =
214
0
                            m_context->peerman->GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
215
0
                    }
216
0
                }
217
0
            }
218
0
            return true;
219
0
        }
220
0
        return false;
221
0
    }
222
    bool getBanned(banmap_t& banmap) override
223
0
    {
224
0
        if (m_context->banman) {
225
0
            m_context->banman->GetBanned(banmap);
226
0
            return true;
227
0
        }
228
0
        return false;
229
0
    }
230
    bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override
231
0
    {
232
0
        if (m_context->banman) {
233
0
            m_context->banman->Ban(net_addr, ban_time_offset);
234
0
            return true;
235
0
        }
236
0
        return false;
237
0
    }
238
    bool unban(const CSubNet& ip) override
239
0
    {
240
0
        if (m_context->banman) {
241
0
            m_context->banman->Unban(ip);
242
0
            return true;
243
0
        }
244
0
        return false;
245
0
    }
246
    bool disconnectByAddress(const CNetAddr& net_addr) override
247
0
    {
248
0
        if (m_context->connman) {
249
0
            return m_context->connman->DisconnectNode(net_addr);
250
0
        }
251
0
        return false;
252
0
    }
253
    bool disconnectById(NodeId id) override
254
0
    {
255
0
        if (m_context->connman) {
256
0
            return m_context->connman->DisconnectNode(id);
257
0
        }
258
0
        return false;
259
0
    }
260
    std::vector<std::unique_ptr<interfaces::ExternalSigner>> listExternalSigners() override
261
0
    {
262
#ifdef ENABLE_EXTERNAL_SIGNER
263
        std::vector<ExternalSigner> signers = {};
264
        const std::string command = args().GetArg("-signer", "");
265
        if (command == "") return {};
266
        ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString());
267
        std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
268
        result.reserve(signers.size());
269
        for (auto& signer : signers) {
270
            result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
271
        }
272
        return result;
273
#else
274
        // This result is indistinguishable from a successful call that returns
275
        // no signers. For the current GUI this doesn't matter, because the wallet
276
        // creation dialog disables the external signer checkbox in both
277
        // cases. The return type could be changed to std::optional<std::vector>
278
        // (or something that also includes error messages) if this distinction
279
        // becomes important.
280
0
        return {};
281
0
#endif // ENABLE_EXTERNAL_SIGNER
282
0
    }
283
0
    int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; }
284
0
    int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; }
285
0
    size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; }
286
0
    size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; }
287
0
    size_t getMempoolMaxUsage() override { return m_context->mempool ? m_context->mempool->m_opts.max_size_bytes : 0; }
288
    bool getHeaderTip(int& height, int64_t& block_time) override
289
0
    {
290
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
291
0
        auto best_header = chainman().m_best_header;
292
0
        if (best_header) {
293
0
            height = best_header->nHeight;
294
0
            block_time = best_header->GetBlockTime();
295
0
            return true;
296
0
        }
297
0
        return false;
298
0
    }
299
    std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() override
300
0
    {
301
0
        if (m_context->connman)
302
0
            return m_context->connman->getNetLocalAddresses();
303
0
        else
304
0
            return {};
305
0
    }
306
    int getNumBlocks() override
307
0
    {
308
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
309
0
        return chainman().ActiveChain().Height();
310
0
    }
311
    uint256 getBestBlockHash() override
312
0
    {
313
0
        const CBlockIndex* tip = WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip());
Line
Count
Source
297
0
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
314
0
        return tip ? tip->GetBlockHash() : chainman().GetParams().GenesisBlock().GetHash();
315
0
    }
316
    int64_t getLastBlockTime() override
317
0
    {
318
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
319
0
        if (chainman().ActiveChain().Tip()) {
320
0
            return chainman().ActiveChain().Tip()->GetBlockTime();
321
0
        }
322
0
        return chainman().GetParams().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
323
0
    }
324
    double getVerificationProgress() override
325
0
    {
326
0
        LOCK(chainman().GetMutex());
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
327
0
        return chainman().GuessVerificationProgress(chainman().ActiveTip());
328
0
    }
329
    bool isInitialBlockDownload() override
330
0
    {
331
0
        return chainman().IsInitialBlockDownload();
332
0
    }
333
0
    bool isLoadingBlocks() override { return chainman().m_blockman.LoadingBlocks(); }
334
    void setNetworkActive(bool active) override
335
0
    {
336
0
        if (m_context->connman) {
337
0
            m_context->connman->SetNetworkActive(active);
338
0
        }
339
0
    }
340
0
    bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
341
    CFeeRate getDustRelayFee() override
342
0
    {
343
0
        if (!m_context->mempool) return CFeeRate{DUST_RELAY_TX_FEE};
344
0
        return m_context->mempool->m_opts.dust_relay_feerate;
345
0
    }
346
    UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
347
0
    {
348
0
        JSONRPCRequest req;
349
0
        req.context = m_context;
350
0
        req.params = params;
351
0
        req.strMethod = command;
352
0
        req.URI = uri;
353
0
        return ::tableRPC.execute(req);
354
0
    }
355
0
    std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
356
    std::optional<Coin> getUnspentOutput(const COutPoint& output) override
357
0
    {
358
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
359
0
        return chainman().ActiveChainstate().CoinsTip().GetCoin(output);
360
0
    }
361
    TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
362
0
    {
363
0
        return BroadcastTransaction(*m_context,
364
0
                                    std::move(tx),
365
0
                                    err_string,
366
0
                                    max_tx_fee,
367
0
                                    TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL,
368
0
                                    /*wait_callback=*/false);
369
0
    }
370
    WalletLoader& walletLoader() override
371
0
    {
372
0
        return *Assert(m_context->wallet_loader);
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
373
0
    }
374
    std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
375
0
    {
376
0
        return MakeSignalHandler(::uiInterface.InitMessage_connect(fn));
377
0
    }
378
    std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override
379
0
    {
380
0
        return MakeSignalHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
381
0
    }
382
    std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override
383
0
    {
384
0
        return MakeSignalHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
385
0
    }
386
    std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
387
0
    {
388
0
        return MakeSignalHandler(::uiInterface.ShowProgress_connect(fn));
389
0
    }
390
    std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) override
391
0
    {
392
0
        return MakeSignalHandler(::uiInterface.InitWallet_connect(fn));
393
0
    }
394
    std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
395
0
    {
396
0
        return MakeSignalHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn));
397
0
    }
398
    std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override
399
0
    {
400
0
        return MakeSignalHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn));
401
0
    }
402
    std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
403
0
    {
404
0
        return MakeSignalHandler(::uiInterface.NotifyAlertChanged_connect(fn));
405
0
    }
406
    std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
407
0
    {
408
0
        return MakeSignalHandler(::uiInterface.BannedListChanged_connect(fn));
409
0
    }
410
    std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
411
0
    {
412
0
        return MakeSignalHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex& block, double verification_progress) {
413
0
            fn(sync_state, BlockTip{block.nHeight, block.GetBlockTime(), block.GetBlockHash()}, verification_progress);
414
0
        }));
415
0
    }
416
    std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
417
0
    {
418
0
        return MakeSignalHandler(
419
0
            ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, int64_t height, int64_t timestamp, bool presync) {
420
0
                fn(sync_state, BlockTip{(int)height, timestamp, uint256{}}, presync);
421
0
            }));
422
0
    }
423
0
    NodeContext* context() override { return m_context; }
424
    void setContext(NodeContext* context) override
425
0
    {
426
0
        m_context = context;
427
0
    }
428
0
    ArgsManager& args() { return *Assert(Assert(m_context)->args); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
429
0
    ChainstateManager& chainman() { return *Assert(m_context->chainman); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
430
    NodeContext* m_context{nullptr};
431
};
432
433
// NOLINTNEXTLINE(misc-no-recursion)
434
bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active, const BlockManager& blockman) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
435
0
{
436
0
    if (!index) return false;
437
0
    if (block.m_hash) *block.m_hash = index->GetBlockHash();
438
0
    if (block.m_height) *block.m_height = index->nHeight;
439
0
    if (block.m_time) *block.m_time = index->GetBlockTime();
440
0
    if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
441
0
    if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
442
0
    if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
443
0
    if (block.m_locator) { *block.m_locator = GetLocator(index); }
444
0
    if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active, blockman);
445
0
    if (block.m_data) {
446
0
        REVERSE_LOCK(lock, cs_main);
Line
Count
Source
252
0
#define REVERSE_LOCK(g, cs) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, cs, #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
447
0
        if (!blockman.ReadBlock(*block.m_data, *index)) block.m_data->SetNull();
448
0
    }
449
0
    block.found = true;
450
0
    return true;
451
0
}
452
453
class NotificationsProxy : public CValidationInterface
454
{
455
public:
456
    explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
457
0
        : m_notifications(std::move(notifications)) {}
458
0
    virtual ~NotificationsProxy() = default;
459
    void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t mempool_sequence) override
460
0
    {
461
0
        m_notifications->transactionAddedToMempool(tx.info.m_tx);
462
0
    }
463
    void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
464
0
    {
465
0
        m_notifications->transactionRemovedFromMempool(tx, reason);
466
0
    }
467
    void BlockConnected(const ChainstateRole& role, const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
468
0
    {
469
0
        m_notifications->blockConnected(role, kernel::MakeBlockInfo(index, block.get()));
470
0
    }
471
    void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
472
0
    {
473
0
        m_notifications->blockDisconnected(kernel::MakeBlockInfo(index, block.get()));
474
0
    }
475
    void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
476
0
    {
477
0
        m_notifications->updatedBlockTip();
478
0
    }
479
    void ChainStateFlushed(const ChainstateRole& role, const CBlockLocator& locator) override
480
0
    {
481
0
        m_notifications->chainStateFlushed(role, locator);
482
0
    }
483
    std::shared_ptr<Chain::Notifications> m_notifications;
484
};
485
486
class NotificationsHandlerImpl : public Handler
487
{
488
public:
489
    explicit NotificationsHandlerImpl(ValidationSignals& signals, std::shared_ptr<Chain::Notifications> notifications)
490
0
        : m_signals{signals}, m_proxy{std::make_shared<NotificationsProxy>(std::move(notifications))}
491
0
    {
492
0
        m_signals.RegisterSharedValidationInterface(m_proxy);
493
0
    }
494
0
    ~NotificationsHandlerImpl() override { disconnect(); }
495
    void disconnect() override
496
0
    {
497
0
        if (m_proxy) {
498
0
            m_signals.UnregisterSharedValidationInterface(m_proxy);
499
0
            m_proxy.reset();
500
0
        }
501
0
    }
502
    ValidationSignals& m_signals;
503
    std::shared_ptr<NotificationsProxy> m_proxy;
504
};
505
506
class RpcHandlerImpl : public Handler
507
{
508
public:
509
0
    explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
510
0
    {
511
0
        m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
512
0
            if (!m_wrapped_command) return false;
513
0
            try {
514
0
                return m_wrapped_command->actor(request, result, last_handler);
515
0
            } catch (const UniValue& e) {
516
                // If this is not the last handler and a wallet not found
517
                // exception was thrown, return false so the next handler can
518
                // try to handle the request. Otherwise, reraise the exception.
519
0
                if (!last_handler) {
520
0
                    const UniValue& code = e["code"];
521
0
                    if (code.isNum() && code.getInt<int>() == RPC_WALLET_NOT_FOUND) {
522
0
                        return false;
523
0
                    }
524
0
                }
525
0
                throw;
526
0
            }
527
0
        };
528
0
        ::tableRPC.appendCommand(m_command.name, &m_command);
529
0
    }
530
531
    void disconnect() final
532
0
    {
533
0
        if (m_wrapped_command) {
534
0
            m_wrapped_command = nullptr;
535
0
            ::tableRPC.removeCommand(m_command.name, &m_command);
536
0
        }
537
0
    }
538
539
0
    ~RpcHandlerImpl() override { disconnect(); }
540
541
    CRPCCommand m_command;
542
    const CRPCCommand* m_wrapped_command;
543
};
544
545
class ChainImpl : public Chain
546
{
547
public:
548
0
    explicit ChainImpl(NodeContext& node) : m_node(node) {}
549
    std::optional<int> getHeight() override
550
0
    {
551
0
        const int height{WITH_LOCK(::cs_main, return chainman().ActiveChain().Height())};
Line
Count
Source
297
0
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
552
0
        return height >= 0 ? std::optional{height} : std::nullopt;
553
0
    }
554
    uint256 getBlockHash(int height) override
555
0
    {
556
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
557
0
        return Assert(chainman().ActiveChain()[height])->GetBlockHash();
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
558
0
    }
559
    bool haveBlockOnDisk(int height) override
560
0
    {
561
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
562
0
        const CBlockIndex* block{chainman().ActiveChain()[height]};
563
0
        return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
564
0
    }
565
    std::optional<int> findLocatorFork(const CBlockLocator& locator) override
566
0
    {
567
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
568
0
        if (const CBlockIndex* fork = chainman().ActiveChainstate().FindForkInGlobalIndex(locator)) {
569
0
            return fork->nHeight;
570
0
        }
571
0
        return std::nullopt;
572
0
    }
573
    bool hasBlockFilterIndex(BlockFilterType filter_type) override
574
0
    {
575
0
        return GetBlockFilterIndex(filter_type) != nullptr;
576
0
    }
577
    std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) override
578
0
    {
579
0
        const BlockFilterIndex* block_filter_index{GetBlockFilterIndex(filter_type)};
580
0
        if (!block_filter_index) return std::nullopt;
581
582
0
        BlockFilter filter;
583
0
        const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};
Line
Count
Source
297
0
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
584
0
        if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;
585
0
        return filter.GetFilter().MatchAny(filter_set);
586
0
    }
587
    bool findBlock(const uint256& hash, const FoundBlock& block) override
588
0
    {
589
0
        WAIT_LOCK(cs_main, lock);
Line
Count
Source
272
0
#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
590
0
        return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain(), chainman().m_blockman);
591
0
    }
592
    bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
593
0
    {
594
0
        WAIT_LOCK(cs_main, lock);
Line
Count
Source
272
0
#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
595
0
        const CChain& active = chainman().ActiveChain();
596
0
        return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active, chainman().m_blockman);
597
0
    }
598
    bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
599
0
    {
600
0
        WAIT_LOCK(cs_main, lock);
Line
Count
Source
272
0
#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
601
0
        const CChain& active = chainman().ActiveChain();
602
0
        if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
603
0
            if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
604
0
                return FillBlock(ancestor, ancestor_out, lock, active, chainman().m_blockman);
605
0
            }
606
0
        }
607
0
        return FillBlock(nullptr, ancestor_out, lock, active, chainman().m_blockman);
608
0
    }
609
    bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
610
0
    {
611
0
        WAIT_LOCK(cs_main, lock);
Line
Count
Source
272
0
#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
612
0
        const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
613
0
        const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
614
0
        if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
615
0
        return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain(), chainman().m_blockman);
616
0
    }
617
    bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
618
0
    {
619
0
        WAIT_LOCK(cs_main, lock);
Line
Count
Source
272
0
#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
620
0
        const CChain& active = chainman().ActiveChain();
621
0
        const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);
622
0
        const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);
623
0
        const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
624
        // Using & instead of && below to avoid short circuiting and leaving
625
        // output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
626
        // compiler warnings.
627
0
        return int{FillBlock(ancestor, ancestor_out, lock, active, chainman().m_blockman)} &
628
0
               int{FillBlock(block1, block1_out, lock, active, chainman().m_blockman)} &
629
0
               int{FillBlock(block2, block2_out, lock, active, chainman().m_blockman)};
630
0
    }
631
0
    void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
632
    double guessVerificationProgress(const uint256& block_hash) override
633
0
    {
634
0
        LOCK(chainman().GetMutex());
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
635
0
        return chainman().GuessVerificationProgress(chainman().m_blockman.LookupBlockIndex(block_hash));
636
0
    }
637
    bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
638
0
    {
639
        // hasBlocks returns true if all ancestors of block_hash in specified
640
        // range have block data (are not pruned), false if any ancestors in
641
        // specified range are missing data.
642
        //
643
        // For simplicity and robustness, min_height and max_height are only
644
        // used to limit the range, and passing min_height that's too low or
645
        // max_height that's too high will not crash or change the result.
646
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
647
0
        if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
648
0
            if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
649
0
            for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
650
                // Check pprev to not segfault if min_height is too low
651
0
                if (block->nHeight <= min_height || !block->pprev) return true;
652
0
            }
653
0
        }
654
0
        return false;
655
0
    }
656
    RBFTransactionState isRBFOptIn(const CTransaction& tx) override
657
0
    {
658
0
        if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx);
659
0
        LOCK(m_node.mempool->cs);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
660
0
        return IsRBFOptIn(tx, *m_node.mempool);
661
0
    }
662
    bool isInMempool(const Txid& txid) override
663
0
    {
664
0
        if (!m_node.mempool) return false;
665
0
        return m_node.mempool->exists(txid);
666
0
    }
667
    bool hasDescendantsInMempool(const Txid& txid) override
668
0
    {
669
0
        if (!m_node.mempool) return false;
670
0
        return m_node.mempool->HasDescendants(txid);
671
0
    }
672
    bool broadcastTransaction(const CTransactionRef& tx,
673
        const CAmount& max_tx_fee,
674
        TxBroadcast broadcast_method,
675
        std::string& err_string) override
676
0
    {
677
0
        const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, broadcast_method, /*wait_callback=*/false);
678
        // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
679
        // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
680
        // that Chain clients do not need to know about.
681
0
        return TransactionError::OK == err;
682
0
    }
683
    void getTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& cluster_count, size_t* ancestorsize, CAmount* ancestorfees) override
684
0
    {
685
0
        ancestors = cluster_count = 0;
686
0
        if (!m_node.mempool) return;
687
0
        m_node.mempool->GetTransactionAncestry(txid, ancestors, cluster_count, ancestorsize, ancestorfees);
688
0
    }
689
690
    std::map<COutPoint, CAmount> calculateIndividualBumpFees(const std::vector<COutPoint>& outpoints, const CFeeRate& target_feerate) override
691
0
    {
692
0
        if (!m_node.mempool) {
693
0
            std::map<COutPoint, CAmount> bump_fees;
694
0
            for (const auto& outpoint : outpoints) {
695
0
                bump_fees.emplace(outpoint, 0);
696
0
            }
697
0
            return bump_fees;
698
0
        }
699
0
        return MiniMiner(*m_node.mempool, outpoints).CalculateBumpFees(target_feerate);
700
0
    }
701
702
    std::optional<CAmount> calculateCombinedBumpFee(const std::vector<COutPoint>& outpoints, const CFeeRate& target_feerate) override
703
0
    {
704
0
        if (!m_node.mempool) {
705
0
            return 0;
706
0
        }
707
0
        return MiniMiner(*m_node.mempool, outpoints).CalculateTotalBumpFees(target_feerate);
708
0
    }
709
    void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
710
0
    {
711
0
        const CTxMemPool::Limits default_limits{};
712
713
0
        const CTxMemPool::Limits& limits{m_node.mempool ? m_node.mempool->m_opts.limits : default_limits};
714
715
0
        limit_ancestor_count = limits.ancestor_count;
716
0
        limit_descendant_count = limits.descendant_count;
717
0
    }
718
    util::Result<void> checkChainLimits(const CTransactionRef& tx) override
719
0
    {
720
0
        if (!m_node.mempool) return {};
721
0
        if (!m_node.mempool->CheckPolicyLimits(tx)) {
722
0
            return util::Error{Untranslated("too many unconfirmed transactions in cluster")};
723
0
        }
724
0
        return {};
725
0
    }
726
    CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
727
0
    {
728
0
        if (!m_node.fee_estimator) return {};
729
0
        return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative);
730
0
    }
731
    unsigned int estimateMaxBlocks() override
732
0
    {
733
0
        if (!m_node.fee_estimator) return 0;
734
0
        return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
735
0
    }
736
    CFeeRate mempoolMinFee() override
737
0
    {
738
0
        if (!m_node.mempool) return {};
739
0
        return m_node.mempool->GetMinFee();
740
0
    }
741
    CFeeRate relayMinFee() override
742
0
    {
743
0
        if (!m_node.mempool) return CFeeRate{DEFAULT_MIN_RELAY_TX_FEE};
744
0
        return m_node.mempool->m_opts.min_relay_feerate;
745
0
    }
746
    CFeeRate relayIncrementalFee() override
747
0
    {
748
0
        if (!m_node.mempool) return CFeeRate{DEFAULT_INCREMENTAL_RELAY_FEE};
749
0
        return m_node.mempool->m_opts.incremental_relay_feerate;
750
0
    }
751
    CFeeRate relayDustFee() override
752
0
    {
753
0
        if (!m_node.mempool) return CFeeRate{DUST_RELAY_TX_FEE};
754
0
        return m_node.mempool->m_opts.dust_relay_feerate;
755
0
    }
756
    bool havePruned() override
757
0
    {
758
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
759
0
        return chainman().m_blockman.m_have_pruned;
760
0
    }
761
    std::optional<int> getPruneHeight() override
762
0
    {
763
0
        LOCK(chainman().GetMutex());
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
764
0
        return GetPruneHeight(chainman().m_blockman, chainman().ActiveChain());
765
0
    }
766
0
    bool isReadyToBroadcast() override { return !chainman().m_blockman.LoadingBlocks() && !isInitialBlockDownload(); }
767
    bool isInitialBlockDownload() override
768
0
    {
769
0
        return chainman().IsInitialBlockDownload();
770
0
    }
771
0
    bool shutdownRequested() override { return ShutdownRequested(m_node); }
772
0
    void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
773
0
    void initWarning(const bilingual_str& message) override { InitWarning(message); }
774
0
    void initError(const bilingual_str& message) override { InitError(message); }
775
    void showProgress(const std::string& title, int progress, bool resume_possible) override
776
0
    {
777
0
        ::uiInterface.ShowProgress(title, progress, resume_possible);
778
0
    }
779
    std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
780
0
    {
781
0
        return std::make_unique<NotificationsHandlerImpl>(validation_signals(), std::move(notifications));
782
0
    }
783
    void waitForNotificationsIfTipChanged(const uint256& old_tip) override
784
0
    {
785
0
        if (!old_tip.IsNull() && old_tip == WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()->GetBlockHash())) return;
Line
Count
Source
297
0
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
786
0
        validation_signals().SyncWithValidationInterfaceQueue();
787
0
    }
788
    void waitForNotifications() override
789
0
    {
790
0
        validation_signals().SyncWithValidationInterfaceQueue();
791
0
    }
792
    std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
793
0
    {
794
0
        return std::make_unique<RpcHandlerImpl>(command);
795
0
    }
796
0
    bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
797
    common::SettingsValue getSetting(const std::string& name) override
798
0
    {
799
0
        return args().GetSetting(name);
800
0
    }
801
    std::vector<common::SettingsValue> getSettingsList(const std::string& name) override
802
0
    {
803
0
        return args().GetSettingsList(name);
804
0
    }
805
    common::SettingsValue getRwSetting(const std::string& name) override
806
0
    {
807
0
        common::SettingsValue result;
808
0
        args().LockSettings([&](const common::Settings& settings) {
809
0
            if (const common::SettingsValue* value = common::FindKey(settings.rw_settings, name)) {
810
0
                result = *value;
811
0
            }
812
0
        });
813
0
        return result;
814
0
    }
815
    bool updateRwSetting(const std::string& name,
816
                         const interfaces::SettingsUpdate& update_settings_func) override
817
0
    {
818
0
        std::optional<interfaces::SettingsAction> action;
819
0
        args().LockSettings([&](common::Settings& settings) {
820
0
            if (auto* value = common::FindKey(settings.rw_settings, name)) {
821
0
                action = update_settings_func(*value);
822
0
                if (value->isNull()) settings.rw_settings.erase(name);
823
0
            } else {
824
0
                UniValue new_value;
825
0
                action = update_settings_func(new_value);
826
0
                if (!new_value.isNull()) settings.rw_settings[name] = std::move(new_value);
827
0
            }
828
0
        });
829
0
        if (!action) return false;
830
        // Now dump value to disk if requested
831
0
        return *action != interfaces::SettingsAction::WRITE || args().WriteSettingsFile();
832
0
    }
833
    bool overwriteRwSetting(const std::string& name, common::SettingsValue value, interfaces::SettingsAction action) override
834
0
    {
835
0
        return updateRwSetting(name, [&](common::SettingsValue& settings) {
836
0
            settings = std::move(value);
837
0
            return action;
838
0
        });
839
0
    }
840
    bool deleteRwSettings(const std::string& name, interfaces::SettingsAction action) override
841
0
    {
842
0
        return overwriteRwSetting(name, {}, action);
843
0
    }
844
    void requestMempoolTransactions(Notifications& notifications) override
845
0
    {
846
0
        if (!m_node.mempool) return;
847
0
        LOCK2(::cs_main, m_node.mempool->cs);
Line
Count
Source
268
0
    UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
269
0
    UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
848
0
        for (const CTxMemPoolEntry& entry : m_node.mempool->entryAll()) {
849
0
            notifications.transactionAddedToMempool(entry.GetSharedTx());
850
0
        }
851
0
    }
852
    bool hasAssumedValidChain() override
853
0
    {
854
0
        LOCK(::cs_main);
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
855
0
        return bool{chainman().CurrentChainstate().m_from_snapshot_blockhash};
856
0
    }
857
858
0
    NodeContext* context() override { return &m_node; }
859
0
    ArgsManager& args() { return *Assert(m_node.args); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
860
0
    ChainstateManager& chainman() { return *Assert(m_node.chainman); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
861
0
    ValidationSignals& validation_signals() { return *Assert(m_node.validation_signals); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
862
    NodeContext& m_node;
863
};
864
865
class BlockTemplateImpl : public BlockTemplate
866
{
867
public:
868
    explicit BlockTemplateImpl(BlockAssembler::Options assemble_options,
869
                               std::unique_ptr<CBlockTemplate> block_template,
870
0
                               NodeContext& node) : m_assemble_options(std::move(assemble_options)),
871
0
                                                    m_block_template(std::move(block_template)),
872
0
                                                    m_node(node)
873
0
    {
874
0
        assert(m_block_template);
875
0
    }
876
877
    CBlockHeader getBlockHeader() override
878
0
    {
879
0
        return m_block_template->block;
880
0
    }
881
882
    CBlock getBlock() override
883
0
    {
884
0
        return m_block_template->block;
885
0
    }
886
887
    std::vector<CAmount> getTxFees() override
888
0
    {
889
0
        return m_block_template->vTxFees;
890
0
    }
891
892
    std::vector<int64_t> getTxSigops() override
893
0
    {
894
0
        return m_block_template->vTxSigOpsCost;
895
0
    }
896
897
    CoinbaseTx getCoinbaseTx() override
898
0
    {
899
0
        return m_block_template->m_coinbase_tx;
900
0
    }
901
902
    std::vector<uint256> getCoinbaseMerklePath() override
903
0
    {
904
0
        return TransactionMerklePath(m_block_template->block, 0);
905
0
    }
906
907
    bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase) override
908
0
    {
909
0
        AddMerkleRootAndCoinbase(m_block_template->block, std::move(coinbase), version, timestamp, nonce);
910
0
        return chainman().ProcessNewBlock(std::make_shared<const CBlock>(m_block_template->block), /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/nullptr);
911
0
    }
912
913
    std::unique_ptr<BlockTemplate> waitNext(BlockWaitOptions options) override
914
0
    {
915
0
        auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options, m_interrupt_wait);
916
0
        if (new_template) return std::make_unique<BlockTemplateImpl>(m_assemble_options, std::move(new_template), m_node);
917
0
        return nullptr;
918
0
    }
919
920
    void interruptWait() override
921
0
    {
922
0
        InterruptWait(notifications(), m_interrupt_wait);
923
0
    }
924
925
    const BlockAssembler::Options m_assemble_options;
926
927
    const std::unique_ptr<CBlockTemplate> m_block_template;
928
929
    bool m_interrupt_wait{false};
930
0
    ChainstateManager& chainman() { return *Assert(m_node.chainman); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
931
0
    KernelNotifications& notifications() { return *Assert(m_node.notifications); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
932
    NodeContext& m_node;
933
};
934
935
class MinerImpl : public Mining
936
{
937
public:
938
0
    explicit MinerImpl(NodeContext& node) : m_node(node) {}
939
940
    bool isTestChain() override
941
0
    {
942
0
        return chainman().GetParams().IsTestChain();
943
0
    }
944
945
    bool isInitialBlockDownload() override
946
0
    {
947
0
        return chainman().IsInitialBlockDownload();
948
0
    }
949
950
    std::optional<BlockRef> getTip() override
951
0
    {
952
0
        return GetTip(chainman());
953
0
    }
954
955
    std::optional<BlockRef> waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
956
0
    {
957
0
        return WaitTipChanged(chainman(), notifications(), current_tip, timeout, m_interrupt_mining);
958
0
    }
959
960
    std::unique_ptr<BlockTemplate> createNewBlock(const BlockCreateOptions& options, bool cooldown) override
961
0
    {
962
        // Reject too-small values instead of clamping so callers don't silently
963
        // end up mining with different options than requested. This matches the
964
        // behavior of the `-blockreservedweight` startup option, which rejects
965
        // values below MINIMUM_BLOCK_RESERVED_WEIGHT.
966
0
        if (options.block_reserved_weight && options.block_reserved_weight < MINIMUM_BLOCK_RESERVED_WEIGHT) {
967
0
            throw std::runtime_error(strprintf("block_reserved_weight (%zu) must be at least %u weight units",
Line
Count
Source
1172
0
#define strprintf tfm::format
968
0
                                               *options.block_reserved_weight,
969
0
                                               MINIMUM_BLOCK_RESERVED_WEIGHT));
970
0
        }
971
972
        // Ensure m_tip_block is set so consumers of BlockTemplate can rely on that.
973
0
        std::optional<BlockRef> maybe_tip{waitTipChanged(uint256::ZERO, MillisecondsDouble::max())};
974
975
0
        if (!maybe_tip) return {};
976
977
0
        if (cooldown) {
978
            // Do not return a template during IBD, because it can have long
979
            // pauses and sometimes takes a while to get started. Although this
980
            // is useful in general, it's gated behind the cooldown argument,
981
            // because on regtest and single miner signets this would wait
982
            // forever if no block was mined in the past day.
983
0
            while (chainman().IsInitialBlockDownload()) {
984
0
                maybe_tip = waitTipChanged(maybe_tip->hash, MillisecondsDouble{1000});
985
0
                if (!maybe_tip || chainman().m_interrupt || WITH_LOCK(notifications().m_tip_block_mutex, return m_interrupt_mining)) return {};
Line
Count
Source
297
0
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
986
0
            }
987
988
            // Also wait during the final catch-up moments after IBD.
989
0
            if (!CooldownIfHeadersAhead(chainman(), notifications(), *maybe_tip, m_interrupt_mining)) return {};
990
0
        }
991
992
0
        BlockAssembler::Options assemble_options{options};
993
0
        ApplyArgsManOptions(*Assert(m_node.args), assemble_options);
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
994
0
        return std::make_unique<BlockTemplateImpl>(assemble_options, BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(), m_node);
995
0
    }
996
997
    void interrupt() override
998
0
    {
999
0
        InterruptWait(notifications(), m_interrupt_mining);
1000
0
    }
1001
1002
    bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) override
1003
0
    {
1004
0
        LOCK(chainman().GetMutex());
Line
Count
Source
266
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
1005
0
        BlockValidationState state{TestBlockValidity(chainman().ActiveChainstate(), block, /*check_pow=*/options.check_pow, /*check_merkle_root=*/options.check_merkle_root)};
1006
0
        reason = state.GetRejectReason();
1007
0
        debug = state.GetDebugMessage();
1008
0
        return state.IsValid();
1009
0
    }
1010
1011
0
    NodeContext* context() override { return &m_node; }
1012
0
    ChainstateManager& chainman() { return *Assert(m_node.chainman); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
1013
0
    KernelNotifications& notifications() { return *Assert(m_node.notifications); }
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
1014
    // Treat as if guarded by notifications().m_tip_block_mutex
1015
    bool m_interrupt_mining{false};
1016
    NodeContext& m_node;
1017
};
1018
} // namespace
1019
} // namespace node
1020
1021
namespace interfaces {
1022
0
std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
1023
0
std::unique_ptr<Chain> MakeChain(node::NodeContext& context) { return std::make_unique<node::ChainImpl>(context); }
1024
std::unique_ptr<Mining> MakeMining(node::NodeContext& context, bool wait_loaded)
1025
0
{
1026
0
    if (wait_loaded) {
1027
0
        node::KernelNotifications& kernel_notifications(*Assert(context.notifications));
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
1028
0
        util::SignalInterrupt& interrupt(*Assert(context.shutdown_signal));
Line
Count
Source
113
0
#define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
1029
0
        WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
Line
Count
Source
272
0
#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
Line
Count
Source
270
0
#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
1030
0
        kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
1031
0
            return kernel_notifications.m_state.chainstate_loaded || interrupt;
1032
0
        });
1033
0
        if (interrupt) return nullptr;
1034
0
    }
1035
0
    return std::make_unique<node::MinerImpl>(context);
1036
0
}
1037
} // namespace interfaces