diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index a852ec783..dbeb916e0 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -1,295 +1,292 @@
 // Copyright (c) 2017-2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <index/txindex.h>
 
 #include <blockdb.h>
 #include <chain.h>
 #include <node/ui_interface.h>
 #include <shutdown.h>
 #include <util/system.h>
 #include <util/translation.h>
 #include <validation.h>
 
-#include <boost/thread.hpp>
-
 constexpr char DB_BEST_BLOCK = 'B';
 constexpr char DB_TXINDEX = 't';
 constexpr char DB_TXINDEX_BLOCK = 'T';
 
 std::unique_ptr<TxIndex> g_txindex;
 
 struct CDiskTxPos : public FlatFilePos {
     unsigned int nTxOffset; // after header
 
     SERIALIZE_METHODS(CDiskTxPos, obj) {
         READWRITEAS(FlatFilePos, obj);
         READWRITE(VARINT(obj.nTxOffset));
     }
 
     CDiskTxPos(const FlatFilePos &blockIn, unsigned int nTxOffsetIn)
         : FlatFilePos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {}
 
     CDiskTxPos() { SetNull(); }
 
     void SetNull() {
         FlatFilePos::SetNull();
         nTxOffset = 0;
     }
 };
 
 /**
  * Access to the txindex database (indexes/txindex/)
  *
  * The database stores a block locator of the chain the database is synced to
  * so that the TxIndex can efficiently determine the point it last stopped at.
  * A locator is used instead of a simple hash of the chain tip because blocks
  * and block index entries may not be flushed to disk until after this database
  * is updated.
  */
 class TxIndex::DB : public BaseIndex::DB {
 public:
     explicit DB(size_t n_cache_size, bool f_memory = false,
                 bool f_wipe = false);
 
     /// Read the disk location of the transaction data with the given ID.
     /// Returns false if the transaction ID is not indexed.
     bool ReadTxPos(const TxId &txid, CDiskTxPos &pos) const;
 
     /// Write a batch of transaction positions to the DB.
     bool WriteTxs(const std::vector<std::pair<TxId, CDiskTxPos>> &v_pos);
 
     /// Migrate txindex data from the block tree DB, where it may be for older
     /// nodes that have not been upgraded yet to the new database.
     bool MigrateData(CBlockTreeDB &block_tree_db,
                      const CBlockLocator &best_locator);
 };
 
 TxIndex::DB::DB(size_t n_cache_size, bool f_memory, bool f_wipe)
     : BaseIndex::DB(GetDataDir() / "indexes" / "txindex", n_cache_size,
                     f_memory, f_wipe) {}
 
 bool TxIndex::DB::ReadTxPos(const TxId &txid, CDiskTxPos &pos) const {
     return Read(std::make_pair(DB_TXINDEX, txid), pos);
 }
 
 bool TxIndex::DB::WriteTxs(
     const std::vector<std::pair<TxId, CDiskTxPos>> &v_pos) {
     CDBBatch batch(*this);
     for (const auto &tuple : v_pos) {
         batch.Write(std::make_pair(DB_TXINDEX, tuple.first), tuple.second);
     }
     return WriteBatch(batch);
 }
 
 /*
  * Safely persist a transfer of data from the old txindex database to the new
  * one, and compact the range of keys updated. This is used internally by
  * MigrateData.
  */
 static void
 WriteTxIndexMigrationBatches(CDBWrapper &newdb, CDBWrapper &olddb,
                              CDBBatch &batch_newdb, CDBBatch &batch_olddb,
                              const std::pair<uint8_t, TxId> &begin_key,
                              const std::pair<uint8_t, TxId> &end_key) {
     // Sync new DB changes to disk before deleting from old DB.
     newdb.WriteBatch(batch_newdb, /*fSync=*/true);
     olddb.WriteBatch(batch_olddb);
     olddb.CompactRange(begin_key, end_key);
 
     batch_newdb.Clear();
     batch_olddb.Clear();
 }
 
 bool TxIndex::DB::MigrateData(CBlockTreeDB &block_tree_db,
                               const CBlockLocator &best_locator) {
     // The prior implementation of txindex was always in sync with block index
     // and presence was indicated with a boolean DB flag. If the flag is set,
     // this means the txindex from a previous version is valid and in sync with
     // the chain tip. The first step of the migration is to unset the flag and
     // write the chain hash to a separate key, DB_TXINDEX_BLOCK. After that, the
     // index entries are copied over in batches to the new database. Finally,
     // DB_TXINDEX_BLOCK is erased from the old database and the block hash is
     // written to the new database.
     //
     // Unsetting the boolean flag ensures that if the node is downgraded to a
     // previous version, it will not see a corrupted, partially migrated index
     // -- it will see that the txindex is disabled. When the node is upgraded
     // again, the migration will pick up where it left off and sync to the block
     // with hash DB_TXINDEX_BLOCK.
     bool f_legacy_flag = false;
     block_tree_db.ReadFlag("txindex", f_legacy_flag);
     if (f_legacy_flag) {
         if (!block_tree_db.Write(DB_TXINDEX_BLOCK, best_locator)) {
             return error("%s: cannot write block indicator", __func__);
         }
         if (!block_tree_db.WriteFlag("txindex", false)) {
             return error("%s: cannot write block index db flag", __func__);
         }
     }
 
     CBlockLocator locator;
     if (!block_tree_db.Read(DB_TXINDEX_BLOCK, locator)) {
         return true;
     }
 
     int64_t count = 0;
     uiInterface.InitMessage(_("Upgrading txindex database").translated);
     LogPrintf("Upgrading txindex database... [0%%]\n");
     uiInterface.ShowProgress(_("Upgrading txindex database").translated, 0,
                              true);
     int report_done = 0;
     const size_t batch_size = 1 << 24; // 16 MiB
 
     CDBBatch batch_newdb(*this);
     CDBBatch batch_olddb(block_tree_db);
 
     std::pair<uint8_t, TxId> key;
     std::pair<uint8_t, TxId> begin_key{DB_TXINDEX, TxId()};
     std::pair<uint8_t, TxId> prev_key = begin_key;
 
     bool interrupted = false;
     std::unique_ptr<CDBIterator> cursor(block_tree_db.NewIterator());
     for (cursor->Seek(begin_key); cursor->Valid(); cursor->Next()) {
-        boost::this_thread::interruption_point();
         if (ShutdownRequested()) {
             interrupted = true;
             break;
         }
 
         if (!cursor->GetKey(key)) {
             return error("%s: cannot get key from valid cursor", __func__);
         }
         if (key.first != DB_TXINDEX) {
             break;
         }
 
         // Log progress every 10%.
         if (++count % 256 == 0) {
             // Since txids are uniformly random and traversed in increasing
             // order, the high 16 bits of the ID can be used to estimate the
             // current progress.
             const TxId &txid = key.second;
             uint32_t high_nibble =
                 (static_cast<uint32_t>(*(txid.begin() + 0)) << 8) +
                 (static_cast<uint32_t>(*(txid.begin() + 1)) << 0);
             int percentage_done = (int)(high_nibble * 100.0 / 65536.0 + 0.5);
 
             uiInterface.ShowProgress(_("Upgrading txindex database").translated,
                                      percentage_done, true);
             if (report_done < percentage_done / 10) {
                 LogPrintf("Upgrading txindex database... [%d%%]\n",
                           percentage_done);
                 report_done = percentage_done / 10;
             }
         }
 
         CDiskTxPos value;
         if (!cursor->GetValue(value)) {
             return error("%s: cannot parse txindex record", __func__);
         }
         batch_newdb.Write(key, value);
         batch_olddb.Erase(key);
 
         if (batch_newdb.SizeEstimate() > batch_size ||
             batch_olddb.SizeEstimate() > batch_size) {
             // NOTE: it's OK to delete the key pointed at by the current DB
             // cursor while iterating because LevelDB iterators are guaranteed
             // to provide a consistent view of the underlying data, like a
             // lightweight snapshot.
             WriteTxIndexMigrationBatches(*this, block_tree_db, batch_newdb,
                                          batch_olddb, prev_key, key);
             prev_key = key;
         }
     }
 
     // If these final DB batches complete the migration, write the best block
     // hash marker to the new database and delete from the old one. This signals
     // that the former is fully caught up to that point in the blockchain and
     // that all txindex entries have been removed from the latter.
     if (!interrupted) {
         batch_olddb.Erase(DB_TXINDEX_BLOCK);
         batch_newdb.Write(DB_BEST_BLOCK, locator);
     }
 
     WriteTxIndexMigrationBatches(*this, block_tree_db, batch_newdb, batch_olddb,
                                  begin_key, key);
 
     if (interrupted) {
         LogPrintf("[CANCELLED].\n");
         return false;
     }
 
     uiInterface.ShowProgress("", 100, false);
 
     LogPrintf("[DONE].\n");
     return true;
 }
 
 TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
     : m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe)) {}
 
 TxIndex::~TxIndex() {}
 
 bool TxIndex::Init() {
     LOCK(cs_main);
 
     // Attempt to migrate txindex from the old database to the new one. Even if
     // chain_tip is null, the node could be reindexing and we still want to
     // delete txindex records in the old database.
     if (!m_db->MigrateData(*pblocktree, ::ChainActive().GetLocator())) {
         return false;
     }
 
     return BaseIndex::Init();
 }
 
 bool TxIndex::WriteBlock(const CBlock &block, const CBlockIndex *pindex) {
     // Exclude genesis block transaction because outputs are not spendable.
     if (pindex->nHeight == 0) {
         return true;
     }
 
     CDiskTxPos pos(pindex->GetBlockPos(),
                    GetSizeOfCompactSize(block.vtx.size()));
     std::vector<std::pair<TxId, CDiskTxPos>> vPos;
     vPos.reserve(block.vtx.size());
     for (const auto &tx : block.vtx) {
         vPos.emplace_back(tx->GetId(), pos);
         pos.nTxOffset += ::GetSerializeSize(*tx, CLIENT_VERSION);
     }
     return m_db->WriteTxs(vPos);
 }
 
 BaseIndex::DB &TxIndex::GetDB() const {
     return *m_db;
 }
 
 bool TxIndex::FindTx(const TxId &txid, BlockHash &block_hash,
                      CTransactionRef &tx) const {
     CDiskTxPos postx;
     if (!m_db->ReadTxPos(txid, postx)) {
         return false;
     }
 
     CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
     if (file.IsNull()) {
         return error("%s: OpenBlockFile failed", __func__);
     }
     CBlockHeader header;
     try {
         file >> header;
         if (fseek(file.Get(), postx.nTxOffset, SEEK_CUR)) {
             return error("%s: fseek(...) failed", __func__);
         }
         file >> tx;
     } catch (const std::exception &e) {
         return error("%s: Deserialize or I/O error - %s", __func__, e.what());
     }
     if (tx->GetId() != txid) {
         return error("%s: txid mismatch", __func__);
     }
     block_hash = header.GetHash();
     return true;
 }
diff --git a/src/init.cpp b/src/init.cpp
index d4c3ff72f..9c7f98bec 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,2978 +1,2976 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #if defined(HAVE_CONFIG_H)
 #include <config/bitcoin-config.h>
 #endif
 
 #include <init.h>
 
 #include <addrman.h>
 #include <amount.h>
 #include <avalanche/processor.h>
 #include <avalanche/validation.h>
 #include <banman.h>
 #include <blockdb.h>
 #include <blockfilter.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <checkpoints.h>
 #include <compat/sanity.h>
 #include <config.h>
 #include <consensus/validation.h>
 #include <flatfile.h>
 #include <fs.h>
 #include <hash.h>
 #include <httprpc.h>
 #include <httpserver.h>
 #include <index/blockfilterindex.h>
 #include <index/txindex.h>
 #include <interfaces/chain.h>
 #include <key.h>
 #include <miner.h>
 #include <net.h>
 #include <net_permissions.h>
 #include <net_processing.h>
 #include <netbase.h>
 #include <network.h>
 #include <node/context.h>
 #include <node/ui_interface.h>
 #include <policy/mempool.h>
 #include <policy/policy.h>
 #include <policy/settings.h>
 #include <rpc/blockchain.h>
 #include <rpc/register.h>
 #include <rpc/server.h>
 #include <rpc/util.h>
 #include <scheduler.h>
 #include <script/scriptcache.h>
 #include <script/sigcache.h>
 #include <script/standard.h>
 #include <shutdown.h>
 #include <sync.h>
 #include <timedata.h>
 #include <torcontrol.h>
 #include <txdb.h>
 #include <txmempool.h>
 #include <util/asmap.h>
 #include <util/check.h>
 #include <util/moneystr.h>
 #include <util/string.h>
 #include <util/threadnames.h>
 #include <util/translation.h>
 #include <validation.h>
 #include <validationinterface.h>
 #include <walletinitinterface.h>
 
