Coverage Report

Created: 2026-04-29 19:21

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