LCOV - code coverage report
Current view: top level - src - init.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 727 947 76.8 %
Date: 2025-02-23 09:33:43 Functions: 27 31 87.1 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin developers
       3             : // Copyright (c) 2014-2015 The Dash developers
       4             : // Copyright (c) 2011-2013 The PPCoin developers
       5             : // Copyright (c) 2013-2014 The NovaCoin Developers
       6             : // Copyright (c) 2014-2018 The BlackCoin Developers
       7             : // Copyright (c) 2015-2022 The PIVX Core developers
       8             : // Distributed under the MIT software license, see the accompanying
       9             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
      10             : 
      11             : #if defined(HAVE_CONFIG_H)
      12             : #include "config/pivx-config.h"
      13             : #endif
      14             : 
      15             : #include "init.h"
      16             : 
      17             : #include "activemasternode.h"
      18             : #include "addrman.h"
      19             : #include "amount.h"
      20             : #include "bls/bls_wrapper.h"
      21             : #include "checkpoints.h"
      22             : #include "compat/sanity.h"
      23             : #include "consensus/upgrades.h"
      24             : #include "fs.h"
      25             : #include "httpserver.h"
      26             : #include "httprpc.h"
      27             : #include "invalid.h"
      28             : #include "key.h"
      29             : #include "mapport.h"
      30             : #include "miner.h"
      31             : #include "netbase.h"
      32             : #include "net_processing.h"
      33             : #include "policy/feerate.h"
      34             : #include "policy/policy.h"
      35             : #include "rpc/register.h"
      36             : #include "rpc/server.h"
      37             : #include "script/sigcache.h"
      38             : #include "script/standard.h"
      39             : #include "scheduler.h"
      40             : #include "shutdown.h"
      41             : #include "spork.h"
      42             : #include "sporkdb.h"
      43             : #include "tiertwo/init.h"
      44             : #include "txdb.h"
      45             : #include "torcontrol.h"
      46             : #include "guiinterface.h"
      47             : #include "guiinterfaceutil.h"
      48             : #include "util/system.h"
      49             : #include "utilmoneystr.h"
      50             : #include "util/threadnames.h"
      51             : #include "validation.h"
      52             : #include "validationinterface.h"
      53             : #include "warnings.h"
      54             : 
      55             : #ifdef ENABLE_WALLET
      56             : #include "wallet/init.h"
      57             : #include "wallet/wallet.h"
      58             : #include "wallet/rpcwallet.h"
      59             : #endif
      60             : 
      61             : #include <atomic>
      62             : #include <fstream>
      63             : #include <stdint.h>
      64             : #include <stdio.h>
      65             : #include <memory>
      66             : 
      67             : #ifndef WIN32
      68             : #include <attributes.h>
      69             : #include <cerrno>
      70             : #include <signal.h>
      71             : #include <sys/stat.h>
      72             : #endif
      73             : 
      74             : #include <boost/algorithm/string.hpp>
      75             : #include <boost/algorithm/string/split.hpp>
      76             : #include <boost/algorithm/string/replace.hpp>
      77             : #include <boost/thread.hpp>
      78             : 
      79             : #if ENABLE_ZMQ
      80             : #include "zmq/zmqnotificationinterface.h"
      81             : #endif
      82             : 
      83             : 
      84             : volatile bool fFeeEstimatesInitialized = false;
      85             : static const bool DEFAULT_PROXYRANDOMIZE = true;
      86             : static const bool DEFAULT_REST_ENABLE = false;
      87             : static const bool DEFAULT_DISABLE_SAFEMODE = false;
      88             : static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
      89             : 
      90             : std::unique_ptr<CConnman> g_connman;
      91             : std::unique_ptr<PeerLogicValidation> peerLogic;
      92             : 
      93             : #if ENABLE_ZMQ
      94             : static CZMQNotificationInterface* pzmqNotificationInterface = nullptr;
      95             : #endif
      96             : 
      97             : #ifdef WIN32
      98             : // Win32 LevelDB doesn't use filedescriptors, and the ones used for
      99             : // accessing block files, don't count towards to fd_set size limit
     100             : // anyway.
     101             : #define MIN_CORE_FILEDESCRIPTORS 0
     102             : #else
     103             : #define MIN_CORE_FILEDESCRIPTORS 150
     104             : #endif
     105             : 
     106             : static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
     107             : 
     108             : static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
     109             : CClientUIInterface uiInterface;  // Declared but not defined in guiinterface.h
     110             : 
     111             : /**
     112             :  * The PID file facilities.
     113             :  */
     114             : const char * const PIVX_PID_FILENAME = "pivx.pid";
     115             : 
     116         756 : fs::path GetPidFile()
     117             : {
     118        1512 :     fs::path pathPidFile(gArgs.GetArg("-pid", PIVX_PID_FILENAME));
     119        1512 :     return AbsPathForConfigVal(pathPidFile);
     120             : }
     121             : 
     122         378 : NODISCARD static bool CreatePidFile()
     123             : {
     124         378 :     FILE* file = fsbridge::fopen(GetPidFile(), "w");
     125         378 :     if (file) {
     126         378 :         fprintf(file, "%d\n", getpid());
     127         378 :         fclose(file);
     128         378 :         return true;
     129             :     } else {
     130           0 :         return UIError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno)));
     131             :     }
     132             : }
     133             : 
     134             : //////////////////////////////////////////////////////////////////////////////
     135             : //
     136             : // Shutdown
     137             : //
     138             : 
     139             : //
     140             : // Thread management and startup/shutdown:
     141             : //
     142             : // The network-processing threads are all part of a thread group
     143             : // created by AppInit() or the Qt main() function.
     144             : //
     145             : // A clean exit happens when StartShutdown() or the SIGTERM
     146             : // signal handler sets ShutdownRequested(), which triggers
     147             : // the DetectShutdownThread(), which interrupts the main thread group.
     148             : // DetectShutdownThread() then exits, which causes AppInit() to
     149             : // continue (it .joins the shutdown thread).
     150             : // Shutdown() is then
     151             : // called to clean up database connections, and stop other
     152             : // threads that should only be stopped after the main network-processing
     153             : // threads have exited.
     154             : //
     155             : // Shutdown for Qt is very similar, only it uses a QTimer to detect
     156             : // ShutdownRequested() getting set, and then does the normal Qt
     157             : // shutdown thing.
     158             : //
     159             : 
     160             : class CCoinsViewErrorCatcher : public CCoinsViewBacked
     161             : {
     162             : public:
     163         714 :     explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
     164     1307110 :     bool GetCoin(const COutPoint& outpoint, Coin& coin) const override
     165             :     {
     166     1307110 :         try {
     167     1307110 :             return CCoinsViewBacked::GetCoin(outpoint, coin);
     168           0 :         } catch (const std::runtime_error& e) {
     169           0 :             uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR);
     170           0 :             LogPrintf("Error reading from database: %s\n", e.what());
     171             :             // Starting the shutdown sequence and returning false to the caller would be
     172             :             // interpreted as 'entry not found' (as opposed to unable to read data), and
     173             :             // could lead to invalid interpration. Just exit immediately, as we can't
     174             :             // continue anyway, and all writes should be atomic.
     175           0 :             abort();
     176             :         }
     177             :     }
     178             :     // Writes do not need similar protection, as failure to write is handled by the caller.
     179             : };
     180             : 
     181             : static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
     182             : static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
     183             : 
     184             : static boost::thread_group threadGroup;
     185             : static CScheduler scheduler;
     186         378 : void Interrupt()
     187             : {
     188         378 :     InterruptHTTPServer();
     189         378 :     InterruptHTTPRPC();
     190         378 :     InterruptRPC();
     191         378 :     InterruptREST();
     192         378 :     InterruptTorControl();
     193         378 :     InterruptMapPort();
     194         378 :     InterruptTierTwo();
     195         378 :     if (g_connman)
     196         366 :         g_connman->Interrupt();
     197         378 : }
     198             : 
     199         378 : void Shutdown()
     200             : {
     201         378 :     StartShutdown();  // Needed when we shutdown the wallet
     202         378 :     LogPrintf("%s: In progress...\n", __func__);
     203         378 :     static RecursiveMutex cs_Shutdown;
     204         756 :     TRY_LOCK(cs_Shutdown, lockShutdown);
     205         378 :     if (!lockShutdown)
     206           0 :         return;
     207             : 
     208             :     /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,
     209             :     /// for example if the data directory was found to be locked.
     210             :     /// Be sure that anything that writes files or flushes caches only does this if the respective
     211             :     /// module was initialized.
     212         378 :     util::ThreadRename("pivx-shutoff");
     213         378 :     mempool.AddTransactionsUpdated(1);
     214         378 :     StopHTTPRPC();
     215         378 :     StopREST();
     216         378 :     StopRPC();
     217         378 :     StopHTTPServer();
     218         378 :     StopTierTwoThreads();
     219             : #ifdef ENABLE_WALLET
     220         740 :     for (CWalletRef pwallet : vpwallets) {
     221         362 :         pwallet->Flush(false);
     222             :     }
     223         378 :     GenerateBitcoins(false, nullptr, 0);
     224             : #endif
     225         378 :     StopMapPort();
     226             : 
     227             :     // Because these depend on each-other, we make sure that neither can be
     228             :     // using the other before destroying them.
     229         378 :     if (peerLogic) UnregisterValidationInterface(peerLogic.get());
     230         378 :     if (g_connman) g_connman->Stop();
     231             : 
     232         378 :     StopTorControl();
     233             : 
     234             :     // After everything has been shut down, but before things get flushed, stop the
     235             :     // CScheduler/checkqueue threadGroup
     236         378 :     scheduler.stop();
     237         378 :     threadGroup.interrupt_all();
     238         378 :     threadGroup.join_all();
     239             : 
     240             :     // After the threads that potentially access these pointers have been stopped,
     241             :     // destruct and reset all to nullptr.
     242         378 :     g_connman.reset();
     243         378 :     peerLogic.reset();
     244             : 
     245         378 :     DumpTierTwo();
     246         741 :     if (::mempool.IsLoaded() && gArgs.GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
     247         347 :         DumpMempool(::mempool);
     248             :     }
     249             : 
     250         378 :     if (fFeeEstimatesInitialized) {
     251         712 :         fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
     252         712 :         CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION);
     253         356 :         if (!est_fileout.IsNull())
     254         356 :             mempool.WriteFeeEstimates(est_fileout);
     255             :         else
     256           0 :             LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string());
     257         356 :         fFeeEstimatesInitialized = false;
     258             :     }
     259             : 
     260             :     // FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
     261         378 :     if (pcoinsTip != nullptr) {
     262         357 :         FlushStateToDisk();
     263             :     }
     264             : 
     265             :     // After there are no more peers/RPC left to give us new data which may generate
     266             :     // CValidationInterface callbacks, flush them...
     267         378 :     GetMainSignals().FlushBackgroundCallbacks();
     268             : 
     269             :     // Any future callbacks will be dropped. This should absolutely be safe - if
     270             :     // missing a callback results in an unrecoverable situation, unclean shutdown
     271             :     // would too. The only reason to do the above flushes is to let the wallet catch
     272             :     // up with our current chain to avoid any strange pruning edge cases and make
     273             :     // next startup faster by avoiding rescan.
     274             : 
     275         378 :     {
     276         378 :         LOCK(cs_main);
     277         378 :         if (pcoinsTip != nullptr) {
     278         357 :             FlushStateToDisk();
     279             : 
     280             :             //record that client took the proper shutdown procedure
     281         714 :             pblocktree->WriteFlag("shutdown", true);
     282             :         }
     283         378 :         pcoinsTip.reset();
     284         378 :         pcoinscatcher.reset();
     285         378 :         pcoinsdbview.reset();
     286         378 :         pblocktree.reset();
     287         378 :         zerocoinDB.reset();
     288         378 :         accumulatorCache.reset();
     289         378 :         pSporkDB.reset();
     290         378 :         DeleteTierTwo();
     291             :     }
     292             : #ifdef ENABLE_WALLET
     293         740 :     for (CWalletRef pwallet : vpwallets) {
     294         362 :         pwallet->Flush(true);
     295             :     }
     296             : #endif
     297             : 
     298             :     // Tier two
     299         378 :     ResetTierTwoInterfaces();
     300             : 
     301             : #if ENABLE_ZMQ
     302         378 :     if (pzmqNotificationInterface) {
     303           1 :         UnregisterValidationInterface(pzmqNotificationInterface);
     304           1 :         delete pzmqNotificationInterface;
     305           1 :         pzmqNotificationInterface = nullptr;
     306             :     }
     307             : #endif
     308             : 
     309             :     // Disconnect all slots
     310         378 :     UnregisterAllValidationInterfaces();
     311         378 :     GetMainSignals().UnregisterBackgroundSignalScheduler();
     312             : 
     313             : #ifndef WIN32
     314         378 :     try {
     315        1134 :         if (!fs::remove(GetPidFile())) {
     316           0 :             LogPrintf("%s: Unable to remove PID file: File does not exist\n", __func__);
     317             :         }
     318           0 :     } catch (const fs::filesystem_error& e) {
     319           0 :         LogPrintf("%s: Unable to remove PID file: %s\n", __func__, e.what());
     320             :     }
     321             : #endif
     322             : 
     323             : #ifdef ENABLE_WALLET
     324         740 :     for (CWalletRef pwallet : vpwallets) {
     325         362 :         delete pwallet;
     326             :     }
     327         378 :     vpwallets.clear();
     328             : #endif
     329         378 :     globalVerifyHandle.reset();
     330         378 :     ECC_Stop();
     331         378 :     LogPrintf("%s: done\n", __func__);
     332             : }
     333             : 
     334             : /**
     335             :  * Signal handlers are very limited in what they are allowed to do, so:
     336             :  */
     337           0 : void HandleSIGTERM(int)
     338             : {
     339           0 :     StartShutdown();
     340           0 : }
     341             : 
     342           0 : void HandleSIGHUP(int)
     343             : {
     344           0 :     g_logger->m_reopen_file = true;
     345           0 : }
     346             : 
     347             : #ifndef WIN32
     348        1161 : static void registerSignalHandler(int signal, void(*handler)(int))
     349             : {
     350        1161 :     struct sigaction sa{};
     351        1161 :     sa.sa_handler = handler;
     352        1161 :     sigemptyset(&sa.sa_mask);
     353        1161 :     sa.sa_flags = 0;
     354        1161 :     sigaction(signal, &sa, nullptr);
     355        1161 : }
     356             : #endif
     357             : 
     358         375 : void OnRPCStarted()
     359             : {
     360         750 :     uiInterface.NotifyBlockTip.connect(RPCNotifyBlockChange);
     361         375 : }
     362             : 
     363         375 : void OnRPCStopped()
     364             : {
     365         375 :     uiInterface.NotifyBlockTip.disconnect(RPCNotifyBlockChange);
     366             :     // TODO: remove unused parameter fInitialDownload
     367         375 :     RPCNotifyBlockChange(false, nullptr);
     368         375 :     g_best_block_cv.notify_all();
     369         375 :     LogPrint(BCLog::RPC, "RPC stopped.\n");
     370         375 : }
     371             : 
     372      298052 : void OnRPCPreCommand(const CRPCCommand& cmd)
     373             : {
     374             :     // Observe safe mode
     375      298052 :     std::string strWarning = GetWarnings("rpc");
     376      298052 :     if (!strWarning.empty() && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) &&
     377           0 :         !cmd.okSafeMode)
     378           0 :         throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning);
     379      298052 : }
     380             : 
     381           1 : std::string HelpMessage(HelpMessageMode mode)
     382             : {
     383           1 :     const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
     384           2 :     const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
     385           2 :     const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);
     386           2 :     const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);
     387           1 :     const bool showDebug = gArgs.GetBoolArg("-help-debug", false);
     388             : 
     389             :     // When adding new options to the categories, please keep and ensure alphabetical ordering.
     390           1 :     std::string strUsage = HelpMessageGroup("Options:");
     391           3 :     strUsage += HelpMessageOpt("-?", "This help message");
     392           3 :     strUsage += HelpMessageOpt("-version", "Print version and exit");
     393           4 :     strUsage += HelpMessageOpt("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)");
     394           4 :     strUsage += HelpMessageOpt("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)");
     395           4 :     strUsage += HelpMessageOpt("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)");
     396           4 :     strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS));
     397           3 :     strUsage += HelpMessageOpt("-checklevel=<n>", strprintf("How thorough the block verification of -checkblocks is (0-4, default: %u)", DEFAULT_CHECKLEVEL));
     398             : 
     399           3 :     strUsage += HelpMessageOpt("-conf=<file>", strprintf("Specify configuration file (default: %s)", PIVX_CONF_FILENAME));
     400           1 :     if (mode == HMM_BITCOIND) {
     401             : #if !defined(WIN32)
     402           4 :         strUsage += HelpMessageOpt("-daemon", "Run in the background as a daemon and accept commands");
     403             : #endif
     404             :     }
     405           3 :     strUsage += HelpMessageOpt("-datadir=<dir>", "Specify data directory");
     406           1 :     if (showDebug) {
     407           0 :         strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize));
     408             :     }
     409           4 :     strUsage += HelpMessageOpt("-paramsdir=<dir>", strprintf("Specify zk params directory (default: %s)", ZC_GetParamsDir().string()));
     410           4 :     strUsage += HelpMessageOpt("-debuglogfile=<file>", strprintf("Specify location of debug log file: this can be an absolute path or a path relative to the data directory (default: %s)", DEFAULT_DEBUGLOGFILE));
     411           4 :     strUsage += HelpMessageOpt("-disablesystemnotifications", strprintf("Disable OS notifications for incoming transactions (default: %u)", 0));
     412           3 :     strUsage += HelpMessageOpt("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache));
     413           4 :     strUsage += HelpMessageOpt("-loadblock=<file>", "Imports blocks from external blk000??.dat file on startup");
     414           3 :     strUsage += HelpMessageOpt("-maxreorg=<n>", strprintf("Set the Maximum reorg depth (default: %u)", DEFAULT_MAX_REORG_DEPTH));
     415           4 :     strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
     416           3 :     strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE));
     417           4 :     strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY));
     418           3 :     strUsage += HelpMessageOpt("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL));
     419           3 :     strUsage += HelpMessageOpt("-par=<n>", strprintf("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)", -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
     420             : #ifndef WIN32
     421           3 :     strUsage += HelpMessageOpt("-pid=<file>", strprintf("Specify pid file (default: %s)", PIVX_PID_FILENAME));
     422             : #endif
     423           4 :     strUsage += HelpMessageOpt("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks");
     424           3 :     strUsage += HelpMessageOpt("-reindex", "Rebuild block chain index from current blk000??.dat files on startup");
     425           3 :     strUsage += HelpMessageOpt("-resync", "Delete blockchain folders and resync from scratch on startup");
     426             : #if !defined(WIN32)
     427           3 :     strUsage += HelpMessageOpt("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)");
     428             : #endif
     429           3 :     strUsage += HelpMessageOpt("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX));
     430           3 :     strUsage += HelpMessageOpt("-forcestart", "Attempt to force blockchain corruption recovery on startup");
     431             : 
     432           3 :     strUsage += HelpMessageGroup("Connection options:");
     433           3 :     strUsage += HelpMessageOpt("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open");
     434           3 :     strUsage += HelpMessageOpt("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME));
     435           3 :     strUsage += HelpMessageOpt("-banscore=<n>", strprintf("Threshold for disconnecting misbehaving peers (default: %u)", DEFAULT_BANSCORE_THRESHOLD));
     436           3 :     strUsage += HelpMessageOpt("-bantime=<n>", strprintf("Number of seconds to keep misbehaving peers from reconnecting (default: %u)", DEFAULT_MISBEHAVING_BANTIME));
     437           3 :     strUsage += HelpMessageOpt("-bind=<addr>", "Bind to given address and always listen on it. Use [host]:port notation for IPv6");
     438           3 :     strUsage += HelpMessageOpt("-connect=<ip>", "Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections");
     439           3 :     strUsage += HelpMessageOpt("-discover", "Discover own IP address (default: 1 when listening and no -externalip)");
     440           3 :     strUsage += HelpMessageOpt("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP));
     441           3 :     strUsage += HelpMessageOpt("-dnsseed", "Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)");
     442           4 :     strUsage += HelpMessageOpt("-externalip=<ip>", "Specify your own public address");
     443           3 :     strUsage += HelpMessageOpt("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED));
     444           3 :     strUsage += HelpMessageOpt("-listen", strprintf("Accept connections from outside (default: %u if no -proxy or -connect/-noconnect)", DEFAULT_LISTEN));
     445           3 :     strUsage += HelpMessageOpt("-listenonion", strprintf("Automatically create Tor hidden service (default: %d)", DEFAULT_LISTEN_ONION));
     446           4 :     strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf("Maintain at most <n> connections to peers (default: %u)", DEFAULT_MAX_PEER_CONNECTIONS));
     447           4 :     strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER));
     448           4 :     strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER));
     449           4 :     strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)", "-proxy"));
     450           3 :     strUsage += HelpMessageOpt("-onlynet=<net>", "Only connect to nodes in network <net> (ipv4, ipv6 or onion)");
     451           4 :     strUsage += HelpMessageOpt("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG));
     452           4 :     strUsage += HelpMessageOpt("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS));
     453           3 :     strUsage += HelpMessageOpt("-port=<port>", strprintf("Listen for connections on <port> (default: %u or testnet: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()));
     454           4 :     strUsage += HelpMessageOpt("-proxy=<ip:port>", "Connect through SOCKS5 proxy");
     455           3 :     strUsage += HelpMessageOpt("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE));
     456           3 :     strUsage += HelpMessageOpt("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect");
     457           3 :     strUsage += HelpMessageOpt("-timeout=<n>", strprintf("Specify connection timeout in milliseconds (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT));
     458           4 :     strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf("Tor control port to use if onion listening enabled (default: %s)", DEFAULT_TOR_CONTROL));
     459           4 :     strUsage += HelpMessageOpt("-torpassword=<pass>", "Tor control port password (default: empty)");
     460           3 :     strUsage += HelpMessageOpt("-upnp", strprintf("Use UPnP to map the listening port (default: %u)", DEFAULT_UPNP));
     461             : #ifdef USE_NATPMP
     462           3 :     strUsage += HelpMessageOpt("-natpmp", strprintf("Use NAT-PMP to map the listening port (default: %s)", DEFAULT_NATPMP ? "1 when listening and no -proxy" : "0"));
     463             : #endif // USE_NATPMP
     464           4 :     strUsage += HelpMessageOpt("-whitebind=<addr>", "Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6");
     465           3 :     strUsage += HelpMessageOpt("-whitelist=<netmask>", "Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times."
     466           1 :         " Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway");
     467             : 
     468             : #if ENABLE_WALLET
     469           2 :     strUsage += GetWalletHelpString(showDebug);
     470             : #endif
     471             : 
     472           1 :     if (mode == HMM_BITCOIN_QT) {
     473           0 :         strUsage += HelpMessageOpt("-windowtitle=<name>", "Wallet window title");
     474             :     }
     475             : 
     476             : #if ENABLE_ZMQ
     477           3 :     strUsage += HelpMessageGroup("ZeroMQ notification options:");
     478           4 :     strUsage += HelpMessageOpt("-zmqpubhashblock=<address>", "Enable publish hash block in <address>");
     479           4 :     strUsage += HelpMessageOpt("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>");
     480           4 :     strUsage += HelpMessageOpt("-zmqpubrawblock=<address>", "Enable publish raw block in <address>");
     481           4 :     strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", "Enable publish raw transaction in <address>");
     482             : #endif
     483             : 
     484           3 :     strUsage += HelpMessageGroup("Debugging/Testing options:");
     485           4 :     strUsage += HelpMessageOpt("-uacomment=<cmt>", "Append comment to the user agent string");
     486           1 :     if (showDebug) {
     487           0 :         strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
     488           0 :         strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
     489           0 :         strUsage += HelpMessageOpt("-checkpoints", strprintf("Only accept block chain matching built-in checkpoints (default: %u)", DEFAULT_CHECKPOINTS_ENABLED));
     490           0 :         strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE));
     491           0 :         strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE));
     492           0 :         strUsage += HelpMessageOpt("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used");
     493           0 :         strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
     494           0 :         strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
     495           0 :         strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
     496           0 :         strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT));
     497           0 :         strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
     498           0 :         strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
     499           0 :         strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
     500           0 :         strUsage += HelpMessageOpt("-sporkkey=<privkey>", "Enable spork administration functionality with the appropriate private key.");
     501           0 :         strUsage += HelpMessageOpt("-nuparams=upgradeName:activationHeight", "Use given activation height for specified network upgrade (regtest-only)");
     502             :     }
     503           5 :     strUsage += HelpMessageOpt("-debug=<category>", strprintf("Output debugging information (default: %u, supplying <category> is optional)", 0) + ". " +
     504           4 :         "If <category> is not supplied, output all debugging information. <category> can be: " + ListLogCategories() + ".");
     505           4 :     strUsage += HelpMessageOpt("-debugexclude=<category>", "Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.");
     506           1 :     if (showDebug)
     507           0 :         strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0");
     508             : 
     509           3 :     strUsage += HelpMessageOpt("-help-debug", "Show all debugging options (usage: --help -help-debug)");
     510           3 :     strUsage += HelpMessageOpt("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS));
     511           3 :     strUsage += HelpMessageOpt("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS));
     512           3 :     strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
     513           1 :     if (showDebug) {
     514           0 :         strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)");
     515           0 :         strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
     516             :     }
     517           3 :     strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
     518           5 :     strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf("Fees (in %s/Kb) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK())));
     519           3 :     strUsage += HelpMessageOpt("-printtoconsole", strprintf("Send trace/debug info to console instead of debug.log file (default: %u)", 0));
     520           1 :     if (showDebug) {
     521           0 :         strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) 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)));
     522           0 :         strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
     523             :     }
     524           4 :     strUsage += HelpMessageOpt("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)");
     525           1 :     AppendParamsHelpMessages(strUsage, showDebug);
     526             : 
     527           2 :     strUsage += GetTierTwoHelpString(showDebug);
     528             : 
     529           3 :     strUsage += HelpMessageGroup("Node relay options:");
     530           1 :     if (showDebug) {
     531           0 :         strUsage += HelpMessageOpt("-acceptnonstdtxn",
     532           0 :                                    strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)",
     533             :                                              "testnet/regtest only; ",
     534           0 :                                              !CreateChainParams(CBaseChainParams::TESTNET)->RequireStandard()));
     535             :     }
     536           3 :     strUsage += HelpMessageOpt("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER));
     537           4 :     strUsage += HelpMessageOpt("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY));
     538           1 :     if (showDebug) {
     539           0 :         strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
     540             :     }
     541             : 
     542           3 :     strUsage += HelpMessageGroup("Block creation options:");
     543           4 :     strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf("Set maximum block size in bytes (default: %d)", DEFAULT_BLOCK_MAX_SIZE));
     544           1 :     if (showDebug)
     545           0 :         strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
     546             : 
     547           3 :     strUsage += HelpMessageGroup("RPC server options:");
     548           3 :     strUsage += HelpMessageOpt("-server", "Accept command line and JSON-RPC commands");
     549           3 :     strUsage += HelpMessageOpt("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE));
     550           3 :     strUsage += HelpMessageOpt("-rpcbind=<addr>", "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)");
     551           4 :     strUsage += HelpMessageOpt("-rpccookiefile=<loc>", "Location of the auth cookie (default: data dir)");
     552           3 :     strUsage += HelpMessageOpt("-rpcuser=<user>", "Username for JSON-RPC connections");
     553           4 :     strUsage += HelpMessageOpt("-rpcpassword=<pw>", "Password for JSON-RPC connections");
     554           4 :     strUsage += HelpMessageOpt("-rpcauth=<userpw>", "Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times");
     555           3 :     strUsage += HelpMessageOpt("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
     556           4 :     strUsage += HelpMessageOpt("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid 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) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times");
     557           3 :     strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS));
     558           1 :     if (showDebug) {
     559           0 :         strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE));
     560           0 :         strUsage += HelpMessageOpt("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT));
     561             :     }
     562             : 
     563           4 :     strUsage += HelpMessageOpt("-blockspamfilter=<n>", strprintf("Use block spam filter (default: %u)", DEFAULT_BLOCK_SPAM_FILTER));
     564           4 :     strUsage += HelpMessageOpt("-blockspamfiltermaxsize=<n>", strprintf("Maximum size of the list of indexes in the block spam filter (default: %u)", DEFAULT_BLOCK_SPAM_FILTER_MAX_SIZE));
     565           4 :     strUsage += HelpMessageOpt("-blockspamfiltermaxavg=<n>", strprintf("Maximum average size of an index occurrence in the block spam filter (default: %u)", DEFAULT_BLOCK_SPAM_FILTER_MAX_AVG));
     566             : 
     567           2 :     return strUsage;
     568             : }
     569             : 
     570           1 : std::string LicenseInfo()
     571             : {
     572           4 :     return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
     573           2 :            "\n" +
     574           6 :            FormatParagraph(strprintf(_("Copyright (C) 2014-%i The Dash Core Developers"), COPYRIGHT_YEAR)) + "\n" +
     575           2 :            "\n" +
     576           6 :            FormatParagraph(strprintf(_("Copyright (C) 2015-%i The %s Developers"), COPYRIGHT_YEAR, PACKAGE_NAME)) + "\n" +
     577           2 :            "\n" +
     578           5 :            FormatParagraph(_("This is experimental software.")) + "\n" +
     579           2 :            "\n" +
     580           5 :            FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" +
     581           2 :            "\n" +
     582           2 :            FormatParagraph(_("This product includes UPnP software written by Thomas Bernard.")) +
     583           2 :            "\n";
     584             : }
     585             : 
     586          64 : static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)
     587             : {
     588             : 
     589          64 :     if (initialSync || !pBlockIndex)
     590           1 :         return;
     591             : 
     592         189 :     std::string strCmd = gArgs.GetArg("-blocknotify", "");
     593             : 
     594          63 :     if (!strCmd.empty()) {
     595          63 :         boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
     596         126 :         std::thread t(runCommand, strCmd);
     597          63 :         t.detach(); // thread runs free
     598             :     }
     599             : }
     600             : 
     601             : ////////////////////////////////////////////////////
     602             : 
     603             : static bool fHaveGenesis = false;
     604             : static std::mutex cs_GenesisWait;
     605             : static std::condition_variable condvar_GenesisWait;
     606             : 
     607         200 : static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
     608             : {
     609         200 :     if (pBlockIndex != nullptr) {
     610         200 :         {
     611         200 :             std::unique_lock<std::mutex> lock_GenesisWait(cs_GenesisWait);
     612         200 :             fHaveGenesis = true;
     613             :         }
     614         200 :         condvar_GenesisWait.notify_all();
     615             :     }
     616         200 : }
     617             : 
     618             : ////////////////////////////////////////////////////
     619             : 
     620             : 
     621             : struct CImportingNow {
     622         355 :     CImportingNow()
     623             :     {
     624         355 :         assert(fImporting == false);
     625         355 :         fImporting = true;
     626         355 :     }
     627             : 
     628         355 :     ~CImportingNow()
     629             :     {
     630         355 :         assert(fImporting == true);
     631         355 :         fImporting = false;
     632         355 :     }
     633             : };
     634             : 
     635         355 : void ThreadImport(const std::vector<fs::path>& vImportFiles)
     636             : {
     637         355 :     util::ThreadRename("pivx-loadblk");
     638         355 :     CImportingNow imp;
     639         355 :     ScheduleBatchPriority();
     640             : 
     641             :     // -reindex
     642         355 :     if (fReindex) {
     643             :         int nFile = 0;
     644          15 :         while (true) {
     645          10 :             FlatFilePos pos(nFile, 0);
     646          30 :             if (!fs::exists(GetBlockPosFilename(pos)))
     647             :                 break; // No block files left to reindex
     648           5 :             FILE* file = OpenBlockFile(pos, true);
     649           5 :             if (!file)
     650             :                 break; // This error is logged in OpenBlockFile
     651           5 :             LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
     652           5 :             LoadExternalBlockFile(file, &pos);
     653           5 :             nFile++;
     654           5 :         }
     655           5 :         pblocktree->WriteReindexing(false);
     656           5 :         fReindex = false;
     657           5 :         LogPrintf("Reindexing finished\n");
     658             :         // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
     659           5 :         if (!LoadGenesisBlock()) {
     660           0 :             throw std::runtime_error("Error initializing block database");
     661             :         }
     662             :     }
     663             : 
     664             :     // hardcoded $DATADIR/bootstrap.dat
     665         710 :     fs::path pathBootstrap = GetDataDir() / "bootstrap.dat";
     666         710 :     if (fs::exists(pathBootstrap)) {
     667           0 :         FILE* file = fsbridge::fopen(pathBootstrap, "rb");
     668           0 :         if (file) {
     669           0 :             fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
     670           0 :             LogPrintf("Importing bootstrap.dat...\n");
     671           0 :             LoadExternalBlockFile(file);
     672           0 :             RenameOver(pathBootstrap, pathBootstrapOld);
     673             :         } else {
     674           0 :             LogPrintf("Warning: Could not open bootstrap file %s\n", pathBootstrap.string());
     675             :         }
     676             :     }
     677             : 
     678             :     // -loadblock=
     679         355 :     for (const fs::path& path : vImportFiles) {
     680           0 :         FILE* file = fsbridge::fopen(path, "rb");
     681           0 :         if (file) {
     682           0 :             LogPrintf("Importing blocks file %s...\n", path.string());
     683           0 :             LoadExternalBlockFile(file);
     684             :         } else {
     685           0 :             LogPrintf("Warning: Could not open blocks file %s\n", path.string());
     686             :         }
     687             :     }
     688             : 
     689         710 :     if (gArgs.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
     690           0 :         LogPrintf("Stopping after block import\n");
     691           0 :         StartShutdown();
     692             :     }
     693             : 
     694             :     // scan for better chains in the block chain database, that are not yet connected in the active best chain
     695         710 :     CValidationState state;
     696         355 :     if (!ActivateBestChain(state)) {
     697           0 :         LogPrintf("Failed to connect best block\n");
     698           0 :         StartShutdown();
     699             :     }
     700             : 
     701             :     // tier two
     702         355 :     InitTierTwoChainTip();
     703             : 
     704         355 :     if (gArgs.GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
     705         347 :         LoadMempool(::mempool);
     706             :     }
     707         355 :     ::mempool.SetIsLoaded(!ShutdownRequested());
     708         355 : }
     709             : 
     710             : /** Sanity checks
     711             :  *  Ensure that PIVX is running in a usable environment with all
     712             :  *  necessary library support.
     713             :  */
     714         379 : bool InitSanityCheck(void)
     715             : {
     716         379 :     if (!ECC_InitSanityCheck()) {
     717           0 :         UIError(_("Elliptic curve cryptography sanity check failure. Aborting."));
     718           0 :         return false;
     719             :     }
     720             : 
     721         379 :     if (!glibc_sanity_test() || !glibcxx_sanity_test()) {
     722           0 :         return false;
     723             :     }
     724             : 
     725         379 :     if (!Random_SanityCheck()) {
     726           0 :         UIError(_("OS cryptographic RNG sanity check failure. Aborting."));
     727           0 :         return false;
     728             :     }
     729             : 
     730         379 :     if (!BLSInit()) {
     731           0 :         return false;
     732             :     }
     733             : 
     734             :     return true;
     735             : }
     736             : 
     737         376 : static void LoadSaplingParams()
     738             : {
     739         376 :     struct timeval tv_start{}, tv_end{};
     740         376 :     float elapsed;
     741         376 :     gettimeofday(&tv_start, nullptr);
     742             : 
     743         376 :     try {
     744         376 :         initZKSNARKS();
     745           0 :     } catch (std::runtime_error &e) {
     746           0 :         std::string strError = strprintf(_("Cannot find the Sapling parameters in the following directory:\n%s"), ZC_GetParamsDir());
     747           0 :         std::string strErrorPosix = strprintf(_("Please run the included %s script and then restart."), "install-params.sh");
     748           0 :         std::string strErrorWin = strprintf(_("Please copy the included params files to the %s directory."), ZC_GetParamsDir());
     749           0 :         uiInterface.ThreadSafeMessageBox(strError + "\n"
     750             : #ifndef WIN32
     751           0 :                       + strErrorPosix,
     752             : #else
     753             :                       + strErrorWin,
     754             : #endif
     755             :                                             "", CClientUIInterface::MSG_ERROR);
     756           0 :         StartShutdown();
     757           0 :         return;
     758             :     }
     759             : 
     760         376 :     gettimeofday(&tv_end, nullptr);
     761         376 :     elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000);
     762         376 :     LogPrintf("Loaded Sapling parameters in %fs seconds.\n", elapsed);
     763             : }
     764             : 
     765         375 : bool AppInitServers()
     766             : {
     767         375 :     RPCServer::OnStarted(&OnRPCStarted);
     768         375 :     RPCServer::OnStopped(&OnRPCStopped);
     769         375 :     RPCServer::OnPreCommand(&OnRPCPreCommand);
     770         375 :     if (!InitHTTPServer())
     771             :         return false;
     772         375 :     if (!StartRPC())
     773             :         return false;
     774         375 :     if (!StartHTTPRPC())
     775             :         return false;
     776         750 :     if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST())
     777             :         return false;
     778         375 :     if (!StartHTTPServer())
     779           0 :         return false;
     780             :     return true;
     781             : }
     782             : 
     783           0 : [[noreturn]] static void new_handler_terminate()
     784             : {
     785             :     // Rather than throwing std::bad-alloc if allocation fails, terminate
     786             :     // immediately to (try to) avoid chain corruption.
     787             :     // Since LogPrintf may itself allocate memory, set the handler directly
     788             :     // to terminate first.
     789           0 :     std::set_new_handler(std::terminate);
     790           0 :     LogPrintf("Error: Out of memory. Terminating.\n");
     791             : 
     792             :     // The log was successful, terminate now.
     793           0 :     std::terminate();
     794             : }
     795             : 
     796             : namespace { // Variables internal to initialization process only
     797             : 
     798             :     ServiceFlags nRelevantServices = NODE_NETWORK;
     799             :     int nMaxConnections;
     800             :     int nUserMaxConnections;
     801             :     int nFD;
     802             :     ServiceFlags nLocalServices = NODE_NETWORK;
     803             : }
     804             : 
     805         387 : bool AppInitBasicSetup()
     806             : {
     807             : // ********************************************************* Step 1: setup
     808             : #ifdef _MSC_VER
     809             :     // Turn off Microsoft heap dump noise
     810             :     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
     811             :     _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, 0));
     812             : #endif
     813             : #if _MSC_VER >= 1400
     814             :     // Disable confusing "helpful" text message on abort, Ctrl-C
     815             :     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
     816             : #endif
     817             : #ifdef WIN32
     818             :     // Enable Data Execution Prevention (DEP)
     819             : // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
     820             : // A failure is non-critical and needs no further attention!
     821             : #ifndef PROCESS_DEP_ENABLE
     822             : // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
     823             : // which is not correct. Can be removed, when GCCs winbase.h is fixed!
     824             : #define PROCESS_DEP_ENABLE 0x00000001
     825             : #endif
     826             :     typedef BOOL(WINAPI * PSETPROCDEPPOL)(DWORD);
     827             :     PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
     828             :     if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE);
     829             : #endif
     830             : 
     831         387 :     if (!SetupNetworking())
     832           0 :         return UIError(_("Error: Initializing networking failed"));
     833             : 
     834             : #ifndef WIN32
     835         387 :     if (!gArgs.GetBoolArg("-sysperms", false)) {
     836         387 :         umask(077);
     837             :     }
     838             : 
     839             :     // Clean shutdown on SIGTERMx
     840         387 :     registerSignalHandler(SIGTERM, HandleSIGTERM);
     841         387 :     registerSignalHandler(SIGINT, HandleSIGTERM);
     842             : 
     843             :     // Reopen debug.log on SIGHUP
     844         387 :     registerSignalHandler(SIGHUP, HandleSIGHUP);
     845             : 
     846             :     // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
     847         387 :     signal(SIGPIPE, SIG_IGN);
     848             : #endif
     849             : 
     850         387 :     std::set_new_handler(new_handler_terminate);
     851             : 
     852         387 :     return true;
     853             : }
     854             : 
     855             : // Parameter interaction based on rules
     856         387 : void InitParameterInteraction()
     857             : {
     858         399 :     if (gArgs.IsArgSet("-bind") || gArgs.IsArgSet("-whitebind")) {
     859             :         // when specifying an explicit binding address, you want to listen on it
     860             :         // even when -connect or -proxy is specified
     861         375 :         if (gArgs.SoftSetBoolArg("-listen", true))
     862         349 :             LogPrintf("%s : parameter interaction: -bind or -whitebind set -> setting -listen=1\n", __func__);
     863             :     }
     864             : 
     865         387 :     if (gArgs.IsArgSet("-connect")) {
     866             :         // when only connecting to trusted nodes, do not seed via DNS, or listen by default
     867           0 :         if (gArgs.SoftSetBoolArg("-dnsseed", false))
     868           0 :             LogPrintf("%s : parameter interaction: -connect set -> setting -dnsseed=0\n", __func__);
     869           0 :         if (gArgs.SoftSetBoolArg("-listen", false))
     870           0 :             LogPrintf("%s : parameter interaction: -connect set -> setting -listen=0\n", __func__);
     871             :     }
     872             : 
     873         387 :     if (gArgs.IsArgSet("-proxy")) {
     874             :         // to protect privacy, do not listen by default if a default proxy server is specified
     875           4 :         if (gArgs.SoftSetBoolArg("-listen", false))
     876           0 :             LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
     877             :         // to protect privacy, do not use map ports when a proxy is set. The user may still specify -listen=1
     878             :         // to listen locally, so don't rely on this happening through -listen below.
     879           4 :         if (gArgs.SoftSetBoolArg("-upnp", false))
     880           4 :             LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
     881           4 :         if (gArgs.SoftSetBoolArg("-natpmp", false)) {
     882           0 :             LogPrintf("%s: parameter interaction: -proxy set -> setting -natpmp=0\n", __func__);
     883             :         }
     884             :         // to protect privacy, do not discover addresses by default
     885           4 :         if (gArgs.SoftSetBoolArg("-discover", false))
     886           0 :             LogPrintf("%s : parameter interaction: -proxy set -> setting -discover=0\n", __func__);
     887             :     }
     888             : 
     889         387 :     if (!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
     890             :         // do not map ports or try to retrieve public IP when not listening (pointless)
     891          10 :         if (gArgs.SoftSetBoolArg("-upnp", false))
     892          10 :             LogPrintf("%s : parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
     893          10 :         if (gArgs.SoftSetBoolArg("-natpmp", false)) {
     894           0 :             LogPrintf("%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", __func__);
     895             :         }
     896          10 :         if (gArgs.SoftSetBoolArg("-discover", false))
     897           0 :             LogPrintf("%s : parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
     898          10 :         if (gArgs.SoftSetBoolArg("-listenonion", false))
     899           0 :             LogPrintf("%s : parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__);
     900             :     }
     901             : 
     902         387 :     if (gArgs.IsArgSet("-externalip")) {
     903             :         // if an explicit public IP is specified, do not try to find others
     904          22 :         if (gArgs.SoftSetBoolArg("-discover", false))
     905           0 :             LogPrintf("%s : parameter interaction: -externalip set -> setting -discover=0\n", __func__);
     906             :     }
     907         387 : }
     908             : 
     909         379 : bool InitNUParams()
     910             : {
     911         379 :     if (gArgs.IsArgSet("-nuparams")) {
     912             :         // Allow overriding network upgrade parameters for testing
     913         136 :         if (Params().NetworkIDString() != "regtest") {
     914           0 :             return UIError(_("Network upgrade parameters may only be overridden on regtest."));
     915             :         }
     916         418 :         for (const std::string& strDeployment : gArgs.GetArgs("-nuparams")) {
     917         282 :             std::vector<std::string> vDeploymentParams;
     918         282 :             boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
     919         282 :             if (vDeploymentParams.size() != 2) {
     920           0 :                 return UIError(strprintf(_("Network upgrade parameters malformed, expecting %s"), "hexBranchId:activationHeight"));
     921             :             }
     922         282 :             int nActivationHeight;
     923         282 :             if (!ParseInt32(vDeploymentParams[1], &nActivationHeight)) {
     924           0 :                 return UIError(strprintf(_("Invalid activation height (%s)"), vDeploymentParams[1]));
     925             :             }
     926        2774 :             bool found = false;
     927             :             // Exclude base network from upgrades
     928        2774 :             for (auto j = Consensus::BASE_NETWORK + 1; j < Consensus::MAX_NETWORK_UPGRADES; ++j) {
     929        2774 :                 if (vDeploymentParams[0] == NetworkUpgradeInfo[j].strName) {
     930         282 :                     UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex(j), nActivationHeight);
     931         282 :                     found = true;
     932         282 :                     LogPrintf("Setting network upgrade activation parameters for %s to height=%d\n", vDeploymentParams[0], nActivationHeight);
     933             :                     break;
     934             :                 }
     935             :             }
     936         282 :             if (!found) {
     937           0 :                 return UIError(strprintf(_("Invalid network upgrade (%s)"), vDeploymentParams[0]));
     938             :             }
     939             :         }
     940             :     }
     941             :     return true;
     942             : }
     943             : 
     944           0 : static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
     945             : {
     946           0 :     return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
     947             : }
     948             : 
     949         387 : void InitLogging()
     950             : {
     951         387 :     g_logger->m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
     952         780 :     g_logger->m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
     953             : 
     954             :     // Add newlines to the logfile to distinguish this execution from the last
     955             :     // one; called before console logging is set up, so this is only sent to
     956             :     // debug.log.
     957         387 :     LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
     958             : 
     959         387 :     g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
     960         387 :     g_logger->m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
     961         387 :     g_logger->m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
     962             : 
     963         387 :     fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
     964             : 
     965         387 :     std::string version_string = FormatFullVersion();
     966             : #ifdef DEBUG
     967             :     version_string += " (debug build)";
     968             : #else
     969         387 :     version_string += " (release build)";
     970             : #endif
     971         387 :     LogPrintf("PIVX version %s\n", version_string);
     972         387 : }
     973             : 
     974         387 : bool AppInitParameterInteraction()
     975             : {
     976             :     // ********************************************************* Step 2: parameter interactions
     977             : 
     978         387 :     if (!fs::is_directory(GetBlocksDir())) {
     979           4 :         return UIError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "").c_str()));
     980             :     }
     981             : 
     982             :     // Make sure enough file descriptors are available
     983             : 
     984             :     // -bind and -whitebind can't be set when not listening
     985         386 :     size_t nUserBind =
     986        1147 :             (gArgs.IsArgSet("-bind") ? gArgs.GetArgs("-bind").size() : 0) +
     987         386 :             (gArgs.IsArgSet("-whitebind") ? gArgs.GetArgs("-whitebind").size() : 0);
     988        1136 :     if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
     989           0 :         return UIError(strprintf(_("Cannot set %s or %s together with %s"), "-bind", "-whitebind", "-listen=0"));
     990             :     }
     991             : 
     992             :     // Make sure enough file descriptors are available
     993         386 :     int nBind = std::max(nUserBind, size_t(1));
     994         386 :     nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
     995         386 :     nMaxConnections = std::max(nUserMaxConnections, 0);
     996             : 
     997             :     // Trim requested connection counts, to fit into system limitations
     998         386 :     nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);
     999             : #ifdef USE_POLL
    1000         386 :     int fd_max = nFD;
    1001             : #else
    1002             :     int fd_max = FD_SETSIZE;
    1003             : #endif
    1004         386 :     nMaxConnections = std::max(std::min<int>(nMaxConnections, fd_max - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS), 0);
    1005         386 :     if (nFD < MIN_CORE_FILEDESCRIPTORS)
    1006           0 :         return UIError(_("Not enough file descriptors available."));
    1007         386 :     nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);
    1008             : 
    1009             :     // ********************************************************* Step 3: parameter-to-internal-flags
    1010             : 
    1011             :     // Special-case: if -debug=0/-nodebug is set, turn off debugging messages
    1012         772 :     const std::vector<std::string>& categories = gArgs.GetArgs("-debug");
    1013             : 
    1014        1158 :     if (!(gArgs.GetBoolArg("-nodebug", false) ||
    1015         772 :           find(categories.begin(), categories.end(), std::string("0")) != categories.end())) {
    1016         867 :         for (const auto& cat : categories) {
    1017         481 :             if (!g_logger->EnableCategory(cat)) {
    1018           0 :                 UIWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
    1019             :             }
    1020             :         }
    1021             :     }
    1022             : 
    1023             :     // Now remove the logging categories which were explicitly excluded
    1024        1150 :     for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
    1025         764 :         if (!g_logger->DisableCategory(cat)) {
    1026           0 :             UIWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
    1027             :         }
    1028             :     }
    1029             : 
    1030             :     // Check for -debugnet
    1031         386 :     if (gArgs.GetBoolArg("-debugnet", false))
    1032           0 :         UIWarning(strprintf(_("Warning: Unsupported argument %s ignored, use %s."), "-debugnet", "-debug=net"));
    1033             :     // Check for -socks - as this is a privacy risk to continue, exit here
    1034         386 :     if (gArgs.IsArgSet("-socks"))
    1035           0 :         return UIError(
    1036           0 :                 strprintf(_("Error: Unsupported argument %s found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."), "-socks"));
    1037             :     // Check for -tor - as this is a privacy risk to continue, exit here
    1038         386 :     if (gArgs.GetBoolArg("-tor", false))
    1039           0 :         return UIError(strprintf(_("Error: Unsupported argument %s found, use %s."), "-tor", "-onion"));
    1040             :     // Check level must be 4 for zerocoin checks
    1041         386 :     if (gArgs.IsArgSet("-checklevel"))
    1042           0 :         return UIError(strprintf(_("Error: Unsupported argument %s found. Checklevel must be level 4."), "-checklevel"));
    1043             :     // Exit early if -masternode=1 and -listen=0
    1044         386 :     if (gArgs.GetBoolArg("-masternode", DEFAULT_MASTERNODE) && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN))
    1045           0 :         return UIError(strprintf(_("Error: %s must be true if %s is set."), "-listen", "-masternode"));
    1046         386 :     if (gArgs.GetBoolArg("-benchmark", false))
    1047           0 :         UIWarning(strprintf(_("Warning: Unsupported argument %s ignored, use %s"), "-benchmark", "-debug=bench."));
    1048             : 
    1049             :     // Checkmempool and checkblockindex default to true in regtest mode
    1050         386 :     int ratio = std::min<int>(
    1051         386 :             std::max<int>(gArgs.GetArg("-checkmempool", Params().DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
    1052         386 :     if (ratio != 0) {
    1053         382 :         mempool.setSanityCheck(1.0 / ratio);
    1054             :     }
    1055         386 :     fCheckBlockIndex = gArgs.GetBoolArg("-checkblockindex", Params().DefaultConsistencyChecks());
    1056         386 :     Checkpoints::fEnabled = gArgs.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
    1057             : 
    1058             :     // -mempoollimit limits
    1059         386 :     int64_t nMempoolSizeLimit = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
    1060         386 :     int64_t nMempoolDescendantSizeLimit = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
    1061         386 :     if (nMempoolSizeLimit < 0 || nMempoolSizeLimit < nMempoolDescendantSizeLimit * 40)
    1062           0 :         return UIError(strprintf(_("Error: %s must be at least %d MB"), "-maxmempool",
    1063           0 :                                  gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) / 25));
    1064             : 
    1065             :     // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
    1066         386 :     nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
    1067         386 :     if (nScriptCheckThreads <= 0)
    1068         386 :         nScriptCheckThreads += GetNumCores();
    1069         386 :     if (nScriptCheckThreads <= 1)
    1070           0 :         nScriptCheckThreads = 0;
    1071         386 :     else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
    1072           0 :         nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
    1073             : 
    1074         386 :     setvbuf(stdout, nullptr, _IOLBF, 0); /// ***TODO*** do we still need this after -printtoconsole is gone?
    1075             : 
    1076             : #ifndef ENABLE_WALLET
    1077             :     if (gArgs.SoftSetBoolArg("-staking", false))
    1078             :         LogPrintf("AppInit2 : parameter interaction: wallet functionality not enabled -> setting -staking=0\n");
    1079             : #endif
    1080             : 
    1081         386 :     nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
    1082         386 :     if (nConnectTimeout <= 0)
    1083           0 :         nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
    1084             : 
    1085             :     // Fee-per-kilobyte amount required for mempool acceptance and relay
    1086             :     // If you are mining, be careful setting this:
    1087             :     // if you set it to zero then
    1088             :     // a transaction spammer can cheaply fill blocks using
    1089             :     // 0-fee transactions. It should be set above the real
    1090             :     // cost to you of processing a transaction.
    1091         386 :     if (gArgs.IsArgSet("-minrelaytxfee")) {
    1092           8 :         CAmount n = 0;
    1093           8 :         if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) {
    1094           0 :             return UIError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", "")));
    1095             :         }
    1096             :         // High fee check is done afterward in CWallet::ParameterInteraction()
    1097           8 :         ::minRelayTxFee = CFeeRate(n);
    1098             :     }
    1099             : 
    1100         386 :     const CChainParams& chainparams = Params();
    1101         386 :     fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
    1102         386 :     if (!chainparams.IsTestChain() && !fRequireStandard)
    1103           0 :         return UIError(strprintf("%s is not currently supported for %s chain", "-acceptnonstdtxn", chainparams.NetworkIDString()));
    1104             : 
    1105             :     // Feerate used to define dust.  Shouldn't be changed lightly as old
    1106             :     // implementations may inadvertently create non-standard transactions
    1107         386 :     if (gArgs.IsArgSet("-dustrelayfee")) {
    1108           0 :         CAmount n = 0;
    1109           0 :         if (!ParseMoney(gArgs.GetArg("-dustrelayfee", ""), n) || 0 == n)
    1110           0 :             return UIError(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", "")));
    1111           0 :         dustRelayFee = CFeeRate(n);
    1112             :     }
    1113             : 
    1114             : #ifdef ENABLE_WALLET
    1115         386 :     if (!WalletParameterInteraction())
    1116             :         return false;
    1117             : #endif // ENABLE_WALLET
    1118             : 
    1119         379 :     fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
    1120         379 :     nMaxDatacarrierBytes = gArgs.GetArg("-datacarriersize", nMaxDatacarrierBytes);
    1121             : 
    1122             :     // Option to startup with mocktime set (used for regression testing):
    1123         379 :     if (Params().IsRegTestNet()) {
    1124         758 :         SetMockTime(gArgs.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
    1125             :     }
    1126             : 
    1127         758 :     if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
    1128         378 :         nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
    1129             : 
    1130         379 :     nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
    1131             : 
    1132         379 :     if (!InitNUParams())
    1133           0 :         return false;
    1134             : 
    1135             :     return true;
    1136             : }
    1137             : 
    1138         757 : static bool LockDataDirectory(bool probeOnly)
    1139             : {
    1140             :     // Make sure only a single PIVX process is using the data directory.
    1141        1514 :     fs::path datadir = GetDataDir();
    1142         757 :     if (!DirIsWritable(datadir)) {
    1143           0 :         return UIError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
    1144             :     }
    1145         757 :     if (!LockDirectory(datadir, ".lock", probeOnly)) {
    1146           3 :         return UIError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME));
    1147             :     }
    1148             :     return true;
    1149             : }
    1150             : 
    1151         379 : bool AppInitSanityChecks()
    1152             : {
    1153             :     // ********************************************************* Step 4: sanity checks
    1154             : 
    1155             :     // Initialize elliptic curve code
    1156         379 :     RandomInit();
    1157         379 :     ECC_Start();
    1158         758 :     globalVerifyHandle.reset(new ECCVerifyHandle());
    1159             : 
    1160             :     // Sanity check
    1161         379 :     if (!InitSanityCheck())
    1162           0 :         return UIError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
    1163             : 
    1164             :     // Probe the data directory lock to give an early error message, if possible
    1165         379 :     return LockDataDirectory(true);
    1166             : }
    1167             : 
    1168         378 : bool AppInitMain()
    1169             : {
    1170             :     // ********************************************************* Step 4a: application initialization
    1171             :     // After daemonization get the data directory lock again and hold on to it until exit
    1172             :     // This creates a slight window for a race condition to happen, however this condition is harmless: it
    1173             :     // will at most make us exit without printing a message to console.
    1174         378 :     if (!LockDataDirectory(false)) {
    1175             :         // Detailed error printed inside LockDataDirectory
    1176             :         return false;
    1177             :     }
    1178             : 
    1179             : #ifndef WIN32
    1180         378 :     if (!CreatePidFile()) {
    1181             :         // Detailed error printed inside CreatePidFile().
    1182             :         return false;
    1183             :     }
    1184             : #endif
    1185         378 :     if (g_logger->m_print_to_file) {
    1186         756 :         if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile()))
    1187           4 :             g_logger->ShrinkDebugFile();
    1188         378 :         if (!g_logger->OpenDebugLog())
    1189           6 :             return UIError(strprintf(_("Could not open debug log file %s"), g_logger->m_file_path.string()));
    1190             :     }
    1191             : #ifdef ENABLE_WALLET
    1192         376 :     LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
    1193             : #endif
    1194         376 :     if (!g_logger->m_log_timestamps)
    1195           0 :         LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
    1196         376 :     LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
    1197         376 :     LogPrintf("Using data directory %s\n", GetDataDir().string());
    1198         754 :     LogPrintf("Using config file %s\n", GetConfigFile(gArgs.GetArg("-conf", PIVX_CONF_FILENAME)).string());
    1199         376 :     LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
    1200         376 :     std::ostringstream strErrors;
    1201             : 
    1202             :     // Warn about relative -datadir path.
    1203        2632 :     if (gArgs.IsArgSet("-datadir") && !fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) {
    1204           0 :         LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
    1205             :                   "current working directory '%s'. This is fragile because if PIVX is started in the future " /* Continued */
    1206             :                   "from a different location. It will be unable to locate the current data files. There could " /* Continued */
    1207             :                   "also be data loss if PIVX is started while in a temporary directory.\n",
    1208           0 :             gArgs.GetArg("-datadir", ""), fs::current_path().string());
    1209             :     }
    1210             : 
    1211         376 :     InitSignatureCache();
    1212             : 
    1213         376 :     LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
    1214         376 :     if (nScriptCheckThreads) {
    1215        3008 :         for (int i = 0; i < nScriptCheckThreads - 1; i++)
    1216        2632 :             threadGroup.create_thread(&ThreadScriptCheck);
    1217             :     }
    1218             : 
    1219         376 :     if (gArgs.IsArgSet("-sporkkey")) // spork priv key
    1220             :     {
    1221         170 :         if (!sporkManager.SetPrivKey(gArgs.GetArg("-sporkkey", "")))
    1222           0 :             return UIError(_("Unable to sign spork message, wrong key?"));
    1223             :     }
    1224             : 
    1225             :     // Start the lightweight task scheduler thread
    1226         752 :     CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
    1227         376 :     threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
    1228             : 
    1229             :     // Gather some entropy once per minute.
    1230         376 :     scheduler.scheduleEvery([]{
    1231         231 :         RandAddPeriodic();
    1232             :     }, 60000);
    1233             : 
    1234         376 :     GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
    1235             : 
    1236             :     // Initialize Sapling circuit parameters
    1237         376 :     LoadSaplingParams();
    1238             : 
    1239             :     /* Register RPC commands regardless of -server setting so they will be
    1240             :      * available in the GUI RPC console even if external calls are disabled.
    1241             :      */
    1242         376 :     RegisterAllCoreRPCCommands(tableRPC);
    1243             : #ifdef ENABLE_WALLET
    1244         376 :     RegisterWalletRPCCommands(tableRPC);
    1245             : #endif
    1246             : 
    1247             :     /* Start the RPC server already.  It will be started in "warmup" mode
    1248             :      * and not really process calls already (but it will signify connections
    1249             :      * that the server is there and will be ready later).  Warmup mode will
    1250             :      * be disabled when initialisation is finished.
    1251             :      */
    1252         376 :     if (gArgs.GetBoolArg("-server", false)) {
    1253         750 :         uiInterface.InitMessage.connect(SetRPCWarmupStatus);
    1254         375 :         if (!AppInitServers())
    1255           0 :             return UIError(_("Unable to start HTTP server. See debug log for details."));
    1256             :     }
    1257             : 
    1258         376 :     if (gArgs.GetBoolArg("-resync", false)) {
    1259           0 :         uiInterface.InitMessage(_("Preparing for resync..."));
    1260             :         // Delete the local blockchain folders to force a resync from scratch to get a consistent blockchain-state
    1261           0 :         fs::path blocksDir = GetBlocksDir();
    1262           0 :         fs::path chainstateDir = GetDataDir() / "chainstate";
    1263           0 :         fs::path sporksDir = GetDataDir() / "sporks";
    1264           0 :         fs::path zerocoinDir = GetDataDir() / "zerocoin";
    1265           0 :         fs::path evoDir = GetDataDir() / "evodb";
    1266             : 
    1267           0 :         LogPrintf("Deleting blockchain folders blocks, chainstate, sporks, zerocoin and evodb\n");
    1268           0 :         std::vector<fs::path> removeDirs{blocksDir, chainstateDir, sporksDir, zerocoinDir, evoDir};
    1269             :         // We delete in 5 individual steps in case one of the folder is missing already
    1270           0 :         try {
    1271           0 :             for (const auto& dir : removeDirs) {
    1272           0 :                 if (fs::exists(dir)) {
    1273           0 :                     fs::remove_all(dir);
    1274           0 :                     LogPrintf("-resync: folder deleted: %s\n", dir.string().c_str());
    1275             :                 }
    1276             :             }
    1277           0 :         } catch (const fs::filesystem_error& error) {
    1278           0 :             LogPrintf("Failed to delete blockchain folders %s\n", error.what());
    1279             :         }
    1280             :     }
    1281             : 
    1282             : // ********************************************************* Step 5: Verify wallet database integrity
    1283             : #ifdef ENABLE_WALLET
    1284         376 :     if (!WalletVerify()) {
    1285             :         return false;
    1286             :     }
    1287             : #endif
    1288             : 
    1289             :     // ********************************************************* Step 6: network initialization
    1290             :     // Note that we absolutely cannot open any actual connections
    1291             :     // until the very end ("start node") as the UTXO/block state
    1292             :     // is not yet setup and may end up being set up twice if we
    1293             :     // need to reindex later.
    1294             : 
    1295         366 :     assert(!g_connman);
    1296         734 :     g_connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()));
    1297         366 :     CConnman& connman = *g_connman;
    1298             : 
    1299         366 :     peerLogic.reset(new PeerLogicValidation(&connman));
    1300         366 :     RegisterValidationInterface(peerLogic.get());
    1301             : 
    1302             :     // sanitize comments per BIP-0014, format user agent and check total size
    1303         366 :     std::vector<std::string> uacomments;
    1304         730 :     for (const std::string& cmt : gArgs.GetArgs("-uacomment")) {
    1305         371 :         if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
    1306          18 :             return UIError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
    1307         364 :         uacomments.push_back(cmt);
    1308             :     }
    1309             : 
    1310             :     // format user agent, check total size
    1311         360 :     strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
    1312         360 :     if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
    1313           2 :         return UIError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of %s."),
    1314           3 :             strSubVersion.size(), MAX_SUBVERSION_LENGTH, "-uacomment"));
    1315             :     }
    1316             : 
    1317         359 :     if (gArgs.IsArgSet("-onlynet")) {
    1318           0 :         std::set<enum Network> nets;
    1319           0 :         for (const std::string& snet : gArgs.GetArgs("-onlynet")) {
    1320           0 :             enum Network net = ParseNetwork(snet);
    1321           0 :             if (net == NET_UNROUTABLE)
    1322           0 :                 return UIError(strprintf(_("Unknown network specified in %s: '%s'"), "-onlynet", snet));
    1323           0 :             nets.insert(net);
    1324             :         }
    1325           0 :         for (int n = 0; n < NET_MAX; n++) {
    1326           0 :             enum Network net = (enum Network)n;
    1327           0 :             if (!nets.count(net))
    1328           0 :                 SetReachable(net, false);
    1329             :         }
    1330             :     }
    1331             : 
    1332             :     // Check for host lookup allowed before parsing any network related parameters
    1333         359 :     fNameLookup = gArgs.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
    1334             : 
    1335         359 :     bool proxyRandomize = gArgs.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
    1336             :     // -proxy sets a proxy for all outgoing network traffic
    1337             :     // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
    1338        1084 :     std::string proxyArg = gArgs.GetArg("-proxy", "");
    1339         359 :     SetReachable(NET_ONION, false);
    1340         363 :     if (!proxyArg.empty() && proxyArg != "0") {
    1341           8 :         CService proxyAddr;
    1342           4 :         if (!Lookup(proxyArg, proxyAddr, 9050, fNameLookup)) {
    1343           0 :             return UIError(strprintf(_("%s Invalid %s address or hostname: '%s'"), "Lookup():", "-proxy", proxyArg));
    1344             :         }
    1345             : 
    1346           8 :         proxyType addrProxy = proxyType(proxyAddr, proxyRandomize);
    1347           4 :         if (!addrProxy.IsValid())
    1348           0 :             return UIError(strprintf(_("%s Invalid %s address or hostname: '%s'"), "isValid():", "-proxy", proxyArg));
    1349             : 
    1350           4 :         SetProxy(NET_IPV4, addrProxy);
    1351           4 :         SetProxy(NET_IPV6, addrProxy);
    1352           4 :         SetProxy(NET_ONION, addrProxy);
    1353           4 :         SetNameProxy(addrProxy);
    1354           4 :         SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later
    1355             :     }
    1356             : 
    1357             :     // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
    1358             :     // -noonion (or -onion=0) disables connecting to .onion entirely
    1359             :     // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
    1360        1077 :     std::string onionArg = gArgs.GetArg("-onion", "");
    1361         359 :     if (!onionArg.empty()) {
    1362           2 :         if (onionArg == "0") { // Handle -noonion/-onion=0
    1363           1 :             SetReachable(NET_ONION, false);
    1364             :         } else {
    1365           2 :             CService onionProxy;
    1366           1 :             if (!Lookup(onionArg, onionProxy, 9050, fNameLookup)) {
    1367           0 :                 return UIError(strprintf(_("%s Invalid %s address or hostname: '%s'"), "Lookup():", "-onion", onionArg));
    1368             :             }
    1369           2 :             proxyType addrOnion = proxyType(onionProxy, proxyRandomize);
    1370           1 :             if (!addrOnion.IsValid())
    1371           0 :                 return UIError(strprintf(_("%s Invalid %s address or hostname: '%s'"), "isValid():", "-onion", onionArg));
    1372           1 :             SetProxy(NET_ONION, addrOnion);
    1373           1 :             SetReachable(NET_ONION, true);
    1374             :         }
    1375             :     }
    1376             : 
    1377             :     // see Step 2: parameter interactions for more information about these
    1378         359 :     fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN);
    1379         359 :     fDiscover = gArgs.GetBoolArg("-discover", true);
    1380             : 
    1381         435 :     for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
    1382         152 :         CService addrLocal;
    1383          76 :         if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
    1384          76 :             AddLocal(addrLocal, LOCAL_MANUAL);
    1385             :         else
    1386           0 :             return UIError(ResolveErrMsg("externalip", strAddr));
    1387             :     }
    1388             : 
    1389             :     // Read asmap file if configured
    1390         359 :     if (gArgs.IsArgSet("-asmap")) {
    1391          17 :         fs::path asmap_path = fs::path(gArgs.GetArg("-asmap", ""));
    1392           6 :         if (asmap_path.empty()) {
    1393           4 :             asmap_path = DEFAULT_ASMAP_FILENAME;
    1394             :         }
    1395           6 :         if (!asmap_path.is_absolute()) {
    1396          10 :             asmap_path = GetDataDir() / asmap_path;
    1397             :         }
    1398           7 :         if (!fs::exists(asmap_path)) {
    1399           2 :             UIError(strprintf(_("Could not find asmap file %s"), asmap_path));
    1400           3 :             return false;
    1401             :         }
    1402          14 :         std::vector<bool> asmap = CAddrMan::DecodeAsmap(asmap_path);
    1403           5 :         if (asmap.size() == 0) {
    1404           2 :             UIError(strprintf(_("Could not parse asmap file %s"), asmap_path));
    1405           3 :             return false;
    1406             :         }
    1407           4 :         const uint256 asmap_version = SerializeHash(asmap);
    1408           4 :         connman.SetAsmap(std::move(asmap));
    1409           8 :         LogPrintf("Using asmap version %s for IP bucketing\n", asmap_version.ToString());
    1410             :     } else {
    1411         353 :         LogPrintf("Using /16 prefix for IP bucketing\n");
    1412             :     }
    1413             : 
    1414             :     // Warn if network-specific options (-addnode, -connect, etc) are
    1415             :     // specified in default section of config file, but not overridden
    1416             :     // on the command line or in this network's section of the config file.
    1417         357 :     gArgs.WarnForSectionOnlyArgs();
    1418             : 
    1419             : #if ENABLE_ZMQ
    1420         357 :     pzmqNotificationInterface = CZMQNotificationInterface::Create();
    1421             : 
    1422         357 :     if (pzmqNotificationInterface) {
    1423           1 :         RegisterValidationInterface(pzmqNotificationInterface);
    1424             :     }
    1425             : #endif
    1426             : 
    1427         357 :     InitTierTwoInterfaces();
    1428             : 
    1429             :     // ********************************************************* Step 7: load block chain
    1430             : 
    1431         357 :     fReindex = gArgs.GetBoolArg("-reindex", false);
    1432         357 :     bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false);
    1433             : 
    1434             :     // cache size calculations
    1435         357 :     int64_t nTotalCache = (gArgs.GetArg("-dbcache", nDefaultDbCache) << 20);
    1436         357 :     nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
    1437         357 :     nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
    1438         357 :     int64_t nBlockTreeDBCache = nTotalCache / 8;
    1439         357 :     nBlockTreeDBCache = std::min(nBlockTreeDBCache, (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);
    1440         357 :     nTotalCache -= nBlockTreeDBCache;
    1441         357 :     int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
    1442         357 :     nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache
    1443         357 :     nTotalCache -= nCoinDBCache;
    1444         357 :     nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
    1445         357 :     LogPrintf("Cache configuration:\n");
    1446         357 :     LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
    1447         357 :     LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
    1448         357 :     LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024));
    1449             : 
    1450         357 :     const CChainParams& chainparams = Params();
    1451         357 :     const Consensus::Params& consensus = chainparams.GetConsensus();
    1452             : 
    1453         357 :     bool fLoaded = false;
    1454         713 :     while (!fLoaded && !ShutdownRequested()) {
    1455         357 :         bool fReset = fReindex;
    1456         713 :         std::string strLoadError;
    1457             : 
    1458         713 :         LOCK(cs_main);
    1459             : 
    1460         357 :         do {
    1461         357 :             const int64_t load_block_index_start_time = GetTimeMillis();
    1462             : 
    1463         357 :             try {
    1464         357 :                 UnloadBlockIndex();
    1465         357 :                 pcoinsTip.reset();
    1466         357 :                 pcoinsdbview.reset();
    1467         357 :                 pcoinscatcher.reset();
    1468         357 :                 pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
    1469             : 
    1470             :                 //PIVX specific: zerocoin and spork DB's
    1471         357 :                 zerocoinDB.reset(new CZerocoinDB(0, false, fReindex));
    1472         357 :                 pSporkDB.reset(new CSporkDB(0, false, false));
    1473         357 :                 accumulatorCache.reset(new AccumulatorCache(zerocoinDB.get()));
    1474             : 
    1475         357 :                 InitTierTwoPreChainLoad(fReindex);
    1476             : 
    1477         357 :                 if (fReset) {
    1478           5 :                     pblocktree->WriteReindexing(true);
    1479             :                 }
    1480             : 
    1481             :                 // End loop if shutdown was requested
    1482         357 :                 if (ShutdownRequested()) break;
    1483             : 
    1484             :                 // PIVX: load previous sessions sporks if we have them.
    1485         357 :                 uiInterface.InitMessage(_("Loading sporks..."));
    1486         357 :                 sporkManager.LoadSporksFromDB();
    1487             : 
    1488             :                 // LoadBlockIndex will load fTxIndex from the db, or set it if
    1489             :                 // we're reindexing. It will also load fHavePruned if we've
    1490             :                 // ever removed a block file from disk.
    1491             :                 // Note that it also sets fReindex based on the disk flag!
    1492             :                 // From here on out fReindex and fReset mean something different!
    1493         357 :                 uiInterface.InitMessage(_("Loading block index..."));
    1494         357 :                 std::string strBlockIndexError;
    1495         357 :                 if (!LoadBlockIndex(strBlockIndexError)) {
    1496           0 :                     if (ShutdownRequested()) break;
    1497           0 :                     strLoadError = _("Error loading block database");
    1498           0 :                     strLoadError = strprintf("%s : %s", strLoadError, strBlockIndexError);
    1499           0 :                     break;
    1500             :                 }
    1501             : 
    1502             :                 // If the loaded chain has a wrong genesis, bail out immediately
    1503             :                 // (we're likely using a testnet datadir, or the other way around).
    1504         357 :                 if (!mapBlockIndex.empty() && !LookupBlockIndex(consensus.hashGenesisBlock)) {
    1505           0 :                     return UIError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
    1506             :                 }
    1507             : 
    1508             :                 // Check for changed -txindex state
    1509         357 :                 if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
    1510           0 :                     strLoadError = strprintf(_("You need to rebuild the database using %s to change %s"), "-reindex-chainstate", "-txindex");
    1511           0 :                     break;
    1512             :                 }
    1513             : 
    1514             :                 // At this point blocktree args are consistent with what's on disk.
    1515             :                 // If we're not mid-reindex (based on disk + args), add a genesis block on disk.
    1516             :                 // This is called again in ThreadImport in the reindex completes.
    1517         357 :                 if (!fReindex && !LoadGenesisBlock()) {
    1518           0 :                     strLoadError = _("Error initializing block database");
    1519           0 :                     break;
    1520             :                 }
    1521             : 
    1522             :                 // At this point we're either in reindex or we've loaded a useful
    1523             :                 // block tree into mapBlockIndex!
    1524             : 
    1525         357 :                 pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
    1526         357 :                 pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
    1527             : 
    1528             :                 // If necessary, upgrade from older database format.
    1529             :                 // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
    1530         357 :                 uiInterface.InitMessage(_("Upgrading coins database if needed..."));
    1531             :                 // If necessary, upgrade from older database format.
    1532         357 :                 if (!pcoinsdbview->Upgrade()) {
    1533           0 :                     strLoadError = _("Error upgrading chainstate database");
    1534           0 :                     break;
    1535             :                 }
    1536             : 
    1537             :                 // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
    1538         357 :                 if (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
    1539           0 :                     strLoadError = strprintf(_("Unable to replay blocks. You will need to rebuild the database using %s."), "-reindex");
    1540           0 :                     break;
    1541             :                 }
    1542             : 
    1543             :                 // The on-disk coinsdb is now in a good state, create the cache
    1544         357 :                 pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
    1545             : 
    1546         357 :                 InitTierTwoPostCoinsCacheLoad(&scheduler);
    1547             : 
    1548         707 :                 bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
    1549         200 :                 if (!is_coinsview_empty) {
    1550             :                     // LoadChainTip sets chainActive based on pcoinsTip's best block
    1551         157 :                     if (!LoadChainTip(chainparams)) {
    1552           0 :                         strLoadError = _("Error initializing block database");
    1553           0 :                         break;
    1554             :                     }
    1555         157 :                     assert(chainActive.Tip() != nullptr);
    1556             :                 }
    1557             : 
    1558         714 :                 if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
    1559             :                     // Prune zerocoin invalid outs if they were improperly stored in the coins database
    1560           0 :                     int chainHeight = chainActive.Height();
    1561           0 :                     bool fZerocoinActive = chainHeight > 0 && consensus.NetworkUpgradeActive(chainHeight, Consensus::UPGRADE_ZC);
    1562             : 
    1563           0 :                     uiInterface.InitMessage(_("Loading/Pruning invalid outputs..."));
    1564           0 :                     if (fZerocoinActive) {
    1565           0 :                         if (!pcoinsTip->PruneInvalidEntries()) {
    1566           0 :                             strLoadError = _("System error while flushing the chainstate after pruning invalid entries. Possible corrupt database.");
    1567           0 :                             break;
    1568             :                         }
    1569           0 :                         MoneySupply.Update(pcoinsTip->GetTotalAmount(), chainHeight);
    1570             :                         // No need to keep the invalid outs in memory. Clear the map 100 blocks after the last invalid UTXO
    1571           0 :                         if (chainHeight > consensus.height_last_invalid_UTXO + 100) {
    1572           0 :                             invalid_out::setInvalidOutPoints.clear();
    1573             :                         }
    1574             :                     } else {
    1575             :                         // Populate list of invalid/fraudulent outpoints that are banned from the chain
    1576             :                         // They will not be added to coins view
    1577           0 :                         invalid_out::LoadOutpoints();
    1578             :                     }
    1579             :                 }
    1580             : 
    1581         357 :                 if (!is_coinsview_empty) {
    1582         157 :                     uiInterface.InitMessage(_("Verifying blocks..."));
    1583         157 :                     CBlockIndex *tip = chainActive.Tip();
    1584         157 :                     RPCNotifyBlockChange(true, tip);
    1585         157 :                     if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
    1586           0 :                         strLoadError = _("The block database contains a block which appears to be from the future. "
    1587             :                                          "This may be due to your computer's date and time being set incorrectly. "
    1588           0 :                                          "Only rebuild the block database if you are sure that your computer's date and time are correct");
    1589           0 :                         break;
    1590             :                     }
    1591             : 
    1592         471 :                     if (!CVerifyDB().VerifyDB(pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
    1593         314 :                             gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
    1594           1 :                         strLoadError = _("Corrupted block database detected");
    1595           1 :                         break;
    1596             :                     }
    1597             :                 }
    1598           0 :             } catch (const std::exception& e) {
    1599           0 :                 LogPrintf("%s\n", e.what());
    1600           0 :                 strLoadError = _("Error opening block database");
    1601           0 :                 break;
    1602             :             }
    1603             : 
    1604         356 :             fLoaded = true;
    1605         356 :             LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
    1606             :         } while (false);
    1607             : 
    1608         357 :         if (!fLoaded && !ShutdownRequested()) {
    1609             :             // first suggest a reindex
    1610           1 :             if (!fReset) {
    1611           2 :                 bool fRet = uiInterface.ThreadSafeMessageBox(
    1612           3 :                     strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?"),
    1613             :                     "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
    1614           1 :                 if (fRet) {
    1615           0 :                     fReindex = true;
    1616           0 :                     AbortShutdown();
    1617             :                 } else {
    1618           1 :                     LogPrintf("Aborted block database rebuild. Exiting.\n");
    1619             :                     return false;
    1620             :                 }
    1621             :             } else {
    1622           0 :                 return UIError(strLoadError);
    1623             :             }
    1624             :         }
    1625             :     }
    1626             : 
    1627             :     // As LoadBlockIndex can take several minutes, it's possible the user
    1628             :     // requested to kill the GUI during the last operation. If so, exit.
    1629             :     // As the program has not fully started yet, Shutdown() is possibly overkill.
    1630         356 :     if (ShutdownRequested()) {
    1631           0 :         LogPrintf("Shutdown requested. Exiting.\n");
    1632             :         return false;
    1633             :     }
    1634             : 
    1635         715 :     fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
    1636         712 :     CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
    1637             :     // Allowed to fail as this file IS missing on first startup.
    1638         356 :     if (!est_filein.IsNull())
    1639          84 :         mempool.ReadFeeEstimates(est_filein);
    1640         356 :     fFeeEstimatesInitialized = true;
    1641             : 
    1642             : // ********************************************************* Step 8: Backup and Load wallet
    1643             : #ifdef ENABLE_WALLET
    1644         356 :     if (!InitLoadWallet())
    1645             :         return false;
    1646             : #else
    1647             :     LogPrintf("No wallet compiled in!\n");
    1648             : #endif
    1649             :     // ********************************************************* Step 9: import blocks
    1650             : 
    1651         355 :     if (!CheckDiskSpace(GetDataDir())) {
    1652           0 :         UIError(strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
    1653           0 :         return false;
    1654             :     }
    1655         355 :     if (!CheckDiskSpace(GetBlocksDir())) {
    1656           0 :         UIError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir()));
    1657           0 :         return false;
    1658             :     }
    1659             : 
    1660             :     // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
    1661             :     // No locking, as this happens before any background thread is started.
    1662         355 :     if (chainActive.Tip() == nullptr) {
    1663         400 :         uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait);
    1664             :     } else {
    1665         155 :         fHaveGenesis = true;
    1666             :     }
    1667             : 
    1668         355 :     if (gArgs.IsArgSet("-blocknotify"))
    1669           3 :         uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
    1670             : 
    1671             :     // update g_best_block if needed
    1672         355 :     {
    1673         355 :         LOCK(g_best_block_mutex);
    1674       12225 :         if (g_best_block.IsNull() && chainActive.Tip()) {
    1675         155 :             CBlockIndex* tip = chainActive.Tip();
    1676         155 :             g_best_block = tip->GetBlockHash();
    1677         155 :             g_best_block_time = tip->GetBlockTime();
    1678         155 :             g_best_block_cv.notify_all();
    1679             :         }
    1680             :     }
    1681             : 
    1682         710 :     std::vector<fs::path> vImportFiles;
    1683         355 :     for (const std::string& strFile : gArgs.GetArgs("-loadblock")) {
    1684           0 :         vImportFiles.emplace_back(strFile);
    1685             :     }
    1686         710 :     threadGroup.create_thread(std::bind(&ThreadImport, vImportFiles));
    1687             : 
    1688             :     // Wait for genesis block to be processed
    1689         355 :     LogPrintf("Waiting for genesis block to be imported...\n");
    1690         355 :     {
    1691         355 :         std::unique_lock<std::mutex> lockG(cs_GenesisWait);
    1692             :         // We previously could hang here if StartShutdown() is called prior to
    1693             :         // ThreadImport getting started, so instead we just wait on a timer to
    1694             :         // check ShutdownRequested() regularly.
    1695         555 :         while (!fHaveGenesis && !ShutdownRequested()) {
    1696         200 :             condvar_GenesisWait.wait_for(lockG, std::chrono::milliseconds(500));
    1697             :         }
    1698         355 :         uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);
    1699             :     }
    1700             : 
    1701         355 :     if (ShutdownRequested()) {
    1702             :         return false;
    1703             :     }
    1704             : 
    1705         355 :     int chain_active_height;
    1706             : 
    1707             :     //// debug print
    1708         355 :     {
    1709         355 :         LOCK(cs_main);
    1710         355 :         chain_active_height = chainActive.Height();
    1711         355 :         LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
    1712             :     }
    1713         355 :     LogPrintf("chainActive.Height() = %d\n", chain_active_height);
    1714             : 
    1715             :     // Update money supply
    1716         355 :     if (!fReindex && !fReindexChainState) {
    1717         348 :         uiInterface.InitMessage(_("Calculating money supply..."));
    1718         348 :         MoneySupply.Update(pcoinsTip->GetTotalAmount(), chain_active_height);
    1719             :     }
    1720             : 
    1721             : 
    1722             :     // ********************************************************* Step 10: setup layer 2 data
    1723             : 
    1724         355 :     bool load_cache_files = !(fReindex || fReindexChainState);
    1725         355 :     {
    1726         355 :         LOCK(cs_main);
    1727             :         // was blocks/chainstate deleted?
    1728         355 :         if (chainActive.Tip() == nullptr) {
    1729           0 :             load_cache_files = false;
    1730             :         }
    1731             :     }
    1732             : 
    1733         355 :     LoadTierTwo(chain_active_height, load_cache_files);
    1734         355 :     RegisterTierTwoValidationInterface();
    1735             : 
    1736             :     // set the mode of budget voting for this node
    1737         710 :     SetBudgetFinMode(gArgs.GetArg("-budgetvotemode", "auto"));
    1738             : 
    1739             :     // Start tier two threads and jobs
    1740         355 :     StartTierTwoThreadsAndScheduleJobs(threadGroup, scheduler);
    1741             : 
    1742         355 :     if (ShutdownRequested()) {
    1743           0 :         LogPrintf("Shutdown requested. Exiting.\n");
    1744             :         return false;
    1745             :     }
    1746             : 
    1747             :     // ********************************************************* Step 11: start node
    1748             : 
    1749         355 :     if (!strErrors.str().empty())
    1750           0 :         return UIError(strErrors.str());
    1751             : 
    1752             : #ifdef ENABLE_WALLET
    1753         355 :     {
    1754         355 :         int idx = 0;
    1755         716 :         for (CWalletRef pwallet : vpwallets) {
    1756         361 :             LogPrintf("Wallet %d\n", idx++);
    1757         722 :             LOCK(pwallet->cs_wallet);
    1758         361 :             LogPrintf("setKeyPool.size() = %u\n", pwallet->GetKeyPoolSize());
    1759         361 :             LogPrintf("mapWallet.size() = %u\n", pwallet->mapWallet.size());
    1760         361 :             LogPrintf("mapAddressBook.size() = %u\n", pwallet->GetAddressBookSize());
    1761             :         }
    1762             :     }
    1763             : #endif
    1764             : 
    1765         355 :     if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
    1766           0 :         StartTorControl();
    1767             : 
    1768         355 :     Discover();
    1769             : 
    1770             :     // Map ports with UPnP or NAT-PMP
    1771         710 :     StartMapPort(gArgs.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP));
    1772             : 
    1773         710 :     CConnman::Options connOptions;
    1774         355 :     connOptions.nLocalServices = nLocalServices;
    1775         355 :     connOptions.nRelevantServices = nRelevantServices;
    1776         355 :     connOptions.nMaxConnections = nMaxConnections;
    1777         355 :     connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
    1778         355 :     connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
    1779         355 :     connOptions.nMaxFeeler = 1;
    1780         355 :     connOptions.nBestHeight = chain_active_height;
    1781         355 :     connOptions.uiInterface = &uiInterface;
    1782         355 :     connOptions.m_msgproc = peerLogic.get();
    1783         355 :     connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
    1784         355 :     connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
    1785         710 :     connOptions.m_added_nodes = gArgs.GetArgs("-addnode");
    1786             : 
    1787         355 :     if (gArgs.IsArgSet("-bind")) {
    1788         688 :         for (const std::string& strBind : gArgs.GetArgs("-bind")) {
    1789         688 :             CService addrBind;
    1790         344 :             if (!Lookup(strBind, addrBind, GetListenPort(), false)) {
    1791           0 :                 return UIError(ResolveErrMsg("bind", strBind));
    1792             :             }
    1793         344 :             connOptions.vBinds.emplace_back(addrBind);
    1794             :         }
    1795             :     }
    1796         355 :     if (gArgs.IsArgSet("-whitebind")) {
    1797           0 :         for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
    1798           0 :             CService addrBind;
    1799           0 :             if (!Lookup(strBind, addrBind, 0, false)) {
    1800           0 :                 return UIError(ResolveErrMsg("whitebind", strBind));
    1801             :             }
    1802           0 :             if (addrBind.GetPort() == 0) {
    1803           0 :                 return UIError(strprintf(_("Need to specify a port with %s: '%s'"), "-whitebind", strBind));
    1804             :             }
    1805           0 :             connOptions.vWhiteBinds.emplace_back(addrBind);
    1806             :         }
    1807             :     }
    1808             : 
    1809         400 :     for (const auto& net : gArgs.GetArgs("-whitelist")) {
    1810          90 :         CSubNet subnet;
    1811          45 :         LookupSubNet(net, subnet);
    1812          45 :         if (!subnet.IsValid())
    1813           0 :             return UIError(strprintf(_("Invalid netmask specified in %s: '%s'"), "-whitelist", net));
    1814          45 :         connOptions.vWhitelistedRange.emplace_back(subnet);
    1815             :     }
    1816             : 
    1817         710 :     connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
    1818             : 
    1819             :     // Initiate outbound connections unless connect=0
    1820         355 :     connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect");
    1821         355 :     if (!connOptions.m_use_addrman_outgoing) {
    1822           0 :         const auto connect = gArgs.GetArgs("-connect");
    1823           0 :         if (connect.size() != 1 || connect[0] != "0") {
    1824           0 :             connOptions.m_specified_outgoing = connect;
    1825             :         }
    1826             :     }
    1827         355 :     if (!connman.Start(scheduler, connOptions)) {
    1828             :         return false;
    1829             :     }
    1830             : 
    1831             : #ifdef ENABLE_WALLET
    1832             :     // Generate coins in the background (disabled on mainnet. use only wallet 0)
    1833         355 :     if (!vpwallets.empty())
    1834         686 :         GenerateBitcoins(gArgs.GetBoolArg("-gen", DEFAULT_GENERATE), vpwallets[0], gArgs.GetArg("-genproclimit", DEFAULT_GENERATE_PROCLIMIT));
    1835             : #endif
    1836             : 
    1837             : #ifdef ENABLE_WALLET
    1838         355 :     uiInterface.InitMessage(_("Reaccepting wallet transactions..."));
    1839         716 :     for (CWalletRef pwallet : vpwallets) {
    1840         361 :         pwallet->postInitProcess(scheduler);
    1841             :     }
    1842             :     // StakeMiner thread disabled by default on regtest
    1843        1041 :     if (!vpwallets.empty() && gArgs.GetBoolArg("-staking", !Params().IsRegTestNet() && DEFAULT_STAKING)) {
    1844           0 :         threadGroup.create_thread(std::bind(&ThreadStakeMinter));
    1845             :     }
    1846             : #endif
    1847             : 
    1848             :     // Enable active MN
    1849         355 :     if (!InitActiveMN()) return false;
    1850             : 
    1851             :     // ********************************************************* Step 12: finished
    1852             : 
    1853         355 :     SetRPCWarmupFinished();
    1854         355 :     uiInterface.InitMessage(_("Done loading"));
    1855             : 
    1856         355 :     return true;
    1857             : }

Generated by: LCOV version 1.14