Coverage Report

Created: 2026-07-14 18:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/bitcoin/src/init.cpp
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
#include <bitcoin-build-config.h> // IWYU pragma: keep
7
8
#include <init.h>
9
10
#include <addrdb.h>
11
#include <addrman.h>
12
#include <banman.h>
13
#include <blockfilter.h>
14
#include <chain.h>
15
#include <chainparams.h>
16
#include <chainparamsbase.h>
17
#include <clientversion.h>
18
#include <common/args.h>
19
#include <common/messages.h>
20
#include <common/system.h>
21
#include <compat/compat.h>
22
#include <consensus/params.h>
23
#include <crypto/hex_base.h>
24
#include <dbwrapper.h>
25
#include <httprpc.h>
26
#include <httpserver.h>
27
#include <index/base.h>
28
#include <index/blockfilterindex.h>
29
#include <index/coinstatsindex.h>
30
#include <index/txindex.h>
31
#include <index/txospenderindex.h>
32
#include <init/common.h>
33
#include <interfaces/chain.h>
34
#include <interfaces/init.h>
35
#include <interfaces/ipc.h>
36
#include <interfaces/mining.h>
37
#include <interfaces/node.h>
38
#include <ipc/exception.h>
39
#include <kernel/blockmanager_opts.h>
40
#include <kernel/caches.h>
41
#include <kernel/chainstatemanager_opts.h>
42
#include <kernel/checks.h>
43
#include <kernel/context.h>
44
#include <kernel/notifications_interface.h>
45
#include <key.h>
46
#include <logging.h>
47
#include <mapport.h>
48
#include <net.h>
49
#include <net_permissions.h>
50
#include <net_processing.h>
51
#include <netaddress.h>
52
#include <netbase.h>
53
#include <netgroup.h>
54
#include <node/blockmanager_args.h>
55
#include <node/blockstorage.h>
56
#include <node/caches.h>
57
#include <node/chainstate.h>
58
#include <node/chainstatemanager_args.h>
59
#include <node/context.h>
60
#include <node/interface_ui.h>
61
#include <node/kernel_notifications.h>
62
#include <node/mempool_args.h>
63
#include <node/mempool_persist.h>
64
#include <node/mempool_persist_args.h>
65
#include <node/mining_args.h>
66
#include <node/mining_types.h>
67
#include <node/peerman_args.h>
68
#include <policy/feerate.h>
69
#include <policy/fees/block_policy_estimator.h>
70
#include <policy/fees/block_policy_estimator_args.h>
71
#include <policy/policy.h>
72
#include <policy/settings.h>
73
#include <protocol.h>
74
#include <random.h>
75
#include <rpc/register.h>
76
#include <rpc/server.h>
77
#include <rpc/util.h>
78
#include <scheduler.h>
79
#include <script/sigcache.h>
80
#include <sync.h>
81
#include <tinyformat.h>
82
#include <torcontrol.h>
83
#include <txgraph.h>
84
#include <txmempool.h>
85
#include <uint256.h>
86
#include <util/asmap.h>
87
#include <util/batchpriority.h>
88
#include <util/btcsignals.h>
89
#include <util/chaintype.h>
90
#include <util/check.h>
91
#include <util/fs.h>
92
#include <util/fs_helpers.h>
93
#include <util/moneystr.h>
94
#include <util/result.h>
95
#include <util/signalinterrupt.h>
96
#include <util/strencodings.h>
97
#include <util/string.h>
98
#include <util/syserror.h>
99
#include <util/thread.h>
100
#include <util/threadnames.h>
101
#include <util/time.h>
102
#include <util/translation.h>
103
#include <validation.h>
104
#include <validationinterface.h>
105
#include <walletinitinterface.h>
106
107
#include <algorithm>
108
#include <any>
109
#include <cerrno>
110
#include <condition_variable>
111
#include <cstddef>
112
#include <cstdint>
113
#include <exception>
114
#include <fstream>
115
#include <functional>
116
#include <initializer_list>
117
#include <list>
118
#include <memory>
119
#include <new>
120
#include <optional>
121
#include <set>
122
#include <span>
123
#include <string>
124
#include <system_error>
125
#include <thread>
126
#include <tuple>
127
#include <utility>
128
#include <variant>
129
#include <vector>
130
131
#ifndef WIN32
132
#include <csignal>
133
#endif
134
135
#ifdef ENABLE_ZMQ
136
#include <zmq/zmqabstractnotifier.h>
137
#include <zmq/zmqnotificationinterface.h>
138
#include <zmq/zmqrpc.h>
139
#endif
140
141
#ifdef ENABLE_EMBEDDED_ASMAP
142
#include <node/data/ip_asn.dat.h>
143
#endif
144
145
using common::InvalidPortErrMsg;
146
using common::ResolveErrMsg;
147
148
using http_bitcoin::InitHTTPServer;
149
using http_bitcoin::InterruptHTTPServer;
150
using http_bitcoin::StartHTTPServer;
151
using http_bitcoin::StopHTTPServer;
152
using node::ApplyArgsManOptions;
153
using node::BlockManager;
154
using node::CalculateCacheSizes;
155
using node::ChainstateLoadResult;
156
using node::ChainstateLoadStatus;
157
using node::DEFAULT_PERSIST_MEMPOOL;
158
using node::DEFAULT_PRINT_MODIFIED_FEE;
159
using node::DEFAULT_STOPATHEIGHT;
160
using node::DumpMempool;
161
using node::ImportBlocks;
162
using node::KernelNotifications;
163
using node::LoadChainstate;
164
using node::LoadMempool;
165
using node::MempoolPath;
166
using node::NodeContext;
167
using node::ShouldPersistMempool;
168
using node::VerifyLoadedChainstate;
169
using util::Join;
170
using util::ReplaceAll;
171
using util::ToString;
172
173
static constexpr bool DEFAULT_PROXYRANDOMIZE{true};
174
static constexpr bool DEFAULT_REST_ENABLE{false};
175
static constexpr bool DEFAULT_I2P_ACCEPT_INCOMING{true};
176
static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false};
177
178
#ifdef WIN32
179
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
180
// accessing block files don't count towards the fd_set size limit
181
// anyway.
182
#define MIN_LEVELDB_FDS 0
183
#else
184
#define MIN_LEVELDB_FDS 150
185
#endif
186
187
static constexpr int MIN_CORE_FDS = MIN_LEVELDB_FDS + NUM_FDS_MESSAGE_CAPTURE;
188
189
/**
190
 * The PID file facilities.
191
 */
192
static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
193
/**
194
 * True if this process has created a PID file.
195
 * Used to determine whether we should remove the PID file on shutdown.
196
 */
197
static bool g_generated_pid{false};
198
199
static fs::path GetPidFile(const ArgsManager& args)
200
150k
{
201
150k
    return AbsPathForConfigVal(args, args.GetPathArg("-pid", BITCOIN_PID_FILENAME));
202
150k
}
203
204
[[nodiscard]] static bool CreatePidFile(const ArgsManager& args)
205
27
{
206
27
    if (args.IsArgNegated("-pid")) return true;
  Branch (206:9): [True: 0, False: 27]
207
208
27
    std::ofstream file{GetPidFile(args).std_path()};
209
27
    if (file) {
  Branch (209:9): [True: 27, False: 0]
210
#ifdef WIN32
211
        tfm::format(file, "%d\n", GetCurrentProcessId());
212
#else
213
27
        tfm::format(file, "%d\n", getpid());
214
27
#endif
215
27
        g_generated_pid = true;
216
27
        return true;
217
27
    } else {
218
0
        return InitError(strprintf(_("Unable to create the PID file '%s': %s"), fs::PathToString(GetPidFile(args)), SysErrorString(errno)));
219
0
    }
220
27
}
221
222
static void RemovePidFile(const ArgsManager& args)
223
150k
{
224
150k
    if (!g_generated_pid) return;
  Branch (224:9): [True: 0, False: 150k]
225
150k
    const auto pid_path{GetPidFile(args)};
226
150k
    if (std::error_code error; !fs::remove(pid_path, error)) {
  Branch (226:32): [True: 0, False: 150k]
227
0
        std::string msg{error ? error.message() : "File does not exist"};
  Branch (227:25): [True: 0, False: 0]
228
0
        LogWarning("Unable to remove PID file (%s): %s", fs::PathToString(pid_path), msg);
229
0
    }
230
150k
}
231
232
static std::optional<util::SignalInterrupt> g_shutdown;
233
234
void InitContext(NodeContext& node)
235
27
{
236
27
    assert(!g_shutdown);
  Branch (236:5): [True: 27, False: 0]
237
27
    g_shutdown.emplace();
238
239
27
    node.args = &gArgs;
240
27
    node.shutdown_signal = &*g_shutdown;
241
140k
    node.shutdown_request = [&node] {
242
140k
        assert(node.shutdown_signal);
  Branch (242:9): [True: 140k, False: 0]
243
140k
        if (!(*node.shutdown_signal)()) return false;
  Branch (243:13): [True: 0, False: 140k]
244
140k
        return true;
245
140k
    };
246
27
}
247
248
//////////////////////////////////////////////////////////////////////////////
249
//
250
// Shutdown
251
//
252
253
//
254
// Thread management and startup/shutdown:
255
//
256
// The network-processing threads are all part of a thread group
257
// created by AppInit() or the Qt main() function.
258
//
259
// A clean exit happens when the SignalInterrupt object is triggered, which
260
// makes the main thread's SignalInterrupt::wait() call return, and join all
261
// other ongoing threads in the thread group to the main thread.
262
// Shutdown() is then called to clean up database connections, and stop other
263
// threads that should only be stopped after the main network-processing
264
// threads have exited.
265
//
266
// Shutdown for Qt is very similar, only it uses a QTimer to detect
267
// ShutdownRequested() getting set, and then does the normal Qt
268
// shutdown thing.
269
//
270
271
bool ShutdownRequested(node::NodeContext& node)
272
81
{
273
81
    return bool{*Assert(node.shutdown_signal)};
274
81
}
275
276
#if HAVE_SYSTEM
277
static void ShutdownNotify(const ArgsManager& args)
278
150k
{
279
150k
    std::vector<std::thread> threads;
280
150k
    for (const auto& cmd : args.GetArgs("-shutdownnotify")) {
  Branch (280:26): [True: 0, False: 150k]
281
0
        threads.emplace_back(runCommand, cmd);
282
0
    }
283
150k
    for (auto& t : threads) {
  Branch (283:18): [True: 0, False: 150k]
284
0
        t.join();
285
0
    }
286
150k
}
287
#endif
288
289
void Interrupt(NodeContext& node)
290
150k
{
291
150k
#if HAVE_SYSTEM
292
150k
    ShutdownNotify(*node.args);
293
150k
#endif
294
    // Wake any threads that may be waiting for the tip to change.
295
150k
    if (node.notifications) WITH_LOCK(node.notifications->m_tip_block_mutex, node.notifications->m_tip_block_cv.notify_all());
  Branch (295:9): [True: 150k, False: 0]
296
150k
    InterruptHTTPServer();
297
150k
    InterruptHTTPRPC();
298
150k
    InterruptRPC();
299
150k
    InterruptREST();
300
150k
    if (node.tor_controller) {
  Branch (300:9): [True: 0, False: 150k]
301
0
        node.tor_controller->Interrupt();
302
0
    }
303
150k
    InterruptMapPort();
304
150k
    if (node.connman)
  Branch (304:9): [True: 150k, False: 0]
305
150k
        node.connman->Interrupt();
306
150k
    for (auto* index : node.indexes) {
  Branch (306:22): [True: 150k, False: 150k]
307
150k
        index->Interrupt();
308
150k
    }
309
150k
}
310
311
void Shutdown(NodeContext& node)
312
150k
{
313
150k
    static Mutex g_shutdown_mutex;
314
150k
    TRY_LOCK(g_shutdown_mutex, lock_shutdown);
315
150k
    if (!lock_shutdown) return;
  Branch (315:9): [True: 0, False: 150k]
316
150k
    LogInfo("Shutdown in progress...");
317
150k
    Assert(node.args);
318
319
    /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,
320
    /// for example if the data directory was found to be locked.
321
    /// Be sure that anything that writes files or flushes caches only does this if the respective
322
    /// module was initialized.
323
150k
    util::ThreadRename("shutoff");
324
150k
    if (node.mempool) node.mempool->AddTransactionsUpdated(1);
  Branch (324:9): [True: 150k, False: 0]
325
326
150k
    StopHTTPRPC();
327
150k
    StopREST();
328
150k
    StopRPC();
329
150k
    StopHTTPServer();
330
150k
    for (auto& client : node.chain_clients) {
  Branch (330:23): [True: 150k, False: 150k]
331
150k
        try {
332
150k
            client->stop();
333
150k
        } catch (const ipc::Exception& e) {
334
0
            LogDebug(BCLog::IPC, "Chain client did not disconnect cleanly: %s", e.what());
335
0
            client.reset();
336
0
        }
337
150k
    }
338
150k
    StopMapPort();
339
340
    // Because these depend on each-other, we make sure that neither can be
341
    // using the other before destroying them.
342
150k
    if (node.peerman && node.validation_signals) node.validation_signals->UnregisterValidationInterface(node.peerman.get());
  Branch (342:9): [True: 150k, False: 0]
  Branch (342:25): [True: 150k, False: 0]
343
150k
    if (node.connman) node.connman->Stop();
  Branch (343:9): [True: 150k, False: 0]
344
345
150k
    if (node.tor_controller) {
  Branch (345:9): [True: 0, False: 150k]
346
0
        node.tor_controller->Join();
347
0
        node.tor_controller.reset();
348
0
    }
349
350
150k
    if (node.background_init_thread.joinable()) node.background_init_thread.join();
  Branch (350:9): [True: 150k, False: 0]
351
    // After everything has been shut down, but before things get flushed, stop the
352
    // the scheduler. After this point, SyncWithValidationInterfaceQueue() should not be called anymore
353
    // as this would prevent the shutdown from completing.
354
150k
    if (node.scheduler) node.scheduler->stop();
  Branch (354:9): [True: 150k, False: 0]
355
356
    // After the threads that potentially access these pointers have been stopped,
357
    // destruct and reset all to nullptr.
358
150k
    node.peerman.reset();
359
150k
    node.connman.reset();
360
150k
    node.banman.reset();
361
150k
    node.addrman.reset();
362
150k
    node.netgroupman.reset();
363
364
150k
    if (node.mempool && node.mempool->GetLoadTried() && ShouldPersistMempool(*node.args)) {
  Branch (364:9): [True: 150k, False: 0]
  Branch (364:25): [True: 150k, False: 0]
  Branch (364:57): [True: 150k, False: 0]
365
150k
        DumpMempool(*node.mempool, MempoolPath(*node.args));
366
150k
    }
367
368
    // Drop transactions we were still watching, record fee estimations and unregister
369
    // fee estimator from validation interface.
370
150k
    if (node.fee_estimator) {
  Branch (370:9): [True: 150k, False: 0]
371
150k
        node.fee_estimator->Flush();
372
150k
        if (node.validation_signals) {
  Branch (372:13): [True: 150k, False: 0]
373
150k
            node.validation_signals->UnregisterValidationInterface(node.fee_estimator.get());
374
150k
        }
375
150k
    }
376
377
    // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
378
150k
    if (node.chainman) {
  Branch (378:9): [True: 150k, False: 0]
379
150k
        LOCK(cs_main);
380
150k
        for (const auto& chainstate : node.chainman->m_chainstates) {
  Branch (380:37): [True: 150k, False: 150k]
381
150k
            if (chainstate->CanFlushToDisk()) {
  Branch (381:17): [True: 150k, False: 0]
382
150k
                chainstate->ForceFlushStateToDisk();
383
150k
            }
384
150k
        }
385
150k
    }
386
387
    // After there are no more peers/RPC left to give us new data which may generate
388
    // CValidationInterface callbacks, flush them...
389
150k
    if (node.validation_signals) node.validation_signals->FlushBackgroundCallbacks();
  Branch (389:9): [True: 150k, False: 0]
390
391
    // Stop and delete all indexes only after flushing background callbacks.
392
150k
    for (auto* index : node.indexes) index->Stop();
  Branch (392:22): [True: 150k, False: 150k]
393
150k
    if (g_txindex) g_txindex.reset();
  Branch (393:9): [True: 0, False: 150k]
394
150k
    if (g_txospenderindex) g_txospenderindex.reset();
  Branch (394:9): [True: 0, False: 150k]
395
150k
    if (g_coin_stats_index) g_coin_stats_index.reset();
  Branch (395:9): [True: 0, False: 150k]
396
150k
    DestroyAllBlockFilterIndexes();
397
150k
    node.indexes.clear(); // all instances are nullptr now
398
399
    // Any future callbacks will be dropped. This should absolutely be safe - if
400
    // missing a callback results in an unrecoverable situation, unclean shutdown
401
    // would too. The only reason to do the above flushes is to let the wallet catch
402
    // up with our current chain to avoid any strange pruning edge cases and make
403
    // next startup faster by avoiding rescan.
404
405
150k
    if (node.chainman) {
  Branch (405:9): [True: 150k, False: 0]
406
150k
        LOCK(cs_main);
407
150k
        for (const auto& chainstate : node.chainman->m_chainstates) {
  Branch (407:37): [True: 150k, False: 150k]
408
150k
            if (chainstate->CanFlushToDisk()) {
  Branch (408:17): [True: 150k, False: 0]
409
150k
                chainstate->ForceFlushStateToDisk();
410
150k
                chainstate->ResetCoinsViews();
411
150k
            }
412
150k
        }
413
150k
    }
414
415
    // If any -ipcbind clients are still connected, disconnect them now so they
416
    // do not block shutdown.
417
150k
    if (interfaces::Ipc* ipc = node.init->ipc()) {
  Branch (417:26): [True: 0, False: 150k]
418
0
        ipc->disconnectIncoming();
419
0
    }
420
421
#ifdef ENABLE_ZMQ
422
    if (g_zmq_notification_interface) {
423
        if (node.validation_signals) node.validation_signals->UnregisterValidationInterface(g_zmq_notification_interface.get());
424
        g_zmq_notification_interface.reset();
425
    }
426
#endif
427
428
150k
    node.chain_clients.clear();
429
150k
    if (node.validation_signals) {
  Branch (429:9): [True: 150k, False: 0]
430
150k
        node.validation_signals->UnregisterAllValidationInterfaces();
431
150k
    }
432
150k
    node.mempool.reset();
433
150k
    node.fee_estimator.reset();
434
150k
    node.chainman.reset();
435
150k
    node.validation_signals.reset();
436
150k
    node.scheduler.reset();
437
150k
    node.ecc_context.reset();
438
150k
    node.kernel.reset();
439
440
150k
    RemovePidFile(*node.args);
441
442
150k
    LogInfo("Shutdown done");
443
150k
}
444
445
/**
446
 * Signal handlers are very limited in what they are allowed to do.
447
 * The execution context the handler is invoked in is not guaranteed,
448
 * so we restrict handler operations to just touching variables:
449
 */