-#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/replace.hpp>
-#include <boost/algorithm/string/split.hpp>
 #include <boost/signals2/signal.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 
 #if ENABLE_ZMQ
 #include <zmq/zmqabstractnotifier.h>
 #include <zmq/zmqnotificationinterface.h>
 #include <zmq/zmqrpc.h>
 #endif
 
 #ifndef WIN32
 #include <attributes.h>
 #include <cerrno>
 #include <csignal>
 #include <sys/stat.h>
 #endif
 #include <cstdint>
 #include <cstdio>
 #include <functional>
 #include <set>
 
 static const bool DEFAULT_PROXYRANDOMIZE = true;
 static const bool DEFAULT_REST_ENABLE = false;
 static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
 
 #ifdef WIN32
 // Win32 LevelDB doesn't use filedescriptors, and the ones used for accessing
 // block files don't count towards the fd_set size limit anyway.
 #define MIN_CORE_FILEDESCRIPTORS 0
 #else
 #define MIN_CORE_FILEDESCRIPTORS 150
 #endif
 
 static const char *DEFAULT_ASMAP_FILENAME = "ip_asn.map";
 
 /**
  * The PID file facilities.
  */
 static const char *BITCOIN_PID_FILENAME = "bitcoind.pid";
 
 static fs::path GetPidFile(const ArgsManager &args) {
     return AbsPathForConfigVal(
         fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME)));
 }
 
 NODISCARD static bool CreatePidFile(const ArgsManager &args) {
     fsbridge::ofstream file{GetPidFile(args)};
     if (file) {
 #ifdef WIN32
         tfm::format(file, "%d\n", GetCurrentProcessId());
 #else
         tfm::format(file, "%d\n", getpid());
 #endif
         return true;
     } else {
         return InitError(strprintf(_("Unable to create the PID file '%s': %s"),
                                    GetPidFile(args).string(),
                                    std::strerror(errno)));
     }
 }
 
 //////////////////////////////////////////////////////////////////////////////
 //
 // Shutdown
 //
 
 //
 // Thread management and startup/shutdown:
 //
 // The network-processing threads are all part of a thread group created by
 // AppInit() or the Qt main() function.
 //
 // A clean exit happens when StartShutdown() or the SIGTERM signal handler sets
 // fRequestShutdown, which makes main thread's WaitForShutdown() interrupts the
 // thread group.
 // And then, WaitForShutdown() makes all other on-going threads in the thread
 // group join the main thread.
 // Shutdown() is then called to clean up database connections, and stop other
 // threads that should only be stopped after the main network-processing threads
 // have exited.
 //
 // Shutdown for Qt is very similar, only it uses a QTimer to detect
 // ShutdownRequested() getting set, and then does the normal Qt shutdown thing.
 //
 
 static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
 
 static boost::thread_group threadGroup;
 
 void Interrupt(NodeContext &node) {
     InterruptHTTPServer();
     InterruptHTTPRPC();
     InterruptRPC();
     InterruptREST();
     InterruptTorControl();
     InterruptMapPort();
     if (g_avalanche) {
         // Avalanche needs to be stopped before we interrupt the thread group as
         // the scheduler will stop working then.
         g_avalanche->stopEventLoop();
     }
     if (node.connman) {
         node.connman->Interrupt();
     }
     if (g_txindex) {
         g_txindex->Interrupt();
     }
     ForEachBlockFilterIndex([](BlockFilterIndex &index) { index.Interrupt(); });
 }
 
 void Shutdown(NodeContext &node) {
     static Mutex g_shutdown_mutex;
     TRY_LOCK(g_shutdown_mutex, lock_shutdown);
     if (!lock_shutdown) {
         return;
     }
     LogPrintf("%s: In progress...\n", __func__);
     Assert(node.args);
 
     /// Note: Shutdown() must be able to handle cases in which initialization
     /// failed part of the way, for example if the data directory was found to
     /// be locked. Be sure that anything that writes files or flushes caches
     /// only does this if the respective module was initialized.
     util::ThreadRename("shutoff");
     g_mempool.AddTransactionsUpdated(1);
 
     StopHTTPRPC();
     StopREST();
     StopRPC();
     StopHTTPServer();
     for (const auto &client : node.chain_clients) {
         client->flush();
     }
     StopMapPort();
 
     // Because avalanche and the network depend on each other, it is important
     // to shut them down in this order:
     // 1. Stop avalanche event loop.
     // 2. Shutdown network processing.
     // 3. Destroy avalanche::Processor.
     // 4. Destroy CConnman
     if (g_avalanche) {
         g_avalanche->stopEventLoop();
     }
 
     // Because these depend on each-other, we make sure that neither can be
     // using the other before destroying them.
     if (node.peerman) {
         UnregisterValidationInterface(node.peerman.get());
     }
     // Follow the lock order requirements:
     // * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling
     //   GetExtraOutboundCount which locks cs_vNodes.
     // * ProcessMessage locks cs_main and g_cs_orphans before indirectly calling
     //   ForEachNode which locks cs_vNodes.
     // * CConnman::Stop calls DeleteNode, which calls FinalizeNode, which locks
     //   cs_main and calls EraseOrphansFor, which locks g_cs_orphans.
     //
     // Thus the implicit locking order requirement is:
     // (1) cs_main, (2) g_cs_orphans, (3) cs_vNodes.
     if (node.connman) {
         node.connman->StopThreads();
         LOCK2(::cs_main, ::g_cs_orphans);
         node.connman->StopNodes();
     }
 
     StopTorControl();
 
     // After everything has been shut down, but before things get flushed, stop
     // the CScheduler/checkqueue threadGroup
     if (node.scheduler) {
         node.scheduler->stop();
     }
     threadGroup.interrupt_all();
     threadGroup.join_all();
 
     // After the threads that potentially access these pointers have been
     // stopped, destruct and reset all to nullptr.
     node.peerman.reset();
 
     // Destroy various global instances
     g_avalanche.reset();
     node.connman.reset();
     node.banman.reset();
 
     if (::g_mempool.IsLoaded() &&
         node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
         DumpMempool(::g_mempool);
     }
 
     // FlushStateToDisk generates a ChainStateFlushed callback, which we should
     // avoid missing
     if (node.chainman) {
         LOCK(cs_main);
         for (CChainState *chainstate : node.chainman->GetAll()) {
             if (chainstate->CanFlushToDisk()) {
                 chainstate->ForceFlushStateToDisk();
             }
         }
     }
 
     // After there are no more peers/RPC left to give us new data which may
     // generate CValidationInterface callbacks, flush them...
     GetMainSignals().FlushBackgroundCallbacks();
 
     // Stop and delete all indexes only after flushing background callbacks.
     if (g_txindex) {
         g_txindex->Stop();
         g_txindex.reset();
     }
     ForEachBlockFilterIndex([](BlockFilterIndex &index) { index.Stop(); });
     DestroyAllBlockFilterIndexes();
 
     // Any future callbacks will be dropped. This should absolutely be safe - if
     // missing a callback results in an unrecoverable situation, unclean
     // shutdown would too. The only reason to do the above flushes is to let the
     // wallet catch up with our current chain to avoid any strange pruning edge
     // cases and make next startup faster by avoiding rescan.
 
     if (node.chainman) {
         LOCK(cs_main);
         for (CChainState *chainstate : node.chainman->GetAll()) {
             if (chainstate->CanFlushToDisk()) {
                 chainstate->ForceFlushStateToDisk();
                 chainstate->ResetCoinsViews();
             }
         }
         pblocktree.reset();
     }
     for (const auto &client : node.chain_clients) {
         client->stop();
     }
 
 #if ENABLE_ZMQ
     if (g_zmq_notification_interface) {
         UnregisterValidationInterface(g_zmq_notification_interface);
         delete g_zmq_notification_interface;
         g_zmq_notification_interface = nullptr;
     }
 #endif
 
     node.chain_clients.clear();
     UnregisterAllValidationInterfaces();
     GetMainSignals().UnregisterBackgroundSignalScheduler();
     globalVerifyHandle.reset();
     ECC_Stop();
     node.mempool = nullptr;
     node.chainman = nullptr;
     node.scheduler.reset();
 
     try {
         if (!fs::remove(GetPidFile(*node.args))) {
             LogPrintf("%s: Unable to remove PID file: File does not exist\n",
                       __func__);
         }
     } catch (const fs::filesystem_error &e) {
         LogPrintf("%s: Unable to remove PID file: %s\n", __func__,
                   fsbridge::get_filesystem_error_message(e));
     }
 
     node.args = nullptr;
     LogPrintf("%s: done\n", __func__);
 }
 
 /**
  * Signal handlers are very limited in what they are allowed to do.
  * The execution context the handler is invoked in is not guaranteed,
  * so we restrict handler operations to just touching variables:
  */
 #ifndef WIN32
 static void HandleSIGTERM(int) {
     StartShutdown();
 }
 
 static void HandleSIGHUP(int) {
     LogInstance().m_reopen_file = true;
 }
 #else
 static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) {
     StartShutdown();
     Sleep(INFINITE);
     return true;
 }
 #endif
 
 #ifndef WIN32
 static void registerSignalHandler(int signal, void (*handler)(int)) {
     struct sigaction sa;
     sa.sa_handler = handler;
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
     sigaction(signal, &sa, NULL);
 }
 #endif
 
 static boost::signals2::connection rpc_notify_block_change_connection;
 static void OnRPCStarted() {
     rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(
         std::bind(RPCNotifyBlockChange, std::placeholders::_2));
 }
 
 static void OnRPCStopped() {
     rpc_notify_block_change_connection.disconnect();
     RPCNotifyBlockChange(nullptr);
     g_best_block_cv.notify_all();
     LogPrint(BCLog::RPC, "RPC stopped.\n");
 }
 
 void SetupServerArgs(NodeContext &node) {
     assert(!node.args);
     node.args = &gArgs;
     ArgsManager &argsman = *node.args;
 
     SetupHelpOptions(argsman);
     // server-only for now
     argsman.AddArg("-help-debug",
                    "Print help message with debugging options and exit", false,
                    OptionsCategory::DEBUG_TEST);
 
     const auto defaultBaseParams =
         CreateBaseChainParams(CBaseChainParams::MAIN);
     const auto testnetBaseParams =
         CreateBaseChainParams(CBaseChainParams::TESTNET);
     const auto regtestBaseParams =
         CreateBaseChainParams(CBaseChainParams::REGTEST);
     const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);
     const auto testnetChainParams =
         CreateChainParams(CBaseChainParams::TESTNET);
     const auto regtestChainParams =
         CreateChainParams(CBaseChainParams::REGTEST);
 
     // Hidden Options
     std::vector<std::string> hidden_args = {
         "-dbcrashratio", "-forcecompactdb", "-parkdeepreorg",
         "-automaticunparking", "-replayprotectionactivationtime",
         "-enableminerfund",
         // GUI args. These will be overwritten by SetupUIArgs for the GUI
         "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>",
         "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash",
         "-uiplatform",
         // TODO remove after the November 2020 upgrade
         "-axionactivationtime"};
 
     // Set all of the args and their help
     // When adding new options to the categories, please keep and ensure
     // alphabetical ordering. Do not translate _(...) -help-debug options, Many
     // technical terms, and only a very small audience, so is unnecessary stress
     // to translators.
     argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY,
                    OptionsCategory::OPTIONS);
 #if defined(HAVE_SYSTEM)
     argsman.AddArg(
         "-alertnotify=<cmd>",
         "Execute command when a relevant alert is received or we see "
         "a really long fork (%s in cmd is replaced by message)",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 #endif
     argsman.AddArg(
         "-assumevalid=<hex>",
         strprintf(
             "If this block is in the chain assume that it and its ancestors "
             "are valid and potentially skip their script verification (0 to "
             "verify all, default: %s, testnet: %s)",
             defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(),
             testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-blocksdir=<dir>",
                    "Specify directory to hold blocks subdirectory for *.dat "
                    "files (default: <datadir>)",
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 #if defined(HAVE_SYSTEM)
     argsman.AddArg("-blocknotify=<cmd>",
                    "Execute command when the best block changes (%s in cmd is "
                    "replaced by block hash)",
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 #endif
     argsman.AddArg("-blockreconstructionextratxn=<n>",
                    strprintf("Extra transactions to keep in memory for compact "
                              "block reconstructions (default: %u)",
                              DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-blocksonly",
         strprintf("Whether to reject transactions from network peers.  "
                   "Automatic broadcast and rebroadcast of any transactions "
                   "from inbound peers is disabled, unless "
                   "'-whitelistforcerelay' is '1', in which case whitelisted "
                   "peers' transactions will be relayed. RPC transactions are"
                   " not affected. (default: %u)",
                   DEFAULT_BLOCKSONLY),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-conf=<file>",
         strprintf("Specify path to read-only configuration file. Relative "
                   "paths will be prefixed by datadir location. (default: %s)",
                   BITCOIN_CONF_FILENAME),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-datadir=<dir>", "Specify data directory",
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-dbbatchsize",
         strprintf("Maximum database write batch size in bytes (default: %u)",
                   DEFAULT_DB_BATCH_SIZE),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-dbcache=<n>",
         strprintf("Set database cache size in MiB (%d to %d, default: %d)",
                   MIN_DB_CACHE_MB, MAX_DB_CACHE_MB, DEFAULT_DB_CACHE_MB),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-debuglogfile=<file>",
         strprintf("Specify location of debug log file. Relative paths "
                   "will be prefixed by a net-specific datadir "
                   "location. (0 to disable; default: %s)",
                   DEFAULT_DEBUGLOGFILE),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-feefilter",
                    strprintf("Tell other nodes to filter invs to us by our "
                              "mempool min fee (default: %d)",
                              DEFAULT_FEEFILTER),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-finalizationdelay=<n>",
         strprintf("Set the minimum amount of time to wait between a "
                   "block header reception and the block finalization. "
                   "Unit is seconds (default: %d)",
                   DEFAULT_MIN_FINALIZATION_DELAY),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-includeconf=<file>",
         "Specify additional configuration file, relative to the -datadir path "
         "(only useable from configuration file, not command line)",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-maxreorgdepth=<n>",
                    strprintf("Configure at what depth blocks are considered "
                              "final (default: %d). Use -1 to disable.",
                              DEFAULT_MAX_REORG_DEPTH),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-loadblock=<file>",
                    "Imports blocks from external file on startup",
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-maxmempool=<n>",
                    strprintf("Keep the transaction memory pool below <n> "
                              "megabytes (default: %u)",
                              DEFAULT_MAX_MEMPOOL_SIZE),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-maxorphantx=<n>",
                    strprintf("Keep at most <n> unconnectable transactions in "
                              "memory (default: %u)",
                              DEFAULT_MAX_ORPHAN_TRANSACTIONS),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-mempoolexpiry=<n>",
                    strprintf("Do not keep transactions in the mempool longer "
                              "than <n> hours (default: %u)",
                              DEFAULT_MEMPOOL_EXPIRY),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-minimumchainwork=<hex>",
         strprintf(
             "Minimum work assumed to exist on a valid chain in hex "
             "(default: %s, testnet: %s)",
             defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(),
             testnetChainParams->GetConsensus().nMinimumChainWork.GetHex()),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-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),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg("-persistmempool",
                    strprintf("Whether to save the mempool on shutdown and load "
                              "on restart (default: %u)",
                              DEFAULT_PERSIST_MEMPOOL),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-pid=<file>",
         strprintf("Specify pid file. Relative paths will be prefixed "
                   "by a net-specific datadir location. (default: %s)",
                   BITCOIN_PID_FILENAME),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-prune=<n>",
         strprintf("Reduce storage requirements by enabling pruning (deleting) "
                   "of old blocks. This allows the pruneblockchain RPC to be "
                   "called to delete specific blocks, and enables automatic "
                   "pruning of old blocks if a target size in MiB is provided. "
                   "This mode is incompatible with -txindex and -rescan. "
                   "Warning: Reverting this setting requires re-downloading the "
                   "entire blockchain. (default: 0 = disable pruning blocks, 1 "
                   "= allow manual pruning via RPC, >=%u = automatically prune "
                   "block files to stay under the specified target size in MiB)",
                   MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-reindex-chainstate",
         "Rebuild chain state from the currently indexed blocks. When "
         "in pruning mode or if blocks on disk might be corrupted, use "
         "full -reindex instead.",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-reindex",
         "Rebuild chain state and block index from the blk*.dat files on disk",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-settings=<file>",
         strprintf(
             "Specify path to dynamic settings data file. Can be disabled with "
             "-nosettings. File is written at runtime and not meant to be "
             "edited by users (use %s instead for custom settings). Relative "
             "paths will be prefixed by datadir location. (default: %s)",
             BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME),
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 #ifndef WIN32
     argsman.AddArg(
         "-sysperms",
         "Create new files with system default permissions, instead of umask "
         "077 (only effective with disabled wallet functionality)",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 #else
     hidden_args.emplace_back("-sysperms");
 #endif
     argsman.AddArg("-txindex",
                    strprintf("Maintain a full transaction index, used by the "
                              "getrawtransaction rpc call (default: %d)",
                              DEFAULT_TXINDEX),
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-blockfilterindex=<type>",
         strprintf("Maintain an index of compact filters by block "
                   "(default: %s, values: %s).",
                   DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
             " If <type> is not supplied or if <type> = 1, indexes for "
             "all known types are enabled.",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     argsman.AddArg(
         "-usecashaddr",
         "Use Cash Address for destination encoding instead of base58 "
         "(activate by default on Jan, 14)",
         ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 
     argsman.AddArg(
         "-addnode=<ip>",
         "Add a node to connect to and attempt to keep the connection "
         "open (see the `addnode` RPC command help for more info)",
         ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY,
         OptionsCategory::CONNECTION);
     argsman.AddArg("-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),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-bantime=<n>",
                    strprintf("Default duration (in seconds) of manually "
                              "configured bans (default: %u)",
                              DEFAULT_MISBEHAVING_BANTIME),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-bind=<addr>",
                    "Bind to given address and always listen on it. Use "
                    "[host]:port notation for IPv6",
                    ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY,
                    OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-connect=<ip>",
         "Connect only to the specified node(s); -connect=0 disables automatic "
         "connections (the rules for this peer are the same as for -addnode)",
         ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY,
         OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-discover",
         "Discover own IP addresses (default: 1 when listening and no "
         "-externalip or -proxy)",
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-dns",
                    strprintf("Allow DNS lookups for -addnode, -seednode and "
                              "-connect (default: %d)",
                              DEFAULT_NAME_LOOKUP),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-dnsseed",
         "Query for peer addresses via DNS lookup, if low on addresses "
         "(default: 1 unless -connect used)",
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
 
     argsman.AddArg("-externalip=<ip>", "Specify your own public address",
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-forcednsseed",
         strprintf(
             "Always query for peer addresses via DNS lookup (default: %d)",
             DEFAULT_FORCEDNSSEED),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-overridednsseed",
                    "If set, only use the specified DNS seed when "
                    "querying for peer addresses via DNS lookup.",
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-listen",
         "Accept connections from outside (default: 1 if no -proxy or -connect)",
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-listenonion",
         strprintf("Automatically create Tor hidden service (default: %d)",
                   DEFAULT_LISTEN_ONION),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-maxconnections=<n>",
         strprintf("Maintain at most <n> connections to peers. The effective "
                   "limit depends on system limitations and might be lower than "
                   "the specified value (default: %u)",
                   DEFAULT_MAX_PEER_CONNECTIONS),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-maxreceivebuffer=<n>",
                    strprintf("Maximum per-connection receive buffer, <n>*1000 "
                              "bytes (default: %u)",
                              DEFAULT_MAXRECEIVEBUFFER),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-maxsendbuffer=<n>",
         strprintf(
             "Maximum per-connection send buffer, <n>*1000 bytes (default: %u)",
             DEFAULT_MAXSENDBUFFER),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-maxtimeadjustment",
         strprintf("Maximum allowed median peer time offset adjustment. Local "
                   "perspective of time may be influenced by peers forward or "
                   "backward by this amount. (default: %u seconds)",
                   DEFAULT_MAX_TIME_ADJUSTMENT),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-onion=<ip:port>",
                    strprintf("Use separate SOCKS5 proxy to reach peers via Tor "
                              "hidden services (default: %s)",
                              "-proxy"),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-onlynet=<net>",
         "Make outgoing connections only through network <net> (ipv4, ipv6 or "
         "onion). Incoming connections are not affected by this option. This "
         "option can be specified multiple times to allow multiple networks.",
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-peerbloomfilters",
                    strprintf("Support filtering of blocks and transaction with "
                              "bloom filters (default: %d)",
                              DEFAULT_PEERBLOOMFILTERS),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-peerblockfilters",
         strprintf(
             "Serve compact block filters to peers per BIP 157 (default: %u)",
             DEFAULT_PEERBLOCKFILTERS),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-permitbaremultisig",
                    strprintf("Relay non-P2SH multisig (default: %d)",
                              DEFAULT_PERMIT_BAREMULTISIG),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-port=<port>",
                    strprintf("Listen for connections on <port> (default: %u, "
                              "testnet: %u, regtest: %u)",
                              defaultChainParams->GetDefaultPort(),
                              testnetChainParams->GetDefaultPort(),
                              regtestChainParams->GetDefaultPort()),
                    ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY,
                    OptionsCategory::CONNECTION);
     argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy",
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-proxyrandomize",
         strprintf("Randomize credentials for every proxy connection. "
                   "This enables Tor stream isolation (default: %d)",
                   DEFAULT_PROXYRANDOMIZE),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-seednode=<ip>",
         "Connect to a node to retrieve peer addresses, and disconnect",
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-timeout=<n>",
                    strprintf("Specify connection timeout in milliseconds "
                              "(minimum: 1, default: %d)",
                              DEFAULT_CONNECT_TIMEOUT),
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-peertimeout=<n>",
         strprintf("Specify p2p connection timeout in seconds. This option "
                   "determines the amount of time a peer may be inactive before "
                   "the connection to it is dropped. (minimum: 1, default: %d)",
                   DEFAULT_PEER_CONNECT_TIMEOUT),
         true, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-torcontrol=<ip>:<port>",
         strprintf(
             "Tor control port to use if onion listening enabled (default: %s)",
             DEFAULT_TOR_CONTROL),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg("-torpassword=<pass>",
                    "Tor control port password (default: empty)",
                    ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE,
                    OptionsCategory::CONNECTION);
 #ifdef USE_UPNP
 #if USE_UPNP
     argsman.AddArg("-upnp",
                    "Use UPnP to map the listening port (default: 1 when "
                    "listening and no -proxy)",
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
 #else
     argsman.AddArg(
         "-upnp",
         strprintf("Use UPnP to map the listening port (default: %u)", 0),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
 #endif
 #else
     hidden_args.emplace_back("-upnp");
 #endif
     argsman.AddArg(
         "-whitebind=<[permissions@]addr>",
         "Bind to the given address and add permission flags to the peers "
         "connecting to it."
         "Use [host]:port notation for IPv6. Allowed permissions: " +
             Join(NET_PERMISSIONS_DOC, ", ") +
             ". "
             "Specify multiple permissions separated by commas (default: "
             "download,noban,mempool,relay). Can be specified multiple times.",
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
 
     argsman.AddArg("-whitelist=<[permissions@]IP address or network>",
                    "Add permission flags to the peers connecting from the "
                    "given IP address (e.g. 1.2.3.4) or CIDR-notated network "
                    "(e.g. 1.2.3.0/24). "
                    "Uses the same permissions as -whitebind. Can be specified "
                    "multiple times.",
                    ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
     argsman.AddArg(
         "-maxuploadtarget=<n>",
         strprintf("Tries to keep outbound traffic under the given target (in "
                   "MiB per 24h). Limit does not apply to peers with 'download' "
                   "permission. 0 = no limit (default: %d)",
                   DEFAULT_MAX_UPLOAD_TARGET),
         ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
 
     g_wallet_init_interface.AddWalletOptions(argsman);
 
 #if ENABLE_ZMQ
     argsman.AddArg("-zmqpubhashblock=<address>",
                    "Enable publish hash block in <address>",
                    ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
     argsman.AddArg("-zmqpubhashtx=<address>",
                    "Enable publish hash transaction in <address>",
                    ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
     argsman.AddArg("-zmqpubrawblock=<address>",
                    "Enable publish raw block in <address>",
                    ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
     argsman.AddArg("-zmqpubrawtx=<address>",
                    "Enable publish raw transaction in <address>",
                    ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
     argsman.AddArg(
         "-zmqpubhashblockhwm=<n>",
         strprintf("Set publish hash block outbound message high water "
                   "mark (default: %d)",
                   CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM),
         false, OptionsCategory::ZMQ);
     argsman.AddArg(
         "-zmqpubhashtxhwm=<n>",
         strprintf("Set publish hash transaction outbound message high "
                   "water mark (default: %d)",
                   CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM),
         false, OptionsCategory::ZMQ);
     argsman.AddArg(
         "-zmqpubrawblockhwm=<n>",
         strprintf("Set publish raw block outbound message high water "
                   "mark (default: %d)",
                   CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM),
         false, OptionsCategory::ZMQ);
     argsman.AddArg(
         "-zmqpubrawtxhwm=<n>",
         strprintf("Set publish raw transaction outbound message high "
                   "water mark (default: %d)",
                   CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM),
         false, OptionsCategory::ZMQ);
 #else
     hidden_args.emplace_back("-zmqpubhashblock=<address>");
     hidden_args.emplace_back("-zmqpubhashtx=<address>");
     hidden_args.emplace_back("-zmqpubrawblock=<address>");
     hidden_args.emplace_back("-zmqpubrawtx=<address>");
     hidden_args.emplace_back("-zmqpubhashblockhwm=<n>");
     hidden_args.emplace_back("-zmqpubhashtxhwm=<n>");
     hidden_args.emplace_back("-zmqpubrawblockhwm=<n>");
     hidden_args.emplace_back("-zmqpubrawtxhwm=<n>");
 #endif
 
     argsman.AddArg(
         "-checkblocks=<n>",
         strprintf("How many blocks to check at startup (default: %u, 0 = all)",
                   DEFAULT_CHECKBLOCKS),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-checklevel=<n>",
                    strprintf("How thorough the block verification of "
                              "-checkblocks is: %s (0-4, default: %u)",
                              Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-checkblockindex",
                    strprintf("Do a consistency check for the block tree, "
                              "chainstate, and other validation data structures "
                              "occasionally. (default: %u, regtest: %u)",
                              defaultChainParams->DefaultConsistencyChecks(),
                              regtestChainParams->DefaultConsistencyChecks()),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-checkmempool=<n>",
         strprintf(
             "Run checks every <n> transactions (default: %u, regtest: %u)",
             defaultChainParams->DefaultConsistencyChecks(),
             regtestChainParams->DefaultConsistencyChecks()),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-checkpoints",
                    strprintf("Only accept block chain matching built-in "
                              "checkpoints (default: %d)",
                              DEFAULT_CHECKPOINTS_ENABLED),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-deprecatedrpc=<method>",
                    "Allows deprecated RPC method(s) to be used",
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-dropmessagestest=<n>",
                    "Randomly drop 1 of every <n> network messages",
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-stopafterblockimport",
         strprintf("Stop running after importing blocks from disk (default: %d)",
                   DEFAULT_STOPAFTERBLOCKIMPORT),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-stopatheight",
                    strprintf("Stop running after reaching the given height in "
                              "the main chain (default: %u)",
                              DEFAULT_STOPATHEIGHT),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-limitancestorcount=<n>",
         strprintf("Do not accept transactions if number of in-mempool "
                   "ancestors is <n> or more (default: %u)",
                   DEFAULT_ANCESTOR_LIMIT),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-limitancestorsize=<n>",
         strprintf("Do not accept transactions whose size with all in-mempool "
                   "ancestors exceeds <n> kilobytes (default: %u)",
                   DEFAULT_ANCESTOR_SIZE_LIMIT),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-limitdescendantcount=<n>",
         strprintf("Do not accept transactions if any ancestor would have <n> "
                   "or more in-mempool descendants (default: %u)",
                   DEFAULT_DESCENDANT_LIMIT),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-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),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-addrmantest", "Allows to test address relay on localhost",
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
 
     argsman.AddArg("-debug=<category>",
                    strprintf("Output debugging information (default: %u, "
                              "supplying <category> is optional)",
                              0) +
                        ". " +
                        "If <category> is not supplied or if <category> = 1, "
                        "output all debugging information. <category> can be: " +
                        LogInstance().LogCategoriesString() + ".",
                    ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-debugexclude=<category>",
         strprintf("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."),
         ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-logips",
         strprintf("Include IP addresses in debug output (default: %d)",
                   DEFAULT_LOGIPS),
         ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-logtimestamps",
         strprintf("Prepend debug output with timestamp (default: %d)",
                   DEFAULT_LOGTIMESTAMPS),
         ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-logthreadnames",
         strprintf(
             "Prepend debug output with name of the originating thread (only "
             "available on platforms supporting thread_local) (default: %u)",
             DEFAULT_LOGTHREADNAMES),
         ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-logtimemicros",
         strprintf("Add microsecond precision to debug timestamps (default: %d)",
                   DEFAULT_LOGTIMEMICROS),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-mocktime=<n>",
                    "Replace actual time with " + UNIX_EPOCH_TIME +
                        " (default: 0)",
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-maxsigcachesize=<n>",
         strprintf("Limit size of signature cache to <n> MiB (default: %u)",
                   DEFAULT_MAX_SIG_CACHE_SIZE),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-maxscriptcachesize=<n>",
         strprintf("Limit size of script cache to <n> MiB (default: %u)",
                   DEFAULT_MAX_SCRIPT_CACHE_SIZE),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-maxtipage=<n>",
                    strprintf("Maximum tip age in seconds to consider node in "
                              "initial block download (default: %u)",
                              DEFAULT_MAX_TIP_AGE),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
 
     argsman.AddArg(
         "-printtoconsole",
         "Send trace/debug info to console instead of debug.log file (default: "
         "1 when no -daemon. To disable logging to file, set debuglogfile=0)",
         ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
     argsman.AddArg("-printpriority",
                    strprintf("Log transaction priority and fee per kB when "
                              "mining blocks (default: %d)",
                              DEFAULT_PRINTPRIORITY),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::DEBUG_TEST);
     argsman.AddArg(
         "-shrinkdebugfile",
         "Shrink debug.log file on client startup (default: 1 when no -debug)",
         ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
 
     argsman.AddArg("-uacomment=<cmt>",
                    "Append comment to the user agent string",
                    ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
 
     SetupChainParamsBaseOptions(argsman);
 
     argsman.AddArg(
         "-acceptnonstdtxn",
         strprintf(
             "Relay and mine \"non-standard\" transactions (%sdefault: %u)",
             "testnet/regtest only; ", defaultChainParams->RequireStandard()),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::NODE_RELAY);
     argsman.AddArg("-excessiveblocksize=<n>",
                    strprintf("Do not accept blocks larger than this limit, in "
                              "bytes (default: %d)",
                              DEFAULT_MAX_BLOCK_SIZE),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::NODE_RELAY);
     argsman.AddArg(
         "-dustrelayfee=<amt>",
         strprintf("Fee rate (in %s/kB) used to define dust, the value of an "
                   "output such that it will cost about 1/3 of its value in "
                   "fees at this fee rate to spend it. (default: %s)",
                   CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)),
         ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
         OptionsCategory::NODE_RELAY);
 
     argsman.AddArg("-bytespersigop",
                    strprintf("Equivalent bytes per sigop in transactions for "
                              "relay and mining (default: %u)",
                              DEFAULT_BYTES_PER_SIGOP),
                    ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
     argsman.AddArg(
         "-datacarrier",
         strprintf("Relay and mine data carrier transactions (default: %d)",
                   DEFAULT_ACCEPT_DATACARRIER),
         ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
     argsman.AddArg(
         "-datacarriersize",
         strprintf("Maximum size of data in data carrier transactions "
                   "we relay and mine (default: %u)",
                   MAX_OP_RETURN_RELAY),
         ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
     argsman.AddArg(
         "-minrelaytxfee=<amt>",
         strprintf("Fees (in %s/kB) smaller than this are rejected for "
                   "relaying, mining and transaction creation (default: %s)",
                   CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE_PER_KB)),
         ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
     argsman.AddArg(
         "-whitelistrelay",
         strprintf("Add 'relay' permission to whitelisted inbound peers "
                   "with default permissions. This will accept relayed "
                   "transactions even when not relaying transactions "
                   "(default: %d)",
                   DEFAULT_WHITELISTRELAY),
         ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
     argsman.AddArg(
         "-whitelistforcerelay",
         strprintf("Add 'forcerelay' permission to whitelisted inbound peers"
                   " with default permissions. This will relay transactions "
                   "even if the transactions were already in the mempool or "
                   "violate local relay policy (default: %d)",
                   DEFAULT_WHITELISTFORCERELAY),
         ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
 
     // Not sure this really belongs here, but it will do for now.
     // FIXME: This doesn't work anyways.
     argsman.AddArg("-excessutxocharge=<amt>",
                    strprintf("Fees (in %s/kB) to charge per utxo created for "
                              "relaying, and mining (default: %s)",
                              CURRENCY_UNIT, FormatMoney(DEFAULT_UTXO_FEE)),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::NODE_RELAY);
 
     argsman.AddArg("-blockmaxsize=<n>",
                    strprintf("Set maximum block size in bytes (default: %d)",
                              DEFAULT_MAX_GENERATED_BLOCK_SIZE),
                    ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
     argsman.AddArg(
         "-blockmintxfee=<amt>",
         strprintf("Set lowest fee rate (in %s/kB) for transactions to "
                   "be included in block creation. (default: %s)",
                   CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB)),
         ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
 
     argsman.AddArg("-blockversion=<n>",
                    "Override block version to test forking scenarios",
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::BLOCK_CREATION);
 
     argsman.AddArg("-server", "Accept command line and JSON-RPC commands",
                    ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
     argsman.AddArg("-rest",
                    strprintf("Accept public REST requests (default: %d)",
                              DEFAULT_REST_ENABLE),
                    ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
     argsman.AddArg(
         "-rpcbind=<addr>[:port]",
         "Bind to given address to listen for JSON-RPC connections. Do not "
         "expose the RPC server to untrusted networks such as the public "
         "internet! This option is ignored unless -rpcallowip is also passed. "
         "Port is optional and overrides -rpcport.  Use [host]:port notation "
         "for IPv6. This option can be specified multiple times (default: "
         "127.0.0.1 and ::1 i.e., localhost)",
         ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY |
             ArgsManager::SENSITIVE,
         OptionsCategory::RPC);
     argsman.AddArg(
         "-rpccookiefile=<loc>",
         "Location of the auth cookie. Relative paths will be prefixed "
         "by a net-specific datadir location. (default: data dir)",
         ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
     argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections",
                    ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE,
                    OptionsCategory::RPC);
     argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections",
                    ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE,
                    OptionsCategory::RPC);
     argsman.AddArg(
         "-rpcwhitelist=<whitelist>",
         "Set a whitelist to filter incoming RPC calls for a specific user. The "
         "field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc "
         "2>,...,<rpc n>. If multiple whitelists are set for a given user, they "
         "are set-intersected. See -rpcwhitelistdefault documentation for "
         "information on default whitelist behavior.",
         ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
     argsman.AddArg(
         "-rpcwhitelistdefault",
         "Sets default behavior for rpc whitelisting. Unless "
         "rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc "
         "server acts as if all rpc users are subject to "
         "empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault "
         "is set to 1 and no -rpcwhitelist is set, rpc server acts as if all "
         "rpc users are subject to empty whitelists.",
         ArgsManager::ALLOW_BOOL, OptionsCategory::RPC);
     argsman.AddArg(
         "-rpcauth=<userpw>",
         "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. "
         "The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A "
         "canonical python script is included in share/rpcauth. The client then "
         "connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> "
         "pair of arguments. This option can be specified multiple times",
         ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
     argsman.AddArg("-rpcport=<port>",
                    strprintf("Listen for JSON-RPC connections on <port> "
                              "(default: %u, testnet: %u, regtest: %u)",
                              defaultBaseParams->RPCPort(),
                              testnetBaseParams->RPCPort(),
                              regtestBaseParams->RPCPort()),
                    ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY,
                    OptionsCategory::RPC);
     argsman.AddArg(
         "-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",
         ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
     argsman.AddArg(
         "-rpcthreads=<n>",
         strprintf(
             "Set the number of threads to service RPC calls (default: %d)",
             DEFAULT_HTTP_THREADS),
         ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
     argsman.AddArg(
         "-rpccorsdomain=value",
         "Domain from which to accept cross origin requests (browser enforced)",
         ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
 
     argsman.AddArg("-rpcworkqueue=<n>",
                    strprintf("Set the depth of the work queue to service RPC "
                              "calls (default: %d)",
                              DEFAULT_HTTP_WORKQUEUE),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::RPC);
     argsman.AddArg("-rpcservertimeout=<n>",
                    strprintf("Timeout during HTTP requests (default: %d)",
                              DEFAULT_HTTP_SERVER_TIMEOUT),
                    ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY,
                    OptionsCategory::RPC);
 
 #if HAVE_DECL_DAEMON
     argsman.AddArg("-daemon",
                    "Run in the background as a daemon and accept commands",
                    ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 #else
     hidden_args.emplace_back("-daemon");
 #endif
 
     // Avalanche options.
     argsman.AddArg(
         "-enableavalanche",
         strprintf("Enable avalanche (default: %u)", AVALANCHE_DEFAULT_ENABLED),
         ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE);
     argsman.AddArg(
         "-avacooldown",
         strprintf("Mandatory cooldown between two avapoll (default: %u)",
                   AVALANCHE_DEFAULT_COOLDOWN),
         ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE);
     argsman.AddArg("-avaproof",
                    "Avalanche proof to be used by this node (default: none)",
                    ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE);
     argsman.AddArg("-avamasterkey",
                    "Master key associated with the proof. If a proof is "
                    "required, this is mandatory.",
                    ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE);
     argsman.AddArg("-avasessionkey", "Avalanche session key (default: random)",
                    ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE);
 
     // Add the hidden options
     argsman.AddHiddenArgs(hidden_args);
 }
 
 std::string LicenseInfo() {
     const std::string URL_SOURCE_CODE =
         "<https://github.com/Bitcoin-ABC/bitcoin-abc>";
     const std::string URL_WEBSITE = "<https://www.bitcoinabc.org>";
 
     return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009,
                                       COPYRIGHT_YEAR) +
                             " ") +
            "\n" + "\n" +
            strprintf(_("Please contribute if you find %s useful. "
                        "Visit %s for further information about the software.")
                          .translated,
                      PACKAGE_NAME, URL_WEBSITE) +
            "\n" +
            strprintf(_("The source code is available from %s.").translated,
                      URL_SOURCE_CODE) +
            "\n" + "\n" + _("This is experimental software.").translated + "\n" +
            strprintf(_("Distributed under the MIT software license, see the "
                        "accompanying file %s or %s")
                          .translated,
                      "COPYING", "<https://opensource.org/licenses/MIT>") +
            "\n" + "\n" +
            strprintf(_("This product includes software developed by the "
                        "OpenSSL Project for use in the OpenSSL Toolkit %s and "
                        "cryptographic software written by Eric Young and UPnP "
                        "software written by Thomas Bernard.")
                          .translated,
                      "<https://www.openssl.org>") +
            "\n";
 }
 
 static bool fHaveGenesis = false;
 static Mutex g_genesis_wait_mutex;
 static std::condition_variable g_genesis_wait_cv;
 
 static void BlockNotifyGenesisWait(const CBlockIndex *pBlockIndex) {
     if (pBlockIndex != nullptr) {
         {
             LOCK(g_genesis_wait_mutex);
             fHaveGenesis = true;
         }
         g_genesis_wait_cv.notify_all();
     }
 }
 
 struct CImportingNow {
     CImportingNow() {
         assert(fImporting == false);
         fImporting = true;
     }
 
     ~CImportingNow() {
         assert(fImporting == true);
         fImporting = false;
     }
 };
 
 // If we're using -prune with -reindex, then delete block files that will be
 // ignored by the reindex.  Since reindexing works by starting at block file 0
 // and looping until a blockfile is missing, do the same here to delete any
 // later block files after a gap. Also delete all rev files since they'll be
 // rewritten by the reindex anyway. This ensures that vinfoBlockFile is in sync
 // with what's actually on disk by the time we start downloading, so that
 // pruning works correctly.
 static void CleanupBlockRevFiles() {
     std::map<std::string, fs::path> mapBlockFiles;
 
     // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
     // Remove the rev files immediately and insert the blk file paths into an
     // ordered map keyed by block file index.
     LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for "
               "-reindex with -prune\n");
     const auto directoryIterator = fs::directory_iterator{GetBlocksDir()};
     for (const auto &file : directoryIterator) {
         const auto fileName = file.path().filename().string();
         if (fs::is_regular_file(file) && fileName.length() == 12 &&
             fileName.substr(8, 4) == ".dat") {
             if (fileName.substr(0, 3) == "blk") {
                 mapBlockFiles[fileName.substr(3, 5)] = file.path();
             } else if (fileName.substr(0, 3) == "rev") {
                 remove(file.path());
             }
         }
     }
 
     // Remove all block files that aren't part of a contiguous set starting at
     // zero by walking the ordered map (keys are block file indices) by keeping
     // a separate counter. Once we hit a gap (or if 0 doesn't exist) start
     // removing block files.
     int contiguousCounter = 0;
     for (const auto &item : mapBlockFiles) {
         if (atoi(item.first) == contiguousCounter) {
             contiguousCounter++;
             continue;
         }
         remove(item.second);
     }
 }
 
 static void ThreadImport(const Config &config, ChainstateManager &chainman,
                          std::vector<fs::path> vImportFiles,
                          const ArgsManager &args) {
     util::ThreadRename("loadblk");
     ScheduleBatchPriority();
 
     {
         const CChainParams &chainParams = config.GetChainParams();
 
         CImportingNow imp;
 
         // -reindex
         if (fReindex) {
             int nFile = 0;
             while (true) {
                 FlatFilePos pos(nFile, 0);
                 if (!fs::exists(GetBlockPosFilename(pos))) {
                     // No block files left to reindex
                     break;
                 }
                 FILE *file = OpenBlockFile(pos, true);
                 if (!file) {
                     // This error is logged in OpenBlockFile
                     break;
                 }
                 LogPrintf("Reindexing block file blk%05u.dat...\n",
                           (unsigned int)nFile);
                 LoadExternalBlockFile(config, file, &pos);
                 if (ShutdownRequested()) {
                     LogPrintf("Shutdown requested. Exit %s\n", __func__);
                     return;
                 }
                 nFile++;
             }
             pblocktree->WriteReindexing(false);
             fReindex = false;
             LogPrintf("Reindexing finished\n");
             // To avoid ending up in a situation without genesis block, re-try
             // initializing (no-op if reindexing worked):
             LoadGenesisBlock(chainParams);
         }
 
         // -loadblock=
         for (const fs::path &path : vImportFiles) {
             FILE *file = fsbridge::fopen(path, "rb");
             if (file) {
                 LogPrintf("Importing blocks file %s...\n", path.string());
                 LoadExternalBlockFile(config, file);
                 if (ShutdownRequested()) {
                     LogPrintf("Shutdown requested. Exit %s\n", __func__);
                     return;
                 }
             } else {
                 LogPrintf("Warning: Could not open blocks file %s\n",
                           path.string());
             }
         }
 
         // Reconsider blocks we know are valid. They may have been marked
         // invalid by, for instance, running an outdated version of the node
         // software.
         const MapCheckpoints &checkpoints =
             chainParams.Checkpoints().mapCheckpoints;
         for (const MapCheckpoints::value_type &i : checkpoints) {
             const BlockHash &hash = i.second;
 
             LOCK(cs_main);
             CBlockIndex *pblockindex = LookupBlockIndex(hash);
             if (pblockindex && !pblockindex->nStatus.isValid()) {
                 LogPrintf("Reconsidering checkpointed block %s ...\n",
                           hash.GetHex());
                 ResetBlockFailureFlags(pblockindex);
             }
         }
 
         // scan for better chains in the block chain database, that are not yet
         // connected in the active best chain
 
         // We can't hold cs_main during ActivateBestChain even though we're
         // accessing the chainman unique_ptrs since ABC requires us not to be
         // holding cs_main, so retrieve the relevant pointers before the ABC
         // call.
         for (CChainState *chainstate :
              WITH_LOCK(::cs_main, return chainman.GetAll())) {
             BlockValidationState state;
             if (!chainstate->ActivateBestChain(config, state, nullptr)) {
                 LogPrintf("Failed to connect best block (%s)\n",
                           state.ToString());
                 StartShutdown();
                 return;
             }
         }
 
         if (args.GetBoolArg("-stopafterblockimport",
                             DEFAULT_STOPAFTERBLOCKIMPORT)) {
             LogPrintf("Stopping after block import\n");
             StartShutdown();
             return;
         }
     } // End scope of CImportingNow
     if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
         LoadMempool(config, ::g_mempool);
     }
     ::g_mempool.SetIsLoaded(!ShutdownRequested());
 }
 
 /** Sanity checks
  *  Ensure that Bitcoin is running in a usable environment with all
  *  necessary library support.
  */
 static bool InitSanityCheck() {
     if (!ECC_InitSanityCheck()) {
         return InitError(Untranslated(
             "Elliptic curve cryptography sanity check failure. Aborting."));
     }
 
     if (!glibcxx_sanity_test()) {
         return false;
     }
 
     if (!Random_SanityCheck()) {
         return InitError(Untranslated(
             "OS cryptographic RNG sanity check failure. Aborting."));
     }
 
     return true;
 }
 
 static bool AppInitServers(Config &config,
                            HTTPRPCRequestProcessor &httpRPCRequestProcessor,
                            NodeContext &node) {
     const ArgsManager &args = *Assert(node.args);
     RPCServerSignals::OnStarted(&OnRPCStarted);
     RPCServerSignals::OnStopped(&OnRPCStopped);
     if (!InitHTTPServer(config)) {
         return false;
     }
 
     StartRPC();
     node.rpc_interruption_point = RpcInterruptionPoint;
 
     if (!StartHTTPRPC(httpRPCRequestProcessor)) {
         return false;
     }
     if (args.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) {
         StartREST(httpRPCRequestProcessor.context);
     }
 
     StartHTTPServer();
     return true;
 }
 
 // Parameter interaction based on rules
 void InitParameterInteraction(ArgsManager &args) {
     // when specifying an explicit binding address, you want to listen on it
     // even when -connect or -proxy is specified.
     if (args.IsArgSet("-bind")) {
         if (args.SoftSetBoolArg("-listen", true)) {
             LogPrintf(
                 "%s: parameter interaction: -bind set -> setting -listen=1\n",
                 __func__);
         }
     }
     if (args.IsArgSet("-whitebind")) {
         if (args.SoftSetBoolArg("-listen", true)) {
             LogPrintf("%s: parameter interaction: -whitebind set -> setting "
                       "-listen=1\n",
                       __func__);
         }
     }
 
     if (args.IsArgSet("-connect")) {
         // when only connecting to trusted nodes, do not seed via DNS, or listen
         // by default.
         if (args.SoftSetBoolArg("-dnsseed", false)) {
             LogPrintf("%s: parameter interaction: -connect set -> setting "
                       "-dnsseed=0\n",
                       __func__);
         }
         if (args.SoftSetBoolArg("-listen", false)) {
             LogPrintf("%s: parameter interaction: -connect set -> setting "
                       "-listen=0\n",
                       __func__);
         }
     }
 
     if (args.IsArgSet("-proxy")) {
         // to protect privacy, do not listen by default if a default proxy
         // server is specified.
         if (args.SoftSetBoolArg("-listen", false)) {
             LogPrintf(
                 "%s: parameter interaction: -proxy set -> setting -listen=0\n",
                 __func__);
         }
         // to protect privacy, do not use UPNP when a proxy is set. The user may
         // still specify -listen=1 to listen locally, so don't rely on this
         // happening through -listen below.
         if (args.SoftSetBoolArg("-upnp", false)) {
             LogPrintf(
                 "%s: parameter interaction: -proxy set -> setting -upnp=0\n",
                 __func__);
         }
         // to protect privacy, do not discover addresses by default
         if (args.SoftSetBoolArg("-discover", false)) {
             LogPrintf("%s: parameter interaction: -proxy set -> setting "
                       "-discover=0\n",
                       __func__);
         }
     }
 
     if (!args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
         // do not map ports or try to retrieve public IP when not listening
         // (pointless)
         if (args.SoftSetBoolArg("-upnp", false)) {
             LogPrintf(
                 "%s: parameter interaction: -listen=0 -> setting -upnp=0\n",
                 __func__);
         }
         if (args.SoftSetBoolArg("-discover", false)) {
             LogPrintf(
                 "%s: parameter interaction: -listen=0 -> setting -discover=0\n",
                 __func__);
         }
         if (args.SoftSetBoolArg("-listenonion", false)) {
             LogPrintf("%s: parameter interaction: -listen=0 -> setting "
                       "-listenonion=0\n",
                       __func__);
         }
     }
 
     if (args.IsArgSet("-externalip")) {
         // if an explicit public IP is specified, do not try to find others
         if (args.SoftSetBoolArg("-discover", false)) {
             LogPrintf("%s: parameter interaction: -externalip set -> setting "
                       "-discover=0\n",
                       __func__);
         }
     }
 
     // disable whitelistrelay in blocksonly mode
     if (args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
         if (args.SoftSetBoolArg("-whitelistrelay", false)) {
             LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting "
                       "-whitelistrelay=0\n",
                       __func__);
         }
     }
 
     // Forcing relay from whitelisted hosts implies we will accept relays from
     // them in the first place.
     if (args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
         if (args.SoftSetBoolArg("-whitelistrelay", true)) {
             LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> "
                       "setting -whitelistrelay=1\n",
                       __func__);
         }
     }
 }
 
 /**
  * Initialize global loggers.
  *
  * Note that this is called very early in the process lifetime, so you should be
  * careful about what global state you rely on here.
  */
 void InitLogging(const ArgsManager &args) {
     LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile");
     LogInstance().m_file_path =
         AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
 
     LogInstance().m_print_to_console =
         args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false));
     LogInstance().m_log_timestamps =
         args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
     LogInstance().m_log_time_micros =
         args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
     LogInstance().m_log_threadnames =
         args.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES);
 
     fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
 
     std::string version_string = FormatFullVersion();
 #ifdef DEBUG
     version_string += " (debug build)";
 #else
     version_string += " (release build)";
 #endif
     LogPrintf("%s version %s\n", CLIENT_NAME, version_string);
 }
 
 namespace { // Variables internal to initialization process only
 
 int nMaxConnections;
 int nUserMaxConnections;
 int nFD;
 ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
 int64_t peer_connect_timeout;
 std::set<BlockFilterType> g_enabled_filter_types;
 
 } // namespace
 
 [[noreturn]] static void new_handler_terminate() {
     // Rather than throwing std::bad-alloc if allocation fails, terminate
     // immediately to (try to) avoid chain corruption. Since LogPrintf may
     // itself allocate memory, set the handler directly to terminate first.
     std::set_new_handler(std::terminate);
     LogPrintf("Error: Out of memory. Terminating.\n");
 
     // The log was successful, terminate now.
     std::terminate();
 };
 
 bool AppInitBasicSetup(ArgsManager &args) {
 // Step 1: setup
 #ifdef _MSC_VER
     // Turn off Microsoft heap dump noise
     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
     _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, nullptr,
                                              OPEN_EXISTING, 0, 0));
     // Disable confusing "helpful" text message on abort, Ctrl-C
     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
 #endif
 #ifdef WIN32
     // Enable Data Execution Prevention (DEP)
     SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
 #endif
 
     if (!SetupNetworking()) {
         return InitError(Untranslated("Initializing networking failed"));
     }
 
 #ifndef WIN32
     if (!args.GetBoolArg("-sysperms", false)) {
         umask(077);
     }
 
     // Clean shutdown on SIGTERM
     registerSignalHandler(SIGTERM, HandleSIGTERM);
     registerSignalHandler(SIGINT, HandleSIGTERM);
 
     // Reopen debug.log on SIGHUP
     registerSignalHandler(SIGHUP, HandleSIGHUP);
 
     // Ignore SIGPIPE, otherwise it will bring the daemon down if the client
     // closes unexpectedly
     signal(SIGPIPE, SIG_IGN);
 #else
     SetConsoleCtrlHandler(consoleCtrlHandler, true);
 #endif
 
     std::set_new_handler(new_handler_terminate);
 
     return true;
 }
 
 bool AppInitParameterInteraction(Config &config, const ArgsManager &args) {
     const CChainParams &chainparams = config.GetChainParams();
     // Step 2: parameter interactions
 
     // also see: InitParameterInteraction()
 
     // Error if network-specific options (-addnode, -connect, etc) are
     // specified in default section of config file, but not overridden
     // on the command line or in this network's section of the config file.
     std::string network = args.GetChainName();
     bilingual_str errors;
     for (const auto &arg : args.GetUnsuitableSectionOnlyArgs()) {
         errors += strprintf(_("Config setting for %s only applied on %s "
                               "network when in [%s] section.") +
                                 Untranslated("\n"),
                             arg, network, network);
     }
 
     if (!errors.empty()) {
         return InitError(errors);
     }
 
     // Warn if unrecognized section name are present in the config file.
     bilingual_str warnings;
     for (const auto &section : args.GetUnrecognizedSections()) {
         warnings += strprintf(Untranslated("%s:%i ") +
                                   _("Section [%s] is not recognized.") +
                                   Untranslated("\n"),
                               section.m_file, section.m_line, section.m_name);
     }
 
     if (!warnings.empty()) {
         InitWarning(warnings);
     }
 
     if (!fs::is_directory(GetBlocksDir())) {
         return InitError(
             strprintf(_("Specified blocks directory \"%s\" does not exist."),
                       args.GetArg("-blocksdir", "")));
     }
 
     // parse and validate enabled filter types
     std::string blockfilterindex_value =
         args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
     if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
         g_enabled_filter_types = AllBlockFilterTypes();
     } else if (blockfilterindex_value != "0") {
         const std::vector<std::string> names =
             args.GetArgs("-blockfilterindex");
         for (const auto &name : names) {
             BlockFilterType filter_type;
             if (!BlockFilterTypeByName(name, filter_type)) {
                 return InitError(
                     strprintf(_("Unknown -blockfilterindex value %s."), name));
             }
             g_enabled_filter_types.insert(filter_type);
         }
     }
 
     // Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index
     // are both enabled.
     if (gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
         if (g_enabled_filter_types.count(BlockFilterType::BASIC) != 1) {
             return InitError(
                 _("Cannot set -peerblockfilters without -blockfilterindex."));
         }
 
         nLocalServices = ServiceFlags(nLocalServices | NODE_COMPACT_FILTERS);
     }
 
     // if using block pruning, then disallow txindex
     if (args.GetArg("-prune", 0)) {
         if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
             return InitError(_("Prune mode is incompatible with -txindex."));
         }
         if (!g_enabled_filter_types.empty()) {
             return InitError(
                 _("Prune mode is incompatible with -blockfilterindex."));
         }
     }
 
     // -bind and -whitebind can't be set when not listening
     size_t nUserBind =
         args.GetArgs("-bind").size() + args.GetArgs("-whitebind").size();
     if (nUserBind != 0 && !args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
         return InitError(Untranslated(
             "Cannot set -bind or -whitebind together with -listen=0"));
     }
 
     // Make sure enough file descriptors are available
     int nBind = std::max(nUserBind, size_t(1));
     nUserMaxConnections =
         args.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
     nMaxConnections = std::max(nUserMaxConnections, 0);
 
     // Trim requested connection counts, to fit into system limitations
     // <int> in std::min<int>(...) to work around FreeBSD compilation issue
     // described in #2695
     nFD = RaiseFileDescriptorLimit(nMaxConnections + nBind +
                                    MIN_CORE_FILEDESCRIPTORS +
                                    MAX_ADDNODE_CONNECTIONS);
 #ifdef USE_POLL
     int fd_max = nFD;
 #else
     int fd_max = FD_SETSIZE;
 #endif
     nMaxConnections =
         std::max(std::min<int>(nMaxConnections, fd_max - nBind -
                                                     MIN_CORE_FILEDESCRIPTORS -
                                                     MAX_ADDNODE_CONNECTIONS),
                  0);
     if (nFD < MIN_CORE_FILEDESCRIPTORS) {
         return InitError(_("Not enough file descriptors available."));
     }
     nMaxConnections =
         std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS,
                  nMaxConnections);
 
     if (nMaxConnections < nUserMaxConnections) {
         // Not categorizing as "Warning" because this is the normal behavior for
         // platforms using the select() interface for which FD_SETSIZE is
         // usually 1024.
         LogPrintf("Reducing -maxconnections from %d to %d, because of system "
                   "limitations.\n",
                   nUserMaxConnections, nMaxConnections);
     }
 
     // Step 3: parameter-to-internal-flags
     if (args.IsArgSet("-debug")) {
         // Special-case: if -debug=0/-nodebug is set, turn off debugging
         // messages
         const std::vector<std::string> &categories = args.GetArgs("-debug");
         if (std::none_of(
                 categories.begin(), categories.end(),
                 [](std::string cat) { return cat == "0" || cat == "none"; })) {
             for (const auto &cat : categories) {
                 if (!LogInstance().EnableCategory(cat)) {
                     InitWarning(
                         strprintf(_("Unsupported logging category %s=%s."),
                                   "-debug", cat));
                 }
             }
         }
     }
 
     // Now remove the logging categories which were explicitly excluded
     for (const std::string &cat : args.GetArgs("-debugexclude")) {
         if (!LogInstance().DisableCategory(cat)) {
             InitWarning(strprintf(_("Unsupported logging category %s=%s."),
                                   "-debugexclude", cat));
         }
     }
 
     // Checkmempool and checkblockindex default to true in regtest mode
     int ratio = std::min<int>(
         std::max<int>(
             args.GetArg("-checkmempool",
                         chainparams.DefaultConsistencyChecks() ? 1 : 0),
             0),
         1000000);
     if (ratio != 0) {
         g_mempool.setSanityCheck(1.0 / ratio);
     }
     fCheckBlockIndex = args.GetBoolArg("-checkblockindex",
                                        chainparams.DefaultConsistencyChecks());
     fCheckpointsEnabled =
         args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
     if (fCheckpointsEnabled) {
         LogPrintf("Checkpoints will be verified.\n");
     } else {
         LogPrintf("Skipping checkpoint verification.\n");
     }
 
     hashAssumeValid = BlockHash::fromHex(
         args.GetArg("-assumevalid",
                     chainparams.GetConsensus().defaultAssumeValid.GetHex()));
     if (!hashAssumeValid.IsNull()) {
         LogPrintf("Assuming ancestors of block %s have valid signatures.\n",
                   hashAssumeValid.GetHex());
     } else {
         LogPrintf("Validating signatures for all blocks.\n");
     }
 
     if (args.IsArgSet("-minimumchainwork")) {
         const std::string minChainWorkStr =
             args.GetArg("-minimumchainwork", "");
         if (!IsHexNumber(minChainWorkStr)) {
             return InitError(strprintf(
                 Untranslated(
                     "Invalid non-hex (%s) minimum chain work value specified"),
                 minChainWorkStr));
         }
         nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr));
     } else {
         nMinimumChainWork =
             UintToArith256(chainparams.GetConsensus().nMinimumChainWork);
     }
     LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
     if (nMinimumChainWork <
         UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
         LogPrintf("Warning: nMinimumChainWork set below default value of %s\n",
                   chainparams.GetConsensus().nMinimumChainWork.GetHex());
     }
 
     // mempool limits
     int64_t nMempoolSizeMax =
         args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
     int64_t nMempoolSizeMin =
         args.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) *
         1000 * 40;
     if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) {
         return InitError(strprintf(_("-maxmempool must be at least %d MB"),
                                    std::ceil(nMempoolSizeMin / 1000000.0)));
     }
 
     // Configure excessive block size.
     const uint64_t nProposedExcessiveBlockSize =
         args.GetArg("-excessiveblocksize", DEFAULT_MAX_BLOCK_SIZE);
     if (!config.SetMaxBlockSize(nProposedExcessiveBlockSize)) {
         return InitError(
             _("Excessive block size must be > 1,000,000 bytes (1MB)"));
     }
 
     // Check blockmaxsize does not exceed maximum accepted block size.
     const uint64_t nProposedMaxGeneratedBlockSize =
         args.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE);
     if (nProposedMaxGeneratedBlockSize > config.GetMaxBlockSize()) {
         auto msg = _("Max generated block size (blockmaxsize) cannot exceed "
                      "the excessive block size (excessiveblocksize)");
         return InitError(msg);
     }
 
     // block pruning; get the amount of disk space (in MiB) to allot for block &
     // undo files
     int64_t nPruneArg = args.GetArg("-prune", 0);
     if (nPruneArg < 0) {
         return InitError(
             _("Prune cannot be configured with a negative value."));
     }
     nPruneTarget = (uint64_t)nPruneArg * 1024 * 1024;
     if (nPruneArg == 1) {
         // manual pruning: -prune=1
         LogPrintf("Block pruning enabled.  Use RPC call "
                   "pruneblockchain(height) to manually prune block and undo "
                   "files.\n");
         nPruneTarget = std::numeric_limits<uint64_t>::max();
         fPruneMode = true;
     } else if (nPruneTarget) {
         if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
             return InitError(
                 strprintf(_("Prune configured below the minimum of %d MiB. "
                             "Please use a higher number."),
                           MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
         }
         LogPrintf("Prune configured to target %u MiB on disk for block and "
                   "undo files.\n",
                   nPruneTarget / 1024 / 1024);
         fPruneMode = true;
     }
 
     nConnectTimeout = args.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
     if (nConnectTimeout <= 0) {
         nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
     }
 
     peer_connect_timeout =
         args.GetArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT);
     if (peer_connect_timeout <= 0) {
         return InitError(Untranslated(
             "peertimeout cannot be configured with a negative value."));
     }
 
     // Obtain the amount to charge excess UTXO
     if (args.IsArgSet("-excessutxocharge")) {
         Amount n = Amount::zero();
         auto parsed = ParseMoney(args.GetArg("-excessutxocharge", ""), n);
         if (!parsed || Amount::zero() > n) {
             return InitError(AmountErrMsg(
                 "excessutxocharge", args.GetArg("-excessutxocharge", "")));
         }
         config.SetExcessUTXOCharge(n);
     } else {
         config.SetExcessUTXOCharge(DEFAULT_UTXO_FEE);
     }
 
     if (args.IsArgSet("-minrelaytxfee")) {
         Amount n = Amount::zero();
         auto parsed = ParseMoney(args.GetArg("-minrelaytxfee", ""), n);
         if (!parsed || n == Amount::zero()) {
             return InitError(AmountErrMsg("minrelaytxfee",
                                           args.GetArg("-minrelaytxfee", "")));
         }
         // High fee check is done afterward in CWallet::CreateWalletFromFile()
         ::minRelayTxFee = CFeeRate(n);
     }
 
     // Sanity check argument for min fee for including tx in block
     // TODO: Harmonize which arguments need sanity checking and where that
     // happens.
     if (args.IsArgSet("-blockmintxfee")) {
         Amount n = Amount::zero();
         if (!ParseMoney(args.GetArg("-blockmintxfee", ""), n)) {
             return InitError(AmountErrMsg("blockmintxfee",
                                           args.GetArg("-blockmintxfee", "")));
         }
     }
 
     // Feerate used to define dust.  Shouldn't be changed lightly as old
     // implementations may inadvertently create non-standard transactions.
     if (args.IsArgSet("-dustrelayfee")) {
         Amount n = Amount::zero();
         auto parsed = ParseMoney(args.GetArg("-dustrelayfee", ""), n);
         if (!parsed || Amount::zero() == n) {
             return InitError(
                 AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
         }
         dustRelayFee = CFeeRate(n);
     }
 
     fRequireStandard =
         !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
     if (!chainparams.IsTestChain() && !fRequireStandard) {
         return InitError(strprintf(
             Untranslated(
                 "acceptnonstdtxn is not currently supported for %s chain"),
             chainparams.NetworkIDString()));
     }
     nBytesPerSigOp = args.GetArg("-bytespersigop", nBytesPerSigOp);
 
     if (!g_wallet_init_interface.ParameterInteraction()) {
         return false;
     }
 
     fIsBareMultisigStd =
         args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
     fAcceptDatacarrier =
         args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
 
     // Option to startup with mocktime set (used for regression testing):
     SetMockTime(args.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
 
     if (args.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) {
         nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
     }
 
     nMaxTipAge = args.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
 
     return true;
 }
 
 static bool LockDataDirectory(bool probeOnly) {
     // Make sure only a single Bitcoin process is using the data directory.
     fs::path datadir = GetDataDir();
     if (!DirIsWritable(datadir)) {
         return InitError(strprintf(
             _("Cannot write to data directory '%s'; check permissions."),
             datadir.string()));
     }
     if (!LockDirectory(datadir, ".lock", probeOnly)) {
         return InitError(strprintf(_("Cannot obtain a lock on data directory "
                                      "%s. %s is probably already running."),
                                    datadir.string(), PACKAGE_NAME));
     }
     return true;
 }
 
 bool AppInitSanityChecks() {
     // Step 4: sanity checks
 
     // Initialize elliptic curve code
     std::string sha256_algo = SHA256AutoDetect();
     LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
     RandomInit();
     ECC_Start();
     globalVerifyHandle.reset(new ECCVerifyHandle());
 
     // Sanity check
     if (!InitSanityCheck()) {
         return InitError(strprintf(
             _("Initialization sanity check failed. %s is shutting down."),
             PACKAGE_NAME));
     }
 
     // Probe the data directory lock to give an early error message, if possible
     // We cannot hold the data directory lock here, as the forking for daemon()
     // hasn't yet happened, and a fork will cause weird behavior to it.
     return LockDataDirectory(true);
 }
 
 bool AppInitLockDataDirectory() {
     // After daemonization get the data directory lock again and hold on to it
     // until exit. This creates a slight window for a race condition to happen,
     // however this condition is harmless: it will at most make us exit without
     // printing a message to console.
     if (!LockDataDirectory(false)) {
         // Detailed error printed inside LockDataDirectory
         return false;
     }
     return true;
 }
 
 bool AppInitMain(Config &config, RPCServer &rpcServer,
                  HTTPRPCRequestProcessor &httpRPCRequestProcessor,
                  NodeContext &node) {
     // Step 4a: application initialization
     const ArgsManager &args = *Assert(node.args);
     const CChainParams &chainparams = config.GetChainParams();
 
     if (!CreatePidFile(args)) {
         // Detailed error printed inside CreatePidFile().
         return false;
     }
 
     BCLog::Logger &logger = LogInstance();
     if (logger.m_print_to_file) {
         if (args.GetBoolArg("-shrinkdebugfile",
                             logger.DefaultShrinkDebugFile())) {
             // Do this first since it both loads a bunch of debug.log into
             // memory, and because this needs to happen before any other
             // debug.log printing.
             logger.ShrinkDebugFile();
         }
     }
 
     if (!logger.StartLogging()) {
         return InitError(
             strprintf(Untranslated("Could not open debug log file %s"),
                       logger.m_file_path.string()));
     }
 
     if (!logger.m_log_timestamps) {
         LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
     }
     LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
     LogPrintf("Using data directory %s\n", GetDataDir().string());
 
     // Only log conf file usage message if conf file actually exists.
     fs::path config_file_path =
         GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
     if (fs::exists(config_file_path)) {
         LogPrintf("Config file: %s\n", config_file_path.string());
     } else if (args.IsArgSet("-conf")) {
         // Warn if no conf file exists at path provided by user
         InitWarning(
             strprintf(_("The specified config file %s does not exist\n"),
                       config_file_path.string()));
     } else {
         // Not categorizing as "Warning" because it's the default behavior
         LogPrintf("Config file: %s (not found, skipping)\n",
                   config_file_path.string());
     }
 
     // Log the config arguments to debug.log
     args.LogArgs();
 
     LogPrintf("Using at most %i automatic connections (%i file descriptors "
               "available)\n",
               nMaxConnections, nFD);
 
     // Warn about relative -datadir path.
     if (args.IsArgSet("-datadir") &&
         !fs::path(args.GetArg("-datadir", "")).is_absolute()) {
         LogPrintf("Warning: relative datadir option '%s' specified, which will "
                   "be interpreted relative to the current working directory "
                   "'%s'. This is fragile, because if bitcoin is started in the "
                   "future from a different location, it will be unable to "
                   "locate the current data files. There could also be data "
                   "loss if bitcoin is started while in a temporary "
                   "directory.\n",
                   args.GetArg("-datadir", ""), fs::current_path().string());
     }
 
     InitSignatureCache();
     InitScriptExecutionCache();
 
     int script_threads = args.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
     if (script_threads <= 0) {
         // -par=0 means autodetect (number of cores - 1 script threads)
         // -par=-n means "leave n cores free" (number of cores - n - 1 script
         // threads)
         script_threads += GetNumCores();
     }
 
     // Subtract 1 because the main thread counts towards the par threads
     script_threads = std::max(script_threads - 1, 0);
 
     // Number of script-checking threads <= MAX_SCRIPTCHECK_THREADS
     script_threads = std::min(script_threads, MAX_SCRIPTCHECK_THREADS);
 
     LogPrintf("Script verification uses %d additional threads\n",
               script_threads);
     if (script_threads >= 1) {
         for (int i = 0; i < script_threads; ++i) {
             threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
         }
     }
 
     assert(!node.scheduler);
     node.scheduler = std::make_unique<CScheduler>();
 
     // Start the lightweight task scheduler thread
     CScheduler::Function serviceLoop = [&node] {
         node.scheduler->serviceQueue();
     };
     threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>,
                                         "scheduler", serviceLoop));
 
     // Gather some entropy once per minute.
     node.scheduler->scheduleEvery(
         [] {
             RandAddPeriodic();
             return true;
         },
         std::chrono::minutes{1});
 
     GetMainSignals().RegisterBackgroundSignalScheduler(*node.scheduler);
 
     // Create client interfaces for wallets that are supposed to be loaded
     // according to -wallet and -disablewallet options. This only constructs
     // the interfaces, it doesn't load wallet data. Wallets actually get loaded
     // when load() and start() interface methods are called below.
     g_wallet_init_interface.Construct(node);
 
     /**
      * Register RPC commands regardless of -server setting so they will be
      * available in the GUI RPC console even if external calls are disabled.
      */
     RegisterAllRPCCommands(config, rpcServer, tableRPC);
     for (const auto &client : node.chain_clients) {
         client->registerRpcs();
     }
 #if ENABLE_ZMQ
     RegisterZMQRPCCommands(tableRPC);
 #endif
 
     /**
      * Start the RPC server.  It will be started in "warmup" mode and not
      * process calls yet (but it will verify that the server is there and will
      * be ready later).  Warmup mode will be completed when initialisation is
      * finished.
      */
     if (args.GetBoolArg("-server", false)) {
         uiInterface.InitMessage_connect(SetRPCWarmupStatus);
         if (!AppInitServers(config, httpRPCRequestProcessor, node)) {
             return InitError(
                 _("Unable to start HTTP server. See debug log for details."));
         }
     }
 
     // Step 5: verify wallet database integrity
     for (const auto &client : node.chain_clients) {
         if (!client->verify(chainparams)) {
             return false;
         }
     }
 
     // Step 6: network initialization
 
     // Note that we absolutely cannot open any actual connections
     // until the very end ("start node") as the UTXO/block state
     // is not yet setup and may end up being set up twice if we
     // need to reindex later.
 
     assert(!node.banman);
     node.banman = std::make_unique<BanMan>(
         GetDataDir() / "banlist.dat", config.GetChainParams(), &uiInterface,
         args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
     assert(!node.connman);
     node.connman = std::make_unique<CConnman>(
         config, GetRand(std::numeric_limits<uint64_t>::max()),
         GetRand(std::numeric_limits<uint64_t>::max()));
 
     // Make mempool generally available in the node context. For example the
     // connection manager, wallet, or RPC threads, which are all started after
     // this, may use it from the node context.
     assert(!node.mempool);
     node.mempool = &::g_mempool;
 
     assert(!node.chainman);
     node.chainman = &g_chainman;
     ChainstateManager &chainman = *Assert(node.chainman);
 
     node.peerman.reset(new PeerManager(chainparams, *node.connman,
                                        node.banman.get(), *node.scheduler,
                                        chainman, *node.mempool));
     RegisterValidationInterface(node.peerman.get());
 
     // sanitize comments per BIP-0014, format user agent and check total size
     std::vector<std::string> uacomments;
     for (const std::string &cmt : args.GetArgs("-uacomment")) {
         if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) {
             return InitError(strprintf(
                 _("User Agent comment (%s) contains unsafe characters."), cmt));
         }
         uacomments.push_back(cmt);
     }
     const std::string strSubVersion =
         FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
     if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
         return InitError(strprintf(
             _("Total length of network version string (%i) exceeds maximum "
               "length (%i). Reduce the number or size of uacomments."),
             strSubVersion.size(), MAX_SUBVERSION_LENGTH));
     }
 
     if (args.IsArgSet("-onlynet")) {
         std::set<enum Network> nets;
         for (const std::string &snet : args.GetArgs("-onlynet")) {
             enum Network net = ParseNetwork(snet);
             if (net == NET_UNROUTABLE) {
                 return InitError(strprintf(
                     _("Unknown network specified in -onlynet: '%s'"), snet));
             }
             nets.insert(net);
         }
         for (int n = 0; n < NET_MAX; n++) {
             enum Network net = (enum Network)n;
             if (!nets.count(net)) {
                 SetReachable(net, false);
             }
         }
     }
 
     // Check for host lookup allowed before parsing any network related
     // parameters
     fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
 
     bool proxyRandomize =
         args.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
     // -proxy sets a proxy for all outgoing network traffic
     // -noproxy (or -proxy=0) as well as the empty string can be used to not set
     // a proxy, this is the default
     std::string proxyArg = args.GetArg("-proxy", "");
     SetReachable(NET_ONION, false);
     if (proxyArg != "" && proxyArg != "0") {
         CService proxyAddr;
         if (!Lookup(proxyArg, proxyAddr, 9050, fNameLookup)) {
             return InitError(strprintf(
                 _("Invalid -proxy address or hostname: '%s'"), proxyArg));
         }
 
         proxyType addrProxy = proxyType(proxyAddr, proxyRandomize);
         if (!addrProxy.IsValid()) {
             return InitError(strprintf(
                 _("Invalid -proxy address or hostname: '%s'"), proxyArg));
         }
 
         SetProxy(NET_IPV4, addrProxy);
         SetProxy(NET_IPV6, addrProxy);
         SetProxy(NET_ONION, addrProxy);
         SetNameProxy(addrProxy);
         // by default, -proxy sets onion as reachable, unless -noonion later
         SetReachable(NET_ONION, true);
     }
 
     // -onion can be used to set only a proxy for .onion, or override normal
     // proxy for .onion addresses.
     // -noonion (or -onion=0) disables connecting to .onion entirely. An empty
     // string is used to not override the onion proxy (in which case it defaults
     // to -proxy set above, or none)
     std::string onionArg = args.GetArg("-onion", "");
     if (onionArg != "") {
         if (onionArg == "0") {
             // Handle -noonion/-onion=0
             SetReachable(NET_ONION, false);
         } else {
             CService onionProxy;
             if (!Lookup(onionArg, onionProxy, 9050, fNameLookup)) {
                 return InitError(strprintf(
                     _("Invalid -onion address or hostname: '%s'"), onionArg));
             }
             proxyType addrOnion = proxyType(onionProxy, proxyRandomize);
             if (!addrOnion.IsValid()) {
                 return InitError(strprintf(
                     _("Invalid -onion address or hostname: '%s'"), onionArg));
             }
             SetProxy(NET_ONION, addrOnion);
             SetReachable(NET_ONION, true);
         }
     }
 
     // see Step 2: parameter interactions for more information about these
     fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
     fDiscover = args.GetBoolArg("-discover", true);
     g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
 
     for (const std::string &strAddr : args.GetArgs("-externalip")) {
         CService addrLocal;
         if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) &&
             addrLocal.IsValid()) {
             AddLocal(addrLocal, LOCAL_MANUAL);
         } else {
             return InitError(ResolveErrMsg("externalip", strAddr));
         }
     }
 
     // Read asmap file if configured
     if (args.IsArgSet("-asmap")) {
         fs::path asmap_path = fs::path(args.GetArg("-asmap", ""));
         if (asmap_path.empty()) {
             asmap_path = DEFAULT_ASMAP_FILENAME;
         }
         if (!asmap_path.is_absolute()) {
             asmap_path = GetDataDir() / asmap_path;
         }
         if (!fs::exists(asmap_path)) {
             InitError(strprintf(_("Could not find asmap file %s"), asmap_path));
             return false;
         }
         std::vector<bool> asmap = CAddrMan::DecodeAsmap(asmap_path);
         if (asmap.size() == 0) {
             InitError(
                 strprintf(_("Could not parse asmap file %s"), asmap_path));
             return false;
         }
         const uint256 asmap_version = SerializeHash(asmap);
         node.connman->SetAsmap(std::move(asmap));
         LogPrintf("Using asmap version %s for IP bucketing\n",
                   asmap_version.ToString());
     } else {
         LogPrintf("Using /16 prefix for IP bucketing\n");
     }
 
 #if ENABLE_ZMQ
     g_zmq_notification_interface = CZMQNotificationInterface::Create();
 
     if (g_zmq_notification_interface) {
         RegisterValidationInterface(g_zmq_notification_interface);
     }
 #endif
     // unlimited unless -maxuploadtarget is set
     uint64_t nMaxOutboundLimit = 0;
     uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME;
 
     if (args.IsArgSet("-maxuploadtarget")) {
         nMaxOutboundLimit =
             args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET) * 1024 *
             1024;
     }
 
     // Step 6.5 (I guess ?): Initialize Avalanche.
     bilingual_str avalancheError;
     g_avalanche = avalanche::Processor::MakeProcessor(
         args, *node.chain, node.connman.get(), node.peerman.get(),
         avalancheError);
     if (!g_avalanche) {
         InitError(avalancheError);
         return false;
     }
 
     if (args.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED) &&
         g_avalanche->isAvalancheServiceAvailable()) {
         nLocalServices = ServiceFlags(nLocalServices | NODE_AVALANCHE);
     }
 
     // Step 7: load block chain
 
     fReindex = args.GetBoolArg("-reindex", false);
     bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
 
     // cache size calculations
     int64_t nTotalCache = (args.GetArg("-dbcache", DEFAULT_DB_CACHE_MB) << 20);
     // total cache cannot be less than MIN_DB_CACHE_MB
     nTotalCache = std::max(nTotalCache, MIN_DB_CACHE_MB << 20);
     // total cache cannot be greater than MAX_DB_CACHE_MB
     nTotalCache = std::min(nTotalCache, MAX_DB_CACHE_MB << 20);
     int64_t nBlockTreeDBCache =
         std::min(nTotalCache / 8, MAX_BLOCK_DB_CACHE_MB << 20);
     nTotalCache -= nBlockTreeDBCache;
     int64_t nTxIndexCache =
         std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX)
                                       ? MAX_TX_INDEX_CACHE_MB << 20
                                       : 0);
     nTotalCache -= nTxIndexCache;
     int64_t filter_index_cache = 0;
     if (!g_enabled_filter_types.empty()) {
         size_t n_indexes = g_enabled_filter_types.size();
         int64_t max_cache =
             std::min(nTotalCache / 8, MAX_FILTER_INDEX_CACHE_MB << 20);
         filter_index_cache = max_cache / n_indexes;
         nTotalCache -= filter_index_cache * n_indexes;
     }
     // use 25%-50% of the remainder for disk cache
     int64_t nCoinDBCache =
         std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23));
     // cap total coins db cache
     nCoinDBCache = std::min(nCoinDBCache, MAX_COINS_DB_CACHE_MB << 20);
     nTotalCache -= nCoinDBCache;
     // the rest goes to in-memory cache
     int64_t nCoinCacheUsage = nTotalCache;
     int64_t nMempoolSizeMax =
         args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
     LogPrintf("Cache configuration:\n");
     LogPrintf("* Using %.1f MiB for block index database\n",
               nBlockTreeDBCache * (1.0 / 1024 / 1024));
     if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
         LogPrintf("* Using %.1f MiB for transaction index database\n",
                   nTxIndexCache * (1.0 / 1024 / 1024));
     }
     for (BlockFilterType filter_type : g_enabled_filter_types) {
         LogPrintf("* Using %.1f MiB for %s block filter index database\n",
                   filter_index_cache * (1.0 / 1024 / 1024),
                   BlockFilterTypeName(filter_type));
     }
     LogPrintf("* Using %.1f MiB for chain state database\n",
               nCoinDBCache * (1.0 / 1024 / 1024));
     LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of "
               "unused mempool space)\n",
               nCoinCacheUsage * (1.0 / 1024 / 1024),
               nMempoolSizeMax * (1.0 / 1024 / 1024));
 
     bool fLoaded = false;
     while (!fLoaded && !ShutdownRequested()) {
         const bool fReset = fReindex;
         auto is_coinsview_empty =
             [&](CChainState *chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
                 return fReset || fReindexChainState ||
                        chainstate->CoinsTip().GetBestBlock().IsNull();
             };
         bilingual_str strLoadError;
 
         uiInterface.InitMessage(_("Loading block index...").translated);
         do {
             bool failed_verification = false;
             const int64_t load_block_index_start_time = GetTimeMillis();
             try {
                 LOCK(cs_main);
                 chainman.InitializeChainstate();
                 chainman.m_total_coinstip_cache = nCoinCacheUsage;
                 chainman.m_total_coinsdb_cache = nCoinDBCache;
 
                 UnloadBlockIndex();
 
                 // new CBlockTreeDB tries to delete the existing file, which
                 // fails if it's still open from the previous loop. Close it
                 // first:
                 pblocktree.reset();
                 pblocktree.reset(
                     new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
 
                 if (fReset) {
                     pblocktree->WriteReindexing(true);
                     // If we're reindexing in prune mode, wipe away unusable
                     // block files and all undo data files
                     if (fPruneMode) {
                         CleanupBlockRevFiles();
                     }
                 }
 
                 const Consensus::Params &params = chainparams.GetConsensus();
 
                 // If necessary, upgrade from older database format.
                 // This is a no-op if we cleared the block tree db with -reindex
                 // or -reindex-chainstate
                 if (!pblocktree->Upgrade(params)) {
                     strLoadError = _("Error upgrading block index database");
                     break;
                 }
 
                 if (ShutdownRequested()) {
                     break;
                 }
 
                 // LoadBlockIndex will load fHavePruned if we've ever removed a
                 // block file from disk.
                 // Note that it also sets fReindex based on the disk flag!
                 // From here on out fReindex and fReset mean something
                 // different!
                 if (!chainman.LoadBlockIndex(params)) {
                     if (ShutdownRequested()) {
                         break;
                     }
                     strLoadError = _("Error loading block database");
                     break;
                 }
 
                 // If the loaded chain has a wrong genesis, bail out immediately
                 // (we're likely using a testnet datadir, or the other way
                 // around).
                 if (!::BlockIndex().empty() &&
                     !LookupBlockIndex(params.hashGenesisBlock)) {
                     return InitError(_("Incorrect or no genesis block found. "
                                        "Wrong datadir for network?"));
                 }
 
                 // Check for changed -prune state.  What we are concerned about
                 // is a user who has pruned blocks in the past, but is now
                 // trying to run unpruned.
                 if (fHavePruned && !fPruneMode) {
                     strLoadError =
                         _("You need to rebuild the database using -reindex to "
                           "go back to unpruned mode.  This will redownload the "
                           "entire blockchain");
                     break;
                 }
 
                 // At this point blocktree args are consistent with what's on
                 // disk. If we're not mid-reindex (based on disk + args), add a
                 // genesis block on disk (otherwise we use the one already on
                 // disk).
                 // This is called again in ThreadImport after the reindex
                 // completes.
                 if (!fReindex && !LoadGenesisBlock(chainparams)) {
                     strLoadError = _("Error initializing block database");
                     break;
                 }
 
                 // At this point we're either in reindex or we've loaded a
                 // useful block tree into BlockIndex()!
 
                 bool failed_chainstate_init = false;
 
                 for (CChainState *chainstate : chainman.GetAll()) {
                     LogPrintf("Initializing chainstate %s\n",
                               chainstate->ToString());
                     chainstate->InitCoinsDB(
                         /* cache_size_bytes */ nCoinDBCache,
                         /* in_memory */ false,
                         /* should_wipe */ fReset || fReindexChainState);
 
                     chainstate->CoinsErrorCatcher().AddReadErrCallback([]() {
                         uiInterface.ThreadSafeMessageBox(
                             _("Error reading from database, shutting down."),
                             "", CClientUIInterface::MSG_ERROR);
                     });
 
                     // If necessary, upgrade from older database format.
                     // This is a no-op if we cleared the coinsviewdb with
                     // -reindex or -reindex-chainstate
                     if (!chainstate->CoinsDB().Upgrade()) {
                         strLoadError = _("Error upgrading chainstate database");
                         failed_chainstate_init = true;
                         break;
                     }
 
                     // ReplayBlocks is a no-op if we cleared the coinsviewdb
                     // with -reindex or -reindex-chainstate
                     if (!chainstate->ReplayBlocks(params)) {
                         strLoadError = _(
                             "Unable to replay blocks. You will need to rebuild "
                             "the database using -reindex-chainstate.");
                         failed_chainstate_init = true;
                         break;
                     }
 
                     // The on-disk coinsdb is now in a good state, create the
                     // cache
                     chainstate->InitCoinsCache(nCoinCacheUsage);
                     assert(chainstate->CanFlushToDisk());
 
                     if (!is_coinsview_empty(chainstate)) {
                         // LoadChainTip initializes the chain based on
                         // CoinsTip()'s best block
                         if (!chainstate->LoadChainTip(chainparams)) {
                             strLoadError =
                                 _("Error initializing block database");
                             failed_chainstate_init = true;
                             // out of the per-chainstate loop
                             break;
                         }
                         assert(chainstate->m_chain.Tip() != nullptr);
                     }
                 }
 
                 if (failed_chainstate_init) {
                     // out of the chainstate activation do-while
                     break;
                 }
 
                 for (CChainState *chainstate : chainman.GetAll()) {
                     if (!is_coinsview_empty(chainstate)) {
                         uiInterface.InitMessage(
                             _("Verifying blocks...").translated);
                         if (fHavePruned &&
                             args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) >
                                 MIN_BLOCKS_TO_KEEP) {
                             LogPrintf(
                                 "Prune: pruned datadir may not have more than "
                                 "%d blocks; only checking available blocks\n",
                                 MIN_BLOCKS_TO_KEEP);
                         }
 
                         const CBlockIndex *tip = chainstate->m_chain.Tip();
                         RPCNotifyBlockChange(tip);
                         if (tip &&
                             tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
                             strLoadError =
                                 _("The block database contains a block which "
                                   "appears to be from the future. "
                                   "This may be due to your computer's date and "
                                   "time being set incorrectly. "
                                   "Only rebuild the block database if you are "
                                   "sure that your computer's date and time are "
                                   "correct");
                             failed_verification = true;
                             break;
                         }
 
                         // Only verify the DB of the active chainstate. This is
                         // fixed in later work when we allow VerifyDB to be
                         // parameterized by chainstate.
                         if (&::ChainstateActive() == chainstate &&
                             !CVerifyDB().VerifyDB(
                                 config, &chainstate->CoinsDB(),
                                 args.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
                                 args.GetArg("-checkblocks",
                                             DEFAULT_CHECKBLOCKS))) {
                             strLoadError =
                                 _("Corrupted block database detected");
                             failed_verification = true;
                             break;
                         }
                     }
                 }
             } catch (const std::exception &e) {
                 LogPrintf("%s\n", e.what());
                 strLoadError = _("Error opening block database");
                 failed_verification = true;
                 break;
             }
 
             if (!failed_verification) {
                 fLoaded = true;
                 LogPrintf(" block index %15dms\n",
                           GetTimeMillis() - load_block_index_start_time);
             }
         } while (false);
 
         if (!fLoaded && !ShutdownRequested()) {
             // first suggest a reindex
             if (!fReset) {
                 bool fRet = uiInterface.ThreadSafeQuestion(
                     strLoadError + Untranslated(".\n\n") +
                         _("Do you want to rebuild the block database now?"),
                     strLoadError.original +
                         ".\nPlease restart with -reindex or "
                         "-reindex-chainstate to recover.",
                     "",
                     CClientUIInterface::MSG_ERROR |
                         CClientUIInterface::BTN_ABORT);
                 if (fRet) {
                     fReindex = true;
                     AbortShutdown();
                 } else {
                     LogPrintf("Aborted block database rebuild. Exiting.\n");
                     return false;
                 }
             } else {
                 return InitError(strLoadError);
             }
         }
     }
 
     // As LoadBlockIndex can take several minutes, it's possible the user
     // requested to kill the GUI during the last operation. If so, exit.
     // As the program has not fully started yet, Shutdown() is possibly
     // overkill.
     if (ShutdownRequested()) {
         LogPrintf("Shutdown requested. Exiting.\n");
         return false;
     }
 
     // Encoded addresses using cashaddr instead of base58.
     // We do this by default to avoid confusion with BTC addresses.
     config.SetCashAddrEncoding(args.GetBoolArg("-usecashaddr", true));
 
     // Step 8: load indexers
     if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
         g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex);
         g_txindex->Start();
     }
 
     for (const auto &filter_type : g_enabled_filter_types) {
         InitBlockFilterIndex(filter_type, filter_index_cache, false, fReindex);
         GetBlockFilterIndex(filter_type)->Start();
     }
 
     // Step 9: load wallet
     for (const auto &client : node.chain_clients) {
         if (!client->load(chainparams)) {
             return false;
         }
     }
 
     // Step 10: data directory maintenance
 
     // if pruning, unset the service bit and perform the initial blockstore
     // prune after any wallet rescanning has taken place.
     if (fPruneMode) {
         LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
         nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
         if (!fReindex) {
             LOCK(cs_main);
             for (CChainState *chainstate : chainman.GetAll()) {
                 uiInterface.InitMessage(_("Pruning blockstore...").translated);
                 chainstate->PruneAndFlush();
             }
         }
     }
 
     // Step 11: import blocks
     if (!CheckDiskSpace(GetDataDir())) {
         InitError(
             strprintf(_("Error: Disk space is low for %s"), GetDataDir()));
         return false;
     }
     if (!CheckDiskSpace(GetBlocksDir())) {
         InitError(
             strprintf(_("Error: Disk space is low for %s"), GetBlocksDir()));
         return false;
     }
 
     // Either install a handler to notify us when genesis activates, or set
     // fHaveGenesis directly.
     // No locking, as this happens before any background thread is started.
     boost::signals2::connection block_notify_genesis_wait_connection;
     if (::ChainActive().Tip() == nullptr) {
         block_notify_genesis_wait_connection =
             uiInterface.NotifyBlockTip_connect(
                 std::bind(BlockNotifyGenesisWait, std::placeholders::_2));
     } else {
         fHaveGenesis = true;
     }
 
 #if defined(HAVE_SYSTEM)
     if (args.IsArgSet("-blocknotify")) {
         const std::string block_notify = args.GetArg("-blocknotify", "");
         const auto BlockNotifyCallback = [block_notify](
                                              SynchronizationState sync_state,
                                              const CBlockIndex *pBlockIndex) {
             if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex) {
                 return;
             }
 
             std::string strCmd = block_notify;
             if (!strCmd.empty()) {
                 boost::replace_all(strCmd, "%s",
                                    pBlockIndex->GetBlockHash().GetHex());
                 std::thread t(runCommand, strCmd);
                 // thread runs free
                 t.detach();
             }
         };
         uiInterface.NotifyBlockTip_connect(BlockNotifyCallback);
     }
 #endif
 
     std::vector<fs::path> vImportFiles;
     for (const std::string &strFile : args.GetArgs("-loadblock")) {
         vImportFiles.push_back(strFile);
     }
 
     threadGroup.create_thread([=, &config, &chainman, &args] {
         ThreadImport(config, chainman, vImportFiles, args);
     });
 
     // Wait for genesis block to be processed
     {
         WAIT_LOCK(g_genesis_wait_mutex, lock);
         // We previously could hang here if StartShutdown() is called prior to
         // ThreadImport getting started, so instead we just wait on a timer to
         // check ShutdownRequested() regularly.
         while (!fHaveGenesis && !ShutdownRequested()) {
             g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500));
         }
         block_notify_genesis_wait_connection.disconnect();
     }
 
     if (ShutdownRequested()) {
         return false;
     }
 
     // Step 12: start node
 
     int chain_active_height;
 
     //// debug print
     {
         LOCK(cs_main);
         LogPrintf("block tree size = %u\n", ::BlockIndex().size());
         chain_active_height = ::ChainActive().Height();
     }
     LogPrintf("nBestHeight = %d\n", chain_active_height);
 
     if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) {
         StartTorControl();
     }
 
     Discover();
 
     // Map ports with UPnP
     if (args.GetBoolArg("-upnp", DEFAULT_UPNP)) {
         StartMapPort();
     }
 
     CConnman::Options connOptions;
     connOptions.nLocalServices = nLocalServices;
     connOptions.nMaxConnections = nMaxConnections;
     connOptions.m_max_outbound_full_relay = std::min(
         MAX_OUTBOUND_FULL_RELAY_CONNECTIONS, connOptions.nMaxConnections);
     connOptions.m_max_outbound_block_relay = std::min(
         MAX_BLOCKS_ONLY_CONNECTIONS,
         connOptions.nMaxConnections - connOptions.m_max_outbound_full_relay);
     connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
     connOptions.nMaxFeeler = MAX_FEELER_CONNECTIONS;
     connOptions.nBestHeight = chain_active_height;
     connOptions.uiInterface = &uiInterface;
     connOptions.m_banman = node.banman.get();
     connOptions.m_msgproc = node.peerman.get();
     connOptions.nSendBufferMaxSize =
         1000 * args.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
     connOptions.nReceiveFloodSize =
         1000 * args.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
     connOptions.m_added_nodes = args.GetArgs("-addnode");
 
     connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
     connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
     connOptions.m_peer_connect_timeout = peer_connect_timeout;
 
     for (const std::string &strBind : args.GetArgs("-bind")) {
         CService addrBind;
         if (!Lookup(strBind, addrBind, GetListenPort(), false)) {
             return InitError(ResolveErrMsg("bind", strBind));
         }
         connOptions.vBinds.push_back(addrBind);
     }
 
     for (const std::string &strBind : args.GetArgs("-whitebind")) {
         NetWhitebindPermissions whitebind;
         bilingual_str error;
         if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) {
             return InitError(error);
         }
         connOptions.vWhiteBinds.push_back(whitebind);
     }
 
     for (const auto &net : args.GetArgs("-whitelist")) {
         NetWhitelistPermissions subnet;
         bilingual_str error;
         if (!NetWhitelistPermissions::TryParse(net, subnet, error)) {
             return InitError(error);
         }
         connOptions.vWhitelistedRange.push_back(subnet);
     }
 
     connOptions.vSeedNodes = args.GetArgs("-seednode");
 
     // Initiate outbound connections unless connect=0
     connOptions.m_use_addrman_outgoing = !args.IsArgSet("-connect");
     if (!connOptions.m_use_addrman_outgoing) {
         const auto connect = args.GetArgs("-connect");
         if (connect.size() != 1 || connect[0] != "0") {
             connOptions.m_specified_outgoing = connect;
         }
     }
     if (!node.connman->Start(*node.scheduler, connOptions)) {
         return false;
     }
 
     // Step 13: finished
 
     SetRPCWarmupFinished();
     uiInterface.InitMessage(_("Done loading").translated);
 
     for (const auto &client : node.chain_clients) {
         client->start(*node.scheduler);
     }
 
     BanMan *banman = node.banman.get();
     node.scheduler->scheduleEvery(
         [banman] {
             banman->DumpBanlist();
             return true;
         },
         DUMP_BANS_INTERVAL);
 
     // Start Avalanche's event loop.
     g_avalanche->startEventLoop(*node.scheduler);
 
     return true;
 }
