// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Copyright (c) 2016-2024 The Hush developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html // What happened to the SuperNET devs, who were dedicated to privacy??? // Did they go the way of the dodo when they embraced KYC? /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #if defined(HAVE_CONFIG_H) #include "config/bitcoin-config.h" #endif #include "init.h" #include "crypto/common.h" #include "primitives/block.h" #include "addrman.h" #include "amount.h" #include "checkpoints.h" #include "compat/sanity.h" #include "consensus/upgrades.h" #include "consensus/validation.h" #include "httpserver.h" #include "httprpc.h" #include "key.h" #include "notarizationdb.h" #include "stratum.h" #ifdef ENABLE_MINING #include "key_io.h" #endif #include "main.h" #include "metrics.h" #include "miner.h" #include "net.h" #include "rpc/server.h" #include "rpc/register.h" #include "script/standard.h" #include "scheduler.h" #include "txdb.h" #include "torcontrol.h" #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" #include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #include "wallet/walletdb.h" #include "wallet/asyncrpcoperation_saplingconsolidation.h" #include "wallet/asyncrpcoperation_sweep.h" #endif #include #include #ifndef _WIN32 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "librustzcash.h" using namespace std; #include "hush_defs.h" static const bool DEFAULT_STRATUM_ENABLE = false; extern bool hush_dailysnapshot(int32_t height); extern int32_t HUSH_LOADINGBLOCKS; extern char SMART_CHAIN_SYMBOL[]; extern int32_t HUSH_SNAPSHOT_INTERVAL; extern void hush_init(int32_t height); #ifdef ENABLE_WALLET CWallet* pwalletMain = NULL; #endif bool fFeeEstimatesInitialized = false; #ifdef WIN32 // Win32 LevelDB doesn't use file descriptors, 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 /** Used to pass flags to the Bind() function */ enum BindFlags { BF_NONE = 0, BF_EXPLICIT = (1U << 0), BF_REPORT_ERROR = (1U << 1), BF_ALLOWLIST = (1U << 2), }; static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; static const char* DEFAULT_ASMAP_FILENAME="asmap.dat"; CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h // Shutdown // // Thread management and startup/shutdown: // // The network-processing threads are all part of a thread group // created by AppInit(). // // A clean exit happens when StartShutdown() or the SIGTERM // signal handler sets fRequestShutdown, which triggers // the DetectShutdownThread(), which interrupts the main thread group. // DetectShutdownThread() then exits, which causes AppInit() to // continue (it .joins the shutdown 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. // // Note that if running -daemon the parent process returns from AppInit2 // before adding any threads to the threadGroup, so .join_all() returns // immediately and the parent exits from main(). std::atomic fRequestShutdown(false); void StartShutdown() { fprintf(stderr,"%s: fRequestShudown=true\n", __FUNCTION__); fRequestShutdown = true; } bool ShutdownRequested() { return fRequestShutdown; } class CCoinsViewErrorCatcher : public CCoinsViewBacked { public: CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} bool GetCoins(const uint256 &txid, CCoins &coins) const { try { return CCoinsViewBacked::GetCoins(txid, coins); } catch(const std::runtime_error& e) { uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR); LogPrintf("Error reading from database: %s\n", e.what()); // Starting the shutdown sequence and returning false to the caller would be // interpreted as 'entry not found' (as opposed to unable to read data), and // could lead to invalid interpretation. Just exit immediately, as we can't // continue anyway, and all writes should be atomic. abort(); } } // Writes do not need similar protection, as failure to write is handled by the caller. }; static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; static boost::scoped_ptr globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) { InterruptStratumServer(); InterruptHTTPServer(); InterruptHTTPRPC(); InterruptRPC(); InterruptREST(); InterruptTorControl(); threadGroup.interrupt_all(); } void Shutdown() { if(fDebug) fprintf(stderr,"%s: start\n", __FUNCTION__); LogPrintf("%s: In progress...\n", __func__); static CCriticalSection cs_Shutdown; TRY_LOCK(cs_Shutdown, lockShutdown); if (!lockShutdown) return; /// Note: Shutdown() must be able to handle cases in which AppInit2() 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. static char shutoffstr[128]; sprintf(shutoffstr,"%s-shutoff","hush"); RenameThread(shutoffstr); mempool.AddTransactionsUpdated(1); fprintf(stderr,"%s: stopping HUSH HTTP/REST/RPC\n", __FUNCTION__); StopHTTPRPC(); StopREST(); StopRPC(); StopStratumServer(); StopHTTPServer(); #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(false); #endif #ifdef ENABLE_MINING #ifdef ENABLE_WALLET GenerateBitcoins(false, NULL, 0); #else GenerateBitcoins(false, 0); #endif #endif fprintf(stderr,"%s: stopping node\n", __FUNCTION__); StopNode(); StopTorControl(); UnregisterNodeSignals(GetNodeSignals()); if (fFeeEstimatesInitialized) { boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_fileout(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION); if (!est_fileout.IsNull()) mempool.WriteFeeEstimates(est_fileout); else LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string()); fFeeEstimatesInitialized = false; } { LOCK(cs_main); if (pcoinsTip != NULL) { FlushStateToDisk(); } if (pcoinsTip != NULL) { delete pcoinsTip; pcoinsTip = NULL; } if (pcoinscatcher != NULL) { delete pcoinscatcher; pcoinscatcher = NULL; } if (pcoinsdbview != NULL) { delete pcoinsdbview; pcoinsdbview = NULL; } if (pblocktree != NULL) { delete pblocktree; pblocktree = NULL; } } #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(true); #endif #ifndef WIN32 try { boost::filesystem::remove(GetPidFile()); } catch (const boost::filesystem::filesystem_error& e) { LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what()); } #endif UnregisterAllValidationInterfaces(); #ifdef ENABLE_WALLET delete pwalletMain; pwalletMain = NULL; #endif globalVerifyHandle.reset(); ECC_Stop(); // CNode::NetCleanup(); LogPrintf("%s: done\n", __func__); } // Signal handlers are very limited in what they are allowed to do, so: #ifndef WIN32 void HandleSIGTERM(int) { fprintf(stderr,"%s\n",__FUNCTION__); fRequestShutdown = true; } void HandleSIGHUP(int) { fprintf(stderr,"%s\n",__FUNCTION__); fReopenDebugLog = true; } #else static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) { fRequestShutdown = true; // This signal now sleeps with the fishes 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, nullptr); } #endif bool static InitError(const std::string &str) { uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); return false; } bool static InitWarning(const std::string &str) { uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); return true; } bool static Bind(const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) return false; std::string strError; if (!BindListenPort(addr, strError, (flags & BF_ALLOWLIST) != 0)) { if (flags & BF_REPORT_ERROR) return InitError(strError); return false; } return true; } void OnRPCStopped() { cvBlockChange.notify_all(); LogPrint("rpc", "RPC stopped.\n"); } void OnRPCPreCommand(const CRPCCommand& cmd) { // Observe safe mode string strWarning = GetWarnings("rpc"); if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && !cmd.okSafeMode) throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); } std::string HelpMessage(HelpMessageMode mode) { const bool showDebug = GetBoolArg("-help-debug", false); // 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 string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); strUsage += HelpMessageOpt("-blocknotify=", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288)); strUsage += HelpMessageOpt("-checklevel=", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3)); strUsage += HelpMessageOpt("-clientname=", _("Full node client name, default 'GoldenSandtrout'")); strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), "HUSH3.conf")); if (mode == HMM_BITCOIND) { #if !defined(WIN32) strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands")); #endif } strUsage += HelpMessageOpt("-datadir=", _("Specify data directory (this path cannot use '~')")); strUsage += HelpMessageOpt("-exportdir=", _("Specify directory to be used when exporting data")); strUsage += HelpMessageOpt("-dbcache=", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); strUsage += HelpMessageOpt("-maxdebugfilesize=", strprintf(_("Set the max size of the debug.log file (default: %u)"), 15)); strUsage += HelpMessageOpt("-maxorphantx=", strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-maxreorg=", _("Specify the maximum length of a blockchain re-organization")); strUsage += HelpMessageOpt("-mempooltxinputlimit=", _("[DEPRECATED/IGNORED] Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)")); strUsage += HelpMessageOpt("-par=", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef _WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "hushd.pid")); #endif strUsage += HelpMessageOpt("-txexpirynotify=", _("Execute command when transaction expires (%s in cmd is replaced by transaction id)")); strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files on startup")); #if !defined(WIN32) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0)); strUsage += HelpMessageOpt("-txsend=", _("Execute command to send a transaction instead of broadcasting (%s in cmd is replaced by transaction hex)")); strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX)); strUsage += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX)); strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX)); strUsage += HelpMessageOpt("-zindex", strprintf(_("Maintain extra statistics about shielded transactions and payments (default: %u)"), 0)); strUsage += HelpMessageGroup(_("Connection options:")); strUsage += HelpMessageOpt("-addnode=", _("Add a node to connect to and attempt to keep the connection open")); strUsage += HelpMessageOpt("-asmap=", 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)); strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); strUsage += HelpMessageOpt("-bantime=", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), 86400)); strUsage += HelpMessageOpt("-bind=", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-connect=", _("Connect only to the specified node(s)")); strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)")); strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + _("(default: 1)")); strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)")); strUsage += HelpMessageOpt("-externalip=", _("Specify your own public address")); strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0)); strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), 5000)); strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), 1000)); strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-nspv_msg", strprintf(_("Enable NSPV messages processing (default: true when -ac_private=1, otherwise false)"))); strUsage += HelpMessageOpt("-i2psam=", strprintf(_("I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)"))); strUsage += HelpMessageOpt("-i2pacceptincoming", strprintf(_("If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)"))); strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6, onion or i2p)")); strUsage += HelpMessageOpt("-disableipv4", _("Disable Ipv4 network connections") + " " + _("(default: 0)")); strUsage += HelpMessageOpt("-disableipv6", _("Disable Ipv6 network connections") + " " + _("(default: 0)")); strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with Bloom filters (default: %u)"), 1)); if (showDebug) strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of Bloom filters (default: %u)", 0)); strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), 55555, 55420)); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); strUsage += HelpMessageOpt("-torcontrol=:", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); strUsage += HelpMessageOpt("-torpassword=", _("Tor control port password (default: empty)")); strUsage += HelpMessageOpt("-tls=