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