diff --git a/src/test/core_io_tests.cpp b/src/test/core_io_tests.cpp
index 670a55d0b..8f099e1b7 100644
--- a/src/test/core_io_tests.cpp
+++ b/src/test/core_io_tests.cpp
@@ -1,159 +1,160 @@
 // Copyright (c) 2018-2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <core_io.h>
 
 #include <test/util/setup_common.h>
 
 #include <boost/test/unit_test.hpp>
 
+#include <iomanip>
 #include <string>
 
 BOOST_FIXTURE_TEST_SUITE(core_io_tests, BasicTestingSetup)
 
 BOOST_AUTO_TEST_CASE(parse_hex_test) {
     std::string s = "0x";
     BOOST_CHECK_THROW(ParseScript(s), std::runtime_error);
 
     for (int numZeroes = 1; numZeroes <= 32; numZeroes++) {
         s += "0";
         if (numZeroes % 2 == 0) {
             BOOST_CHECK_NO_THROW(ParseScript(s));
         } else {
             BOOST_CHECK_THROW(ParseScript(s), std::runtime_error);
         }
     }
 }
 
 static void PrintLE(std::ostringstream &testString, size_t bytes,
                     size_t pushLength) {
     testString << "0x";
     while (bytes != 0) {
         testString << std::setfill('0') << std::setw(2) << std::hex
                    << pushLength % 256;
         pushLength /= 256;
         bytes--;
     }
 }
 
 static std::string TestPushOpcode(size_t pushWidth, size_t pushLength,
                                   size_t actualLength) {
     std::ostringstream testString;
 
     switch (pushWidth) {
         case 1:
             testString << "PUSHDATA1 ";
             break;
         case 2:
             testString << "PUSHDATA2 ";
             break;
         case 4:
             testString << "PUSHDATA4 ";
             break;
         default:
             assert(false);
     }
     PrintLE(testString, pushWidth, pushLength);
     testString << " 0x";
 
     for (size_t i = 0; i < actualLength; i++) {
         testString << "01";
     }
 
     return testString.str();
 }
 
 BOOST_AUTO_TEST_CASE(printle_tests) {
     // Ensure the test generator is doing what we think it is.
     std::ostringstream testString;
     PrintLE(testString, 04, 0x8001);
     BOOST_CHECK_EQUAL(testString.str(), "0x01800000");
 }
 
 BOOST_AUTO_TEST_CASE(testpushopcode_tests) {
     BOOST_CHECK_EQUAL(TestPushOpcode(1, 2, 2), "PUSHDATA1 0x02 0x0101");
     BOOST_CHECK_EQUAL(TestPushOpcode(2, 2, 2), "PUSHDATA2 0x0200 0x0101");
     BOOST_CHECK_EQUAL(TestPushOpcode(4, 2, 2), "PUSHDATA4 0x02000000 0x0101");
 }
 
 BOOST_AUTO_TEST_CASE(parse_push_test) {
     BOOST_CHECK_NO_THROW(ParseScript("0x01 0x01"));
     BOOST_CHECK_NO_THROW(ParseScript("0x01 XOR"));
     BOOST_CHECK_NO_THROW(ParseScript("0x01 1"));
     BOOST_CHECK_NO_THROW(ParseScript("0x01 ''"));
     BOOST_CHECK_NO_THROW(ParseScript("0x02 0x0101"));
     BOOST_CHECK_NO_THROW(ParseScript("0x02 42"));
     BOOST_CHECK_NO_THROW(ParseScript("0x02 'a'"));
 
     BOOST_CHECK_THROW(ParseScript("0x01 0x0101"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x01 42"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x02 0x01"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x02 XOR"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x02 1"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x02 ''"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x02 0x010101"), std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("0x02 'ab'"), std::runtime_error);
 
     // Note sizes are LE encoded.  Also, some of these values are not
     // minimally encoded intentionally -- nor are they being required to be
     // minimally encoded.
     BOOST_CHECK_NO_THROW(ParseScript("PUSHDATA4 0x02000000 0x0101"));
     BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x03000000 0x0101"),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x02000000 0x010101"),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x020000 0x0101"),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("PUSHDATA4 0x0200000000 0x0101"),
                       std::runtime_error);
 
     BOOST_CHECK_NO_THROW(ParseScript("PUSHDATA2 0x0200 0x0101"));
     BOOST_CHECK_THROW(ParseScript("PUSHDATA2 0x0300 0x0101"),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("PUSHDATA2 0x030000 0x0101"),
                       std::runtime_error);
     BOOST_CHECK_NO_THROW(ParseScript("PUSHDATA1 0x02 0x0101"));
     BOOST_CHECK_THROW(ParseScript("PUSHDATA1 0x02 0x010101"),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript("PUSHDATA1 0x0200 0x010101"),
                       std::runtime_error);
 
     // Ensure pushdata handling is not using 1's complement
     BOOST_CHECK_NO_THROW(ParseScript(TestPushOpcode(1, 0xC8, 0xC8)));
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(1, 0xC8, 0xC9)),
                       std::runtime_error);
 
     BOOST_CHECK_NO_THROW(ParseScript(TestPushOpcode(2, 0x8000, 0x8000)));
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x8000, 0x8001)),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x8001, 0x8000)),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x80, 0x81)),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(2, 0x80, 0x7F)),
                       std::runtime_error);
 
     // Can't build something too long.
     BOOST_CHECK_NO_THROW(ParseScript(TestPushOpcode(4, 0x8000, 0x8000)));
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x8000, 0x8001)),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x8001, 0x8000)),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x80, 0x81)),
                       std::runtime_error);
     BOOST_CHECK_THROW(ParseScript(TestPushOpcode(4, 0x80, 0x7F)),
                       std::runtime_error);
 }
 
 void TestFormatRoundTrip(const std::string &script) {
     BOOST_CHECK_EQUAL(script, FormatScript(ParseScript(script)));
 }
 
 BOOST_AUTO_TEST_CASE(format_script_test) {
     TestFormatRoundTrip("0 1 5 CHECKDATASIG CHECKSIG XOR NOP5 NOP10 "
                         "CHECKDATASIGVERIFY DEPTH RETURN VERIFY SPLIT INVERT "
                         "EQUAL HASH256 GREATERTHANOREQUAL RSHIFT");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 319d96b18..35359dd6c 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -1,288 +1,288 @@
 // Copyright (c) 2012-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <scheduler.h>
 #include <util/time.h>
 
 #include <random.h>
 #include <sync.h>
 
 #include <boost/test/unit_test.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 
 #include <atomic>
 #include <condition_variable>
 #include <mutex>
 #include <thread>
 
 BOOST_AUTO_TEST_SUITE(scheduler_tests)
 
 static void microTask(CScheduler &s, std::mutex &mutex, int &counter, int delta,
                       std::chrono::system_clock::time_point rescheduleTime) {
     {
         std::lock_guard<std::mutex> lock(mutex);
         counter += delta;
     }
     std::chrono::system_clock::time_point noTime =
         std::chrono::system_clock::time_point::min();
     if (rescheduleTime != noTime) {
         CScheduler::Function f =
             std::bind(&microTask, std::ref(s), std::ref(mutex),
                       std::ref(counter), -delta + 1, noTime);
         s.schedule(f, rescheduleTime);
     }
 }
 
 BOOST_AUTO_TEST_CASE(manythreads) {
     // Stress test: hundreds of microsecond-scheduled tasks,
     // serviced by 10 threads.
     //
     // So... ten shared counters, which if all the tasks execute
     // properly will sum to the number of tasks done.
     // Each task adds or subtracts a random amount from one of the
     // counters, and then schedules another task 0-1000
     // microseconds in the future to subtract or add from
     // the counter -random_amount+1, so in the end the shared
     // counters should sum to the number of initial tasks performed.
     CScheduler microTasks;
 
     std::mutex counterMutex[10];
     int counter[10] = {0};
     FastRandomContext rng{/* fDeterministic */ true};
     // [0, 9]
     auto zeroToNine = [](FastRandomContext &rc) -> int {
         return rc.randrange(10);
     };
     // [-11, 1000]
     auto randomMsec = [](FastRandomContext &rc) -> int {
         return -11 + int(rc.randrange(1012));
     };
     // [-1000, 1000]
     auto randomDelta = [](FastRandomContext &rc) -> int {
         return -1000 + int(rc.randrange(2001));
     };
 
     std::chrono::system_clock::time_point start =
         std::chrono::system_clock::now();
     std::chrono::system_clock::time_point now = start;
     std::chrono::system_clock::time_point first, last;
     size_t nTasks = microTasks.getQueueInfo(first, last);
     BOOST_CHECK(nTasks == 0);
 
     for (int i = 0; i < 100; ++i) {
         std::chrono::system_clock::time_point t =
             now + std::chrono::microseconds(randomMsec(rng));
         std::chrono::system_clock::time_point tReschedule =
             now + std::chrono::microseconds(500 + randomMsec(rng));
         int whichCounter = zeroToNine(rng);
         CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),
                                            std::ref(counterMutex[whichCounter]),
                                            std::ref(counter[whichCounter]),
                                            randomDelta(rng), tReschedule);
         microTasks.schedule(f, t);
     }
     nTasks = microTasks.getQueueInfo(first, last);
     BOOST_CHECK(nTasks == 100);
     BOOST_CHECK(first < last);
     BOOST_CHECK(last > now);
 
     // As soon as these are created they will start running and servicing the
     // queue
     boost::thread_group microThreads;
     for (int i = 0; i < 5; i++) {
         microThreads.create_thread(
             std::bind(&CScheduler::serviceQueue, &microTasks));
     }
 
     UninterruptibleSleep(std::chrono::microseconds{600});
     now = std::chrono::system_clock::now();
 
     // More threads and more tasks:
     for (int i = 0; i < 5; i++) {
         microThreads.create_thread(
             std::bind(&CScheduler::serviceQueue, &microTasks));
     }
 
     for (int i = 0; i < 100; i++) {
         std::chrono::system_clock::time_point t =
             now + std::chrono::microseconds(randomMsec(rng));
         std::chrono::system_clock::time_point tReschedule =
             now + std::chrono::microseconds(500 + randomMsec(rng));
         int whichCounter = zeroToNine(rng);
         CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),
                                            std::ref(counterMutex[whichCounter]),
                                            std::ref(counter[whichCounter]),
                                            randomDelta(rng), tReschedule);
         microTasks.schedule(f, t);
     }
 
     // Drain the task queue then exit threads
     microTasks.stop(true);
     // ... wait until all the threads are done
     microThreads.join_all();
 
     int counterSum = 0;
     for (int i = 0; i < 10; i++) {
         BOOST_CHECK(counter[i] != 0);
         counterSum += counter[i];
     }
     BOOST_CHECK_EQUAL(counterSum, 200);
 }
 
 BOOST_AUTO_TEST_CASE(schedule_every) {
     CScheduler scheduler;
 
     std::condition_variable cvar;
     std::atomic<int> counter{15};
     std::atomic<bool> keepRunning{true};
 
     scheduler.scheduleEvery(
         [&keepRunning, &cvar, &counter, &scheduler]() {
             assert(counter > 0);
             cvar.notify_all();
             if (--counter > 0) {
                 return true;
             }
 
             // We reached the end of our test, make sure nothing run again for
             // 100ms.
             scheduler.scheduleFromNow(
                 [&keepRunning, &cvar]() {
                     keepRunning = false;
                     cvar.notify_all();
                 },
                 std::chrono::milliseconds{100});
 
             // We set the counter to some magic value to check the scheduler
             // empty its queue properly after 120ms.
             scheduler.scheduleFromNow([&counter]() { counter = 42; },
                                       std::chrono::milliseconds{120});
             return false;
         },
         std::chrono::milliseconds{5});
 
     // Start the scheduler thread.
     std::thread schedulerThread(
         std::bind(&CScheduler::serviceQueue, &scheduler));
 
     Mutex mutex;
     WAIT_LOCK(mutex, lock);
     while (keepRunning) {
         cvar.wait(lock);
         BOOST_CHECK(counter >= 0);
     }
 
     BOOST_CHECK_EQUAL(counter, 0);
     scheduler.stop(true);
     schedulerThread.join();
     BOOST_CHECK_EQUAL(counter, 42);
 }
 
 BOOST_AUTO_TEST_CASE(wait_until_past) {
     std::condition_variable condvar;
     Mutex mtx;
     WAIT_LOCK(mtx, lock);
 
     const auto no_wait = [&](const std::chrono::seconds &d) {
         return condvar.wait_until(lock, std::chrono::system_clock::now() - d);
     };
 
     BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::seconds{1}));
     BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::minutes{1}));
     BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1}));
     BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{10}));
     BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{100}));
     BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1000}));
 }
 
 BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered) {
     CScheduler scheduler;
 
     // each queue should be well ordered with respect to itself but not other
     // queues
     SingleThreadedSchedulerClient queue1(&scheduler);
     SingleThreadedSchedulerClient queue2(&scheduler);
 
     // create more threads than queues
     // if the queues only permit execution of one task at once then
     // the extra threads should effectively be doing nothing
     // if they don't we'll get out of order behaviour
     boost::thread_group threads;
     for (int i = 0; i < 5; ++i) {
         threads.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
     }
 
     // these are not atomic, if SinglethreadedSchedulerClient prevents
     // parallel execution at the queue level no synchronization should be
     // required here
     int counter1 = 0;
     int counter2 = 0;
 
     // just simply count up on each queue - if execution is properly ordered
     // then the callbacks should run in exactly the order in which they were
     // enqueued
     for (int i = 0; i < 100; ++i) {
         queue1.AddToProcessQueue([i, &counter1]() {
             bool expectation = i == counter1++;
             assert(expectation);
         });
 
         queue2.AddToProcessQueue([i, &counter2]() {
             bool expectation = i == counter2++;
             assert(expectation);
         });
     }
 
     // finish up
     scheduler.stop(true);
     threads.join_all();
 
     BOOST_CHECK_EQUAL(counter1, 100);
     BOOST_CHECK_EQUAL(counter2, 100);
 }
 
 BOOST_AUTO_TEST_CASE(mockforward) {
     CScheduler scheduler;
 
     int counter{0};
     CScheduler::Function dummy = [&counter] { counter++; };
 
     // schedule jobs for 2, 5 & 8 minutes into the future
     scheduler.scheduleFromNow(dummy, std::chrono::minutes{2});
     scheduler.scheduleFromNow(dummy, std::chrono::minutes{5});
     scheduler.scheduleFromNow(dummy, std::chrono::minutes{8});
 
     // check taskQueue
     std::chrono::system_clock::time_point first, last;
     size_t num_tasks = scheduler.getQueueInfo(first, last);
     BOOST_CHECK_EQUAL(num_tasks, 3ul);
 
     std::thread scheduler_thread([&]() { scheduler.serviceQueue(); });
 
     // bump the scheduler forward 5 minutes
     scheduler.MockForward(std::chrono::minutes{5});
 
     // ensure scheduler has chance to process all tasks queued for before 1 ms
     // from now.
     scheduler.scheduleFromNow([&scheduler] { scheduler.stop(false); },
                               std::chrono::milliseconds{1});
     scheduler_thread.join();
 
     // check that the queue only has one job remaining
     num_tasks = scheduler.getQueueInfo(first, last);
     BOOST_CHECK_EQUAL(num_tasks, 1ul);
 
     // check that the dummy function actually ran
     BOOST_CHECK_EQUAL(counter, 2);
 
     // check that the time of the remaining job has been updated
     std::chrono::system_clock::time_point now =
         std::chrono::system_clock::now();
     int delta =
         std::chrono::duration_cast<std::chrono::seconds>(first - now).count();
     // should be between 2 & 3 minutes from now
     BOOST_CHECK(delta > 2 * 60 && delta < 3 * 60);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 791a64759..4840b7c21 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -1,220 +1,220 @@
 // Copyright (c) 2015-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_TEST_UTIL_SETUP_COMMON_H
 #define BITCOIN_TEST_UTIL_SETUP_COMMON_H
 
 #include <amount.h>
 #include <chainparamsbase.h>
 #include <fs.h>
 #include <key.h>
 #include <node/context.h>
 #include <primitives/transaction.h>
 #include <pubkey.h>
 #include <random.h>
 #include <scheduler.h>
 #include <util/check.h>
 #include <util/string.h>
 #include <util/system.h>
 
-#include <boost/thread.hpp> // For boost::thread_group
+#include <boost/thread/thread.hpp>
 
 #include <type_traits>
 
 /**
  * Version of Boost::test prior to 1.64 have issues when dealing with nullptr_t.
  * In order to work around this, we ensure that the null pointers are typed in a
  * way that Boost will like better.
  *
  * TODO: Use nullptr directly once the minimum version of boost is 1.64 or more.
  */
 #define NULLPTR(T) static_cast<T *>(nullptr)
 
 // Enable BOOST_CHECK_EQUAL for enum class types
 template <typename T>
 std::ostream &operator<<(
     typename std::enable_if<std::is_enum<T>::value, std::ostream>::type &stream,
     const T &e) {
     return stream << static_cast<typename std::underlying_type<T>::type>(e);
 }
 
 /**
  * This global and the helpers that use it are not thread-safe.
  *
  * If thread-safety is needed, the global could be made thread_local (given
  * that thread_local is supported on all architectures we support) or a
  * per-thread instance could be used in the multi-threaded test.
  */
 extern FastRandomContext g_insecure_rand_ctx;
 
 /**
  * Flag to make GetRand in random.h return the same number
  */
 extern bool g_mock_deterministic_tests;
 
 enum class SeedRand {
     ZEROS, //!< Seed with a compile time constant of zeros
     SEED,  //!< Call the Seed() helper
 };
 
 /**
  * Seed the given random ctx or use the seed passed in via an
  * environment var
  */
 void Seed(FastRandomContext &ctx);
 
 static inline void SeedInsecureRand(SeedRand seed = SeedRand::SEED) {
     if (seed == SeedRand::ZEROS) {
         g_insecure_rand_ctx = FastRandomContext(/* deterministic */ true);
     } else {
         Seed(g_insecure_rand_ctx);
     }
 }
 
 static inline uint32_t InsecureRand32() {
     return g_insecure_rand_ctx.rand32();
 }
 static inline uint160 InsecureRand160() {
     return g_insecure_rand_ctx.rand160();
 }
 static inline uint256 InsecureRand256() {
     return g_insecure_rand_ctx.rand256();
 }
 static inline uint64_t InsecureRandBits(int bits) {
     return g_insecure_rand_ctx.randbits(bits);
 }
 static inline uint64_t InsecureRandRange(uint64_t range) {
     return g_insecure_rand_ctx.randrange(range);
 }
 static inline bool InsecureRandBool() {
     return g_insecure_rand_ctx.randbool();
 }
 
 static constexpr Amount CENT(COIN / 100);
 
 extern std::vector<const char *> fixture_extra_args;
 
 /**
  * Basic testing setup.
  * This just configures logging, data dir and chain parameters.
  */
 struct BasicTestingSetup {
     ECCVerifyHandle globalVerifyHandle;
     NodeContext m_node;
 
     explicit BasicTestingSetup(
         const std::string &chainName = CBaseChainParams::MAIN,
         const std::vector<const char *> &extra_args = {});
     ~BasicTestingSetup();
 
 private:
     const fs::path m_path_root;
 };
 
 /**
  * Testing setup that configures a complete environment.
  * Included are coins database, script check threads setup.
  */
 struct TestingSetup : public BasicTestingSetup {
     boost::thread_group threadGroup;
 
     explicit TestingSetup(const std::string &chainName = CBaseChainParams::MAIN,
                           const std::vector<const char *> &extra_args = {});
     ~TestingSetup();
 };
 
 /** Identical to TestingSetup, but chain set to regtest */
 struct RegTestingSetup : public TestingSetup {
     RegTestingSetup() : TestingSetup{CBaseChainParams::REGTEST} {}
 };
 
 class CBlock;
 class CMutableTransaction;
 class CScript;
 
 //
 // Testing fixture that pre-creates a
 // 100-block REGTEST-mode block chain
 //
 struct TestChain100Setup : public RegTestingSetup {
     TestChain100Setup();
 
     // Create a new block with just given transactions, coinbase paying to
     // scriptPubKey, and try to add it to the current chain.
     CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction> &txns,
                                  const CScript &scriptPubKey);
 
     ~TestChain100Setup();
 
     // For convenience, coinbase transactions.
     std::vector<CTransactionRef> m_coinbase_txns;
     // private/public key needed to spend coinbase transactions.
     CKey coinbaseKey;
 };
 
 class CTxMemPoolEntry;
 
 struct TestMemPoolEntryHelper {
     // Default values
     Amount nFee;
     int64_t nTime;
     unsigned int nHeight;
     bool spendsCoinbase;
     unsigned int nSigOpCount;
 
     TestMemPoolEntryHelper()
         : nFee(), nTime(0), nHeight(1), spendsCoinbase(false), nSigOpCount(1) {}
 
     CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
     CTxMemPoolEntry FromTx(const CTransactionRef &tx);
 
     // Change the default value
     TestMemPoolEntryHelper &Fee(Amount _fee) {
         nFee = _fee;
         return *this;
     }
     TestMemPoolEntryHelper &Time(int64_t _time) {
         nTime = _time;
         return *this;
     }
     TestMemPoolEntryHelper &Height(unsigned int _height) {
         nHeight = _height;
         return *this;
     }
     TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) {
         spendsCoinbase = _flag;
         return *this;
     }
     TestMemPoolEntryHelper &SigOpCount(unsigned int _nSigOpCount) {
         nSigOpCount = _nSigOpCount;
         return *this;
     }
 };
 
 enum class ScriptError;
 
 // define implicit conversions here so that these types may be used in
 // BOOST_*_EQUAL
 std::ostream &operator<<(std::ostream &os, const uint256 &num);
 std::ostream &operator<<(std::ostream &os, const ScriptError &err);
 
 CBlock getBlock13b8a();
 
 /**
  * BOOST_CHECK_EXCEPTION predicates to check the specific validation error.
  * Use as
  * BOOST_CHECK_EXCEPTION(code that throws, exception type, HasReason("foo"));
  */
 class HasReason {
 public:
     explicit HasReason(const std::string &reason) : m_reason(reason) {}
     template <typename E> bool operator()(const E &e) const {
         return std::string(e.what()).find(m_reason) != std::string::npos;
     };
 
 private:
     const std::string m_reason;
 };
 
 #endif // BITCOIN_TEST_UTIL_SETUP_COMMON_H
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 4d753dd94..97735a25c 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -1,567 +1,563 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2018 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <txdb.h>
 
 #include <blockdb.h>
 #include <chain.h>
 #include <node/ui_interface.h>
 #include <pow/pow.h>
 #include <random.h>
 #include <shutdown.h>
 #include <util/system.h>
 #include <util/translation.h>
 #include <util/vector.h>
 #include <version.h>
 
