Coverage Report

Created: 2025-04-14 16:24

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