450
#ifndef WIN32
451
static void HandleSIGTERM(int)
452
0
{
453
    // Return value is intentionally ignored because there is not a better way
454
    // of handling this failure in a signal handler.
455
0
    (void)(*Assert(g_shutdown))();
456
0
}
457
458
static void HandleSIGHUP(int)
459
0
{
460
0
    LogInstance().m_reopen_file = true;
461
0
}
462
463
#if defined(__clang__)
464
extern "C" __attribute__((weak)) void __llvm_profile_reset_counters(void);
465
0
extern "C" __attribute__((weak)) void __llvm_profile_reset_counters(void) {}
466
467
static void HandleSIGUSR1(int)
468
0
{
469
0
    __llvm_profile_reset_counters();
470
0
}
471
#endif
472
473
#else
474
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
475
{
476
    if (!(*Assert(g_shutdown))()) {
477
        LogError("Failed to send shutdown signal on Ctrl-C\n");
478
        return false;
479
    }
480
    Sleep(INFINITE);
481
    return true;
482
}
483
#endif
484
485
#ifndef WIN32
486
static void registerSignalHandler(int signal, void(*handler)(int))
487
108
{
488
108
    struct sigaction sa;
489
108
    sa.sa_handler = handler;
490
108
    sigemptyset(&sa.sa_mask);
491
108
    sa.sa_flags = 0;
492
108
    sigaction(signal, &sa, nullptr);
493
108
}
494
#endif
495
496
void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
497
27
{
498
27
    SetupHelpOptions(argsman);
499
27
    argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now
500
501
27
    init::AddLoggingArgs(argsman);
502
503
27
    const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN);
504
27
    const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET);
505
27
    const auto testnet4BaseParams = CreateBaseChainParams(ChainType::TESTNET4);
506
27
    const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET);
507
27
    const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST);
508
27
    const auto defaultChainParams = CreateChainParams(argsman, ChainType::MAIN);
509
27
    const auto testnetChainParams = CreateChainParams(argsman, ChainType::TESTNET);
510
27
    const auto testnet4ChainParams = CreateChainParams(argsman, ChainType::TESTNET4);
511
27
    const auto signetChainParams = CreateChainParams(argsman, ChainType::SIGNET);
512
27
    const auto regtestChainParams = CreateChainParams(argsman, ChainType::REGTEST);
513
514
    // Hidden Options
515
27
    std::vector<std::string> hidden_args = {
516
27
        "-dbcrashratio", "-forcecompactdb",
517
        // GUI args. These will be overwritten by SetupUIArgs for the GUI
518
27
        "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-splash", "-uiplatform"};
519
520
27
    argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
