Coverage Report

Created: 2026-09-14 20:36

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