Coverage Report

Created: 2026-05-30 09:47

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