-#include <boost/thread.hpp> // boost::this_thread::interruption_point() (mingw)
-
 #include <cstdint>
 #include <memory>
 
 static const char DB_COIN = 'C';
 static const char DB_COINS = 'c';
 static const char DB_BLOCK_FILES = 'f';
 static const char DB_BLOCK_INDEX = 'b';
 
 static const char DB_BEST_BLOCK = 'B';
 static const char DB_HEAD_BLOCKS = 'H';
 static const char DB_FLAG = 'F';
 static const char DB_REINDEX_FLAG = 'R';
 static const char DB_LAST_BLOCK = 'l';
 
 namespace {
 
 struct CoinEntry {
     COutPoint *outpoint;
     char key;
     explicit CoinEntry(const COutPoint *ptr)
         : outpoint(const_cast<COutPoint *>(ptr)), key(DB_COIN) {}
 
     SERIALIZE_METHODS(CoinEntry, obj) {
         TxId id = obj.outpoint->GetTxId();
         uint32_t n = obj.outpoint->GetN();
         READWRITE(obj.key, id, VARINT(n));
         SER_READ(obj, *obj.outpoint = COutPoint(id, n));
     }
 };
 } // namespace
 
 CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory,
                            bool fWipe)
     : m_db(std::make_unique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe,
                                         true)),
       m_ldb_path(ldb_path), m_is_memory(fMemory) {}
 
 void CCoinsViewDB::ResizeCache(size_t new_cache_size) {
     // Have to do a reset first to get the original `m_db` state to release its
     // filesystem lock.
     m_db.reset();
     m_db = std::make_unique<CDBWrapper>(m_ldb_path, new_cache_size, m_is_memory,
                                         /*fWipe*/ false, /*obfuscate*/ true);
 }
 
 bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
     return m_db->Read(CoinEntry(&outpoint), coin);
 }
 
 bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
     return m_db->Exists(CoinEntry(&outpoint));
 }
 
 BlockHash CCoinsViewDB::GetBestBlock() const {
     BlockHash hashBestChain;
     if (!m_db->Read(DB_BEST_BLOCK, hashBestChain)) {
         return BlockHash();
     }
     return hashBestChain;
 }
 
 std::vector<BlockHash> CCoinsViewDB::GetHeadBlocks() const {
     std::vector<BlockHash> vhashHeadBlocks;
     if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
         return std::vector<BlockHash>();
     }
     return vhashHeadBlocks;
 }
 
 bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const BlockHash &hashBlock) {
     CDBBatch batch(*m_db);
     size_t count = 0;
     size_t changed = 0;
     size_t batch_size =
         (size_t)gArgs.GetArg("-dbbatchsize", DEFAULT_DB_BATCH_SIZE);
     int crash_simulate = gArgs.GetArg("-dbcrashratio", 0);
     assert(!hashBlock.IsNull());
 
     BlockHash old_tip = GetBestBlock();
     if (old_tip.IsNull()) {
         // We may be in the middle of replaying.
         std::vector<BlockHash> old_heads = GetHeadBlocks();
         if (old_heads.size() == 2) {
             assert(old_heads[0] == hashBlock);
             old_tip = old_heads[1];
         }
     }
 
     // In the first batch, mark the database as being in the middle of a
     // transition from old_tip to hashBlock.
     // A vector is used for future extensibility, as we may want to support
     // interrupting after partial writes from multiple independent reorgs.
     batch.Erase(DB_BEST_BLOCK);
     batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
 
     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
         if (it->second.flags & CCoinsCacheEntry::DIRTY) {
             CoinEntry entry(&it->first);
             if (it->second.coin.IsSpent()) {
                 batch.Erase(entry);
             } else {
                 batch.Write(entry, it->second.coin);
             }
             changed++;
         }
         count++;
         CCoinsMap::iterator itOld = it++;
         mapCoins.erase(itOld);
         if (batch.SizeEstimate() > batch_size) {
             LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n",
                      batch.SizeEstimate() * (1.0 / 1048576.0));
             m_db->WriteBatch(batch);
             batch.Clear();
             if (crash_simulate) {
                 static FastRandomContext rng;
                 if (rng.randrange(crash_simulate) == 0) {
                     LogPrintf("Simulating a crash. Goodbye.\n");
                     _Exit(0);
                 }
             }
         }
     }
 
     // In the last batch, mark the database as consistent with hashBlock again.
     batch.Erase(DB_HEAD_BLOCKS);
     batch.Write(DB_BEST_BLOCK, hashBlock);
 
     LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n",
              batch.SizeEstimate() * (1.0 / 1048576.0));
     bool ret = m_db->WriteBatch(batch);
     LogPrint(BCLog::COINDB,
              "Committed %u changed transaction outputs (out of "
              "%u) to coin database...\n",
              (unsigned int)changed, (unsigned int)count);
     return ret;
 }
 
 size_t CCoinsViewDB::EstimateSize() const {
     return m_db->EstimateSize(DB_COIN, char(DB_COIN + 1));
 }
 
 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe)
     : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory,
                  fWipe) {}
 
 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
     return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
 }
 
 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
     if (fReindexing) {
         return Write(DB_REINDEX_FLAG, '1');
     } else {
         return Erase(DB_REINDEX_FLAG);
     }
 }
 
 bool CBlockTreeDB::IsReindexing() const {
     return Exists(DB_REINDEX_FLAG);
 }
 
 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
     return Read(DB_LAST_BLOCK, nFile);
 }
 
 CCoinsViewCursor *CCoinsViewDB::Cursor() const {
     CCoinsViewDBCursor *i = new CCoinsViewDBCursor(
         const_cast<CDBWrapper &>(*m_db).NewIterator(), GetBestBlock());
     /**
      * It seems that there are no "const iterators" for LevelDB. Since we only
      * need read operations on it, use a const-cast to get around that
      * restriction.
      */
     i->pcursor->Seek(DB_COIN);
     // Cache key of first record
     if (i->pcursor->Valid()) {
         CoinEntry entry(&i->keyTmp.second);
         i->pcursor->GetKey(entry);
         i->keyTmp.first = entry.key;
     } else {
         // Make sure Valid() and GetKey() return false
         i->keyTmp.first = 0;
     }
     return i;
 }
 
 bool CCoinsViewDBCursor::GetKey(COutPoint &key) const {
     // Return cached key
     if (keyTmp.first == DB_COIN) {
         key = keyTmp.second;
         return true;
     }
     return false;
 }
 
 bool CCoinsViewDBCursor::GetValue(Coin &coin) const {
     return pcursor->GetValue(coin);
 }
 
 unsigned int CCoinsViewDBCursor::GetValueSize() const {
     return pcursor->GetValueSize();
 }
 
 bool CCoinsViewDBCursor::Valid() const {
     return keyTmp.first == DB_COIN;
 }
 
 void CCoinsViewDBCursor::Next() {
     pcursor->Next();
     CoinEntry entry(&keyTmp.second);
     if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
         // Invalidate cached key after last record so that Valid() and GetKey()
         // return false
         keyTmp.first = 0;
     } else {
         keyTmp.first = entry.key;
     }
 }
 
 bool CBlockTreeDB::WriteBatchSync(
     const std::vector<std::pair<int, const CBlockFileInfo *>> &fileInfo,
     int nLastFile, const std::vector<const CBlockIndex *> &blockinfo) {
     CDBBatch batch(*this);
     for (std::vector<std::pair<int, const CBlockFileInfo *>>::const_iterator
              it = fileInfo.begin();
          it != fileInfo.end(); it++) {
         batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
     }
     batch.Write(DB_LAST_BLOCK, nLastFile);
     for (std::vector<const CBlockIndex *>::const_iterator it =
              blockinfo.begin();
          it != blockinfo.end(); it++) {
         batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()),
                     CDiskBlockIndex(*it));
     }
     return WriteBatch(batch, true);
 }
 
 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
     return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
 }
 
 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
     char ch;
     if (!Read(std::make_pair(DB_FLAG, name), ch)) {
         return false;
     }
     fValue = ch == '1';
     return true;
 }
 
 bool CBlockTreeDB::LoadBlockIndexGuts(
     const Consensus::Params &params,
     std::function<CBlockIndex *(const BlockHash &)> insertBlockIndex) {
     std::unique_ptr<CDBIterator> pcursor(NewIterator());
 
     uint64_t version = 0;
     pcursor->Seek("version");
     if (pcursor->Valid()) {
         pcursor->GetValue(version);
     }
 
     if (version != CLIENT_VERSION) {
         return error("%s: Invalid block index database version: %s", __func__,
                      version);
     }
 
     pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
 
     // Load m_block_index
     while (pcursor->Valid()) {
-        boost::this_thread::interruption_point();
         if (ShutdownRequested()) {
             return false;
         }
         std::pair<char, uint256> key;
         if (!pcursor->GetKey(key) || key.first != DB_BLOCK_INDEX) {
             break;
         }
 
         CDiskBlockIndex diskindex;
         if (!pcursor->GetValue(diskindex)) {
             return error("%s : failed to read value", __func__);
         }
 
         // Construct block index object
         CBlockIndex *pindexNew = insertBlockIndex(diskindex.GetBlockHash());
         pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
         pindexNew->nHeight = diskindex.nHeight;
         pindexNew->nFile = diskindex.nFile;
         pindexNew->nDataPos = diskindex.nDataPos;
         pindexNew->nUndoPos = diskindex.nUndoPos;
         pindexNew->nVersion = diskindex.nVersion;
         pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
         pindexNew->nTime = diskindex.nTime;
         pindexNew->nBits = diskindex.nBits;
         pindexNew->nNonce = diskindex.nNonce;
         pindexNew->nStatus = diskindex.nStatus;
         pindexNew->nTx = diskindex.nTx;
 
         if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits,
                               params)) {
             return error("%s: CheckProofOfWork failed: %s", __func__,
                          pindexNew->ToString());
         }
 
         pcursor->Next();
     }
 
     return true;
 }
 
 namespace {
 //! Legacy class to deserialize pre-pertxout database entries without reindex.
 class CCoins {
 public:
     //! whether transaction is a coinbase
     bool fCoinBase;
 
     //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs
     //! at the end of the array are dropped
     std::vector<CTxOut> vout;
 
     //! at which height this transaction was included in the active block chain
     int nHeight;
 
     //! empty constructor
     CCoins() : fCoinBase(false), vout(0), nHeight(0) {}
 
     template <typename Stream> void Unserialize(Stream &s) {
         uint32_t nCode = 0;
         // version
         unsigned int nVersionDummy = 0;
         ::Unserialize(s, VARINT(nVersionDummy));
         // header code
         ::Unserialize(s, VARINT(nCode));
         fCoinBase = nCode & 1;
         std::vector<bool> vAvail(2, false);
         vAvail[0] = (nCode & 2) != 0;
         vAvail[1] = (nCode & 4) != 0;
         uint32_t nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
         // spentness bitmask
         while (nMaskCode > 0) {
             uint8_t chAvail = 0;
             ::Unserialize(s, chAvail);
             for (unsigned int p = 0; p < 8; p++) {
                 bool f = (chAvail & (1 << p)) != 0;
                 vAvail.push_back(f);
             }
             if (chAvail != 0) {
                 nMaskCode--;
             }
         }
         // txouts themself
         vout.assign(vAvail.size(), CTxOut());
         for (size_t i = 0; i < vAvail.size(); i++) {
             if (vAvail[i]) {
                 ::Unserialize(s, Using<TxOutCompression>(vout[i]));
             }
         }
         // coinbase height
         ::Unserialize(s, VARINT_MODE(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
     }
 };
 } // namespace
 
 /**
  * Upgrade the database from older formats.
  *
  * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
  */
 bool CCoinsViewDB::Upgrade() {
     std::unique_ptr<CDBIterator> pcursor(m_db->NewIterator());
     pcursor->Seek(std::make_pair(DB_COINS, uint256()));
     if (!pcursor->Valid()) {
         return true;
     }
 
     int64_t count = 0;
     LogPrintf("Upgrading utxo-set database...\n");
     size_t batch_size = 1 << 24;
     CDBBatch batch(*m_db);
     int reportDone = -1;
     std::pair<uint8_t, uint256> key;
     std::pair<uint8_t, uint256> prev_key = {DB_COINS, uint256()};
     while (pcursor->Valid()) {
-        boost::this_thread::interruption_point();
         if (ShutdownRequested()) {
             break;
         }
 
         if (!pcursor->GetKey(key) || key.first != DB_COINS) {
             break;
         }
 
         if (count++ % 256 == 0) {
             uint32_t high =
                 0x100 * *key.second.begin() + *(key.second.begin() + 1);
             int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5);
             uiInterface.ShowProgress(_("Upgrading UTXO database").translated,
                                      percentageDone, true);
             if (reportDone < percentageDone / 10) {
                 // report max. every 10% step
                 LogPrintfToBeContinued("[%d%%]...", percentageDone);
                 reportDone = percentageDone / 10;
             }
         }
 
         CCoins old_coins;
         if (!pcursor->GetValue(old_coins)) {
             return error("%s: cannot parse CCoins record", __func__);
         }
 
         const TxId id(key.second);
         for (size_t i = 0; i < old_coins.vout.size(); ++i) {
             if (!old_coins.vout[i].IsNull() &&
                 !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
                 Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight,
                              old_coins.fCoinBase);
                 COutPoint outpoint(id, i);
                 CoinEntry entry(&outpoint);
                 batch.Write(entry, newcoin);
             }
         }
 
         batch.Erase(key);
         if (batch.SizeEstimate() > batch_size) {
             m_db->WriteBatch(batch);
             batch.Clear();
             m_db->CompactRange(prev_key, key);
             prev_key = key;
         }
 
         pcursor->Next();
     }
 
     m_db->WriteBatch(batch);
     m_db->CompactRange({DB_COINS, uint256()}, key);
     uiInterface.ShowProgress("", 100, false);
     LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE");
     return !ShutdownRequested();
 }
 
 bool CBlockTreeDB::Upgrade(const Consensus::Params &params) {
     std::unique_ptr<CDBIterator> pcursor(NewIterator());
 
     uint64_t version = 0;
     pcursor->Seek("version");
     if (pcursor->Valid()) {
         pcursor->GetValue(version);
     }
 
     if (version >= CLIENT_VERSION) {
         // The DB is already up to date.
         return true;
     }
 
     CDBBatch batch(*this);
 
     pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
     if (!pcursor->Valid()) {
         // The DB is empty, so just write the version number and consider the
         // upgrade done.
         batch.Write("version", uint64_t(CLIENT_VERSION));
         WriteBatch(batch);
         return true;
     }
 
     int64_t count = 0;
     LogPrintf("Upgrading block index database...\n");
     int reportDone = -1;
     std::pair<uint8_t, uint256> key = {DB_BLOCK_INDEX, uint256()};
     while (pcursor->Valid()) {
         boost::this_thread::interruption_point();
         if (ShutdownRequested()) {
             break;
         }
 
         if (!pcursor->GetKey(key) || key.first != DB_BLOCK_INDEX) {
             break;
         }
 
         if (count++ % 256 == 0) {
             uint32_t high =
                 0x100 * *key.second.begin() + *(key.second.begin() + 1);
             int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5);
             uiInterface.ShowProgress(
                 _("Upgrading block index database").translated, percentageDone,
                 true);
             if (reportDone < percentageDone / 10) {
                 // report max. every 10% step
                 LogPrintfToBeContinued("[%d%%]...", percentageDone);
                 reportDone = percentageDone / 10;
             }
         }
 
         // Read the block index entry and update it.
         CDiskBlockIndex diskindex;
         if (!pcursor->GetValue(diskindex)) {
             return error("%s: cannot parse CDiskBlockIndex record", __func__);
         }
 
         // The block hash needs to be usable.
         BlockHash blockhash = diskindex.GetBlockHash();
         diskindex.phashBlock = &blockhash;
 
         bool mustUpdate = false;
 
         // We must update the block index to add the size.
         if (CLIENT_VERSION >= CDiskBlockIndex::TRACK_SIZE_VERSION &&
             version < CDiskBlockIndex::TRACK_SIZE_VERSION &&
             diskindex.nTx > 0 && diskindex.nSize == 0) {
             if (!diskindex.nStatus.hasData()) {
                 // The block was pruned, we need a full reindex.
                 LogPrintf("\nThe block %s is pruned. The block index cannot be "
                           "upgraded and reindexing is required.\n",
                           blockhash.GetHex());
                 return false;
             }
 
             CBlock block;
             if (!ReadBlockFromDisk(block, &diskindex, params)) {
                 // Failed to read the block from disk, even though it is marked
                 // that we have data for this block.
                 return false;
             }
 
             mustUpdate = true;
             diskindex.nSize = ::GetSerializeSize(block, PROTOCOL_VERSION);
         }
 
         if (mustUpdate) {
             batch.Write(std::make_pair(DB_BLOCK_INDEX, blockhash), diskindex);
         }
 
         pcursor->Next();
     }
 
     // Upgrade is done, now let's update the version number.
     batch.Write("version", uint64_t(CLIENT_VERSION));
 
     WriteBatch(batch);
     CompactRange({DB_BLOCK_INDEX, uint256()}, key);
     uiInterface.ShowProgress("", 100, false);
     LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE");
     return !ShutdownRequested();
 }