521
27
#if HAVE_SYSTEM
522
27
    argsman.AddArg("-alertnotify=<cmd>", "Execute command when an alert is raised (%s in cmd is replaced by message)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
523
27
#endif
524
27
    argsman.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnet4ChainParams->GetConsensus().defaultAssumeValid.GetHex(), signetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
525
27
    argsman.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
526
27
    argsman.AddArg("-blocksxor",
527
27
                   strprintf("Whether an XOR-key applies to blocksdir *.dat files. "
528
27
                             "The created XOR-key will be zeros for an existing blocksdir or when `-blocksxor=0` is "
529
27
                             "set, and random for a freshly initialized blocksdir. "
530
27
                             "(default: %u)",
531
27
                             kernel::DEFAULT_XOR_BLOCKSDIR),
532
27
                   ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
533
27
    argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
534
27
#if HAVE_SYSTEM
535
27
    argsman.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
536
27
#endif
537
27
    argsman.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
538
27
    argsman.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Disables automatic broadcast and rebroadcast of transactions, unless the source peer has the 'forcerelay' permission. RPC transactions are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
539
27
    argsman.AddArg("-coinstatsindex", strprintf("Maintain coinstats index used by the gettxoutsetinfo RPC (default: %u)", DEFAULT_COINSTATSINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
540
27
    argsman.AddArg("-conf=<file>", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location (only useable from command line, not configuration file) (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
541
27
    argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
542
27
    argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", DEFAULT_DB_CACHE_BATCH), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
543
27
    argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (minimum %d, default: %d). Make sure you have enough RAM. In addition, unused memory allocated to the mempool is shared with this cache (see -maxmempool).", MIN_DB_CACHE >> 20, node::GetDefaultDBCache() >> 20), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
544
27
    argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
545
27
    argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
546
27
    argsman.AddArg("-loadblock=<file>", "Imports blocks from an external file on startup. Obfuscated blocks are not supported.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
547
27
    argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
548
27
    argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
549
27
    argsman.AddArg("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnet4ChainParams->GetConsensus().nMinimumChainWork.GetHex(), signetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
550
27
    argsman.AddArg("-par=<n>", strprintf("Set the number of script verification threads (0 = auto, up to %d, <0 = leave that many cores free, default: %d)",
551
27
        MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
552
27
    argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
553
27
    argsman.AddArg("-persistmempoolv1",
554
27
                   strprintf("Whether a mempool.dat file created by -persistmempool or the savemempool RPC will be written in the legacy format "
555
27
                             "(version 1) or the current format (version 2). This temporary option will be removed in the future. (default: %u)",
556
27
                             DEFAULT_PERSIST_V1_DAT),
557
27
                   ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
558
27
    argsman.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
559
27
    argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex. "
560
27
            "Warning: Reverting this setting requires re-downloading the entire blockchain. "
561
27
            "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1_MiB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
562
27
    argsman.AddArg("-reindex", "If enabled, wipe chain state and block index, and rebuild them from blk*.dat files on disk. Also wipe and rebuild other optional indexes that are active. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
563
27
    argsman.AddArg("-reindex-chainstate", "If enabled, wipe chain state, and rebuild it from blk*.dat files on disk. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
564
27
    argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
565
27
#if HAVE_SYSTEM
566
27
    argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
567
27
    argsman.AddArg("-shutdownnotify=<cmd>", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
568
27
#endif
569
27
    argsman.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
570
27
    argsman.AddArg("-txospenderindex", strprintf("Maintain a transaction output spender index, used by the gettxspendingprevout rpc call (default: %u)", DEFAULT_TXOSPENDERINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
571
27
    argsman.AddArg("-blockfilterindex=<type>",
572
27
                 strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
573
27
                 " If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
574
27
                 ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
575
576
27
    argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
577
27
    argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers. Relative paths will be prefixed by the net-specific datadir location.%s",
578
27
                #ifdef ENABLE_EMBEDDED_ASMAP
579
27
                    " If a bool arg is given (-asmap or -asmap=1), the embedded mapping data in the binary will be used."
580
                #else
581
                    ""
582
                #endif
583
27
                ), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
584
27
    argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
585
27
    argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultChainParams->GetDefaultPort() + 1, testnetChainParams->GetDefaultPort() + 1, testnet4ChainParams->GetDefaultPort() + 1, signetChainParams->GetDefaultPort() + 1, regtestChainParams->GetDefaultPort() + 1), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
586
27
    argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
587
27
    argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
588
27
    argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
589
27
    argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
590
27
    argsman.AddArg("-dnsseed", strprintf("Query for peer addresses via DNS lookup, if low on addresses (default: %u unless -connect used or -maxconnections=0)", DEFAULT_DNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
591
27
    argsman.AddArg("-externalip=<ip>", "Specify your own public address", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
592
27
    argsman.AddArg("-fixedseeds", strprintf("Allow fixed seeds if DNS seeds don't provide peers (default: %u)", DEFAULT_FIXEDSEEDS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
593
27
    argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
594
27
    argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
595
27
    argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
596
27
    argsman.AddArg("-maxconnections=<n>", strprintf("Maintain at most <n> automatic connections to peers (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u. It does not apply to short-lived private broadcast connections either, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS, MAX_PRIVATE_BROADCAST_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
597
27
    argsman.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
598
27
    argsman.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection memory usage for the send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
599
27
    argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
600
27
#ifdef HAVE_SOCKADDR_UN
601
27
    argsman.AddArg("-onion=<ip:port|path>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy). May be a local file path prefixed with 'unix:'.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
602
#else
603
    argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
604
#endif
605
27
    argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
606
27
    argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
607
27
    argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
608
27
    argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
609
27
    argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
610
27
    argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
611
27
    argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
612
27
    argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md). If set to a value x, the default onion listening port will be set to x+1.", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), testnet4ChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
613
27
    const std::string proxy_doc_for_value =
614
27
#ifdef HAVE_SOCKADDR_UN
615
27
        "<ip>[:<port>]|unix:<path>";
616
#else
617
        "<ip>[:<port>]";
618
#endif
619
27
    const std::string proxy_doc_for_unix_socket =
620
27
#ifdef HAVE_SOCKADDR_UN
621
27
        "May be a local file path prefixed with 'unix:' if the proxy supports it. ";
622
#else
623
        "";
624
#endif
625
27
    argsman.AddArg("-proxy=" + proxy_doc_for_value + "[=<network>]",
626
27
                   "Connect through SOCKS5 proxy, set -noproxy to disable. " +
627
27
                   proxy_doc_for_unix_socket +
628
27
                   "Could end in =network to set the proxy only for that network. " +
629
27
                   "The network can be any of ipv4, ipv6, tor or cjdns. " +
630
27
                   "(default: disabled)",
631
27
                   ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION,
632
27
                   OptionsCategory::CONNECTION);
633
27
    argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
634
27
    argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes. During startup, seednodes will be tried before dnsseeds.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
635
27
    argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
636
27
    argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
637
27
    argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
638
27
    argsman.AddArg("-torcontrol=<ip>:<port>", strprintf("Tor control host and port to use if onion listening enabled (default: %s). If no port is specified, the default port of %i will be used.", DEFAULT_TOR_CONTROL, DEFAULT_TOR_CONTROL_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
639
27
    argsman.AddArg("-torpassword=<pass>", "Tor control port password (default: empty)", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::CONNECTION);
640
27
    argsman.AddArg("-natpmp", strprintf("Use PCP or NAT-PMP to map the listening port (default: %u)", DEFAULT_NATPMP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
641
27
    argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. "
642
27
        "Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". "
643
27
        "Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
644
645
27
    argsman.AddArg("-whitelist=<[permissions@]IP address or network>", "Add permission flags to the peers using the given IP address (e.g. 1.2.3.4) or "
646
27
        "CIDR-notated network (e.g. 1.2.3.0/24). Uses the same permissions as "
647
27
        "-whitebind. "
648
27
        "Additional flags \"in\" and \"out\" control whether permissions apply to incoming connections and/or manual (default: incoming only). "
649
27
        "Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
650
651
27
    g_wallet_init_interface.AddWalletOptions(argsman);
652
653
#ifdef ENABLE_ZMQ
654
    argsman.AddArg("-zmqpubhashblock=<address>", "Enable publish hash block in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
655
    argsman.AddArg("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
656
    argsman.AddArg("-zmqpubrawblock=<address>", "Enable publish raw block in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
657
    argsman.AddArg("-zmqpubrawtx=<address>", "Enable publish raw transaction in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
658
    argsman.AddArg("-zmqpubsequence=<address>", "Enable publish hash block and tx sequence in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
659
    argsman.AddArg("-zmqpubhashblockhwm=<n>", strprintf("Set publish hash block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
660
    argsman.AddArg("-zmqpubhashtxhwm=<n>", strprintf("Set publish hash transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
661
    argsman.AddArg("-zmqpubrawblockhwm=<n>", strprintf("Set publish raw block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
662
    argsman.AddArg("-zmqpubrawtxhwm=<n>", strprintf("Set publish raw transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
663
    argsman.AddArg("-zmqpubsequencehwm=<n>", strprintf("Set publish hash sequence message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
664
#else
665
27
    hidden_args.emplace_back("-zmqpubhashblock=<address>");
666
27
    hidden_args.emplace_back("-zmqpubhashtx=<address>");
667
27
    hidden_args.emplace_back("-zmqpubrawblock=<address>");
668
27
    hidden_args.emplace_back("-zmqpubrawtx=<address>");
669
27
    hidden_args.emplace_back("-zmqpubsequence=<n>");
670
27
    hidden_args.emplace_back("-zmqpubhashblockhwm=<n>");
671
27
    hidden_args.emplace_back("-zmqpubhashtxhwm=<n>");
672
27
    hidden_args.emplace_back("-zmqpubrawblockhwm=<n>");
673
27
    hidden_args.emplace_back("-zmqpubrawtxhwm=<n>");
674
27
    hidden_args.emplace_back("-zmqpubsequencehwm=<n>");
675
27
#endif
676
677
27
    argsman.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
678
27
    argsman.AddArg("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
679
27
    argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures every <n> operations. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
680
27
    argsman.AddArg("-checkaddrman=<n>", strprintf("Run addrman consistency checks every <n> operations. Use 0 to disable. (default: %u)", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
681
27
    argsman.AddArg("-checkmempool=<n>", strprintf("Run mempool consistency checks every <n> transactions. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
682
    // Checkpoints were removed. We keep `-checkpoints` as a hidden arg to display a more user friendly error when set.
683
27
    argsman.AddArg("-checkpoints", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
684
27
    argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
685
27
    argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
686
27
    argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u). Blocks after target height may be processed during shutdown.", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
687
27
    argsman.AddArg("-limitancestorcount=<n>", strprintf("Deprecated setting to not accept transactions if number of in-mempool ancestors is <n> or more (default: %u); replaced by cluster limits (see -limitclustercount) and only used by wallet for coin selection", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
688
    // Ancestor and descendant size limits were removed. We keep
689
    // -limitancestorsize/-limitdescendantsize as hidden args to display a more
690
    // user friendly error when set.
691
27
    argsman.AddArg("-limitancestorsize", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
692
27
    argsman.AddArg("-limitdescendantsize", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
693
27
    argsman.AddArg("-limitdescendantcount=<n>", strprintf("Deprecated setting to not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u); replaced by cluster limits (see -limitclustercount) and only used by wallet for coin selection", DEFAULT_DESCENDANT_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
694
27
    argsman.AddArg("-test=<option>", "Pass a test-only option. Options include : " + Join(TEST_OPTIONS_DOC, ", ") + ".", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
695
27
    argsman.AddArg("-limitclustercount=<n>", strprintf("Do not accept transactions into mempool which are directly or indirectly connected to <n> or more other unconfirmed transactions (default: %u, maximum: %u)", DEFAULT_CLUSTER_LIMIT, MAX_CLUSTER_COUNT_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
696
27
    argsman.AddArg("-limitclustersize=<n>", strprintf("Do not accept transactions whose virtual size with all in-mempool connected transactions exceeds <n> kilobytes (default: %u)", DEFAULT_CLUSTER_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
697
27
    argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
698
27
    argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
699
27
    argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_VALIDATION_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
700
27
    argsman.AddArg("-maxtipage=<n>",
701
27
                   strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)",
702
27
                             Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)),
703
27
                   ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
704
27
    argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in %s/kvB when mining blocks (default: %u)", CURRENCY_UNIT, DEFAULT_PRINT_MODIFIED_FEE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
705
27
    argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
706
707
27
    SetupChainParamsBaseOptions(argsman);
708
709
27
    argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (test networks only; default: %u)", DEFAULT_ACCEPT_NON_STD_TXN), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
710
27
    argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and replacement policy. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
711
27
    argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
712
27
    argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
713
27
    argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
714
27
    argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
715
27
    argsman.AddArg("-datacarriersize",
716
27
                   strprintf("Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate "
717
27
                             "are of this size or less, allowing multiple outputs (default: %u)",
718
27
                             MAX_OP_RETURN_RELAY),
719
27
                   ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
720
27
    argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY,
721
27
                   OptionsCategory::NODE_RELAY);
722
27
    argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
723
27
        CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
724
27
    argsman.AddArg("-privatebroadcast",
725
27
                   strprintf(
726
27
                       "Broadcast transactions submitted via sendrawtransaction RPC using short-lived "
727
27
                       "connections through the Tor or I2P networks, without putting them in the mempool first. "
728
27
                       "Transactions submitted through the wallet are not affected by this option "
729
27
                       "(default: %u)",
730
27
                   DEFAULT_PRIVATE_BROADCAST),
731
27
                   ArgsManager::ALLOW_ANY,
732
27
                   OptionsCategory::NODE_RELAY);
733
27
    argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
734
27
    argsman.AddArg("-whitelistrelay", strprintf("Add 'relay' permission to whitelisted peers with default permissions. This will accept relayed transactions even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
735
736
737
27
    argsman.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
738
27
    argsman.AddArg("-blockreservedweight=<n>", strprintf("Reserve space for the fixed-size block header plus the largest coinbase transaction the mining software may add to the block. Only affects mining RPC clients, not IPC clients. (default: %d).", DEFAULT_BLOCK_RESERVED_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
739
27
    argsman.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
740
27
    argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
741
742
27
    argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
743
27
    argsman.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid values for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). RFC4193 is allowed only if -cjdnsreachable=0. This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
744
27
    argsman.AddArg("-rpcauth=<userpw>", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
745
27
    argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
746
27
    argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
747
27
    argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
748
27
    argsman.AddArg("-rpccookieperms=<readable-by>", strprintf("Set permissions on the RPC auth cookie file so that it is readable by [owner|group|all] (default: owner [via umask 0077])"), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
749
27
    argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
750
27
    argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
751
27
    argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
752
27
    argsman.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
753
27
    argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
754
27
    argsman.AddArg("-rpcwhitelist=<whitelist>", "Set a whitelist to filter incoming RPC calls for a specific user. The field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc 2>,...,<rpc n>. If multiple whitelists are set for a given user, they are set-intersected. See -rpcwhitelistdefault documentation for information on default whitelist behavior.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
755
27
    argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
756
27
    argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the maximum depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
757
27
    argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
758
27
    if (can_listen_ipc) {
  Branch (758:9): [True: 0, False: 27]
759
0
        argsman.AddArg("-ipcbind=<address>", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, <datadir>/node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created. Enabling this gives local processes that can access the socket unauthenticated RPC access, so it's important to choose a path with secure permissions if customizing this.", ArgsManager::ALLOW_ANY, OptionsCategory::IPC);
760
0
    }
761
762
27
#if HAVE_DECL_FORK
763
27
    argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
764
27
    argsman.AddArg("-daemonwait", strprintf("Wait for initialization to be finished before exiting. This implies -daemon (default: %d)", DEFAULT_DAEMONWAIT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
765
#else
766
    hidden_args.emplace_back("-daemon");
767
    hidden_args.emplace_back("-daemonwait");
768
#endif
769
770
    // Add the hidden options
771
27
    argsman.AddHiddenArgs(hidden_args);
772
27
}
773
774
#if HAVE_SYSTEM
775
static void StartupNotify(const ArgsManager& args)
776
0
{
777
0
    std::string cmd = args.GetArg("-startupnotify", "");
778
0
    if (!cmd.empty()) {
  Branch (778:9): [True: 0, False: 0]
779
0
        std::thread t(runCommand, cmd);
780
0
        t.detach(); // thread runs free
781
0
    }
782
0
}
783
#endif
784
785
static bool AppInitServers(NodeContext& node)
786
27
{
787
27
    const ArgsManager& args = *Assert(node.args);
788
27
    if (!InitHTTPServer()) {
  Branch (788:9): [True: 0, False: 27]
789
0
        return false;
790
0
    }
791
27
    StartRPC();
792
27
    node.rpc_interruption_point = RpcInterruptionPoint;
793
27
    if (!StartHTTPRPC(&node))
  Branch (793:9): [True: 0, False: 27]
794
0
        return false;
795
27
    if (args.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(&node);
  Branch (795:9): [True: 0, False: 27]
796
27
    StartHTTPServer();
797
27
    return true;
798
27
}
799
800
// Parameter interaction based on rules
801
void InitParameterInteraction(ArgsManager& args)
802
27
{
803
    // when specifying an explicit binding address, you want to listen on it
804
    // even when -connect or -proxy is specified
805
27
    if (!args.GetArgs("-bind").empty()) {
  Branch (805:9): [True: 27, False: 0]
806
27
        if (args.SoftSetBoolArg("-listen", true))
  Branch (806:13): [True: 27, False: 0]
807
27
            LogInfo("parameter interaction: -bind set -> setting -listen=1\n");
808
27
    }
809
27
    if (!args.GetArgs("-whitebind").empty()) {
  Branch (809:9): [True: 0, False: 27]
810
0
        if (args.SoftSetBoolArg("-listen", true))
  Branch (810:13): [True: 0, False: 0]
811
0
            LogInfo("parameter interaction: -whitebind set -> setting -listen=1\n");
812
0
    }
813
814
27
    if (!args.GetArgs("-connect").empty() || args.IsArgNegated("-connect") || args.GetIntArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS) <= 0) {
  Branch (814:9): [True: 0, False: 27]
  Branch (814:9): [True: 27, False: 0]
  Branch (814:46): [True: 27, False: 0]
  Branch (814:79): [True: 0, False: 0]
815
        // when only connecting to trusted nodes, do not seed via DNS, or listen by default
816
        // do the same when connections are disabled
817
27
        if (args.SoftSetBoolArg("-dnsseed", false))
  Branch (817:13): [True: 27, False: 0]
818
27
            LogInfo("parameter interaction: -connect or -maxconnections=0 set -> setting -dnsseed=0\n");
819
27
        if (args.SoftSetBoolArg("-listen", false))
  Branch (819:13): [True: 0, False: 27]
820
27
            LogInfo("parameter interaction: -connect or -maxconnections=0 set -> setting -listen=0\n");
821
27
    }
822
823
27
    std::string proxy_arg = args.GetArg("-proxy", "");
824
27
    if (proxy_arg != "" && proxy_arg != "0") {
  Branch (824:9): [True: 0, False: 27]
  Branch (824:28): [True: 0, False: 0]
825
        // to protect privacy, do not listen by default if a default proxy server is specified
826
0
        if (args.SoftSetBoolArg("-listen", false))
  Branch (826:13): [True: 0, False: 0]
827
0
            LogInfo("parameter interaction: -proxy set -> setting -listen=0\n");
828
        // to protect privacy, do not map ports when a proxy is set. The user may still specify -listen=1
829
        // to listen locally, so don't rely on this happening through -listen below.
830
0
        if (args.SoftSetBoolArg("-natpmp", false)) {
  Branch (830:13): [True: 0, False: 0]
831
0
            LogInfo("parameter interaction: -proxy set -> setting -natpmp=0\n");
832
0
        }
833
        // to protect privacy, do not discover addresses by default
834
0
        if (args.SoftSetBoolArg("-discover", false))
  Branch (834:13): [True: 0, False: 0]
835
0
            LogInfo("parameter interaction: -proxy set -> setting -discover=0\n");
836
0
    }
837
838
27
    if (!args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
  Branch (838:9): [True: 0, False: 27]
839
        // do not map ports or try to retrieve public IP when not listening (pointless)
840
0
        if (args.SoftSetBoolArg("-natpmp", false)) {
  Branch (840:13): [True: 0, False: 0]
841
0
            LogInfo("parameter interaction: -listen=0 -> setting -natpmp=0\n");
842
0
        }
843
0
        if (args.SoftSetBoolArg("-discover", false))
  Branch (843:13): [True: 0, False: 0]
844
0
            LogInfo("parameter interaction: -listen=0 -> setting -discover=0\n");
845
0
        if (args.SoftSetBoolArg("-listenonion", false))
  Branch (845:13): [True: 0, False: 0]
846
0
            LogInfo("parameter interaction: -listen=0 -> setting -listenonion=0\n");
847
0
        if (args.SoftSetBoolArg("-i2pacceptincoming", false)) {
  Branch (847:13): [True: 0, False: 0]
848
0
            LogInfo("parameter interaction: -listen=0 -> setting -i2pacceptincoming=0\n");
849
0
        }
850
0
    }
851
852
27
    if (!args.GetArgs("-externalip").empty()) {
  Branch (852:9): [True: 0, False: 27]
853
        // if an explicit public IP is specified, do not try to find others
854
0
        if (args.SoftSetBoolArg("-discover", false))
  Branch (854:13): [True: 0, False: 0]
855
0
            LogInfo("parameter interaction: -externalip set -> setting -discover=0\n");
856
0
    }
857
858
27
    if (args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
  Branch (858:9): [True: 0, False: 27]
859
        // disable whitelistrelay in blocksonly mode
860
0
        if (args.SoftSetBoolArg("-whitelistrelay", false))
  Branch (860:13): [True: 0, False: 0]
861
0
            LogInfo("parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n");
862
        // Reduce default mempool size in blocksonly mode to avoid unexpected resource usage
863
0
        if (args.SoftSetArg("-maxmempool", ToString(DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB)))
  Branch (863:13): [True: 0, False: 0]
864
0
            LogInfo("parameter interaction: -blocksonly=1 -> setting -maxmempool=%d\n", DEFAULT_BLOCKSONLY_MAX_MEMPOOL_SIZE_MB);
865
0
    }
866
867
    // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
868
27
    if (args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
  Branch (868:9): [True: 0, False: 27]
869
0
        if (args.SoftSetBoolArg("-whitelistrelay", true))
  Branch (869:13): [True: 0, False: 0]
870
0
            LogInfo("parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n");
871
0
    }
872
27
    const auto onlynets = args.GetArgs("-onlynet");
873
27
    if (!onlynets.empty()) {
  Branch (873:9): [True: 0, False: 27]
874
0
        bool clearnet_reachable = std::any_of(onlynets.begin(), onlynets.end(), [](const auto& net) {
875
0
            const auto n = ParseNetwork(net);
876
0
            return n == NET_IPV4 || n == NET_IPV6;
  Branch (876:20): [True: 0, False: 0]
  Branch (876:37): [True: 0, False: 0]
877
0
        });
878
0
        if (!clearnet_reachable && args.SoftSetBoolArg("-dnsseed", false)) {
  Branch (878:13): [True: 0, False: 0]
  Branch (878:13): [True: 0, False: 0]
  Branch (878:36): [True: 0, False: 0]
879
0
            LogInfo("parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n");
880
0
        }
881
0
    }
882
27
}
883
884
/**
885
 * Initialize global loggers.
886
 *
887
 * Note that this is called very early in the process lifetime, so you should be
888
 * careful about what global state you rely on here.
889
 */
890
void InitLogging(const ArgsManager& args)
891
27
{
892
27
    init::SetLoggingOptions(args);
893
27
    init::LogPackageVersion();
894
27
}
895
896
namespace { // Variables internal to initialization process only
897
898
int nMaxConnections;
899
int available_fds;
900
ServiceFlags g_local_services = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
901
int64_t peer_connect_timeout;
902
std::set<BlockFilterType> g_enabled_filter_types;
903
904
} // namespace
905
906
[[noreturn]] static void new_handler_terminate()
907
0
{
908
    // Rather than throwing std::bad-alloc if allocation fails, terminate
909
    // immediately to (try to) avoid chain corruption.
910
    // Since logging may itself allocate memory, set the handler directly
911
    // to terminate first.
912
0
    std::set_new_handler(std::terminate);
913
0
    LogError("Out of memory. Terminating.\n");
914
915
    // The log was successful, terminate now.
916
0
    std::terminate();
917
0
};
918
919
bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status)
920
27
{
921
    // ********************************************************* Step 1: setup
922
#ifdef _MSC_VER
923
    // Turn off Microsoft heap dump noise
924
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
925
    _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, 0));
926
    // Disable confusing "helpful" text message on abort, Ctrl-C
927
    _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
928
#endif
929
#ifdef WIN32
930
    // Enable heap terminate-on-corruption
931
    HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);
932
#endif
933
27
    if (!SetupNetworking()) {
  Branch (933:9): [True: 0, False: 27]
934
0
        return InitError(Untranslated("Initializing networking failed."));
935
0
    }
936
937
27
#ifndef WIN32
938
    // Clean shutdown on SIGTERM
939
27
    registerSignalHandler(SIGTERM, HandleSIGTERM);
940
27
    registerSignalHandler(SIGINT, HandleSIGTERM);
941
942
27
#if defined(__clang__)
943
    // Wipe coverage counters on SIGUSR1
944
27
    registerSignalHandler(SIGUSR1, HandleSIGUSR1);
945
27
#endif
946
947
    // Reopen debug.log on SIGHUP
948
27
    registerSignalHandler(SIGHUP, HandleSIGHUP);
949
950
    // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
951
27
    signal(SIGPIPE, SIG_IGN);
952
#else
953
    SetConsoleCtrlHandler(consoleCtrlHandler, true);
954
#endif
955
956
27
    std::set_new_handler(new_handler_terminate);
957
958
27
    return true;
959
27
}
960
961
bool AppInitParameterInteraction(const ArgsManager& args)
962
54
{
963
54
    const CChainParams& chainparams = Params();
964
    // ********************************************************* Step 2: parameter interactions
965
966
    // also see: InitParameterInteraction()
967
968
    // We removed checkpoints but keep the option to warn users who still have it in their config.
969
54
    if (args.IsArgSet("-checkpoints")) {
  Branch (969:9): [True: 0, False: 54]
970
0
        InitWarning(_("Option '-checkpoints' is set but checkpoints were removed. This option has no effect."));
971
0
    }
972
54
    if (args.IsArgSet("-limitancestorsize")) {
  Branch (972:9): [True: 0, False: 54]
973
0
        InitWarning(_("Option '-limitancestorsize' is given but ancestor size limits have been replaced with cluster size limits (see -limitclustersize). This option has no effect."));
974
0
    }
975
54
    if (args.IsArgSet("-limitdescendantsize")) {
  Branch (975:9): [True: 0, False: 54]
976
0
        InitWarning(_("Option '-limitdescendantsize' is given but descendant size limits have been replaced with cluster size limits (see -limitclustersize). This option has no effect."));
977
0
    }
978
979
    // Error if network-specific options (-addnode, -connect, etc) are
980
    // specified in default section of config file, but not overridden
981
    // on the command line or in this chain's section of the config file.
982
54
    ChainType chain = args.GetChainType();
983
54
    if (chain == ChainType::SIGNET) {
  Branch (983:9): [True: 0, False: 54]
984
0
        LogInfo("Signet derived magic (message start): %s", HexStr(chainparams.MessageStart()));
985
0
    }
986
54
    bilingual_str errors;
987
54
    for (const auto& arg : args.GetUnsuitableSectionOnlyArgs()) {
  Branch (987:26): [True: 0, False: 54]
988
0
        errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, ChainTypeToString(chain), ChainTypeToString(chain)) + Untranslated("\n");
989
0
    }
990
991
54
    if (!errors.empty()) {
  Branch (991:9): [True: 0, False: 54]
992
0
        return InitError(errors);
993
0
    }
994
995
    // Testnet3 deprecation warning
996
54
    if (chain == ChainType::TESTNET) {
  Branch (996:9): [True: 0, False: 54]
997
0
        LogInfo("Warning: Support for testnet3 is deprecated and will be removed in an upcoming release. Consider switching to testnet4.\n");
998
0
    }
999
1000
    // Warn if unrecognized section name are present in the config file.
1001
54
    bilingual_str warnings;
1002
54
    for (const auto& section : args.GetUnrecognizedSections()) {
  Branch (1002:30): [True: 0, False: 54]
1003
0
        warnings += Untranslated(strprintf("%s:%i ", section.m_file, section.m_line)) + strprintf(_("Section [%s] is not recognized."), section.m_name) + Untranslated("\n");
1004
0
    }
1005
1006
54
    if (!warnings.empty()) {
  Branch (1006:9): [True: 0, False: 54]
1007
0
        InitWarning(warnings);
1008
0
    }
1009
1010
54
    if (!fs::is_directory(args.GetBlocksDirPath())) {
  Branch (1010:9): [True: 0, False: 54]
1011
0
        return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", "")));
1012
0
    }
1013
1014
    // parse and validate enabled filter types
1015
54
    std::string blockfilterindex_value = args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
1016
54
    if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
  Branch (1016:9): [True: 54, False: 0]
  Branch (1016:41): [True: 0, False: 0]
1017
27
        g_enabled_filter_types = AllBlockFilterTypes();
1018
27
    } else if (blockfilterindex_value != "0") {
  Branch (1018:16): [True: 0, False: 27]
1019
0
        const std::vector<std::string> names = args.GetArgs("-blockfilterindex");
1020
0
        for (const auto& name : names) {
  Branch (1020:31): [True: 0, False: 0]
1021
0
            BlockFilterType filter_type;
1022
0
            if (!BlockFilterTypeByName(name, filter_type)) {
  Branch (1022:17): [True: 0, False: 0]
1023
0
                return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name));
1024
0
            }
1025
0
            g_enabled_filter_types.insert(filter_type);
1026
0
        }
1027
0
    }
1028
1029
    // Signal NODE_P2P_V2 if BIP324 v2 transport is enabled.
1030
54
    if (args.GetBoolArg("-v2transport", DEFAULT_V2_TRANSPORT)) {
  Branch (1030:9): [True: 27, False: 27]
1031
27
        g_local_services = ServiceFlags(g_local_services | NODE_P2P_V2);
1032
27
    }
1033
1034
    // Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled.
1035
54
    if (args.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
  Branch (1035:9): [True: 27, False: 27]
1036
27
        if (!g_enabled_filter_types.contains(BlockFilterType::BASIC)) {
  Branch (1036:13): [True: 0, False: 27]
1037
0
            return InitError(_("Cannot set -peerblockfilters without -blockfilterindex."));
1038
0
        }
1039
1040
27
        g_local_services = ServiceFlags(g_local_services | NODE_COMPACT_FILTERS);
1041
27
    }
1042
1043
54
    if (args.GetIntArg("-prune", 0)) {
  Branch (1043:9): [True: 0, False: 54]
1044
0
        if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
  Branch (1044:13): [True: 0, False: 0]
1045
0
            return InitError(_("Prune mode is incompatible with -txindex."));
1046
0
        if (args.GetBoolArg("-txospenderindex", DEFAULT_TXOSPENDERINDEX))
  Branch (1046:13): [True: 0, False: 0]
1047
0
            return InitError(_("Prune mode is incompatible with -txospenderindex."));
1048
0
        if (args.GetBoolArg("-reindex-chainstate", false)) {
  Branch (1048:13): [True: 0, False: 0]
1049
0
            return InitError(_("Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead."));
1050
0
        }
1051
0
    }
1052
1053
    // If -forcednsseed is set to true, ensure -dnsseed has not been set to false
1054
54
    if (args.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED) && !args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED)){
  Branch (1054:9): [True: 0, False: 54]
  Branch (1054:9): [True: 0, False: 54]
  Branch (1054:67): [True: 0, False: 0]
1055
0
        return InitError(_("Cannot set -forcednsseed to true when setting -dnsseed to false."));
1056
0
    }
1057
1058
    // -bind and -whitebind can't be set when not listening
1059
54
    size_t nUserBind = args.GetArgs("-bind").size() + args.GetArgs("-whitebind").size();
1060
54
    if (nUserBind != 0 && !args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
  Branch (1060:9): [True: 27, False: 27]
  Branch (1060:9): [True: 0, False: 54]
  Branch (1060:27): [True: 0, False: 27]
1061
0
        return InitError(Untranslated("Cannot set -bind or -whitebind together with -listen=0"));
1062
0
    }
1063
1064
    // if listen=0, then disallow listenonion=1
1065
54
    if (!args.GetBoolArg("-listen", DEFAULT_LISTEN) && args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) {
  Branch (1065:9): [True: 0, False: 54]
  Branch (1065:9): [True: 0, False: 54]
  Branch (1065:56): [True: 0, False: 0]
1066
0
        return InitError(Untranslated("Cannot set -listen=0 together with -listenonion=1"));
1067
0
    }
1068
1069
    // Make sure enough file descriptors are available. We need to reserve enough FDs to account for the bare minimum,
1070
    // plus all manual connections and all bound interfaces. Any remainder will be available for connection sockets
1071
1072
    // Number of bound interfaces (we have at least one)
1073
54
    int nBind = std::max(nUserBind, size_t(1));
1074
    // Maximum number of connections with other nodes, this accounts for all types of outbounds and inbounds except for manual
1075
54
    int user_max_connection = args.GetIntArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
1076
54
    if (user_max_connection < 0) {
  Branch (1076:9): [True: 0, False: 54]
1077
0
        return InitError(Untranslated("-maxconnections must be greater or equal than zero"));
1078
0
    }
1079
54
    const size_t max_private{args.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)
  Branch (1079:30): [True: 0, False: 54]
1080
54
                             ? MAX_PRIVATE_BROADCAST_CONNECTIONS
1081
54
                             : 0};
1082
    // Reserve enough FDs to account for the bare minimum, plus any manual connections, plus the bound interfaces
1083
54
    int min_required_fds = MIN_CORE_FDS + MAX_ADDNODE_CONNECTIONS + nBind;
1084
1085
    // Try raising the FD limit to what we need (available_fds may be smaller than the requested amount if this fails)
1086
54
    available_fds = RaiseFileDescriptorLimit(user_max_connection + max_private + min_required_fds);
1087
    // If we are using select instead of poll, our actual limit may be even smaller
1088
#ifndef USE_POLL
1089
    available_fds = std::min(FD_SETSIZE, available_fds);
1090
#endif
1091
54
    if (available_fds < min_required_fds)
  Branch (1091:9): [True: 0, False: 54]
1092
0
        return InitError(strprintf(_("Not enough file descriptors available. %d available, %d required."), available_fds, min_required_fds));
1093
1094
    // Trim requested connection counts, to fit into system limitations
1095
54
    nMaxConnections = std::min(available_fds - min_required_fds, user_max_connection);
1096
1097
54
    if (nMaxConnections < user_max_connection)
  Branch (1097:9): [True: 0, False: 54]
1098
0
        InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), user_max_connection, nMaxConnections));
1099
1100
    // ********************************************************* Step 3: parameter-to-internal-flags
1101
54
    if (auto result{init::SetLoggingCategories(args)}; !result) return InitError(util::ErrorString(result));
  Branch (1101:56): [True: 0, False: 54]
1102
54
    if (auto result{init::SetLoggingLevel(args)}; !result) return InitError(util::ErrorString(result));
  Branch (1102:51): [True: 0, False: 54]
1103
1104
54
    nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
1105
54
    if (nConnectTimeout <= 0) {
  Branch (1105:9): [True: 0, False: 54]
1106
0
        nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
1107
0
    }
1108
1109
54
    peer_connect_timeout = args.GetIntArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT);
1110
54
    if (peer_connect_timeout <= 0) {
  Branch (1110:9): [True: 0, False: 54]
1111
0
        return InitError(Untranslated("peertimeout must be a positive integer."));
1112
0
    }
1113
1114
54
    auto mining_result{node::ReadMiningArgs(args)};
1115
54
    if (!mining_result) {
  Branch (1115:9): [True: 0, False: 54]
1116
0
        return InitError(util::ErrorString(mining_result));
1117
0
    }
1118
1119
54
    nBytesPerSigOp = args.GetIntArg("-bytespersigop", nBytesPerSigOp);
1120
1121
54
    if (!g_wallet_init_interface.ParameterInteraction()) return false;
  Branch (1121:9): [True: 0, False: 54]
1122
1123
    // Option to startup with mocktime set (used for regression testing):
1124
54
    if (const auto mocktime{args.GetIntArg("-mocktime")}) {
  Branch (1124:20): [True: 0, False: 54]
1125
0
        SetMockTime(std::chrono::seconds{*mocktime});
1126
0
    }
1127
1128
54
    if (args.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
  Branch (1128:9): [True: 27, False: 27]
1129
27
        g_local_services = ServiceFlags(g_local_services | NODE_BLOOM);
1130
1131
54
    const std::vector<std::string> test_options = args.GetArgs("-test");
1132
54
    if (!test_options.empty()) {
  Branch (1132:9): [True: 0, False: 54]
1133
0
        if (chainparams.GetChainType() != ChainType::REGTEST) {
  Branch (1133:13): [True: 0, False: 0]
1134
0
            return InitError(Untranslated("-test=<option> can only be used with regtest"));
1135
0
        }
1136
0
        for (const std::string& option : test_options) {
  Branch (1136:40): [True: 0, False: 0]
1137
0
            auto it = std::find_if(TEST_OPTIONS_DOC.begin(), TEST_OPTIONS_DOC.end(), [&option](const std::string& doc_option) {
1138
0
                size_t pos = doc_option.find(" (");
1139
0
                return (pos != std::string::npos) && (doc_option.substr(0, pos) == option);
  Branch (1139:24): [True: 0, False: 0]
  Branch (1139:54): [True: 0, False: 0]
1140
0
            });
1141
0
            if (it == TEST_OPTIONS_DOC.end()) {
  Branch (1141:17): [True: 0, False: 0]
1142
0
                InitWarning(strprintf(_("Unrecognised option \"%s\" provided in -test=<option>."), option));
1143
0
            }
1144
0
        }
1145
0
    }
1146
1147
    // Prevent setting deployment parameters on mainnet.
1148
54
    if (chainparams.GetChainType() == ChainType::MAIN) {
  Branch (1148:9): [True: 0, False: 54]
1149
0
        if (args.IsArgSet("-testactivationheight")) {
  Branch (1149:13): [True: 0, False: 0]
1150
0
            return InitError(_("The -testactivationheight option may not be used on mainnet."));
1151
0
        }
1152
0
        if (args.IsArgSet("-vbparams")) {
  Branch (1152:13): [True: 0, False: 0]
1153
0
            return InitError(_("The -vbparams option may not be used on mainnet."));
1154
0
        }
1155
0
    }
1156
1157
    // Also report errors from parsing before daemonization
1158
54
    {
1159
54
        kernel::Notifications notifications{};
1160
54
        ChainstateManager::Options chainman_opts_dummy{
1161
54
            .chainparams = chainparams,
1162
54
            .datadir = args.GetDataDirNet(),
1163
54
            .notifications = notifications,
1164
54
        };
1165
54
        auto chainman_result{ApplyArgsManOptions(args, chainman_opts_dummy)};
1166
54
        if (!chainman_result) {
  Branch (1166:13): [True: 0, False: 54]
1167
0
            return InitError(util::ErrorString(chainman_result));
1168
0
        }
1169
54
        BlockManager::Options blockman_opts_dummy{
1170
54
            .chainparams = chainman_opts_dummy.chainparams,
1171
54
            .blocks_dir = args.GetBlocksDirPath(),
1172
54
            .notifications = chainman_opts_dummy.notifications,
1173
54
            .block_tree_db_params = DBParams{
1174
54
                .path = args.GetDataDirNet() / "blocks" / "index",
1175
54
                .cache_bytes = 0,
1176
54
            },
1177
54
        };
1178
54
        auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
1179
54
        if (!blockman_result) {
  Branch (1179:13): [True: 0, False: 54]
1180
0
            return InitError(util::ErrorString(blockman_result));
1181
0
        }
1182
54
        CTxMemPool::Options mempool_opts{};
1183
54
        auto mempool_result{ApplyArgsManOptions(args, chainparams, mempool_opts)};
1184
54
        if (!mempool_result) {
  Branch (1184:13): [True: 0, False: 54]
1185
0
            return InitError(util::ErrorString(mempool_result));
1186
0
        }
1187
54
    }
1188
1189
54
    return true;
1190
54
}
1191
1192
static bool LockDirectory(const fs::path& dir, bool probeOnly)
1193
108
{
1194
    // Make sure only a single process is using the directory.
1195
108
    switch (util::LockDirectory(dir, ".lock", probeOnly)) {
  Branch (1195:13): [True: 0, False: 108]
1196
0
    case util::LockResult::ErrorWrite:
  Branch (1196:5): [True: 0, False: 108]
1197
0
        return InitError(strprintf(_("Cannot write to directory '%s'; check permissions."), fs::PathToString(dir)));
1198
0
    case util::LockResult::ErrorLock:
  Branch (1198:5): [True: 0, False: 108]
1199
0
        return InitError(strprintf(_("Cannot obtain a lock on directory %s. %s is probably already running."), fs::PathToString(dir), CLIENT_NAME));
1200
108
    case util::LockResult::Success: return true;
  Branch (1200:5): [True: 108, False: 0]
1201
108
    } // no default case, so the compiler can warn about missing cases
1202
108
    assert(false);
  Branch (1202:5): [Folded - Ignored]
1203
0
}
1204
static bool LockDirectories(bool probeOnly)
1205
54
{
1206
54
    return LockDirectory(gArgs.GetDataDirNet(), probeOnly) && \
  Branch (1206:12): [True: 54, False: 0]
1207
54
           LockDirectory(gArgs.GetBlocksDirPath(), probeOnly);
  Branch (1207:12): [True: 54, False: 0]
1208
54
}
1209
1210
bool AppInitSanityChecks(const kernel::Context& kernel)
1211
27
{
1212
    // ********************************************************* Step 4: sanity checks
1213
27
    auto result{kernel::SanityChecks(kernel)};
1214
27
    if (!result) {
  Branch (1214:9): [True: 0, False: 27]
1215
0
        InitError(util::ErrorString(result));
1216
0
        return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), CLIENT_NAME));
1217
0
    }
1218
1219
27
    if (!ECC_InitSanityCheck()) {
  Branch (1219:9): [True: 0, False: 27]
1220
0
        return InitError(strprintf(_("Elliptic curve cryptography sanity check failure. %s is shutting down."), CLIENT_NAME));
1221
0
    }
1222
1223
    // Probe the directory locks to give an early error message, if possible
1224
    // We cannot hold the directory locks here, as the forking for daemon() hasn't yet happened,
1225
    // and a fork will cause weird behavior to them.
1226
27
    return LockDirectories(true);
1227
27
}
1228
1229
bool AppInitLockDirectories()
1230
27
{
1231
    // After daemonization get the directory locks again and hold on to them until exit
1232
    // This creates a slight window for a race condition to happen, however this condition is harmless: it
1233
    // will at most make us exit without printing a message to console.
1234
27
    if (!LockDirectories(false)) {
  Branch (1234:9): [True: 0, False: 27]
1235
        // Detailed error printed inside LockDirectory
1236
0
        return false;
1237
0
    }
1238
27
    return true;
1239
27
}
1240
1241
bool AppInitInterfaces(NodeContext& node)
1242
27
{
1243
27
    node.chain = interfaces::MakeChain(node);
1244
    // Specify wait_loaded=false so internal mining interface can be initialized
1245
    // on early startup and does not need to be tied to chainstate loading.
1246
27
    node.mining = interfaces::MakeMining(node, /*wait_loaded=*/false);
1247
27
    return true;
1248
27
}
1249
1250
27
bool CheckHostPortOptions(const ArgsManager& args) {
1251
27
    for (const std::string port_option : {
  Branch (1251:40): [True: 54, False: 27]
1252
27
        "-port",
1253
27
        "-rpcport",
1254
54
    }) {
1255
54
        if (const auto port{args.GetArg(port_option)}) {
  Branch (1255:24): [True: 27, False: 27]
1256
27
            const auto n{ToIntegral<uint16_t>(*port)};
1257
27
            if (!n || *n == 0) {
  Branch (1257:17): [True: 0, False: 27]
  Branch (1257:23): [True: 0, False: 27]
1258
0
                return InitError(InvalidPortErrMsg(port_option, *port));
1259
0
            }
1260
27
        }
1261
54
    }
1262
1263
27
    for ([[maybe_unused]] const auto& [param_name, unix, suffix_allowed] : std::vector<std::tuple<std::string, bool, bool>>{
  Branch (1263:74): [True: 324, False: 27]
1264
        // arg name          UNIX socket support  =suffix allowed
1265
27
        {"-i2psam",          false,               false},
1266
27
        {"-onion",           true,                false},
1267
27
        {"-proxy",           true,                true},
1268
27
        {"-bind",            false,               true},
1269
27
        {"-rpcbind",         false,               false},
1270
27
        {"-torcontrol",      false,               false},
1271
27
        {"-whitebind",       false,               false},
1272
27
        {"-zmqpubhashblock", true,                false},
1273
27
        {"-zmqpubhashtx",    true,                false},
1274
27
        {"-zmqpubrawblock",  true,                false},
1275
27
        {"-zmqpubrawtx",     true,                false},
1276
27
        {"-zmqpubsequence",  true,                false},
1277
324
    }) {
1278
324
        for (const std::string& param_value : args.GetArgs(param_name)) {
  Branch (1278:45): [True: 27, False: 324]
1279
27
            const std::string param_value_hostport{
1280
27
                suffix_allowed ? param_value.substr(0, param_value.rfind('=')) : param_value};
  Branch (1280:17): [True: 27, False: 0]
1281
27
            std::string host_out;
1282
27
            uint16_t port_out{0};
1283
27
            if (!SplitHostPort(param_value_hostport, port_out, host_out)) {
  Branch (1283:17): [True: 0, False: 27]
1284
0
#ifdef HAVE_SOCKADDR_UN
1285
                // Allow unix domain sockets for some options e.g. unix:/some/file/path
1286
0
                if (!unix || !param_value.starts_with(ADDR_PREFIX_UNIX)) {
  Branch (1286:21): [True: 0, False: 0]
  Branch (1286:30): [True: 0, False: 0]
1287
0
                    return InitError(InvalidPortErrMsg(param_name, param_value));
1288
0
                }
1289
#else
1290
                return InitError(InvalidPortErrMsg(param_name, param_value));
1291
#endif
1292
0
            }
1293
27
        }
1294
324
    }
1295
1296
27
    return true;
1297
27
}
1298
1299
/**
1300
 * @brief Checks for duplicate bindings across all binding configurations.
1301
 *
1302
 * @param[in] conn_options Connection options containing the binding vectors to check
1303
 * @return std::optional<CService> containing the first duplicate found, or std::nullopt if no duplicates
1304
 */
1305
static std::optional<CService> CheckBindingConflicts(const CConnman::Options& conn_options)
1306
27
{
1307
27
    std::set<CService> seen;
1308
1309
    // Check all whitelisted bindings
1310
27
    for (const auto& wb : conn_options.vWhiteBinds) {
  Branch (1310:25): [True: 0, False: 27]
1311
0
        if (!seen.insert(wb.m_service).second) {
  Branch (1311:13): [True: 0, False: 0]
1312
0
            return wb.m_service;
1313
0
        }
1314
0
    }
1315
1316
    // Check regular bindings
1317
27
    for (const auto& bind : conn_options.vBinds) {
  Branch (1317:27): [True: 27, False: 27]
1318
27
        if (!seen.insert(bind).second) {
  Branch (1318:13): [True: 0, False: 27]
1319
0
            return bind;
1320
0
        }
1321
27
    }
1322
1323
    // Check onion bindings
1324
27
    for (const auto& onion_bind : conn_options.onion_binds) {
  Branch (1324:33): [True: 0, False: 27]
1325
0
        if (!seen.insert(onion_bind).second) {
  Branch (1325:13): [True: 0, False: 0]
1326
0
            return onion_bind;
1327
0
        }
1328
0
    }
1329
1330
27
    return std::nullopt;
1331
27
}
1332
1333
// A GUI user may opt to retry once with do_reindex set if there is a failure during chainstate initialization.
1334
// The function therefore has to support re-entry.
1335
static ChainstateLoadResult InitAndLoadChainstate(
1336
    NodeContext& node,
1337
    bool do_reindex,
1338
    const bool do_reindex_chainstate,
1339
    const kernel::CacheSizes& cache_sizes,
1340
    const ArgsManager& args)
1341
54
{
1342
    // This function may be called twice, so any dirty state must be reset.
1343
54
    node.notifications->setChainstateLoaded(false); // Drop state, such as a cached tip block
1344
54
    node.mempool.reset();
1345
54
    node.chainman.reset(); // Drop state, such as an initialized m_block_tree_db
1346
1347
54
    const CChainParams& chainparams = Params();
1348
1349
54
    CTxMemPool::Options mempool_opts{
1350
54
        .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
  Branch (1350:24): [True: 27, False: 27]
1351
54
        .signals = node.validation_signals.get(),
1352
54
    };
1353
54
    Assert(ApplyArgsManOptions(args, chainparams, mempool_opts)); // no error can happen, already checked in AppInitParameterInteraction
1354
54
    bilingual_str mempool_error;
1355
54
    Assert(!node.mempool); // Was reset above
1356
54
    node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
1357
54
    if (!mempool_error.empty()) {
  Branch (1357:9): [True: 0, False: 54]
1358
0
        return {ChainstateLoadStatus::FAILURE_FATAL, mempool_error};
1359
0
    }
1360
54
    auto mining_args{node::ReadMiningArgs(args)};
1361
54
    Assert(mining_args); // no error can happen, already checked in AppInitParameterInteraction
1362
54
    node.mining_args = std::move(*mining_args);
1363
54
    LogInfo("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)",
1364
54
            cache_sizes.coins / double(1_MiB),
1365
54
            mempool_opts.max_size_bytes / double(1_MiB));
1366
54
    ChainstateManager::Options chainman_opts{
1367
54
        .chainparams = chainparams,
1368
54
        .datadir = args.GetDataDirNet(),
1369
54
        .notifications = *node.notifications,
1370
54
        .signals = node.validation_signals.get(),
1371
54
    };
1372
54
    Assert(ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1373
1374
54
    BlockManager::Options blockman_opts{
1375
54
        .chainparams = chainman_opts.chainparams,
1376
54
        .blocks_dir = args.GetBlocksDirPath(),
1377
54
        .notifications = chainman_opts.notifications,
1378
54
        .block_tree_db_params = DBParams{
1379
54
            .path = args.GetDataDirNet() / "blocks" / "index",
1380
54
            .cache_bytes = cache_sizes.block_tree_db,
1381
54
            .wipe_data = do_reindex,
1382
54
        },
1383
54
    };
1384
54
    Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1385
1386
    // Creating the chainstate manager internally creates a BlockManager, opens
1387
    // the blocks tree db, and wipes existing block files in case of a reindex.
1388
    // The coinsdb is opened at a later point on LoadChainstate.
1389
54
    Assert(!node.chainman); // Was reset above
1390
54
    try {
1391
54
        node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);
1392
54
    } catch (dbwrapper_error& e) {
1393
0
        LogError("%s", e.what());
1394
0
        return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
1395
0
    } catch (std::exception& e) {
1396
0
        return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated(strprintf("Failed to initialize ChainstateManager: %s", e.what()))};
1397
0
    }
1398
27
    ChainstateManager& chainman = *node.chainman;
1399
27
    if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
  Branch (1399:9): [True: 0, False: 27]
1400
1401
    // This is defined and set here instead of inline in validation.h to avoid a hard
1402
    // dependency between validation and index/base, since the latter is not in
1403
    // libbitcoinkernel.
1404
27
    chainman.snapshot_download_completed = [&node]() {
1405
0
        if (!node.chainman->m_blockman.IsPruneMode()) {
  Branch (1405:13): [True: 0, False: 0]
1406
0
            LogInfo("[snapshot] re-enabling NODE_NETWORK services");
1407
0
            node.connman->AddLocalServices(NODE_NETWORK);
1408
0
        }
1409
0
        LogInfo("[snapshot] restarting indexes");
1410
        // Drain the validation interface queue to ensure that the old indexes
1411
        // don't have any pending work.
1412
0
        Assert(node.validation_signals)->SyncWithValidationInterfaceQueue();
1413
0
        for (auto* index : node.indexes) {
  Branch (1413:26): [True: 0, False: 0]
1414
0
            index->Interrupt();
1415
0
            index->Stop();
1416
0
            if (!(index->Init() && index->StartBackgroundSync())) {
  Branch (1416:19): [True: 0, False: 0]
  Branch (1416:36): [True: 0, False: 0]
1417
0
                LogWarning("[snapshot] Failed to restart index %s on snapshot chain", index->GetName());
1418
0
            }
1419
0
        }
1420
0
    };
1421
27
    node::ChainstateLoadOptions options;
1422
27
    options.mempool = Assert(node.mempool.get());
1423
27
    options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
  Branch (1423:34): [True: 0, False: 27]
  Branch (1423:48): [True: 0, False: 27]
1424
27
    options.prune = chainman.m_blockman.IsPruneMode();
1425
27
    options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
1426
27
    options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
1427
27
    options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel");
  Branch (1427:41): [True: 0, False: 27]
  Branch (1427:74): [True: 0, False: 27]
1428
27
    options.coins_error_cb = [] {
1429
0
        uiInterface.ThreadSafeMessageBox(
1430
0
            _("Error reading from database, shutting down."),
1431
0
            CClientUIInterface::MSG_ERROR);
1432
0
    };
1433
27
    uiInterface.InitMessage(_("Loading block index…"));
1434
54
    auto catch_exceptions = [](auto&& f) -> ChainstateLoadResult {
1435
54
        try {
1436
54
            return f();
1437
54
        } catch (const std::exception& e) {
1438
0
            LogError("%s\n", e.what());
1439
0
            return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error loading databases"));
1440
0
        }
1441
54
    };
init.cpp:std::tuple<node::ChainstateLoadStatus, bilingual_str> InitAndLoadChainstate(node::NodeContext&, bool, bool, kernel::CacheSizes const&, ArgsManager const&)::$_2::operator()<InitAndLoadChainstate(node::NodeContext&, bool, bool, kernel::CacheSizes const&, ArgsManager const&)::$_3>(InitAndLoadChainstate(node::NodeContext&, bool, bool, kernel::CacheSizes const&, ArgsManager const&)::$_3&&) const
Line
Count
Source
1434
27
    auto catch_exceptions = [](auto&& f) -> ChainstateLoadResult {
1435
27
        try {
1436
27
            return f();
1437
27
        } catch (const std::exception& e) {
1438
0
            LogError("%s\n", e.what());
1439
0
            return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error loading databases"));
1440
0
        }
1441
27
    };
init.cpp:std::tuple<node::ChainstateLoadStatus, bilingual_str> InitAndLoadChainstate(node::NodeContext&, bool, bool, kernel::CacheSizes const&, ArgsManager const&)::$_2::operator()<InitAndLoadChainstate(node::NodeContext&, bool, bool, kernel::CacheSizes const&, ArgsManager const&)::$_4>(InitAndLoadChainstate(node::NodeContext&, bool, bool, kernel::CacheSizes const&, ArgsManager const&)::$_4&&) const
Line
Count
Source
1434
27
    auto catch_exceptions = [](auto&& f) -> ChainstateLoadResult {
1435
27
        try {
1436
27
            return f();
1437
27
        } catch (const std::exception& e) {
1438
0
            LogError("%s\n", e.what());
1439
0
            return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error loading databases"));
1440
0
        }
1441
27
    };
1442
27
    auto [status, error] = catch_exceptions([&] { return LoadChainstate(chainman, cache_sizes, options); });
1443
27
    if (status == node::ChainstateLoadStatus::SUCCESS) {
  Branch (1443:9): [True: 27, False: 0]
1444
27
        uiInterface.InitMessage(_("Verifying blocks…"));
1445
27
        if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
  Branch (1445:13): [True: 0, False: 27]
  Branch (1445:50): [True: 0, False: 0]
1446
0
            LogWarning("pruned datadir may not have more than %d blocks; only checking available blocks\n",
1447
0
                       MIN_BLOCKS_TO_KEEP);
1448
0
        }
1449
27
        std::tie(status, error) = catch_exceptions([&] { return VerifyLoadedChainstate(chainman, options); });
1450
27
        if (status == node::ChainstateLoadStatus::SUCCESS) {
  Branch (1450:13): [True: 27, False: 0]
1451
27
            LogInfo("Block index and chainstate loaded");
1452
27
            node.notifications->setChainstateLoaded(true);
1453
27
        }
1454
27
    }
1455
27
    return {status, error};
1456
27
};
1457
1458
bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1459
27
{
1460
27
    const ArgsManager& args = *Assert(node.args);
1461
27
    const CChainParams& chainparams = Params();
1462
1463
27
    auto opt_max_upload = ParseByteUnits(args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET), ByteUnit::M);
1464
27
    if (!opt_max_upload) {
  Branch (1464:9): [True: 0, False: 27]
1465
0
        return InitError(strprintf(_("Unable to parse -maxuploadtarget: '%s'"), args.GetArg("-maxuploadtarget", "")));
1466
0
    }
1467
1468
    // ********************************************************* Step 4a: application initialization
1469
27
    if (!CreatePidFile(args)) {
  Branch (1469:9): [True: 0, False: 27]
1470
        // Detailed error printed inside CreatePidFile().
1471
0
        return false;
1472
0
    }
1473
27
    if (!init::StartLogging(args)) {
  Branch (1473:9): [True: 0, False: 27]
1474
        // Detailed error printed inside StartLogging().
1475
0
        return false;
1476
0
    }
1477
1478
27
    LogInfo("Using at most %i automatic connections (%i file descriptors available)", nMaxConnections, available_fds);
1479
1480
    // Warn about relative -datadir path.
1481
27
    if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) {
  Branch (1481:9): [True: 27, False: 0]
  Branch (1481:9): [True: 0, False: 27]
  Branch (1481:38): [True: 0, False: 27]
1482
0
        LogWarning("Relative datadir option '%s' specified, which will be interpreted relative to the "
1483
0
                   "current working directory '%s'. This is fragile, because if bitcoin is started in the future "
1484
0
                   "from a different location, it will be unable to locate the current data files. There could "
1485
0
                   "also be data loss if bitcoin is started while in a temporary directory.",
1486
0
                   args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
1487
0
    }
1488
1489
27
    assert(!node.scheduler);
  Branch (1489:5): [True: 27, False: 0]
1490
27
    node.scheduler = std::make_unique<CScheduler>();
1491
27
    auto& scheduler = *node.scheduler;
1492
1493
    // Start the lightweight task scheduler thread
1494
27
    scheduler.m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { scheduler.serviceQueue(); });
1495
1496
    // Gather some entropy once per minute.
1497
74.3k
    scheduler.scheduleEvery([]{
1498
74.3k
        RandAddPeriodic();
1499
74.3k
    }, std::chrono::minutes{1});
1500
1501
    // Check disk space every 5 minutes to avoid db corruption.
1502
69.0k
    scheduler.scheduleEvery([&args, &node]{
1503
69.0k
        constexpr uint64_t min_disk_space{50_MiB};
1504
69.0k
        if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) {
  Branch (1504:13): [True: 0, False: 69.0k]
1505
0
            LogError("Shutting down due to lack of disk space!\n");
1506
0
            if (!(Assert(node.shutdown_request))()) {
  Branch (1506:17): [True: 0, False: 0]
1507
0
                LogError("Failed to send shutdown signal after disk space check\n");
1508
0
            }
1509
0
        }
1510
69.0k
    }, std::chrono::minutes{5});
1511
1512
27
    if (args.GetBoolArg("-logratelimit", BCLog::DEFAULT_LOGRATELIMIT)) {
  Branch (1512:9): [True: 27, False: 0]
1513
27
        LogInstance().SetRateLimiting(BCLog::LogRateLimiter::Create(
1514
27
            [&scheduler](auto func, auto window) { scheduler.scheduleEvery(std::move(func), window); },
1515
27
            BCLog::RATELIMIT_MAX_BYTES,
1516
27
            BCLog::RATELIMIT_WINDOW));
1517
27
    } else {
1518
0
        LogInfo("Log rate limiting disabled");
1519
0
    }
1520
1521
27
    assert(!node.validation_signals);
  Branch (1521:5): [True: 27, False: 0]
1522
27
    node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(scheduler));
1523
27
    auto& validation_signals = *node.validation_signals;
1524
1525
    // Create KernelNotifications object. Important to do this early before
1526
    // calling ipc->listenAddress() below so makeMining and other IPC methods
1527
    // can use this.
1528
27
    assert(!node.notifications);
  Branch (1528:5): [True: 27, False: 0]
1529
27
    node.notifications = std::make_unique<KernelNotifications>(Assert(node.shutdown_request), node.exit_status, *Assert(node.warnings));
1530
27
    ReadNotificationArgs(args, *node.notifications);
1531
1532
    // Create client interfaces for wallets that are supposed to be loaded
1533
    // according to -wallet and -disablewallet options. This only constructs
1534
    // the interfaces, it doesn't load wallet data. Wallets actually get loaded
1535
    // when load() and start() interface methods are called below.
1536
27
    g_wallet_init_interface.Construct(node);
1537
27
    uiInterface.InitWallet();
1538
1539
27
    if (interfaces::Ipc* ipc = node.init->ipc()) {
  Branch (1539:26): [True: 0, False: 27]
1540
0
        for (std::string address : gArgs.GetArgs("-ipcbind")) {
  Branch (1540:34): [True: 0, False: 0]
1541
0
            try {
1542
0
                ipc->listenAddress(address);
1543
0
            } catch (const std::exception& e) {
1544
0
                return InitError(Untranslated(strprintf("Unable to bind to IPC address '%s'. %s", address, e.what())));
1545
0
            }
1546
0
            LogInfo("Listening for IPC requests on address %s", address);
1547
0
        }
1548
0
    }
1549
1550
    /* Register RPC commands regardless of -server setting so they will be
1551
     * available in the GUI RPC console even if external calls are disabled.
1552
     */
1553
27
    RegisterAllCoreRPCCommands(tableRPC);
1554
27
    for (const auto& client : node.chain_clients) {
  Branch (1554:29): [True: 27, False: 27]
1555
27
        client->registerRpcs();
1556
27
    }
1557
#ifdef ENABLE_ZMQ
1558
    RegisterZMQRPCCommands(tableRPC);
1559
#endif
1560
1561
    // Check port numbers
1562
27
    if (!CheckHostPortOptions(args)) return false;
  Branch (1562:9): [True: 0, False: 27]
1563
1564
    // Configure reachable networks before we start the RPC server.
1565
    // This is necessary for -rpcallowip to distinguish CJDNS from other RFC4193
1566
27
    const auto onlynets = args.GetArgs("-onlynet");
1567
27
    if (!onlynets.empty()) {
  Branch (1567:9): [True: 0, False: 27]
1568
0
        g_reachable_nets.RemoveAll();
1569
0
        for (const std::string& snet : onlynets) {
  Branch (1569:38): [True: 0, False: 0]
1570
0
            enum Network net = ParseNetwork(snet);
1571
0
            if (net == NET_UNROUTABLE)
  Branch (1571:17): [True: 0, False: 0]
1572
0
                return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
1573
0
            g_reachable_nets.Add(net);
1574
0
        }
1575
0
    }
1576
1577
27
    if (!args.IsArgSet("-cjdnsreachable")) {
  Branch (1577:9): [True: 27, False: 0]
1578
27
        if (!onlynets.empty() && g_reachable_nets.Contains(NET_CJDNS)) {
  Branch (1578:13): [True: 0, False: 27]
  Branch (1578:34): [True: 0, False: 0]
1579
0
            return InitError(
1580
0
                _("Outbound connections restricted to CJDNS (-onlynet=cjdns) but "
1581
0
                  "-cjdnsreachable is not provided"));
1582
0
        }
1583
27
        g_reachable_nets.Remove(NET_CJDNS);
1584
27
    }
1585
    // Now g_reachable_nets.Contains(NET_CJDNS) is true if:
1586
    // 1. -cjdnsreachable is given and
1587
    // 2.1. -onlynet is not given or
1588
    // 2.2. -onlynet=cjdns is given
1589
1590
    /* Start the RPC server already.  It will be started in "warmup" mode
1591
     * and not really process calls already (but it will signify connections
1592
     * that the server is there and will be ready later).  Warmup mode will
1593
     * be disabled when initialisation is finished.
1594
     */
1595
27
    if (args.GetBoolArg("-server", false)) {
  Branch (1595:9): [True: 27, False: 0]
1596
27
        uiInterface.InitMessage.connect(SetRPCWarmupStatus);
1597
27
        if (!AppInitServers(node))
  Branch (1597:13): [True: 0, False: 27]
1598
0
            return InitError(_("Unable to start HTTP server. See debug log for details."));
1599
27
    }
1600
1601
    // ********************************************************* Step 5: verify wallet database integrity
1602
27
    for (const auto& client : node.chain_clients) {
  Branch (1602:29): [True: 27, False: 27]
1603
27
        if (!client->verify()) {
  Branch (1603:13): [True: 0, False: 27]
1604
0
            return false;
1605
0
        }
1606
27
    }
1607
1608
    // ********************************************************* Step 6: network initialization
1609
    // Note that we absolutely cannot open any actual connections
1610
    // until the very end ("start node") as the UTXO/block state
1611
    // is not yet setup and may end up being set up twice if we
1612
    // need to reindex later.
1613
1614
27
    fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
1615
27
    fDiscover = args.GetBoolArg("-discover", true);
1616
1617
27
    PeerManager::Options peerman_opts{};
1618
27
    ApplyArgsManOptions(args, peerman_opts);
1619
1620
27
    {
1621
        // Read asmap file if configured or embedded asmap data and initialize
1622
        // Netgroupman with or without it
1623
27
        assert(!node.netgroupman);
  Branch (1623:9): [True: 27, False: 0]
1624
27
        if (args.IsArgSet("-asmap") && !args.IsArgNegated("-asmap")) {
  Branch (1624:13): [True: 0, False: 27]
  Branch (1624:13): [True: 0, False: 27]
  Branch (1624:40): [True: 0, False: 0]
1625
0
            uint256 asmap_version{};
1626
0
            if (!args.GetBoolArg("-asmap", false)) {
  Branch (1626:17): [True: 0, False: 0]
1627
0
                fs::path asmap_path = args.GetPathArg("-asmap");
1628
0
                if (!asmap_path.is_absolute()) {
  Branch (1628:21): [True: 0, False: 0]
1629
0
                    asmap_path = args.GetDataDirNet() / asmap_path;
1630
0
                }
1631
1632
                // If a specific path was passed with the asmap argument check if
1633
                // the file actually exists in that location
1634
0
                if (!fs::exists(asmap_path)) {
  Branch (1634:21): [True: 0, False: 0]
1635
0
                    InitError(strprintf(_("Could not find asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
1636
0
                    return false;
1637
0
                }
1638
1639
                // If a file exists at the path, try to read the file
1640
0
                std::vector<std::byte> asmap{DecodeAsmap(asmap_path)};
1641
0
                if (asmap.empty()) {
  Branch (1641:21): [True: 0, False: 0]
1642
0
                    InitError(strprintf(_("Could not parse asmap file %s"), fs::quoted(fs::PathToString(asmap_path))));
1643
0
                    return false;
1644
0
                }
1645
0
                asmap_version = AsmapVersion(asmap);
1646
0
                node.netgroupman = std::make_unique<NetGroupManager>(NetGroupManager::WithLoadedAsmap(std::move(asmap)));
1647
0
            } else {
1648
0
                #ifdef ENABLE_EMBEDDED_ASMAP
1649
                    // Use the embedded asmap data
1650
0
                    std::span<const std::byte> asmap{node::data::ip_asn};
1651
0
                    if (asmap.empty() || !CheckStandardAsmap(asmap)) {
  Branch (1651:25): [True: 0, False: 0]
  Branch (1651:42): [True: 0, False: 0]
1652
0
                        InitError(strprintf(_("Could not read embedded asmap data")));
1653
0
                        return false;
1654
0
                    }
1655
0
                    node.netgroupman = std::make_unique<NetGroupManager>(NetGroupManager::WithEmbeddedAsmap(asmap));
1656
0
                    asmap_version = AsmapVersion(asmap);
1657
0
                    LogInfo("Opened asmap data (%zu bytes) from embedded byte array\n", asmap.size());
1658
                #else
1659
                    // If there is no embedded data, fail and report it since
1660
                    // the user tried to use it
1661
                    InitError(strprintf(_("Embedded asmap data not available")));
1662
                    return false;
1663
                #endif
1664
0
            }
1665
0
            LogInfo("Using asmap version %s for IP bucketing", asmap_version.ToString());
1666
27
        } else {
1667
27
            node.netgroupman = std::make_unique<NetGroupManager>(NetGroupManager::NoAsmap());
1668
27
            LogInfo("Using /16 prefix for IP bucketing");
1669
27
        }
1670
1671
        // Initialize addrman
1672
27
        assert(!node.addrman);
  Branch (1672:9): [True: 27, False: 0]
1673
27
        uiInterface.InitMessage(_("Loading P2P addresses…"));
1674
27
        auto addrman{LoadAddrman(*node.netgroupman, args)};
1675
27
        if (!addrman) return InitError(util::ErrorString(addrman));
  Branch (1675:13): [True: 0, False: 27]
1676
27
        node.addrman = std::move(*addrman);
1677
27
    }
1678
1679
0
    FastRandomContext rng;
1680
27
    assert(!node.banman);
  Branch (1680:5): [True: 27, False: 0]
1681
27
    node.banman = std::make_unique<BanMan>(args.GetDataDirNet() / "banlist", &uiInterface, args.GetIntArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
1682
27
    assert(!node.connman);
  Branch (1682:5): [True: 27, False: 0]
1683
27
    node.connman = std::make_unique<CConnman>(rng.rand64(),
1684
27
                                              rng.rand64(),
1685
27
                                              *node.addrman, *node.netgroupman, chainparams, args.GetBoolArg("-networkactive", true));
1686
1687
27
    assert(!node.fee_estimator);
  Branch (1687:5): [True: 27, False: 0]
1688
    // Don't initialize fee estimation with old data if we don't relay transactions,
1689
    // as they would never get updated.
1690
27
    if (!peerman_opts.ignore_incoming_txs) {
  Branch (1690:9): [True: 27, False: 0]
1691
27
        bool read_stale_estimates = args.GetBoolArg("-acceptstalefeeestimates", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
1692
27
        if (read_stale_estimates && (chainparams.GetChainType() != ChainType::REGTEST)) {
  Branch (1692:13): [True: 0, False: 27]
  Branch (1692:37): [True: 0, False: 0]
1693
0
            return InitError(strprintf(_("acceptstalefeeestimates is not supported on %s chain."), chainparams.GetChainTypeString()));
1694
0
        }
1695
27
        node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args), read_stale_estimates);
1696
1697
        // Flush estimates to disk periodically
1698
27
        CBlockPolicyEstimator* fee_estimator = node.fee_estimator.get();
1699
62.0k
        scheduler.scheduleEvery([fee_estimator] { fee_estimator->FlushFeeEstimates(); }, FEE_FLUSH_INTERVAL);
1700
27
        validation_signals.RegisterValidationInterface(fee_estimator);
1701
27
    }
1702
1703
27
    for (const std::string& socket_addr : args.GetArgs("-bind")) {
  Branch (1703:41): [True: 27, False: 27]
1704
27
        std::string host_out;
1705
27
        uint16_t port_out{0};
1706
27
        std::string bind_socket_addr = socket_addr.substr(0, socket_addr.rfind('='));
1707
27
        if (!SplitHostPort(bind_socket_addr, port_out, host_out)) {
  Branch (1707:13): [True: 0, False: 27]
1708
0
            return InitError(InvalidPortErrMsg("-bind", socket_addr));
1709
0
        }
1710
27
    }
1711
1712
    // sanitize comments per BIP-0014, format user agent and check total size
1713
27
    std::vector<std::string> uacomments;
1714
27
    for (const std::string& cmt : args.GetArgs("-uacomment")) {
  Branch (1714:33): [True: 0, False: 27]
1715
0
        if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
  Branch (1715:13): [True: 0, False: 0]
1716
0
            return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
1717
0
        uacomments.push_back(cmt);
1718
0
    }
1719
27
    strSubVersion = FormatSubVersion(UA_NAME, CLIENT_VERSION, uacomments);
1720
27
    if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
  Branch (1720:9): [True: 0, False: 27]
1721
0
        return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."),
1722
0
            strSubVersion.size(), MAX_SUBVERSION_LENGTH));
1723
0
    }
1724
1725
    // Requesting DNS seeds entails connecting to IPv4/IPv6, which -onlynet options may prohibit:
1726
    // If -dnsseed=1 is explicitly specified, abort. If it's left unspecified by the user, we skip
1727
    // the DNS seeds by adjusting -dnsseed in InitParameterInteraction.
1728
27
    if (args.GetBoolArg("-dnsseed") == true && !g_reachable_nets.Contains(NET_IPV4) && !g_reachable_nets.Contains(NET_IPV6)) {
  Branch (1728:9): [True: 0, False: 27]
  Branch (1728:9): [True: 0, False: 27]
  Branch (1728:48): [True: 0, False: 0]
  Branch (1728:88): [True: 0, False: 0]
1729
0
        return InitError(strprintf(_("Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6")));
1730
27
    };
1731
1732
    // Check for host lookup allowed before parsing any network related parameters
1733
27
    fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
1734
1735
27
    bool proxyRandomize = args.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
1736
    // -proxy sets a proxy for outgoing network traffic, possibly per network.
1737
    // -noproxy, -proxy=0 or -proxy="" can be used to remove the proxy setting, this is the default
1738
27
    Proxy ipv4_proxy;
1739
27
    Proxy ipv6_proxy;
1740
27
    Proxy onion_proxy;
1741
27
    Proxy name_proxy;
1742
27
    Proxy cjdns_proxy;
1743
27
    for (const std::string& param_value : args.GetArgs("-proxy")) {
  Branch (1743:41): [True: 0, False: 27]
1744
0
        const auto eq_pos{param_value.rfind('=')};
1745
0
        const std::string proxy_str{param_value.substr(0, eq_pos)}; // e.g. 127.0.0.1:9050=ipv4 -> 127.0.0.1:9050
1746
0
        std::string net_str;
1747
0
        if (eq_pos != std::string::npos) {
  Branch (1747:13): [True: 0, False: 0]
1748
0
            if (eq_pos + 1 == param_value.length()) {
  Branch (1748:17): [True: 0, False: 0]
1749
0
                return InitError(strprintf(_("Invalid -proxy address or hostname, ends with '=': '%s'"), param_value));
1750
0
            }
1751
0
            net_str = ToLower(param_value.substr(eq_pos + 1)); // e.g. 127.0.0.1:9050=ipv4 -> ipv4
1752
0
        }
1753
1754
0
        Proxy proxy;
1755
0
        if (!proxy_str.empty() && proxy_str != "0") {
  Branch (1755:13): [True: 0, False: 0]
  Branch (1755:35): [True: 0, False: 0]
1756
0
            if (IsUnixSocketPath(proxy_str)) {
  Branch (1756:17): [True: 0, False: 0]
1757
0
                proxy = Proxy{proxy_str, /*tor_stream_isolation=*/proxyRandomize};
1758
0
            } else {
1759
0
                const std::optional<CService> addr{Lookup(proxy_str, DEFAULT_TOR_SOCKS_PORT, fNameLookup)};
1760
0
                if (!addr.has_value()) {
  Branch (1760:21): [True: 0, False: 0]
1761
0
                    return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxy_str));
1762
0
                }
1763
0
                proxy = Proxy{addr.value(), /*tor_stream_isolation=*/proxyRandomize};
1764
0
            }
1765
0
            if (!proxy.IsValid()) {
  Branch (1765:17): [True: 0, False: 0]
1766
0
                return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxy_str));
1767
0
            }
1768
0
        }
1769
1770
0
        if (net_str.empty()) { // For all networks.
  Branch (1770:13): [True: 0, False: 0]
1771
0
            ipv4_proxy = ipv6_proxy = name_proxy = cjdns_proxy = onion_proxy = proxy;
1772
0
        } else if (net_str == "ipv4") {
  Branch (1772:20): [True: 0, False: 0]
1773
0
            ipv4_proxy = name_proxy = proxy;
1774
0
        } else if (net_str == "ipv6") {
  Branch (1774:20): [True: 0, False: 0]
1775
0
            ipv6_proxy = name_proxy = proxy;
1776
0
        } else if (net_str == "onion") {
  Branch (1776:20): [True: 0, False: 0]
1777
0
            onion_proxy = proxy;
1778
0
        } else if (net_str == "cjdns") {
  Branch (1778:20): [True: 0, False: 0]
1779
0
            cjdns_proxy = proxy;
1780
0
        } else {
1781
0
            return InitError(strprintf(_("Unrecognized network in -proxy='%s': '%s'"), param_value, net_str));
1782
0
        }
1783
0
    }
1784
27
    if (ipv4_proxy.IsValid()) {
  Branch (1784:9): [True: 0, False: 27]
1785
0
        SetProxy(NET_IPV4, ipv4_proxy);
1786
0
    }
1787
27
    if (ipv6_proxy.IsValid()) {
  Branch (1787:9): [True: 0, False: 27]
1788
0
        SetProxy(NET_IPV6, ipv6_proxy);
1789
0
    }
1790
27
    if (name_proxy.IsValid()) {
  Branch (1790:9): [True: 0, False: 27]
1791
0
        SetNameProxy(name_proxy);
1792
0
    }
1793
27
    if (cjdns_proxy.IsValid()) {
  Branch (1793:9): [True: 0, False: 27]
1794
0
        SetProxy(NET_CJDNS, cjdns_proxy);
1795
0
    }
1796
1797
27
    const bool onlynet_used_with_onion{!onlynets.empty() && g_reachable_nets.Contains(NET_ONION)};
  Branch (1797:40): [True: 0, False: 27]
  Branch (1797:61): [True: 0, False: 0]
1798
1799
    // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
1800
    // -noonion (or -onion=0) disables connecting to .onion entirely
1801
    // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
1802
27
    std::string onionArg = args.GetArg("-onion", "");
1803
27
    if (onionArg != "") {
  Branch (1803:9): [True: 0, False: 27]
1804
0
        if (onionArg == "0") { // Handle -noonion/-onion=0
  Branch (1804:13): [True: 0, False: 0]
1805
0
            onion_proxy = Proxy{};
1806
0
            if (onlynet_used_with_onion) {
  Branch (1806:17): [True: 0, False: 0]
1807
0
                return InitError(
1808
0
                    _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
1809
0
                      "reaching the Tor network is explicitly forbidden: -onion=0"));
1810
0
            }
1811
0
        } else {
1812
0
            if (IsUnixSocketPath(onionArg)) {
  Branch (1812:17): [True: 0, False: 0]
1813
0
                onion_proxy = Proxy(onionArg, /*tor_stream_isolation=*/proxyRandomize);
1814
0
            } else {
1815
0
                const std::optional<CService> addr{Lookup(onionArg, DEFAULT_TOR_SOCKS_PORT, fNameLookup)};
1816
0
                if (!addr.has_value() || !addr->IsValid()) {
  Branch (1816:21): [True: 0, False: 0]
  Branch (1816:42): [True: 0, False: 0]
1817
0
                    return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
1818
0
                }
1819
1820
0
                onion_proxy = Proxy(addr.value(), /*tor_stream_isolation=*/proxyRandomize);
1821
0
            }
1822
0
        }
1823
0
    }
1824
1825
27
    const bool listenonion{args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)};
1826
27
    if (onion_proxy.IsValid()) {
  Branch (1826:9): [True: 0, False: 27]
1827
0
        SetProxy(NET_ONION, onion_proxy);
1828
27
    } else {
1829
        // If -listenonion is set, then we will (try to) connect to the Tor control port
1830
        // later from the torcontrol thread and may retrieve the onion proxy from there.
1831
27
        if (onlynet_used_with_onion && !listenonion) {
  Branch (1831:13): [True: 0, False: 27]
  Branch (1831:40): [True: 0, False: 0]
1832
0
            return InitError(
1833
0
                _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
1834
0
                  "reaching the Tor network is not provided: none of -proxy, -onion or "
1835
0
                  "-listenonion is given"));
1836
0
        }
1837
27
        g_reachable_nets.Remove(NET_ONION);
1838
27
    }
1839
1840
27
    for (const std::string& strAddr : args.GetArgs("-externalip")) {
  Branch (1840:37): [True: 0, False: 27]
1841
0
        const std::optional<CService> addrLocal{Lookup(strAddr, GetListenPort(), fNameLookup)};
1842
0
        if (addrLocal.has_value() && addrLocal->IsValid())
  Branch (1842:13): [True: 0, False: 0]
  Branch (1842:38): [True: 0, False: 0]
1843
0
            AddLocal(addrLocal.value(), LOCAL_MANUAL);
1844
0
        else
1845
0
            return InitError(ResolveErrMsg("externalip", strAddr));
1846
0
    }
1847
1848
#ifdef ENABLE_ZMQ
1849
    g_zmq_notification_interface = CZMQNotificationInterface::Create(
1850
        [&chainman = node.chainman](std::vector<std::byte>& block, const CBlockIndex& index) {
1851
            assert(chainman);
1852
            if (auto ret{chainman->m_blockman.ReadRawBlock(WITH_LOCK(cs_main, return index.GetBlockPos()))}) {
1853
                block = std::move(*ret);
1854
                return true;
1855
            }
1856
            return false;
1857
        });
1858
1859
    if (g_zmq_notification_interface) {
1860
        validation_signals.RegisterValidationInterface(g_zmq_notification_interface.get());
1861
    }
1862
#endif
1863
1864
    // ********************************************************* Step 7: load block chain
1865
1866
    // cache size calculations
1867
27
    node::LogOversizedDbCache(args);
1868
27
    const auto [index_cache_sizes, kernel_cache_sizes] = CalculateCacheSizes(args, g_enabled_filter_types.size());
1869
1870
27
    LogInfo("Cache configuration:");
1871
27
    LogInfo("* Using %.1f MiB for block index database", kernel_cache_sizes.block_tree_db / double(1_MiB));
1872
27
    if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
  Branch (1872:9): [True: 0, False: 27]
1873
0
        LogInfo("* Using %.1f MiB for transaction index database", index_cache_sizes.tx_index / double(1_MiB));
1874
0
    }
1875
27
    if (args.GetBoolArg("-txospenderindex", DEFAULT_TXOSPENDERINDEX)) {
  Branch (1875:9): [True: 0, False: 27]
1876
0
        LogInfo("* Using %.1f MiB for transaction output spender index database", index_cache_sizes.txospender_index / double(1_MiB));
1877
0
    }
1878
27
    for (BlockFilterType filter_type : g_enabled_filter_types) {
  Branch (1878:38): [True: 27, False: 27]
1879
27
        LogInfo("* Using %.1f MiB for %s block filter index database",
1880
27
                  index_cache_sizes.filter_index / double(1_MiB), BlockFilterTypeName(filter_type));
1881
27
    }
1882
27
    LogInfo("* Using %.1f MiB for chain state database", kernel_cache_sizes.coins_db / double(1_MiB));
1883
1884
27
    assert(!node.mempool);
  Branch (1884:5): [True: 27, False: 0]
1885
27
    assert(!node.chainman);
  Branch (1885:5): [True: 27, False: 0]
1886
1887
27
    bool do_reindex{args.GetBoolArg("-reindex", false)};
1888
27
    const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)};
1889
1890
    // Chainstate initialization and loading may be retried once with reindexing by GUI users
1891
27
    auto [status, error] = InitAndLoadChainstate(
1892
27
        node,
1893
27
        do_reindex,
1894
27
        do_reindex_chainstate,
1895
27
        kernel_cache_sizes,
1896
27
        args);
1897
27
    if (status == ChainstateLoadStatus::FAILURE && !do_reindex && !ShutdownRequested(node)) {
  Branch (1897:9): [True: 0, False: 27]
  Branch (1897:52): [True: 0, False: 0]
  Branch (1897:67): [True: 0, False: 0]
1898
        // suggest a reindex
1899
0
        bool do_retry{HasTestOption(args, "reindex_after_failure_noninteractive_yes") ||
  Branch (1899:23): [True: 0, False: 0]
1900
0
            uiInterface.ThreadSafeQuestion(
  Branch (1900:13): [True: 0, False: 0]
1901
0
            error + Untranslated(".\n\n") + _("Do you want to rebuild the databases now?"),
1902
0
            error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
1903
0
            CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT)};
1904
0
        if (!do_retry) {
  Branch (1904:13): [True: 0, False: 0]
1905
0
            return false;
1906
0
        }
1907
0
        do_reindex = true;
1908
0
        if (!Assert(node.shutdown_signal)->reset()) {
  Branch (1908:13): [True: 0, False: 0]
1909
0
            LogError("Internal error: failed to reset shutdown signal.\n");
1910
0
        }
1911
0
        std::tie(status, error) = InitAndLoadChainstate(
1912
0
            node,
1913
0
            do_reindex,
1914
0
            do_reindex_chainstate,
1915
0
            kernel_cache_sizes,
1916
0
            args);
1917
0
    }
1918
27
    if (status != ChainstateLoadStatus::SUCCESS && status != ChainstateLoadStatus::INTERRUPTED) {
  Branch (1918:9): [True: 0, False: 27]
  Branch (1918:52): [True: 0, False: 0]
1919
0
        return InitError(error);
1920
0
    }
1921
1922
    // As LoadBlockIndex can take several minutes, it's possible the user
1923
    // requested to kill the GUI during the last operation. If so, exit.
1924
27
    if (ShutdownRequested(node)) {
  Branch (1924:9): [True: 0, False: 27]
1925
0
        LogInfo("Shutdown requested. Exiting.");
1926
0
        return true;
1927
0
    }
1928
1929
27
    ChainstateManager& chainman = *Assert(node.chainman);
1930
27
    auto& kernel_notifications{*Assert(node.notifications)};
1931
1932
27
    assert(!node.peerman);
  Branch (1932:5): [True: 27, False: 0]
1933
27
    node.peerman = PeerManager::make(*node.connman, *node.addrman,
1934
27
                                     node.banman.get(), chainman,
1935
27
                                     *node.mempool, *node.warnings,
1936
27
                                     peerman_opts);
1937
27
    validation_signals.RegisterValidationInterface(node.peerman.get());
1938
1939
    // ********************************************************* Step 8: start indexers
1940
1941
27
    if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
  Branch (1941:9): [True: 0, False: 27]
1942
0
        g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), index_cache_sizes.tx_index, false, do_reindex);
1943
0
        node.indexes.emplace_back(g_txindex.get());
1944
0
    }
1945
1946
27
    if (args.GetBoolArg("-txospenderindex", DEFAULT_TXOSPENDERINDEX)) {
  Branch (1946:9): [True: 0, False: 27]
1947
0
        g_txospenderindex = std::make_unique<TxoSpenderIndex>(interfaces::MakeChain(node), index_cache_sizes.txospender_index, false, do_reindex);
1948
0
        node.indexes.emplace_back(g_txospenderindex.get());
1949
0
    }
1950
1951
27
    for (const auto& filter_type : g_enabled_filter_types) {
  Branch (1951:34): [True: 27, False: 27]
1952
27
        InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, index_cache_sizes.filter_index, false, do_reindex);
1953
27
        node.indexes.emplace_back(GetBlockFilterIndex(filter_type));
1954
27
    }
1955
1956
27
    if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
  Branch (1956:9): [True: 0, False: 27]
1957
0
        g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, do_reindex);
1958
0
        node.indexes.emplace_back(g_coin_stats_index.get());
1959
0
    }
1960
1961
    // Init indexes
1962
27
    for (auto index : node.indexes) if (!index->Init()) return false;
  Branch (1962:21): [True: 27, False: 27]
  Branch (1962:41): [True: 0, False: 27]
1963
1964
    // ********************************************************* Step 9: load wallet
1965
27
    for (const auto& client : node.chain_clients) {
  Branch (1965:29): [True: 27, False: 27]
1966
27
        if (!client->load()) {
  Branch (1966:13): [True: 0, False: 27]
1967
0
            return false;
1968
0
        }
1969
27
    }
1970
1971
    // ********************************************************* Step 10: data directory maintenance
1972
1973
    // if pruning, perform the initial blockstore prune
1974
    // after any wallet rescanning has taken place.
1975
27
    if (chainman.m_blockman.IsPruneMode()) {
  Branch (1975:9): [True: 0, False: 27]
1976
0
        if (chainman.m_blockman.m_blockfiles_indexed) {
  Branch (1976:13): [True: 0, False: 0]
1977
0
            LOCK(cs_main);
1978
0
            for (const auto& chainstate : chainman.m_chainstates) {
  Branch (1978:41): [True: 0, False: 0]
1979
0
                uiInterface.InitMessage(_("Pruning blockstore…"));
1980
0
                chainstate->PruneAndFlush();
1981
0
            }
1982
0
        }
1983
27
    } else {
1984
        // Prior to setting NODE_NETWORK, check if we can provide historical blocks.
1985
27
        if (!WITH_LOCK(chainman.GetMutex(), return chainman.HistoricalChainstate())) {
  Branch (1985:13): [True: 27, False: 0]
1986
27
            LogInfo("Setting NODE_NETWORK in non-prune mode");
1987
27
            g_local_services = ServiceFlags(g_local_services | NODE_NETWORK);
1988
27
        } else {
1989
0
            LogInfo("Running node in NODE_NETWORK_LIMITED mode until snapshot background sync completes");
1990
0
        }
1991
27
    }
1992
1993
    // ********************************************************* Step 11: import blocks
1994
1995
27
    if (!CheckDiskSpace(args.GetDataDirNet())) {
  Branch (1995:9): [True: 0, False: 27]
1996
0
        InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(args.GetDataDirNet()))));
1997
0
        return false;
1998
0
    }
1999
27
    if (!CheckDiskSpace(args.GetBlocksDirPath())) {
  Branch (1999:9): [True: 0, False: 27]
2000
0
        InitError(strprintf(_("Error: Disk space is low for %s"), fs::quoted(fs::PathToString(args.GetBlocksDirPath()))));
2001
0
        return false;
2002
0
    }
2003
2004
27
    int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());
2005
2006
    // On first startup, warn on low block storage space
2007
27
    if (!do_reindex && !do_reindex_chainstate && chain_active_height <= 1) {
  Branch (2007:9): [True: 27, False: 0]
  Branch (2007:24): [True: 27, False: 0]
  Branch (2007:50): [True: 27, False: 0]
2008
27
        uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1_GiB};
2009
27
        uint64_t additional_bytes_needed{
2010
27
            chainman.m_blockman.IsPruneMode() ?
  Branch (2010:13): [True: 0, False: 27]
2011
0
                std::min(chainman.m_blockman.GetPruneTarget(), assumed_chain_bytes) :
2012
27
                assumed_chain_bytes};
2013
2014
27
        if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
  Branch (2014:13): [True: 0, False: 27]
2015
0
            InitWarning(strprintf(_(
2016
0
                    "Disk space for %s may not accommodate the block files. " \
2017
0
                    "Approximately %u GB of data will be stored in this directory."
2018
0
                ),
2019
0
                fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
2020
0
                chainparams.AssumedBlockchainSize()
2021
0
            ));
2022
0
        }
2023
27
    }
2024
2025
#ifdef __APPLE__
2026
    auto check_and_warn_fs{[&](const fs::path& path, std::string_view desc) {
2027
        const auto path_desc{strprintf("%s (\"%s\")", desc, fs::PathToString(path))};
2028
        switch (GetFilesystemType(path)) {
2029
        case FSType::EXFAT:
2030
            InitWarning(strprintf(_("The %s path uses exFAT, which is known to have intermittent corruption problems on macOS. "
2031
                "Move this directory to a different filesystem to avoid data loss."), path_desc));
2032
            break;
2033
        case FSType::ERROR:
2034
            LogInfo("Failed to detect filesystem type for %s", path_desc);
2035
            break;
2036
        case FSType::OTHER:
2037
            break;
2038
        }
2039
    }};
2040
2041
    check_and_warn_fs(args.GetDataDirNet(), "data directory");
2042
    check_and_warn_fs(args.GetBlocksDirPath(), "blocks directory");
2043
#endif
2044
2045
27
#if HAVE_SYSTEM
2046
27
    const std::string block_notify = args.GetArg("-blocknotify", "");
2047
27
    if (!block_notify.empty()) {
  Branch (2047:9): [True: 0, False: 27]
2048
0
        uiInterface.NotifyBlockTip.connect([block_notify](SynchronizationState sync_state, const CBlockIndex& block, double /* verification_progress */) {
2049
0
            if (sync_state != SynchronizationState::POST_INIT) return;
  Branch (2049:17): [True: 0, False: 0]
2050
0
            std::string command = block_notify;
2051
0
            ReplaceAll(command, "%s", block.GetBlockHash().GetHex());
2052
0
            std::thread t(runCommand, command);
2053
0
            t.detach(); // thread runs free
2054
0
        });
2055
0
    }
2056
27
#endif
2057
2058
27
    std::vector<fs::path> vImportFiles;
2059
27
    for (const std::string& strFile : args.GetArgs("-loadblock")) {
  Branch (2059:37): [True: 0, False: 27]
2060
0
        vImportFiles.push_back(fs::PathFromString(strFile));
2061
0
    }
2062
2063
    /// \anchor initload
2064
27
    node.background_init_thread = std::thread(&util::TraceThread, "initload", [=, &chainman, &args, &kernel_notifications, &node] {
2065
27
        ScheduleBatchPriority();
2066
        // Import blocks and ActivateBestChain()
2067
27
        ImportBlocks(chainman, vImportFiles);
2068
        // An interrupted import may return without activating genesis. Wake
2069
        // the init thread's genesis wait, which is otherwise only notified
2070
        // on blockTip, and that never fires when the import was interrupted
2071
        // before activating genesis. This wakeup lets the wait observe the
2072
        // shutdown request.
2073
27
        WITH_LOCK(kernel_notifications.m_tip_block_mutex, kernel_notifications.m_tip_block_cv.notify_all());
2074
27
        WITH_LOCK(::cs_main, chainman.UpdateIBDStatus());
2075
27
        if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
  Branch (2075:13): [True: 0, False: 27]
2076
0
            LogInfo("Stopping after block import");
2077
0
            if (!(Assert(node.shutdown_request))()) {
  Branch (2077:17): [True: 0, False: 0]
2078
0
                LogError("Failed to send shutdown signal after finishing block import\n");
2079
0
            }
2080
0
            return;
2081
0
        }
2082
2083
        // Start indexes initial sync
2084
27
        if (!StartIndexBackgroundSync(node)) {
  Branch (2084:13): [True: 0, False: 27]
2085
0
            bilingual_str err_str = _("Failed to start indexes, shutting down…");
2086
0
            chainman.GetNotifications().fatalError(err_str);
2087
0
            return;
2088
0
        }
2089
        // Load mempool from disk
2090
27
        if (auto* pool{chainman.ActiveChainstate().GetMempool()}) {
  Branch (2090:19): [True: 27, False: 0]
2091
27
            LoadMempool(*pool, ShouldPersistMempool(args) ? MempoolPath(args) : fs::path{}, chainman.ActiveChainstate(), {});
  Branch (2091:32): [True: 27, False: 0]
2092
27
            pool->SetLoadTried(!chainman.m_interrupt);
2093
27
        }
2094
27
    });
2095
2096
    /*
2097
     * Wait for genesis block to be processed. Typically kernel_notifications.m_tip_block
2098
     * has already been set by a call to LoadChainTip() in CompleteChainstateInitialization().
2099
     * But this is skipped if the chainstate doesn't exist yet or is being wiped:
2100
     *
2101
     * 1. first startup with an empty datadir
2102
     * 2. reindex
2103
     * 3. reindex-chainstate
2104
     *
2105
     * In these case it's connected by a call to ActivateBestChain() in the initload thread.
2106
     */
2107
27
    {
2108
27
        WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
2109
54
        kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
2110
54
            return kernel_notifications.TipBlock() || ShutdownRequested(node);
  Branch (2110:20): [True: 27, False: 27]
  Branch (2110:55): [True: 0, False: 27]
2111
54
        });
2112
27
    }
2113
2114
27
    if (ShutdownRequested(node)) {
  Branch (2114:9): [True: 0, False: 27]
2115
0
        return true;
2116
0
    }
2117
2118
    // ********************************************************* Step 12: start node
2119
2120
27
    int64_t best_block_time{};
2121
27
    {
2122
27
        LOCK(chainman.GetMutex());
2123
27
        const auto& tip{*Assert(chainman.ActiveTip())};
2124
27
        LogInfo("block tree size = %u", chainman.BlockIndex().size());
2125
27
        chain_active_height = tip.nHeight;
2126
27
        best_block_time = tip.GetBlockTime();
2127
27
        if (tip_info) {
  Branch (2127:13): [True: 0, False: 27]
2128
0
            tip_info->block_height = chain_active_height;
2129
0
            tip_info->block_time = best_block_time;
2130
0
            tip_info->verification_progress = chainman.GuessVerificationProgress(&tip);
2131
0
        }
2132
27
        if (tip_info && chainman.m_best_header) {
  Branch (2132:13): [True: 0, False: 27]
  Branch (2132:25): [True: 0, False: 0]
2133
0
            tip_info->header_height = chainman.m_best_header->nHeight;
2134
0
            tip_info->header_time = chainman.m_best_header->GetBlockTime();
2135
0
        }
2136
27
    }
2137
27
    LogInfo("nBestHeight = %d", chain_active_height);
2138
27
    if (node.peerman) node.peerman->SetBestBlock(chain_active_height, std::chrono::seconds{best_block_time});
  Branch (2138:9): [True: 27, False: 0]
2139
2140
    // Map ports with NAT-PMP
2141
27
    StartMapPort(args.GetBoolArg("-natpmp", DEFAULT_NATPMP));
2142
2143
27
    CConnman::Options connOptions;
2144
27
    connOptions.m_local_services = g_local_services;
2145
27
    connOptions.m_max_automatic_connections = nMaxConnections;
2146
27
    connOptions.uiInterface = &uiInterface;
2147
27
    connOptions.m_banman = node.banman.get();
2148
27
    connOptions.m_msgproc = node.peerman.get();
2149
27
    connOptions.nSendBufferMaxSize = 1000 * args.GetIntArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
2150
27
    connOptions.nReceiveFloodSize = 1000 * args.GetIntArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
2151
27
    connOptions.m_added_nodes = args.GetArgs("-addnode");
2152
27
    connOptions.nMaxOutboundLimit = *opt_max_upload;
2153
27
    connOptions.m_peer_connect_timeout = peer_connect_timeout;
2154
27
    connOptions.whitelist_forcerelay = args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY);
2155
27
    connOptions.whitelist_relay = args.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY);
2156
27
    connOptions.m_capture_messages = args.GetBoolArg("-capturemessages", false);
2157
2158
    // Port to bind to if `-bind=addr` is provided without a `:port` suffix.
2159
27
    const uint16_t default_bind_port =
2160
27
        static_cast<uint16_t>(args.GetIntArg("-port", Params().GetDefaultPort()));
2161
2162
27
    const uint16_t default_bind_port_onion = default_bind_port + 1;
2163
2164
27
    const auto BadPortWarning = [](const char* prefix, uint16_t port) {
2165
0
        return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "
2166
0
                           "thus it is unlikely that any peer will connect to it. See "
2167
0
                           "doc/p2p-bad-ports.md for details and a full list."),
2168
0
                         prefix,
2169
0
                         port);
2170
0
    };
2171
2172
27
    for (const std::string& bind_arg : args.GetArgs("-bind")) {
  Branch (2172:38): [True: 27, False: 27]
2173
27
        std::optional<CService> bind_addr;
2174
27
        const size_t index = bind_arg.rfind('=');
2175
27
        if (index == std::string::npos) {
  Branch (2175:13): [True: 27, False: 0]
2176
27
            bind_addr = Lookup(bind_arg, default_bind_port, /*fAllowLookup=*/false);
2177
27
            if (bind_addr.has_value()) {
  Branch (2177:17): [True: 27, False: 0]
2178
27
                connOptions.vBinds.push_back(bind_addr.value());
2179
27
                if (IsBadPort(bind_addr.value().GetPort())) {
  Branch (2179:21): [True: 0, False: 27]
2180
0
                    InitWarning(BadPortWarning("-bind", bind_addr.value().GetPort()));
2181
0
                }
2182
27
                continue;
2183
27
            }
2184
27
        } else {
2185
0
            const std::string network_type = bind_arg.substr(index + 1);
2186
0
            if (network_type == "onion") {
  Branch (2186:17): [True: 0, False: 0]
2187
0
                const std::string truncated_bind_arg = bind_arg.substr(0, index);
2188
0
                bind_addr = Lookup(truncated_bind_arg, default_bind_port_onion, false);
2189
0
                if (bind_addr.has_value()) {
  Branch (2189:21): [True: 0, False: 0]
2190
0
                    connOptions.onion_binds.push_back(bind_addr.value());
2191
0
                    continue;
2192
0
                }
2193
0
            }
2194
0
        }
2195
0
        return InitError(ResolveErrMsg("bind", bind_arg));
2196
27
    }
2197
2198
27
    for (const std::string& strBind : args.GetArgs("-whitebind")) {
  Branch (2198:37): [True: 0, False: 27]
2199
0
        NetWhitebindPermissions whitebind;
2200
0
        bilingual_str error;
2201
0
        if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error);
  Branch (2201:13): [True: 0, False: 0]
2202
0
        connOptions.vWhiteBinds.push_back(whitebind);
2203
0
    }
2204
2205
    // If the user did not specify -bind= or -whitebind= then we bind
2206
    // on any address - 0.0.0.0 (IPv4) and :: (IPv6).
2207
27
    connOptions.bind_on_any = args.GetArgs("-bind").empty() && args.GetArgs("-whitebind").empty();
  Branch (2207:31): [True: 0, False: 27]
  Branch (2207:64): [True: 0, False: 0]
2208
2209
    // Emit a warning if a bad port is given to -port= but only if -bind and -whitebind are not
2210
    // given, because if they are, then -port= is ignored.
2211
27
    if (connOptions.bind_on_any && args.IsArgSet("-port")) {
  Branch (2211:9): [True: 0, False: 27]
  Branch (2211:9): [True: 0, False: 27]
  Branch (2211:36): [True: 0, False: 0]
2212
0
        const uint16_t port_arg = args.GetIntArg("-port", 0);
2213
0
        if (IsBadPort(port_arg)) {
  Branch (2213:13): [True: 0, False: 0]
2214
0
            InitWarning(BadPortWarning("-port", port_arg));
2215
0
        }
2216
0
    }
2217
2218
27
    CService onion_service_target;
2219
27
    if (!connOptions.onion_binds.empty()) {
  Branch (2219:9): [True: 0, False: 27]
2220
0
        onion_service_target = connOptions.onion_binds.front();
2221
27
    } else if (!connOptions.vBinds.empty()) {
  Branch (2221:16): [True: 27, False: 0]
2222
27
        onion_service_target = connOptions.vBinds.front();
2223
27
    } else {
2224
0
        onion_service_target = DefaultOnionServiceTarget(default_bind_port_onion);
2225
0
        connOptions.onion_binds.push_back(onion_service_target);
2226
0
    }
2227
2228
27
    if (listenonion) {
  Branch (2228:9): [True: 0, False: 27]
2229
0
        if (connOptions.onion_binds.size() > 1) {
  Branch (2229:13): [True: 0, False: 0]
2230
0
            InitWarning(strprintf(_("More than one onion bind address is provided. Using %s "
2231
0
                                    "for the automatically created Tor onion service."),
2232
0
                                  onion_service_target.ToStringAddrPort()));
2233
0
        }
2234
0
        node.tor_controller = std::make_unique<TorController>(gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL), onion_service_target);
2235
0
    }
2236
2237
27
    bool should_discover = connOptions.bind_on_any;
2238
27
    if (!should_discover) {
  Branch (2238:9): [True: 27, False: 0]
2239
27
        for (const auto& bind : connOptions.vBinds) {
  Branch (2239:31): [True: 27, False: 27]
2240
27
            if (bind.IsBindAny()) {
  Branch (2240:17): [True: 0, False: 27]
2241
0
                should_discover = true;
2242
0
                break;
2243
0
            }
2244
27
        }
2245
27
    }
2246
2247
27
    if (!should_discover) {
  Branch (2247:9): [True: 27, False: 0]
2248
27
        for (const auto& whitebind : connOptions.vWhiteBinds) {
  Branch (2248:36): [True: 0, False: 27]
2249
0
            if (whitebind.m_service.IsBindAny()) {
  Branch (2249:17): [True: 0, False: 0]
2250
0
                should_discover = true;
2251
0
                break;
2252
0
            }
2253
0
        }
2254
27
    }
2255
2256
27
    if (should_discover) {
  Branch (2256:9): [True: 0, False: 27]
2257
        // Only add all IP addresses of the machine if we would be listening on
2258
        // any address - 0.0.0.0 (IPv4) and :: (IPv6).
2259
0
        Discover();
2260
0
    }
2261
2262
27
    for (const auto& net : args.GetArgs("-whitelist")) {
  Branch (2262:26): [True: 0, False: 27]
2263
0
        NetWhitelistPermissions subnet;
2264
0
        ConnectionDirection connection_direction;
2265
0
        bilingual_str error;
2266
0
        if (!NetWhitelistPermissions::TryParse(net, subnet, connection_direction, error)) return InitError(error);
  Branch (2266:13): [True: 0, False: 0]
2267
0
        if (connection_direction & ConnectionDirection::In) {
  Branch (2267:13): [True: 0, False: 0]
2268
0
            connOptions.vWhitelistedRangeIncoming.push_back(subnet);
2269
0
        }
2270
0
        if (connection_direction & ConnectionDirection::Out) {
  Branch (2270:13): [True: 0, False: 0]
2271
0
            connOptions.vWhitelistedRangeOutgoing.push_back(subnet);
2272
0
        }
2273
0
    }
2274
2275
27
    connOptions.vSeedNodes = args.GetArgs("-seednode");
2276
2277
27
    const auto connect = args.GetArgs("-connect");
2278
27
    if (!connect.empty() || args.IsArgNegated("-connect")) {
  Branch (2278:9): [True: 0, False: 27]
  Branch (2278:9): [True: 27, False: 0]
  Branch (2278:29): [True: 27, False: 0]
2279
        // Do not initiate other outgoing connections when connecting to trusted
2280
        // nodes, or when -noconnect is specified.
2281
27
        connOptions.m_use_addrman_outgoing = false;
2282
2283
27
        if (connect.size() != 1 || connect[0] != "0") {
  Branch (2283:13): [True: 27, False: 0]
  Branch (2283:36): [True: 0, False: 0]
2284
27
            connOptions.m_specified_outgoing = connect;
2285
27
        }
2286
27
        if (!connOptions.m_specified_outgoing.empty() && !connOptions.vSeedNodes.empty()) {
  Branch (2286:13): [True: 0, False: 27]
  Branch (2286:58): [True: 0, False: 0]
2287
0
            LogInfo("-seednode is ignored when -connect is used");
2288
0
        }
2289
2290
27
        if (args.IsArgSet("-dnsseed") && args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED) && args.IsArgSet("-proxy")) {
  Branch (2290:13): [True: 27, False: 0]
  Branch (2290:13): [True: 0, False: 27]
  Branch (2290:42): [True: 0, False: 27]
  Branch (2290:90): [True: 0, False: 0]
2291
0
            LogInfo("-dnsseed is ignored when -connect is used and -proxy is specified");
2292
0
        }
2293
27
    }
2294
2295
27
    const std::string& i2psam_arg = args.GetArg("-i2psam", "");
2296
27
    if (!i2psam_arg.empty()) {
  Branch (2296:9): [True: 0, False: 27]
2297
0
        const std::optional<CService> addr{Lookup(i2psam_arg, 7656, fNameLookup)};
2298
0
        if (!addr.has_value() || !addr->IsValid()) {
  Branch (2298:13): [True: 0, False: 0]
  Branch (2298:34): [True: 0, False: 0]
2299
0
            return InitError(strprintf(_("Invalid -i2psam address or hostname: '%s'"), i2psam_arg));
2300
0
        }
2301
0
        SetProxy(NET_I2P, Proxy{addr.value()});
2302
27
    } else {
2303
27
        if (!onlynets.empty() && g_reachable_nets.Contains(NET_I2P)) {
  Branch (2303:13): [True: 0, False: 27]
  Branch (2303:34): [True: 0, False: 0]
2304
0
            return InitError(
2305
0
                _("Outbound connections restricted to i2p (-onlynet=i2p) but "
2306
0
                  "-i2psam is not provided"));
2307
0
        }
2308
27
        g_reachable_nets.Remove(NET_I2P);
2309
27
    }
2310
2311
27
    connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", DEFAULT_I2P_ACCEPT_INCOMING);
2312
2313
27
    if (auto conflict = CheckBindingConflicts(connOptions)) {
  Branch (2313:14): [True: 0, False: 27]
2314
0
        return InitError(strprintf(
2315
0
            _("Duplicate binding configuration for address %s. "
2316
0
                "Please check your -bind, -bind=...=onion and -whitebind settings."),
2317
0
                    conflict->ToStringAddrPort()));
2318
0
    }
2319
2320
27
    if (args.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)) {
  Branch (2320:9): [True: 0, False: 27]
2321
        // If -listenonion is set, then NET_ONION may not be reachable now
2322
        // but may become reachable later, thus only error here if it is not
2323
        // reachable and will not become reachable for sure.
2324
0
        const bool onion_may_become_reachable{listenonion && (!args.IsArgSet("-onlynet") || onlynet_used_with_onion)};
  Branch (2324:47): [True: 0, False: 0]
  Branch (2324:63): [True: 0, False: 0]
  Branch (2324:93): [True: 0, False: 0]
2325
0
        if (!g_reachable_nets.Contains(NET_I2P) &&
  Branch (2325:13): [True: 0, False: 0]
2326
0
            !g_reachable_nets.Contains(NET_ONION) &&
  Branch (2326:13): [True: 0, False: 0]
2327
0
            !onion_may_become_reachable) {
  Branch (2327:13): [True: 0, False: 0]
2328
0
            return InitError(_("Private broadcast of own transactions requested (-privatebroadcast), "
2329
0
                               "but none of Tor or I2P networks is reachable"));
2330
0
        }
2331
0
        if (!connOptions.m_use_addrman_outgoing) {
  Branch (2331:13): [True: 0, False: 0]
2332
0
            return InitError(_("Private broadcast of own transactions requested (-privatebroadcast), "
2333
0
                               "but -connect is also configured. They are incompatible because the "
2334
0
                               "private broadcast needs to open new connections to randomly "
2335
0
                               "chosen Tor or I2P peers. Consider using -maxconnections=0 -addnode=... "
2336
0
                               "instead"));
2337
0
        }
2338
0
        if (!proxyRandomize && (g_reachable_nets.Contains(NET_ONION) || onion_may_become_reachable)) {
  Branch (2338:13): [True: 0, False: 0]
  Branch (2338:33): [True: 0, False: 0]
  Branch (2338:73): [True: 0, False: 0]
2339
0
            InitWarning(_("Private broadcast of own transactions requested (-privatebroadcast) and "
2340
0
                          "-proxyrandomize is disabled. Tor circuits for private broadcast connections "
2341
0
                          "may be correlated to other connections over Tor. For maximum privacy set "
2342
0
                          "-proxyrandomize=1."));
2343
0
        }
2344
0
    }
2345
2346
27
    if (!node.connman->Start(scheduler, connOptions)) {
  Branch (2346:9): [True: 27, False: 0]
2347
27
        return false;
2348
27
    }
2349
2350
    // ********************************************************* Step 13: finished
2351
2352
    // At this point, the RPC is "started", but still in warmup, which means it
2353
    // cannot yet be called. Before we make it callable, we need to make sure
2354
    // that the RPC's view of the best block is valid and consistent with
2355
    // ChainstateManager's active tip.
2356
0
    SetRPCWarmupFinished();
2357
2358
0
    uiInterface.InitMessage(_("Done loading"));
2359
2360
0
    for (const auto& client : node.chain_clients) {
  Branch (2360:29): [True: 0, False: 0]
2361
0
        client->start(scheduler);
2362
0
    }
2363
2364
0
    BanMan* banman = node.banman.get();
2365
65.4k
    scheduler.scheduleEvery([banman]{
2366
65.4k
        banman->DumpBanlist();
2367
65.4k
    }, DUMP_BANS_INTERVAL);
2368
2369
0
    if (node.peerman) node.peerman->StartScheduledTasks(scheduler);
  Branch (2369:9): [True: 0, False: 0]
2370
2371
0
#if HAVE_SYSTEM
2372
0
    StartupNotify(args);
2373
0
#endif
2374
2375
0
    return true;
2376
27
}
2377
2378
bool StartIndexBackgroundSync(NodeContext& node)
2379
27
{
2380
27
    ChainstateManager& chainman = *Assert(node.chainman);
2381
27
    const Chainstate& chainstate = WITH_LOCK(::cs_main, return chainman.ValidatedChainstate());
2382
27
    const CChain& index_chain = chainstate.m_chain;
2383
27
    const int current_height = WITH_LOCK(::cs_main, return index_chain.Height());
2384
2385
    // Skip checking data availability if we have not synced any blocks yet
2386
27
    if (current_height > 0) {
  Branch (2386:9): [True: 0, False: 27]
2387
        // Before starting index sync, verify that all required block data is available
2388
        // on disk from each index's current sync position up to the chain tip.
2389
        //
2390
        // This is done separately for undo and block data: First we verify block + undo
2391
        // data existence from tip down to the lowest height required by any index that
2392
        // needs undo data (e.g., coinstatsindex, blockfilterindex). Then, if any
2393
        // block-only index needs to sync from a lower height than previously covered,
2394
        // verify block data existence down to that lower height.
2395
        //
2396
        // This avoids checking undo data for blocks where no index requires it,
2397
        // though currently block and undo data availability are synchronized on disk
2398
        // under normal circumstances.
2399
0
        std::optional<const CBlockIndex*> block_start;
2400
0
        std::string block_start_name;
2401
0
        std::optional<const CBlockIndex*> undo_start;
2402
0
        std::string undo_start_name;
2403
2404
0
        for (const auto& index : node.indexes) {
  Branch (2404:32): [True: 0, False: 0]
2405
0
            const IndexSummary& summary = index->GetSummary();
2406
0
            if (summary.synced) continue;
  Branch (2406:17): [True: 0, False: 0]
2407
2408
            // Get the last common block between the index best block and the active chain
2409
0
            const CBlockIndex* pindex = nullptr;
2410
0
            {
2411
0
                LOCK(::cs_main);
2412
0
                pindex = chainman.m_blockman.LookupBlockIndex(summary.best_block_hash);
2413
0
                if (!pindex) {
  Branch (2413:21): [True: 0, False: 0]
2414
0
                    LogWarning("Failed to find block manager entry for best block %s from %s, falling back to genesis for index sync",
2415
0
                        summary.best_block_hash.ToString(), summary.name);
2416
0
                } else if (!index_chain.Contains(*pindex)) {
  Branch (2416:28): [True: 0, False: 0]
2417
0
                    pindex = index_chain.FindFork(*pindex);
2418
0
                }
2419
0
            }
2420
0
            if (!pindex) {
  Branch (2420:17): [True: 0, False: 0]
2421
0
                pindex = index_chain.Genesis();
2422
0
            }
2423
2424
0
            bool need_undo = index->CustomOptions().connect_undo_data;
2425
0
            auto& op_start_index = need_undo ? undo_start : block_start;
  Branch (2425:36): [True: 0, False: 0]
2426
0
            auto& name_index = need_undo ? undo_start_name : block_start_name;
  Branch (2426:32): [True: 0, False: 0]
2427
2428
0
            if (op_start_index && pindex->nHeight >= op_start_index.value()->nHeight) continue;
  Branch (2428:17): [True: 0, False: 0]
  Branch (2428:35): [True: 0, False: 0]
2429
0
            op_start_index = pindex;
2430
0
            name_index = summary.name;
2431
0
        }
2432
2433
        // Verify all blocks needed to sync to current tip are present including undo data.
2434
0
        if (undo_start) {
  Branch (2434:13): [True: 0, False: 0]
2435
0
            LOCK(::cs_main);
2436
0
            if (!chainman.m_blockman.CheckBlockDataAvailability(*index_chain.Tip(), *Assert(undo_start.value()), BlockStatus{BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO})) {
  Branch (2436:17): [True: 0, False: 0]
2437
0
                return InitError(Untranslated(strprintf("%s best block of the index goes beyond pruned data (including undo data). Please disable the index or reindex (which will download the whole blockchain again)", undo_start_name)));
2438
0
            }
2439
0
        }
2440
2441
        // Verify all blocks needed to sync to current tip are present unless we already checked all of them above.
2442
0
        if (block_start && !(undo_start && undo_start.value()->nHeight <= block_start.value()->nHeight)) {
  Branch (2442:13): [True: 0, False: 0]
  Branch (2442:30): [True: 0, False: 0]
  Branch (2442:44): [True: 0, False: 0]
2443
0
            LOCK(::cs_main);
2444
0
            if (!chainman.m_blockman.CheckBlockDataAvailability(*index_chain.Tip(), *Assert(block_start.value()), BlockStatus{BLOCK_HAVE_DATA})) {
  Branch (2444:17): [True: 0, False: 0]
2445
0
                return InitError(Untranslated(strprintf("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)", block_start_name)));
2446
0
            }
2447
0
        }
2448
0
    }
2449
2450
    // Start threads
2451
27
    for (auto index : node.indexes) if (!index->StartBackgroundSync()) return false;
  Branch (2451:21): [True: 27, False: 27]
  Branch (2451:41): [True: 0, False: 27]
2452
27
    return true;
2453
27
}