Coverage Report

Created: 2026-10-07 20:27

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