diff --git a/src/util/system.cpp b/src/util/system.cpp
index d22f5050f..33ddbd5a4 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1,1391 +1,1389 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <util/system.h>
 
 #include <chainparamsbase.h>
 #include <sync.h>
 #include <util/strencodings.h>
 #include <util/string.h>
 #include <util/translation.h>
 
 #include <univalue.h>
 
-#include <boost/thread.hpp>
-
 #include <memory>
 #include <thread>
 #include <typeinfo>
 
 #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
 #include <pthread.h>
 #include <pthread_np.h>
 #endif
 
 #ifndef WIN32
 // for posix_fallocate, in config/CMakeLists.txt we check if it is present after
 // this
 #ifdef __linux__
 
 #ifdef _POSIX_C_SOURCE
 #undef _POSIX_C_SOURCE
 #endif
 
 #define _POSIX_C_SOURCE 200112L
 
 #endif // __linux__
 
 #include <algorithm>
 #include <fcntl.h>
 #include <sched.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 
 #else
 
 #ifdef _MSC_VER
 #pragma warning(disable : 4786)
 #pragma warning(disable : 4804)
 #pragma warning(disable : 4805)
 #pragma warning(disable : 4717)
 #endif
 
 #ifndef NOMINMAX
 #define NOMINMAX
 #endif
 #include <codecvt>
 
 #include <io.h> /* for _commit */
 #include <shellapi.h>
 #include <shlobj.h>
 #endif
 
 #ifdef HAVE_MALLOPT_ARENA_MAX
 #include <malloc.h>
 #endif
 
 #include <boost/algorithm/string/replace.hpp>
 
 // Application startup time (used for uptime calculation)
 const int64_t nStartupTime = GetTime();
 
 const char *const BITCOIN_CONF_FILENAME = "bitcoin.conf";
 const char *const BITCOIN_SETTINGS_FILENAME = "settings.json";
 
 ArgsManager gArgs;
 
 /** Mutex to protect dir_locks. */
 static Mutex cs_dir_locks;
 /**
  * A map that contains all the currently held directory locks. After successful
  * locking, these will be held here until the global destructor cleans them up
  * and thus automatically unlocks them, or ReleaseDirectoryLocks is called.
  */
 static std::map<std::string, std::unique_ptr<fsbridge::FileLock>>
     dir_locks GUARDED_BY(cs_dir_locks);
 
 bool LockDirectory(const fs::path &directory, const std::string lockfile_name,
                    bool probe_only) {
     LOCK(cs_dir_locks);
     fs::path pathLockFile = directory / lockfile_name;
 
     // If a lock for this directory already exists in the map, don't try to
     // re-lock it
     if (dir_locks.count(pathLockFile.string())) {
         return true;
     }
 
     // Create empty lock file if it doesn't exist.
     FILE *file = fsbridge::fopen(pathLockFile, "a");
     if (file) {
         fclose(file);
     }
     auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
     if (!lock->TryLock()) {
         return error("Error while attempting to lock directory %s: %s",
                      directory.string(), lock->GetReason());
     }
     if (!probe_only) {
         // Lock successful and we're not just probing, put it into the map
         dir_locks.emplace(pathLockFile.string(), std::move(lock));
     }
     return true;
 }
 
 void UnlockDirectory(const fs::path &directory,
                      const std::string &lockfile_name) {
     LOCK(cs_dir_locks);
     dir_locks.erase((directory / lockfile_name).string());
 }
 
 void ReleaseDirectoryLocks() {
     LOCK(cs_dir_locks);
     dir_locks.clear();
 }
 
 bool DirIsWritable(const fs::path &directory) {
     fs::path tmpFile = directory / fs::unique_path();
 
     FILE *file = fsbridge::fopen(tmpFile, "a");
     if (!file) {
         return false;
     }
 
     fclose(file);
     remove(tmpFile);
 
     return true;
 }
 
 bool CheckDiskSpace(const fs::path &dir, uint64_t additional_bytes) {
     // 50 MiB
     constexpr uint64_t min_disk_space = 52428800;
 
     uint64_t free_bytes_available = fs::space(dir).available;
     return free_bytes_available >= min_disk_space + additional_bytes;
 }
 
 std::streampos GetFileSize(const char *path, std::streamsize max) {
     std::ifstream file(path, std::ios::binary);
     file.ignore(max);
     return file.gcount();
 }
 
 /**
  * Interpret a string argument as a boolean.
  *
  * The definition of atoi() requires that non-numeric string values like "foo",
  * return 0. This means that if a user unintentionally supplies a non-integer
  * argument here, the return value is always false. This means that -foo=false
  * does what the user probably expects, but -foo=true is well defined but does
  * not do what they probably expected.
  *
  * The return value of atoi() is undefined when given input not representable as
  * an int. On most systems this means string value between "-2147483648" and
  * "2147483647" are well defined (this method will return true). Setting
  * -txindex=2147483648 on most systems, however, is probably undefined.
  *
  * For a more extensive discussion of this topic (and a wide range of opinions
  * on the Right Way to change this code), see PR12713.
  */
 static bool InterpretBool(const std::string &strValue) {
     if (strValue.empty()) {
         return true;
     }
     return (atoi(strValue) != 0);
 }
 
 static std::string SettingName(const std::string &arg) {
     return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
 }
 
 /**
  * Interpret -nofoo as if the user supplied -foo=0.
  *
  * This method also tracks when the -no form was supplied, and if so, checks
  * whether there was a double-negative (-nofoo=0 -> -foo=1).
  *
  * If there was not a double negative, it removes the "no" from the key
  * and returns false.
  *
  * If there was a double negative, it removes "no" from the key, and
  * returns true.
  *
  * If there was no "no", it returns the string value untouched.
  *
  * Where an option was negated can be later checked using the IsArgNegated()
  * method. One use case for this is to have a way to disable options that are
  * not normally boolean (e.g. using -nodebuglogfile to request that debug log
  * output is not sent to any file at all).
  */
 
 static util::SettingsValue InterpretOption(std::string &section,
                                            std::string &key,
                                            const std::string &value) {
     // Split section name from key name for keys like "testnet.foo" or
     // "regtest.bar"
     size_t option_index = key.find('.');
     if (option_index != std::string::npos) {
         section = key.substr(0, option_index);
         key.erase(0, option_index + 1);
     }
     if (key.substr(0, 2) == "no") {
         key.erase(0, 2);
         // Double negatives like -nofoo=0 are supported (but discouraged)
         if (!InterpretBool(value)) {
             LogPrintf("Warning: parsed potentially confusing double-negative "
                       "-%s=%s\n",
                       key, value);
             return true;
         }
         return false;
     }
     return value;
 }
 
 /**
  * Check settings value validity according to flags.
  *
  * TODO: Add more meaningful error checks here in the future
  * See "here's how the flags are meant to behave" in
  * https://github.com/bitcoin/bitcoin/pull/16097#issuecomment-514627823
  */
 static bool CheckValid(const std::string &key, const util::SettingsValue &val,
                        unsigned int flags, std::string &error) {
     if (val.isBool() && !(flags & ArgsManager::ALLOW_BOOL)) {
         error = strprintf(
             "Negating of -%s is meaningless and therefore forbidden", key);
         return false;
     }
     return true;
 }
 
 // Define default constructor and destructor that are not inline, so code
 // instantiating this class doesn't need to #include class definitions for all
 // members. For example, m_settings has an internal dependency on univalue.
 ArgsManager::ArgsManager() {}
 ArgsManager::~ArgsManager() {}
 
 const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const {
     std::set<std::string> unsuitables;
 
     LOCK(cs_args);
 
     // if there's no section selected, don't worry
     if (m_network.empty()) {
         return std::set<std::string>{};
     }
 
     // if it's okay to use the default section for this network, don't worry
     if (m_network == CBaseChainParams::MAIN) {
         return std::set<std::string>{};
     }
 
     for (const auto &arg : m_network_only_args) {
         if (OnlyHasDefaultSectionSetting(m_settings, m_network,
                                          SettingName(arg))) {
             unsuitables.insert(arg);
         }
     }
     return unsuitables;
 }
 
 const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const {
     // Section names to be recognized in the config file.
     static const std::set<std::string> available_sections{
         CBaseChainParams::REGTEST, CBaseChainParams::TESTNET,
         CBaseChainParams::MAIN};
 
     LOCK(cs_args);
     std::list<SectionInfo> unrecognized = m_config_sections;
     unrecognized.remove_if([](const SectionInfo &appeared) {
         return available_sections.find(appeared.m_name) !=
                available_sections.end();
     });
     return unrecognized;
 }
 
 void ArgsManager::SelectConfigNetwork(const std::string &network) {
     LOCK(cs_args);
     m_network = network;
 }
 
 bool ParseKeyValue(std::string &key, std::string &val) {
     size_t is_index = key.find('=');
     if (is_index != std::string::npos) {
         val = key.substr(is_index + 1);
         key.erase(is_index);
     }
 #ifdef WIN32
     key = ToLower(key);
     if (key[0] == '/') {
         key[0] = '-';
     }
 #endif
 
     if (key[0] != '-') {
         return false;
     }
 
     // Transform --foo to -foo
     if (key.length() > 1 && key[1] == '-') {
         key.erase(0, 1);
     }
     return true;
 }
 
 bool ArgsManager::ParseParameters(int argc, const char *const argv[],
                                   std::string &error) {
     LOCK(cs_args);
     m_settings.command_line_options.clear();
 
     for (int i = 1; i < argc; i++) {
         std::string key(argv[i]);
         if (key == "-") {
             // bitcoin-tx using stdin
             break;
         }
         std::string val;
         if (!ParseKeyValue(key, val)) {
             break;
         }
 
         // Transform -foo to foo
         key.erase(0, 1);
         std::string section;
         util::SettingsValue value = InterpretOption(section, key, val);
         std::optional<unsigned int> flags = GetArgFlags('-' + key);
 
         // Unknown command line options and command line options with dot
         // characters (which are returned from InterpretOption with nonempty
         // section strings) are not valid.
         if (!flags || !section.empty()) {
             error = strprintf("Invalid parameter %s", argv[i]);
             return false;
         }
 
         if (!CheckValid(key, value, *flags, error)) {
             return false;
         }
 
         m_settings.command_line_options[key].push_back(value);
     }
 
     // we do not allow -includeconf from command line
     bool success = true;
     if (auto *includes =
             util::FindKey(m_settings.command_line_options, "includeconf")) {
         for (const auto &include : util::SettingsSpan(*includes)) {
             error +=
                 "-includeconf cannot be used from commandline; -includeconf=" +
                 include.get_str() + "\n";
             success = false;
         }
     }
     return success;
 }
 
 std::optional<unsigned int>
 ArgsManager::GetArgFlags(const std::string &name) const {
     LOCK(cs_args);
     for (const auto &arg_map : m_available_args) {
         const auto search = arg_map.second.find(name);
         if (search != arg_map.second.end()) {
             return search->second.m_flags;
         }
     }
     return std::nullopt;
 }
 
 std::vector<std::string> ArgsManager::GetArgs(const std::string &strArg) const {
     std::vector<std::string> result;
     for (const util::SettingsValue &value : GetSettingsList(strArg)) {
         result.push_back(
             value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
     }
     return result;
 }
 
 bool ArgsManager::IsArgSet(const std::string &strArg) const {
     return !GetSetting(strArg).isNull();
 }
 
 bool ArgsManager::InitSettings(std::string &error) {
     if (!GetSettingsPath()) {
         return true; // Do nothing if settings file disabled.
     }
 
     std::vector<std::string> errors;
     if (!ReadSettingsFile(&errors)) {
         error = strprintf("Failed loading settings file:\n- %s\n",
                           Join(errors, "\n- "));
         return false;
     }
     if (!WriteSettingsFile(&errors)) {
         error = strprintf("Failed saving settings file:\n- %s\n",
                           Join(errors, "\n- "));
         return false;
     }
     return true;
 }
 
 bool ArgsManager::GetSettingsPath(fs::path *filepath, bool temp) const {
     if (IsArgNegated("-settings")) {
         return false;
     }
     if (filepath) {
         std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
         *filepath = fs::absolute(temp ? settings + ".tmp" : settings,
                                  GetDataDir(/* net_specific= */ true));
     }
     return true;
 }
 
 static void SaveErrors(const std::vector<std::string> errors,
                        std::vector<std::string> *error_out) {
     for (const auto &error : errors) {
         if (error_out) {
             error_out->emplace_back(error);
         } else {
             LogPrintf("%s\n", error);
         }
     }
 }
 
 bool ArgsManager::ReadSettingsFile(std::vector<std::string> *errors) {
     fs::path path;
     if (!GetSettingsPath(&path, /* temp= */ false)) {
         return true; // Do nothing if settings file disabled.
     }
 
     LOCK(cs_args);
     m_settings.rw_settings.clear();
     std::vector<std::string> read_errors;
     if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
         SaveErrors(read_errors, errors);
         return false;
     }
     return true;
 }
 
 bool ArgsManager::WriteSettingsFile(std::vector<std::string> *errors) const {
     fs::path path, path_tmp;
     if (!GetSettingsPath(&path, /* temp= */ false) ||
         !GetSettingsPath(&path_tmp, /* temp= */ true)) {
         throw std::logic_error("Attempt to write settings file when dynamic "
                                "settings are disabled.");
     }
 
     LOCK(cs_args);
     std::vector<std::string> write_errors;
     if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
         SaveErrors(write_errors, errors);
         return false;
     }
     if (!RenameOver(path_tmp, path)) {
         SaveErrors({strprintf("Failed renaming settings file %s to %s\n",
                               path_tmp.string(), path.string())},
                    errors);
         return false;
     }
     return true;
 }
 
 bool ArgsManager::IsArgNegated(const std::string &strArg) const {
     return GetSetting(strArg).isFalse();
 }
 
 std::string ArgsManager::GetArg(const std::string &strArg,
                                 const std::string &strDefault) const {
     const util::SettingsValue value = GetSetting(strArg);
     return value.isNull()
                ? strDefault
                : value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str();
 }
 
 int64_t ArgsManager::GetArg(const std::string &strArg, int64_t nDefault) const {
     const util::SettingsValue value = GetSetting(strArg);
     return value.isNull()
                ? nDefault
                : value.isFalse()
                      ? 0
                      : value.isTrue() ? 1
                                       : value.isNum() ? value.get_int64()
                                                       : atoi64(value.get_str());
 }
 
 bool ArgsManager::GetBoolArg(const std::string &strArg, bool fDefault) const {
     const util::SettingsValue value = GetSetting(strArg);
     return value.isNull() ? fDefault
                           : value.isBool() ? value.get_bool()
                                            : InterpretBool(value.get_str());
 }
 
 bool ArgsManager::SoftSetArg(const std::string &strArg,
                              const std::string &strValue) {
     LOCK(cs_args);
     if (IsArgSet(strArg)) {
         return false;
     }
     ForceSetArg(strArg, strValue);
     return true;
 }
 
 bool ArgsManager::SoftSetBoolArg(const std::string &strArg, bool fValue) {
     if (fValue) {
         return SoftSetArg(strArg, std::string("1"));
     } else {
         return SoftSetArg(strArg, std::string("0"));
     }
 }
 
 void ArgsManager::ForceSetArg(const std::string &strArg,
                               const std::string &strValue) {
     LOCK(cs_args);
     m_settings.forced_settings[SettingName(strArg)] = strValue;
 }
 
 /**
  * This function is only used for testing purpose so
  * so we should not worry about element uniqueness and
  * integrity of mapMultiArgs data structure
  */
 void ArgsManager::ForceSetMultiArg(const std::string &strArg,
                                    const std::vector<std::string> &values) {
     LOCK(cs_args);
     util::SettingsValue value;
     value.setArray();
     for (const std::string &s : values) {
         value.push_back(s);
     }
 
     m_settings.forced_settings[SettingName(strArg)] = value;
 }
 
 void ArgsManager::AddArg(const std::string &name, const std::string &help,
                          unsigned int flags, const OptionsCategory &cat) {
     // Split arg name from its help param
     size_t eq_index = name.find('=');
     if (eq_index == std::string::npos) {
         eq_index = name.size();
     }
     std::string arg_name = name.substr(0, eq_index);
 
     LOCK(cs_args);
     std::map<std::string, Arg> &arg_map = m_available_args[cat];
     auto ret = arg_map.emplace(
         arg_name,
         Arg{name.substr(eq_index, name.size() - eq_index), help, flags});
     // Make sure an insertion actually happened.
     assert(ret.second);
 
     if (flags & ArgsManager::NETWORK_ONLY) {
         m_network_only_args.emplace(arg_name);
     }
 }
 
 void ArgsManager::AddHiddenArgs(const std::vector<std::string> &names) {
     for (const std::string &name : names) {
         AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
     }
 }
 
 void ArgsManager::ClearForcedArg(const std::string &strArg) {
     LOCK(cs_args);
     m_settings.forced_settings.erase(SettingName(strArg));
 }
 
 std::string ArgsManager::GetHelpMessage() const {
     const bool show_debug = gArgs.GetBoolArg("-help-debug", false);
 
     std::string usage = "";
     LOCK(cs_args);
     for (const auto &arg_map : m_available_args) {
         switch (arg_map.first) {
             case OptionsCategory::OPTIONS:
                 usage += HelpMessageGroup("Options:");
                 break;
             case OptionsCategory::CONNECTION:
                 usage += HelpMessageGroup("Connection options:");
                 break;
             case OptionsCategory::ZMQ:
                 usage += HelpMessageGroup("ZeroMQ notification options:");
                 break;
             case OptionsCategory::DEBUG_TEST:
                 usage += HelpMessageGroup("Debugging/Testing options:");
                 break;
             case OptionsCategory::NODE_RELAY:
                 usage += HelpMessageGroup("Node relay options:");
                 break;
             case OptionsCategory::BLOCK_CREATION:
                 usage += HelpMessageGroup("Block creation options:");
                 break;
             case OptionsCategory::RPC:
                 usage += HelpMessageGroup("RPC server options:");
                 break;
             case OptionsCategory::WALLET:
                 usage += HelpMessageGroup("Wallet options:");
                 break;
             case OptionsCategory::WALLET_DEBUG_TEST:
                 if (show_debug) {
                     usage +=
                         HelpMessageGroup("Wallet debugging/testing options:");
                 }
                 break;
             case OptionsCategory::CHAINPARAMS:
                 usage += HelpMessageGroup("Chain selection options:");
                 break;
             case OptionsCategory::GUI:
                 usage += HelpMessageGroup("UI Options:");
                 break;
             case OptionsCategory::COMMANDS:
                 usage += HelpMessageGroup("Commands:");
                 break;
             case OptionsCategory::REGISTER_COMMANDS:
                 usage += HelpMessageGroup("Register Commands:");
                 break;
             default:
                 break;
         }
 
         // When we get to the hidden options, stop
         if (arg_map.first == OptionsCategory::HIDDEN) {
             break;
         }
 
         for (const auto &arg : arg_map.second) {
             if (show_debug || !(arg.second.m_flags & ArgsManager::DEBUG_ONLY)) {
                 std::string name;
                 if (arg.second.m_help_param.empty()) {
                     name = arg.first;
                 } else {
                     name = arg.first + arg.second.m_help_param;
                 }
                 usage += HelpMessageOpt(name, arg.second.m_help_text);
             }
         }
     }
     return usage;
 }
 
 bool HelpRequested(const ArgsManager &args) {
     return args.IsArgSet("-?") || args.IsArgSet("-h") ||
            args.IsArgSet("-help") || args.IsArgSet("-help-debug");
 }
 
 void SetupHelpOptions(ArgsManager &args) {
     args.AddArg("-?", "Print this help message and exit", false,
                 OptionsCategory::OPTIONS);
     args.AddHiddenArgs({"-h", "-help"});
 }
 
 static const int screenWidth = 79;
 static const int optIndent = 2;
 static const int msgIndent = 7;
 
 std::string HelpMessageGroup(const std::string &message) {
     return std::string(message) + std::string("\n\n");
 }
 
 std::string HelpMessageOpt(const std::string &option,
                            const std::string &message) {
     return std::string(optIndent, ' ') + std::string(option) +
            std::string("\n") + std::string(msgIndent, ' ') +
            FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
            std::string("\n\n");
 }
 
 static std::string FormatException(const std::exception *pex,
                                    const char *pszThread) {
 #ifdef WIN32
     char pszModule[MAX_PATH] = "";
     GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
 #else
     const char *pszModule = "bitcoin";
 #endif
     if (pex) {
         return strprintf("EXCEPTION: %s       \n%s       \n%s in %s       \n",
                          typeid(*pex).name(), pex->what(), pszModule,
                          pszThread);
     } else {
         return strprintf("UNKNOWN EXCEPTION       \n%s in %s       \n",
                          pszModule, pszThread);
     }
 }
 
 void PrintExceptionContinue(const std::exception *pex, const char *pszThread) {
     std::string message = FormatException(pex, pszThread);
     LogPrintf("\n\n************************\n%s\n", message);
     tfm::format(std::cerr, "\n\n************************\n%s\n", message);
 }
 
 fs::path GetDefaultDataDir() {
 // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
 // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
 // Mac: ~/Library/Application Support/Bitcoin
 // Unix: ~/.bitcoin
 #ifdef WIN32
     // Windows
     return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
 #else
     fs::path pathRet;
     char *pszHome = getenv("HOME");
     if (pszHome == nullptr || strlen(pszHome) == 0) {
         pathRet = fs::path("/");
     } else {
         pathRet = fs::path(pszHome);
     }
 #ifdef MAC_OSX
     // Mac
     return pathRet / "Library/Application Support/Bitcoin";
 #else
     // Unix
     return pathRet / ".bitcoin";
 #endif
 #endif
 }
 
 static fs::path g_blocks_path_cache_net_specific;
 static fs::path pathCached;
 static fs::path pathCachedNetSpecific;
 static RecursiveMutex csPathCached;
 
 const fs::path &GetBlocksDir() {
     LOCK(csPathCached);
     fs::path &path = g_blocks_path_cache_net_specific;
 
     // Cache the path to avoid calling fs::create_directories on every call of
     // this function
     if (!path.empty()) {
         return path;
     }
 
     if (gArgs.IsArgSet("-blocksdir")) {
         path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
         if (!fs::is_directory(path)) {
             path = "";
             return path;
         }
     } else {
         path = GetDataDir(false);
     }
 
     path /= BaseParams().DataDir();
     path /= "blocks";
     fs::create_directories(path);
     return path;
 }
 
 const fs::path &GetDataDir(bool fNetSpecific) {
     LOCK(csPathCached);
     fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
 
     // Cache the path to avoid calling fs::create_directories on every call of
     // this function
     if (!path.empty()) {
         return path;
     }
 
     std::string datadir = gArgs.GetArg("-datadir", "");
     if (!datadir.empty()) {
         path = fs::system_complete(datadir);
         if (!fs::is_directory(path)) {
             path = "";
             return path;
         }
     } else {
         path = GetDefaultDataDir();
     }
 
     if (fNetSpecific) {
         path /= BaseParams().DataDir();
     }
 
     if (fs::create_directories(path)) {
         // This is the first run, create wallets subdirectory too
         //
         // TODO: this is an ugly way to create the wallets/ directory and
         // really shouldn't be done here. Once this is fixed, please
         // also remove the corresponding line in bitcoind.cpp AppInit.
         // See more info at:
         // https://reviews.bitcoinabc.org/D3312
         fs::create_directories(path / "wallets");
     }
 
     return path;
 }
 
 bool CheckDataDirOption() {
     std::string datadir = gArgs.GetArg("-datadir", "");
     return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
 }
 
 void ClearDatadirCache() {
     LOCK(csPathCached);
 
     pathCached = fs::path();
     pathCachedNetSpecific = fs::path();
     g_blocks_path_cache_net_specific = fs::path();
 }
 
 fs::path GetConfigFile(const std::string &confPath) {
     return AbsPathForConfigVal(fs::path(confPath), false);
 }
 
 static bool
 GetConfigOptions(std::istream &stream, const std::string &filepath,
                  std::string &error,
                  std::vector<std::pair<std::string, std::string>> &options,
                  std::list<SectionInfo> &sections) {
     std::string str, prefix;
     std::string::size_type pos;
     int linenr = 1;
     while (std::getline(stream, str)) {
         bool used_hash = false;
         if ((pos = str.find('#')) != std::string::npos) {
             str = str.substr(0, pos);
             used_hash = true;
         }
         const static std::string pattern = " \t\r\n";
         str = TrimString(str, pattern);
         if (!str.empty()) {
             if (*str.begin() == '[' && *str.rbegin() == ']') {
                 const std::string section = str.substr(1, str.size() - 2);
                 sections.emplace_back(SectionInfo{section, filepath, linenr});
                 prefix = section + '.';
             } else if (*str.begin() == '-') {
                 error = strprintf(
                     "parse error on line %i: %s, options in configuration file "
                     "must be specified without leading -",
                     linenr, str);
                 return false;
             } else if ((pos = str.find('=')) != std::string::npos) {
                 std::string name =
                     prefix + TrimString(str.substr(0, pos), pattern);
                 std::string value = TrimString(str.substr(pos + 1), pattern);
                 if (used_hash &&
                     name.find("rpcpassword") != std::string::npos) {
                     error = strprintf(
                         "parse error on line %i, using # in rpcpassword can be "
                         "ambiguous and should be avoided",
                         linenr);
                     return false;
                 }
                 options.emplace_back(name, value);
                 if ((pos = name.rfind('.')) != std::string::npos &&
                     prefix.length() <= pos) {
                     sections.emplace_back(
                         SectionInfo{name.substr(0, pos), filepath, linenr});
                 }
             } else {
                 error = strprintf("parse error on line %i: %s", linenr, str);
                 if (str.size() >= 2 && str.substr(0, 2) == "no") {
                     error += strprintf(", if you intended to specify a negated "
                                        "option, use %s=1 instead",
                                        str);
                 }
                 return false;
             }
         }
         ++linenr;
     }
     return true;
 }
 
 bool ArgsManager::ReadConfigStream(std::istream &stream,
                                    const std::string &filepath,
                                    std::string &error,
                                    bool ignore_invalid_keys) {
     LOCK(cs_args);
     std::vector<std::pair<std::string, std::string>> options;
     if (!GetConfigOptions(stream, filepath, error, options,
                           m_config_sections)) {
         return false;
     }
     for (const std::pair<std::string, std::string> &option : options) {
         std::string section;
         std::string key = option.first;
         util::SettingsValue value =
             InterpretOption(section, key, option.second);
         std::optional<unsigned int> flags = GetArgFlags('-' + key);
         if (flags) {
             if (!CheckValid(key, value, *flags, error)) {
                 return false;
             }
             m_settings.ro_config[section][key].push_back(value);
         } else {
             if (ignore_invalid_keys) {
                 LogPrintf("Ignoring unknown configuration value %s\n",
                           option.first);
             } else {
                 error = strprintf("Invalid configuration value %s",
                                   option.first.c_str());
                 return false;
             }
         }
     }
     return true;
 }
 
 bool ArgsManager::ReadConfigFiles(std::string &error,
                                   bool ignore_invalid_keys) {
     {
         LOCK(cs_args);
         m_settings.ro_config.clear();
         m_config_sections.clear();
     }
 
     const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
     fsbridge::ifstream stream(GetConfigFile(confPath));
 
     // ok to not have a config file
     if (stream.good()) {
         if (!ReadConfigStream(stream, confPath, error, ignore_invalid_keys)) {
             return false;
         }
         // `-includeconf` cannot be included in the command line arguments
         // except as `-noincludeconf` (which indicates that no included conf
         // file should be used).
         bool use_conf_file{true};
         {
             LOCK(cs_args);
             if (auto *includes = util::FindKey(m_settings.command_line_options,
                                                "includeconf")) {
                 // ParseParameters() fails if a non-negated -includeconf is
                 // passed on the command-line
                 assert(util::SettingsSpan(*includes).last_negated());
                 use_conf_file = false;
             }
         }
         if (use_conf_file) {
             std::string chain_id = GetChainName();
             std::vector<std::string> conf_file_names;
 
             auto add_includes = [&](const std::string &network,
                                     size_t skip = 0) {
                 size_t num_values = 0;
                 LOCK(cs_args);
                 if (auto *section =
                         util::FindKey(m_settings.ro_config, network)) {
                     if (auto *values = util::FindKey(*section, "includeconf")) {
                         for (size_t i = std::max(
                                  skip, util::SettingsSpan(*values).negated());
                              i < values->size(); ++i) {
                             conf_file_names.push_back((*values)[i].get_str());
                         }
                         num_values = values->size();
                     }
                 }
                 return num_values;
             };
 
             // We haven't set m_network yet (that happens in SelectParams()), so
             // manually check for network.includeconf args.
             const size_t chain_includes = add_includes(chain_id);
             const size_t default_includes = add_includes({});
 
             for (const std::string &conf_file_name : conf_file_names) {
                 fsbridge::ifstream conf_file_stream(
                     GetConfigFile(conf_file_name));
                 if (conf_file_stream.good()) {
                     if (!ReadConfigStream(conf_file_stream, conf_file_name,
                                           error, ignore_invalid_keys)) {
                         return false;
                     }
                     LogPrintf("Included configuration file %s\n",
                               conf_file_name);
                 } else {
                     error = "Failed to include configuration file " +
                             conf_file_name;
                     return false;
                 }
             }
 
             // Warn about recursive -includeconf
             conf_file_names.clear();
             add_includes(chain_id, /* skip= */ chain_includes);
             add_includes({}, /* skip= */ default_includes);
             std::string chain_id_final = GetChainName();
             if (chain_id_final != chain_id) {
                 // Also warn about recursive includeconf for the chain that was
                 // specified in one of the includeconfs
                 add_includes(chain_id_final);
             }
             for (const std::string &conf_file_name : conf_file_names) {
                 tfm::format(std::cerr,
                             "warning: -includeconf cannot be used from "
                             "included files; ignoring -includeconf=%s\n",
                             conf_file_name);
             }
         }
     }
 
     // If datadir is changed in .conf file:
     ClearDatadirCache();
     if (!CheckDataDirOption()) {
         error = strprintf("specified data directory \"%s\" does not exist.",
                           gArgs.GetArg("-datadir", "").c_str());
         return false;
     }
     return true;
 }
 
 std::string ArgsManager::GetChainName() const {
     auto get_net = [&](const std::string &arg) {
         LOCK(cs_args);
         util::SettingsValue value =
             util::GetSetting(m_settings, /* section= */ "", SettingName(arg),
                              /* ignore_default_section_config= */ false,
                              /* get_chain_name= */ true);
         return value.isNull() ? false
                               : value.isBool() ? value.get_bool()
                                                : InterpretBool(value.get_str());
     };
 
     const bool fRegTest = get_net("-regtest");
     const bool fTestNet = get_net("-testnet");
     const bool is_chain_arg_set = IsArgSet("-chain");
 
     if (int(is_chain_arg_set) + int(fRegTest) + int(fTestNet) > 1) {
         throw std::runtime_error("Invalid combination of -regtest, -testnet "
                                  "and -chain. Can use at most one.");
     }
     if (fRegTest) {
         return CBaseChainParams::REGTEST;
     }
     if (fTestNet) {
         return CBaseChainParams::TESTNET;
     }
     return GetArg("-chain", CBaseChainParams::MAIN);
 }
 
 bool ArgsManager::UseDefaultSection(const std::string &arg) const {
     return m_network == CBaseChainParams::MAIN ||
            m_network_only_args.count(arg) == 0;
 }
 
 util::SettingsValue ArgsManager::GetSetting(const std::string &arg) const {
     LOCK(cs_args);
     return util::GetSetting(m_settings, m_network, SettingName(arg),
                             !UseDefaultSection(arg),
                             /* get_chain_name= */ false);
 }
 
 std::vector<util::SettingsValue>
 ArgsManager::GetSettingsList(const std::string &arg) const {
     LOCK(cs_args);
     return util::GetSettingsList(m_settings, m_network, SettingName(arg),
                                  !UseDefaultSection(arg));
 }
 
 void ArgsManager::logArgsPrefix(
     const std::string &prefix, const std::string &section,
     const std::map<std::string, std::vector<util::SettingsValue>> &args) const {
     std::string section_str = section.empty() ? "" : "[" + section + "] ";
     for (const auto &arg : args) {
         for (const auto &value : arg.second) {
             std::optional<unsigned int> flags = GetArgFlags('-' + arg.first);
             if (flags) {
                 std::string value_str =
                     (*flags & SENSITIVE) ? "****" : value.write();
                 LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first,
                           value_str);
             }
         }
     }
 }
 
 void ArgsManager::LogArgs() const {
     LOCK(cs_args);
     for (const auto &section : m_settings.ro_config) {
         logArgsPrefix("Config file arg:", section.first, section.second);
     }
     for (const auto &setting : m_settings.rw_settings) {
         LogPrintf("Setting file arg: %s = %s\n", setting.first,
                   setting.second.write());
     }
     logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
 }
 
 bool RenameOver(fs::path src, fs::path dest) {
 #ifdef WIN32
     return MoveFileExA(src.string().c_str(), dest.string().c_str(),
                        MOVEFILE_REPLACE_EXISTING) != 0;
 #else
     int rc = std::rename(src.string().c_str(), dest.string().c_str());
     return (rc == 0);
 #endif /* WIN32 */
 }
 
 /**
  * Ignores exceptions thrown by Boost's create_directories if the requested
  * directory exists. Specifically handles case where path p exists, but it
  * wasn't possible for the user to write to the parent directory.
  */
 bool TryCreateDirectories(const fs::path &p) {
     try {
         return fs::create_directories(p);
     } catch (const fs::filesystem_error &) {
         if (!fs::exists(p) || !fs::is_directory(p)) {
             throw;
         }
     }
 
     // create_directory didn't create the directory, it had to have existed
     // already.
     return false;
 }
 
 bool FileCommit(FILE *file) {
     // harmless if redundantly called
     if (fflush(file) != 0) {
         LogPrintf("%s: fflush failed: %d\n", __func__, errno);
         return false;
     }
 #ifdef WIN32
     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
     if (FlushFileBuffers(hFile) == 0) {
         LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__,
                   GetLastError());
         return false;
     }
 #else
 #if defined(__linux__) || defined(__NetBSD__)
     // Ignore EINVAL for filesystems that don't support sync
     if (fdatasync(fileno(file)) != 0 && errno != EINVAL) {
         LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
         return false;
     }
 #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
     // Manpage says "value other than -1" is returned on success
     if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) {
         LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
         return false;
     }
 #else
     if (fsync(fileno(file)) != 0 && errno != EINVAL) {
         LogPrintf("%s: fsync failed: %d\n", __func__, errno);
         return false;
     }
 #endif
 #endif
     return true;
 }
 
 bool TruncateFile(FILE *file, unsigned int length) {
 #if defined(WIN32)
     return _chsize(_fileno(file), length) == 0;
 #else
     return ftruncate(fileno(file), length) == 0;
 #endif
 }
 
 /**
  * This function tries to raise the file descriptor limit to the requested
  * number. It returns the actual file descriptor limit (which may be more or
  * less than nMinFD)
  */
 int RaiseFileDescriptorLimit(int nMinFD) {
 #if defined(WIN32)
     return 8192;
 #else
     struct rlimit limitFD;
     if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
         if (limitFD.rlim_cur < (rlim_t)nMinFD) {
             limitFD.rlim_cur = nMinFD;
             if (limitFD.rlim_cur > limitFD.rlim_max) {
                 limitFD.rlim_cur = limitFD.rlim_max;
             }
             setrlimit(RLIMIT_NOFILE, &limitFD);
             getrlimit(RLIMIT_NOFILE, &limitFD);
         }
         return limitFD.rlim_cur;
     }
     // getrlimit failed, assume it's fine.
     return nMinFD;
 #endif
 }
 
 /**
  * This function tries to make a particular range of a file allocated
  * (corresponding to disk space) it is advisory, and the range specified in the
  * arguments will never contain live data.
  */
 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
 #if defined(WIN32)
     // Windows-specific version.
     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
     LARGE_INTEGER nFileSize;
     int64_t nEndPos = (int64_t)offset + length;
     nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
     nFileSize.u.HighPart = nEndPos >> 32;
     SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
     SetEndOfFile(hFile);
 #elif defined(MAC_OSX)
     // OSX specific version
     // NOTE: Contrary to other OS versions, the OSX version assumes that
     // NOTE: offset is the size of the file.
     fstore_t fst;
     fst.fst_flags = F_ALLOCATECONTIG;
     fst.fst_posmode = F_PEOFPOSMODE;
     fst.fst_offset = 0;
     // mac os fst_length takes the number of free bytes to allocate,
     // not the desired file size
     fst.fst_length = length;
     fst.fst_bytesalloc = 0;
     if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
         fst.fst_flags = F_ALLOCATEALL;
         fcntl(fileno(file), F_PREALLOCATE, &fst);
     }
     ftruncate(fileno(file), static_cast<off_t>(offset) + length);
 #elif defined(HAVE_POSIX_FALLOCATE)
     // Version using posix_fallocate
     off_t nEndPos = (off_t)offset + length;
     posix_fallocate(fileno(file), 0, nEndPos);
 #else
     // Fallback version
     // TODO: just write one byte per block
     static const char buf[65536] = {};
     if (fseek(file, offset, SEEK_SET)) {
         return;
     }
     while (length > 0) {
         unsigned int now = 65536;
         if (length < now) {
             now = length;
         }
         // Allowed to fail; this function is advisory anyway.
         fwrite(buf, 1, now, file);
         length -= now;
     }
 #endif
 }
 
 #ifdef WIN32
 fs::path GetSpecialFolderPath(int nFolder, bool fCreate) {
     WCHAR pszPath[MAX_PATH] = L"";
 
     if (SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) {
         return fs::path(pszPath);
     }
 
     LogPrintf(
         "SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
     return fs::path("");
 }
 #endif
 
 #ifndef WIN32
 std::string ShellEscape(const std::string &arg) {
     std::string escaped = arg;
     boost::replace_all(escaped, "'", "'\"'\"'");
     return "'" + escaped + "'";
 }
 #endif
 
 #if defined(HAVE_SYSTEM)
 void runCommand(const std::string &strCommand) {
     if (strCommand.empty()) {
         return;
     }
 #ifndef WIN32
     int nErr = ::system(strCommand.c_str());
 #else
     int nErr = ::_wsystem(
         std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>()
             .from_bytes(strCommand)
             .c_str());
 #endif
     if (nErr) {
         LogPrintf("runCommand error: system(%s) returned %d\n", strCommand,
                   nErr);
     }
 }
 #endif
 
 void SetupEnvironment() {
 #ifdef HAVE_MALLOPT_ARENA_MAX
     // glibc-specific: On 32-bit systems set the number of arenas to 1. By
     // default, since glibc 2.10, the C library will create up to two heap
     // arenas per core. This is known to cause excessive virtual address space
     // usage in our usage. Work around it by setting the maximum number of
     // arenas to 1.
     if (sizeof(void *) == 4) {
         mallopt(M_ARENA_MAX, 1);
     }
 #endif
 // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale may
 // be invalid, in which case the "C.UTF-8" locale is used as fallback.
 #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) &&           \
     !defined(__OpenBSD__)
     try {
         // Raises a runtime error if current locale is invalid.
         std::locale("");
     } catch (const std::runtime_error &) {
         setenv("LC_ALL", "C.UTF-8", 1);
     }
 #elif defined(WIN32)
     // Set the default input/output charset is utf-8
     SetConsoleCP(CP_UTF8);
     SetConsoleOutputCP(CP_UTF8);
 #endif
     // The path locale is lazy initialized and to avoid deinitialization errors
     // in multithreading environments, it is set explicitly by the main thread.
     // A dummy locale is used to extract the internal default locale, used by
     // fs::path, which is then used to explicitly imbue the path.
     std::locale loc = fs::path::imbue(std::locale::classic());
 #ifndef WIN32
     fs::path::imbue(loc);
 #else
     fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>()));
 #endif
 }
 
 bool SetupNetworking() {
 #ifdef WIN32
     // Initialize Windows Sockets.
     WSADATA wsadata;
     int ret = WSAStartup(MAKEWORD(2, 2), &wsadata);
     if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 ||
         HIBYTE(wsadata.wVersion) != 2) {
         return false;
     }
 #endif
     return true;
 }
 
 int GetNumCores() {
     return std::thread::hardware_concurrency();
 }
 
 std::string CopyrightHolders(const std::string &strPrefix) {
     return strPrefix + strprintf(_(COPYRIGHT_HOLDERS).translated,
                                  COPYRIGHT_HOLDERS_SUBSTITUTION);
 }
 
 // Obtain the application startup time (used for uptime calculation)
 int64_t GetStartupTime() {
     return nStartupTime;
 }
 
 fs::path AbsPathForConfigVal(const fs::path &path, bool net_specific) {
     if (path.is_absolute()) {
         return path;
     }
     return fs::absolute(path, GetDataDir(net_specific));
 }
 
 void ScheduleBatchPriority() {
 #ifdef SCHED_BATCH
     const static sched_param param{};
     if (pthread_setschedparam(pthread_self(), SCHED_BATCH, &param) != 0) {
         LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(errno));
     }
 #endif
 }
 
 namespace util {
 #ifdef WIN32
 WinCmdLineArgs::WinCmdLineArgs() {
     wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
     argv = new char *[argc];
     args.resize(argc);
     for (int i = 0; i < argc; i++) {
         args[i] = utf8_cvt.to_bytes(wargv[i]);
         argv[i] = &*args[i].begin();
     }
     LocalFree(wargv);
 }
 
 WinCmdLineArgs::~WinCmdLineArgs() {
     delete[] argv;
 }
 
 std::pair<int, char **> WinCmdLineArgs::get() {
     return std::make_pair(argc, argv);
 }
 #endif
 } // namespace util
diff --git a/test/lint/lint-boost-dependencies.sh b/test/lint/lint-boost-dependencies.sh
index e3896f060..8a89fad0b 100755
--- a/test/lint/lint-boost-dependencies.sh
+++ b/test/lint/lint-boost-dependencies.sh
@@ -1,67 +1,66 @@
 #!/usr/bin/env bash
 #
 # Copyright (c) 2018 The Bitcoin Core developers
 # Distributed under the MIT software license, see the accompanying
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 #
 # Guard against accidental introduction of new Boost dependencies.
 
 export LC_ALL=C
 
 EXPECTED_BOOST_INCLUDES=(
     boost/algorithm/string.hpp
     boost/algorithm/string/classification.hpp
     boost/algorithm/string/replace.hpp
     boost/algorithm/string/split.hpp
     boost/date_time/posix_time/posix_time.hpp
     boost/filesystem.hpp
     boost/filesystem/fstream.hpp
     boost/multi_index/composite_key.hpp
     boost/multi_index/hashed_index.hpp
     boost/multi_index/member.hpp
     boost/multi_index/ordered_index.hpp
     boost/multi_index/sequenced_index.hpp
     boost/multi_index_container.hpp
     boost/noncopyable.hpp
     boost/preprocessor/cat.hpp
     boost/preprocessor/stringize.hpp
     boost/range/iterator.hpp
     boost/range/adaptor/sliced.hpp
     boost/signals2/connection.hpp
     boost/signals2/last_value.hpp
     boost/signals2/signal.hpp
     boost/test/unit_test.hpp
-    boost/thread.hpp
     boost/thread/condition_variable.hpp
     boost/thread/locks.hpp
     boost/thread/mutex.hpp
     boost/thread/shared_mutex.hpp
     boost/thread/thread.hpp
     boost/variant.hpp
     boost/variant/apply_visitor.hpp
     boost/variant/static_visitor.hpp
 )
 
 for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do
     IS_EXPECTED_INCLUDE=0
     for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do
         if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then
             IS_EXPECTED_INCLUDE=1
             break
         fi
     done
     if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then
         echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:"
         git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h"
         echo
     fi
 done
 
 for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do
     if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then
         echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used."
         echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0"
         echo "to make sure this dependency is not accidentally reintroduced."
         echo
     fi
 done