Files
thehub/libs/server/init.cpp
T

1278 lines
51 KiB
C++
Raw Permalink Normal View History

2017-11-09 19:34:51 +01:00
/*
* This file is part of the Flowee project
* Copyright (c) 2009-2010 Satoshi Nakamoto
* Copyright (c) 2009-2015 The Bitcoin Core developers
2021-01-20 19:21:53 +01:00
* Copyright (C) 2019-2021 Tom Zander <tom@flowee.org>
2017-11-09 19:34:51 +01:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2013-05-27 19:55:01 -04:00
#if defined(HAVE_CONFIG_H)
2018-01-16 10:47:52 +00:00
#include "config/flowee-config.h"
2013-05-27 19:55:01 -04:00
#endif
2013-01-07 08:07:51 -08:00
#include "init.h"
2018-02-12 14:15:24 +01:00
#include <SettingsDefaults.h>
2016-08-16 16:51:22 +02:00
#include "Application.h"
2013-04-13 00:13:08 -05:00
#include "addrman.h"
#include "amount.h"
2015-07-05 14:17:46 +02:00
#include "chain.h"
#include "chainparams.h"
2013-04-13 00:13:08 -05:00
#include "checkpoints.h"
2014-09-14 12:43:56 +02:00
#include "compat/sanity.h"
#include "consensus/validation.h"
2019-09-02 23:28:14 +02:00
#include "DoubleSpendProofStorage.h"
2015-01-23 07:53:17 +01:00
#include "httpserver.h"
#include "httprpc.h"
2019-03-13 14:50:11 +01:00
#include <primitives/key.h>
#include "main.h"
2013-04-13 00:13:08 -05:00
#include "miner.h"
#include "net.h"
#include "policy/policy.h"
#include "rpcserver.h"
#include "script/standard.h"
2015-10-30 23:14:38 +01:00
#include "script/sigcache.h"
#include "scheduler.h"
2017-02-14 11:17:46 +01:00
#include "BlocksDB.h"
2015-07-05 14:17:46 +02:00
#include "txmempool.h"
#include "torcontrol.h"
2018-02-10 22:48:07 +01:00
#include "UiInterface.h"
2019-08-24 13:20:37 +02:00
#include <util.h>
#include "serverutil.h"
#include <utilmoneystr.h>
#include <utilstrencodings.h>
2017-02-08 17:17:38 +01:00
#include "txorphancache.h"
#include "validationinterface.h"
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
2015-07-05 14:17:46 +02:00
#include "wallet/db.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
2013-11-29 16:04:29 +01:00
#endif
2018-01-15 15:26:12 +00:00
#include <validation/Engine.h>
#include <cstdint>
#include <cstdio>
2011-05-14 20:10:21 +02:00
2012-04-15 22:10:54 +02:00
#ifndef WIN32
#include <csignal>
2018-01-15 15:26:12 +00:00
#include "CrashCatcher.h"
2019-08-24 13:20:37 +02:00
#include <sys/resource.h>
2012-03-18 23:14:03 +01:00
#endif
2018-01-15 15:26:12 +00:00
#include <validation/VerifyDB.h>
2019-08-24 13:20:37 +02:00
#include <utxo/UnspentOutputDatabase.h>
#include <boost/algorithm/string/classification.hpp>
2013-04-13 00:13:08 -05:00
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
2018-01-16 20:15:22 +00:00
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
2019-03-21 21:41:56 +01:00
#include <boost/lexical_cast.hpp>
2013-04-13 00:13:08 -05:00
#include <boost/filesystem.hpp>
#include <boost/function.hpp>
2013-04-13 00:13:08 -05:00
#include <boost/interprocess/sync/file_lock.hpp>
2014-08-21 16:11:09 +02:00
#include <boost/thread.hpp>
2013-04-13 00:13:08 -05:00
#include <openssl/crypto.h>
2019-10-20 19:17:18 +02:00
#include <boost/date_time/posix_time/posix_time.hpp>
2019-08-24 13:20:37 +02:00
2013-04-13 00:13:08 -05:00
#if ENABLE_ZMQ
#include "zmq/zmqnotificationinterface.h"
#endif
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
2014-09-25 09:03:30 +02:00
CWallet* pwalletMain = NULL;
2013-11-29 16:04:29 +01:00
#endif
2011-06-26 19:23:24 +02:00
#if ENABLE_ZMQ
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
#endif
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
2015-04-28 14:48:28 +00:00
// 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),
2014-06-21 13:34:36 +02:00
BF_REPORT_ERROR = (1U << 1),
BF_WHITELIST = (1U << 2),
};
CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h
2019-08-24 13:20:37 +02:00
namespace {
/**
* 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 2048;
#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;
}
return nMinFD; // getrlimit failed, assume it's fine
#endif
}
#ifndef WIN32
boost::filesystem::path GetPidFile()
{
boost::filesystem::path pathPidFile(GetArg("-pid", Settings::hubPidFilename()));
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
return pathPidFile;
}
void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
{
FILE* file = fopen(path.string().c_str(), "w");
if (file)
{
fprintf(file, "%d\n", pid);
fclose(file);
}
}
#endif
void ShrinkDebugFile()
{
// Scroll hub.log if it's getting too big
boost::filesystem::path pathLog = GetDataDir() / "hub.log";
FILE* file = fopen(pathLog.string().c_str(), "r");
if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000)
{
// Restart the file with some of the end
std::vector <char> vch(200000,0);
fseek(file, -((long)vch.size()), SEEK_END);
int nBytes = fread(begin_ptr(vch), 1, vch.size(), file);
fclose(file);
file = fopen(pathLog.string().c_str(), "w");
if (file)
{
fwrite(begin_ptr(vch), 1, nBytes, file);
fclose(file);
}
}
else if (file != NULL)
fclose(file);
}
}
2011-05-14 20:10:21 +02:00
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
2013-03-09 12:02:57 -05:00
//
// 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 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().
//
// Shutdown for Qt is very similar, only it uses a QTimer to detect
// fRequestShutdown getting set, and then does the normal Qt
// shutdown thing.
2013-03-09 12:02:57 -05:00
//
volatile bool fRequestShutdown = false;
2011-05-14 20:10:21 +02:00
void StartShutdown()
{
2013-03-09 12:02:57 -05:00
fRequestShutdown = true;
}
bool ShutdownRequested()
{
return fRequestShutdown;
}
static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
2012-07-06 16:33:34 +02:00
UnspentOutputDatabase *g_utxo = nullptr;
2015-01-23 07:53:17 +01:00
void Interrupt(boost::thread_group& threadGroup)
{
InterruptHTTPServer();
InterruptRPC();
2015-09-08 17:48:45 +02:00
InterruptTorControl();
2015-01-23 07:53:17 +01:00
threadGroup.interrupt_all();
}
2013-03-09 12:02:57 -05:00
void Shutdown()
2011-05-14 20:10:21 +02:00
{
2018-03-19 22:41:13 +01:00
logCritical(Log::Bitcoin) << "Shutdown in progress...";
2011-05-14 20:10:21 +02:00
static CCriticalSection cs_Shutdown;
2013-03-09 12:02:57 -05:00
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.
2018-07-22 22:20:40 +02:00
RenameThread("hub-shutoff");
mempool.AddTransactionsUpdated(1);
2015-01-23 07:53:17 +01:00
StopHTTPRPC();
StopREST();
StopRPC();
StopHTTPServer();
2013-12-08 15:26:08 +01:00
#ifdef ENABLE_WALLET
if (pwalletMain)
pwalletMain->Flush(false);
2013-11-29 16:04:29 +01:00
#endif
2016-05-05 14:36:07 +01:00
Mining::Stop();
2013-03-06 22:31:26 -05:00
StopNode();
StopTorControl();
2013-11-18 01:25:17 +01:00
UnregisterNodeSignals(GetNodeSignals());
2014-03-17 08:19:54 -04:00
2017-02-24 14:35:58 +01:00
Application::quit(0);
Application::exec(); // waits for threads to finish.
2011-05-14 20:10:21 +02:00
{
2013-03-09 12:02:57 -05:00
LOCK(cs_main);
FlushStateToDisk();
delete g_utxo;
g_utxo = nullptr;
2017-12-15 13:42:40 +01:00
Blocks::DB::shutdown();
2011-05-14 20:10:21 +02:00
}
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
if (pwalletMain)
pwalletMain->Flush(true);
2013-11-29 16:04:29 +01:00
#endif
#if ENABLE_ZMQ
if (pzmqNotificationInterface) {
2018-02-15 18:06:38 +01:00
ValidationNotifier().removeListener(pzmqNotificationInterface);
delete pzmqNotificationInterface;
pzmqNotificationInterface = NULL;
}
#endif
2014-09-20 10:56:25 +02:00
#ifndef WIN32
try {
boost::filesystem::remove(GetPidFile());
} catch (const boost::filesystem::filesystem_error& e) {
2018-03-19 22:41:13 +01:00
logCritical(Log::Bitcoin) << "Shutdown: Unable to remove pidfile:" << e;
}
2014-09-20 10:56:25 +02:00
#endif
2018-02-15 18:06:38 +01:00
ValidationNotifier().removeAll();
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
2014-09-25 09:03:30 +02:00
delete pwalletMain;
pwalletMain = NULL;
2013-11-29 16:04:29 +01:00
#endif
globalVerifyHandle.reset();
2015-04-22 14:28:26 -07:00
ECC_Stop();
2018-03-19 22:41:13 +01:00
logCritical(Log::Bitcoin) << "Shutdown: done";
2011-05-14 20:10:21 +02:00
}
/**
* Signal handlers are very limited in what they are allowed to do, so:
*/
2011-05-14 20:10:21 +02:00
void HandleSIGTERM(int)
{
fRequestShutdown = true;
}
2012-03-02 12:31:16 -07:00
void HandleSIGHUP(int)
{
Log::Manager::instance()->reopenLogFiles();
2018-03-08 19:32:14 +01:00
Log::Manager::instance()->parseConfig(GetConfigFile("logs.conf"), GetDataDir(true) / "hub.log");
2012-03-02 12:31:16 -07:00
}
2011-05-14 20:10:21 +02:00
2012-05-13 12:35:39 +02:00
bool static InitError(const std::string &str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR);
2012-05-13 12:35:39 +02:00
return false;
}
bool static InitWarning(const std::string &str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
2012-05-13 12:35:39 +02:00
return true;
}
bool static Bind(const CService &addr, unsigned int flags) {
if (!(flags & BF_EXPLICIT) && IsLimited(addr))
2012-05-11 15:28:59 +02:00
return false;
std::string strError;
if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
if (flags & BF_REPORT_ERROR)
2012-05-24 19:02:21 +02:00
return InitError(strError);
return false;
}
2012-05-11 15:28:59 +02:00
return true;
}
void OnRPCStopped()
{
cvBlockChange.notify_all();
2019-02-25 21:35:05 +01:00
logInfo(Log::RPC) << "RPC stopped.";
}
void OnRPCPreCommand(const CRPCCommand& cmd)
{
// Observe safe mode
2017-08-04 19:02:56 +05:30
std::string strWarning = GetWarnings("rpc");
2018-02-12 14:15:24 +01:00
if (strWarning != "" && !GetBoolArg("-disablesafemode", Settings::DefaultDisableSafemode) &&
!cmd.okSafeMode)
2017-08-04 19:02:56 +05:30
throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning);
}
static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)
{
if (initialSync || !pBlockIndex)
return;
std::string strCmd = GetArg("-blocknotify", "");
boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
2015-02-23 14:27:44 -05:00
/** Sanity checks
* Ensure that Bitcoin is running in a usable environment with all
* necessary library support.
*/
bool InitSanityCheck(void)
{
if(!ECC_InitSanityCheck()) {
InitError("Elliptic curve cryptography sanity check failure. Aborting.");
return false;
}
2014-06-13 19:23:01 -04:00
if (!glibc_sanity_test() || !glibcxx_sanity_test())
return false;
return true;
}
2017-02-21 13:44:48 +01:00
bool AppInitServers()
2015-01-23 07:53:17 +01:00
{
RPCServer::OnStopped(&OnRPCStopped);
RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
2015-01-23 07:53:17 +01:00
return false;
2018-08-10 18:07:35 +03:00
StartRPC();
2015-01-23 07:53:17 +01:00
if (!StartHTTPRPC())
return false;
2018-08-10 18:07:35 +03:00
if (GetBoolArg("-rest", Settings::DefaultRestEnable))
StartREST();
StartHTTPServer();
2015-01-23 07:53:17 +01:00
return true;
}
// Parameter interaction based on rules
void InitParameterInteraction()
{
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
if (mapArgs.count("-bind")) {
if (SoftSetBoolArg("-listen", true))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -bind set -> setting -listen=1";
}
if (mapArgs.count("-whitebind")) {
if (SoftSetBoolArg("-listen", true))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -whitebind set -> setting -listen=1";
}
if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) {
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
if (SoftSetBoolArg("-dnsseed", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -connect set -> setting -dnsseed=0";
if (SoftSetBoolArg("-listen", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -connect set -> setting -listen=0";
}
if (mapArgs.count("-proxy")) {
// to protect privacy, do not listen by default if a default proxy server is specified
if (SoftSetBoolArg("-listen", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Proxy) << "parameter interaction: -proxy set -> setting -listen=0";
// 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 (SoftSetBoolArg("-upnp", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Proxy) << "parameter interaction: -proxy set -> setting -upnp=0";
// to protect privacy, do not discover addresses by default
if (SoftSetBoolArg("-discover", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Proxy) << "parameter interaction: -proxy set -> setting -discover=0";
}
if (!GetBoolArg("-listen", DEFAULT_LISTEN)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
if (SoftSetBoolArg("-upnp", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -listen=0 -> setting -upnp=0";
if (SoftSetBoolArg("-discover", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -listen=0 -> setting -discover=0";
if (SoftSetBoolArg("-listenonion", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Net) << "parameter interaction: -listen=0 -> setting -listenonion=0";
}
if (mapArgs.count("-externalip")) {
// if an explicit public IP is specified, do not try to find others
if (SoftSetBoolArg("-discover", false))
logCritical(Log::Net) << "parameter interaction: -externalip set -> setting -discover=false";
}
if (GetBoolArg("-salvagewallet", false)) {
// Rewrite just private keys: rescan to find transactions
if (SoftSetBoolArg("-rescan", true))
logCritical(Log::Wallet) << "parameter interaction: -salvagewallet -> setting -rescan=true";
}
// -zapwallettx implies a rescan
if (GetBoolArg("-zapwallettxes", false)) {
if (SoftSetBoolArg("-rescan", true))
logCritical(Log::Wallet) << "parameter interaction: -zapwallettxes=<mode> -> setting -rescan=true";
}
// disable walletbroadcast and whitelistrelay in blocksonly mode
2018-02-12 14:15:24 +01:00
if (GetBoolArg("-blocksonly", Settings::DefaultBlocksOnly)) {
if (SoftSetBoolArg("-whitelistrelay", false))
logCritical(Log::Net) << "parameter interaction: -blocksonly=true -> setting -whitelistrelay=false";
#ifdef ENABLE_WALLET
if (SoftSetBoolArg("-walletbroadcast", false))
2017-08-29 11:42:11 +02:00
logCritical(Log::Wallet) << "parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0";
#endif
}
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
2018-02-12 14:15:24 +01:00
if (GetBoolArg("-whitelistforcerelay", Settings::DefaultWhitelistForceRelay)) {
if (SoftSetBoolArg("-whitelistrelay", true))
logCritical(Log::Net) << "parameter interaction: -whitelistforcerelay=true -> setting -whitelistrelay=true";
}
2020-11-10 17:25:56 +01:00
auto miningSize = GetArg("-blockmaxsize", -1);
if (miningSize > 0x7FFFFFFF) { // overflow
logCritical(Log::Mining) << "parameter -blockmaxsize is too large. Max is 31bit int";
throw std::runtime_error("invalid parameter passed to -blockmaxsize");
}
2020-11-10 17:25:56 +01:00
2020-11-10 22:18:53 +01:00
int32_t acceptSize = Policy::blockSizeAcceptLimit();
2020-11-10 17:25:56 +01:00
if (GetBoolArg("-scalenet", false) && acceptSize < 268435456) {
logCritical(Log::Net) << "parameter interaction: -scalenet -> setting -blockmaxsize";
miningSize = acceptSize = 268435456;
2020-11-10 22:18:53 +01:00
SoftSetArg("-blocksizeacceptlimit", "270");
2020-11-10 17:25:56 +01:00
SoftSetArg("-blockmaxsize", "268435456");
}
if ((int) miningSize > acceptSize) {
2019-03-21 21:41:56 +01:00
if (SoftSetArg("-blocksizeacceptlimit", boost::lexical_cast<std::string>((miningSize + 100000) / 1E6)))
logCritical(Log::Net) << "parameter interaction: -blockmaxsize N -> setting -blockacceptlimit=N";
else
throw std::runtime_error("Block Accept setting smaller than block mining size. Please adjust and restart");
}
assert(Policy::blockSizeAcceptLimit() >= miningSize);
2019-03-24 21:21:32 +01:00
const int64_t mempoolMaxSize = GetArg("-maxmempool", Settings::DefaultMaxMempoolSize) * 4500000;
if (mempoolMaxSize < miningSize * 4) {
if (SoftSetArg("-maxmempool", boost::lexical_cast<std::string>(miningSize * 4)))
2019-03-24 21:21:32 +01:00
logCritical(Log::Net) << "parameter interaction: -blockmaxsize N -> setting -maxmempool=4N";
}
}
void InitLogging()
{
fLogIPs = GetBoolArg("-logips", DEFAULT_LOGIPS);
2018-03-08 19:32:14 +01:00
Log::Manager::instance()->parseConfig(GetConfigFile("logs.conf"), GetDataDir(true) / "hub.log");
2018-03-19 22:41:13 +01:00
logCritical(Log::Bitcoin) << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
2019-08-05 22:37:49 +02:00
logCritical(Log::Bitcoin) << "Flowee the Hub version " << CLIENT_BUILD.c_str()
<< "Built:" << CLIENT_DATE.c_str();
}
2012-05-13 11:36:10 +02:00
/** Initialize bitcoin.
* @pre Parameters should be parsed and config file should be read.
*/
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
2011-05-14 20:10:21 +02:00
{
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 1: setup
2011-05-14 20:10:21 +02:00
#ifdef _MSC_VER
2012-07-26 00:48:39 +00:00
// Turn off Microsoft heap dump noise
2011-05-14 20:10:21 +02:00
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
#if _MSC_VER >= 1400
2012-07-26 00:48:39 +00:00
// Disable confusing "helpful" text message on abort, Ctrl-C
2011-05-14 20:10:21 +02:00
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#ifdef WIN32
// Enable Data Execution Prevention (DEP)
// Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
// A failure is non-critical and needs no further attention!
#ifndef PROCESS_DEP_ENABLE
2013-10-01 09:47:16 +02:00
// We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
// which is not correct. Can be removed, when GCCs winbase.h is fixed!
#define PROCESS_DEP_ENABLE 0x00000001
#endif
typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE);
2011-05-14 20:10:21 +02:00
#endif
2019-10-20 19:17:18 +02:00
#ifdef USE_UNSAFE_RANDOM
/* Intializes random number generator in case the operator wanted non-safe random */
srand(unsigned(boost::posix_time::microsec_clock::local_time().time_of_day().total_microseconds()));
#endif
2018-01-16 20:15:22 +00:00
if (!SetupNetworking())
2015-10-22 18:09:19 +02:00
return InitError("Initializing networking failed");
#ifndef WIN32
2011-05-14 20:10:21 +02:00
// Clean shutdown on SIGTERM
struct sigaction sa;
sa.sa_handler = HandleSIGTERM;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
2012-03-02 12:31:16 -07:00
2018-11-21 12:18:32 +01:00
// Reopen hub.log on SIGHUP
2012-03-02 12:31:16 -07:00
struct sigaction sa_hup;
sa_hup.sa_handler = HandleSIGHUP;
sigemptyset(&sa_hup.sa_mask);
sa_hup.sa_flags = 0;
sigaction(SIGHUP, &sa_hup, NULL);
2013-05-05 13:37:03 +08:00
2015-09-15 01:39:12 +02:00
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
2013-05-05 13:37:03 +08:00
signal(SIGPIPE, SIG_IGN);
2018-01-15 15:26:12 +00:00
if (GetBoolArg("catch-crash", false))
setupBacktraceCatcher();
2011-05-14 20:10:21 +02:00
#endif
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 2: parameter interactions
const CChainParams& chainparams = Params();
2014-11-13 15:15:53 +01:00
// also see: InitParameterInteraction()
2014-11-16 03:19:23 -08:00
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
2018-02-12 14:15:24 +01:00
int nUserMaxConnections = GetArg("-maxconnections", Settings::DefaultMaxPeerConnections);
2014-11-16 03:19:23 -08:00
nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
if (nMaxConnections < nUserMaxConnections)
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
2012-05-21 16:47:29 +02:00
// ********************************************************* Step 3: parameter-to-internal-flags
2018-02-12 14:15:24 +01:00
fCheckpointsEnabled = GetBoolArg("-checkpoints", Settings::DefaultCheckpointsEnabled);
2015-11-19 21:48:02 +01:00
// mempool limits
2018-02-12 14:15:24 +01:00
int64_t nMempoolSizeMax = GetArg("-maxmempool", Settings::DefaultMaxMempoolSize) * 1000000;
int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", Settings::DefaultDescendantSizeLimit) * 1000 * 40;
2015-11-19 21:48:02 +01:00
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
2015-11-27 16:44:30 +01:00
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
2013-12-20 11:48:22 +01:00
fServer = GetBoolArg("-server", false);
2015-02-23 14:27:44 -05:00
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
2013-11-29 16:04:29 +01:00
#endif
2011-05-14 20:10:21 +02:00
2018-02-12 14:15:24 +01:00
nConnectTimeout = GetArg("-timeout", Settings::DefaultConnectTimeout);
if (nConnectTimeout <= 0)
2018-02-12 14:15:24 +01:00
nConnectTimeout = Settings::DefaultConnectTimeout;
2012-05-21 16:47:29 +02:00
2013-04-25 20:11:27 -04:00
// Fee-per-kilobyte amount considered the same as "free"
// If you are mining, be careful setting this:
// if you set it to zero then
// a transaction spammer can cheaply fill blocks using
// 1-satoshi-fee transactions. It should be set above the real
// cost to you of processing a transaction.
if (mapArgs.count("-minrelaytxfee"))
{
2021-01-20 19:21:53 +01:00
int64_t n = 0;
2017-08-29 12:41:19 +02:00
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) {
logCritical(Log::Bitcoin) << "Setting min relay Transaction fee to" << n << "satoshi";
2014-07-03 14:25:32 -04:00
::minRelayTxFee = CFeeRate(n);
2017-08-29 12:41:19 +02:00
} else {
2014-01-16 16:15:27 +01:00
return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
2017-08-29 12:41:19 +02:00
}
2013-04-25 20:11:27 -04:00
}
2012-05-21 16:47:29 +02:00
fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard());
#ifdef ENABLE_WALLET
2014-07-03 14:25:32 -04:00
if (mapArgs.count("-mintxfee"))
{
2021-01-20 19:21:53 +01:00
int64_t n = 0;
2014-07-03 14:25:32 -04:00
if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
CWallet::minTxFee = CFeeRate(n);
else
return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
}
2016-01-05 13:10:19 -05:00
if (mapArgs.count("-fallbackfee"))
{
2021-01-20 19:21:53 +01:00
int64_t nFeePerK = 0;
2016-01-05 13:10:19 -05:00
if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK))
return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"]));
if (nFeePerK > nHighTransactionFeeWarning)
InitWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available."));
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
2012-05-21 16:47:29 +02:00
if (mapArgs.count("-paytxfee"))
{
2021-01-20 19:21:53 +01:00
int64_t nFeePerK = 0;
2014-04-10 14:14:18 -04:00
if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
2014-01-16 16:15:27 +01:00
return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"]));
2014-04-10 14:14:18 -04:00
if (nFeePerK > nHighTransactionFeeWarning)
2015-10-22 18:09:19 +02:00
InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
2014-04-10 14:14:18 -04:00
payTxFee = CFeeRate(nFeePerK, 1000);
2014-07-03 14:25:32 -04:00
if (payTxFee < ::minRelayTxFee)
{
return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
2014-07-03 14:25:32 -04:00
mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
}
2012-05-21 16:47:29 +02:00
}
if (mapArgs.count("-maxtxfee"))
{
2021-01-20 19:21:53 +01:00
int64_t nMaxFee = 0;
if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maxtxfee"]));
if (nMaxFee > nHighTransactionMaxFeeWarning)
2015-10-22 18:09:19 +02:00
InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
maxTxFee = nMaxFee;
if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
{
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
}
}
2018-02-12 14:15:24 +01:00
nTxConfirmTarget = GetArg("-txconfirmtarget", Settings::defaultTxConfirmTarget);
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", Settings::DefaultSpendZeroconfChange);
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", Settings::DefaultSendFreeTransactions);
2012-05-21 16:47:29 +02:00
2014-06-05 14:52:07 +02:00
std::string strWalletFile = GetArg("-wallet", "wallet.dat");
#endif // ENABLE_WALLET
2018-02-12 14:15:24 +01:00
fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", Settings::DefaultPermitBareMultisig);
fAcceptDatacarrier = GetBoolArg("-datacarrier", Settings::DefaultAcceptDataCarrier);
2021-03-13 13:47:44 +01:00
nMaxDatacarrierBytes = GetArg("-datacarriersize", Settings::MaxOpReturnRelay);
2015-06-19 10:42:39 -04:00
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
if (GetBoolArg("-peerbloomfilters", true))
nLocalServices |= NODE_BLOOM;
if (GetBoolArg("-use-thinblocks", false))
2016-07-06 21:44:46 +02:00
nLocalServices |= NODE_XTHIN;
if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
if (Policy::blockSizeAcceptLimit() < 8000000)
return InitError("The block size accept limit is too low, the minimum is 8MB. The Hub is shutting down.");
if (GetArg("-blockmaxsize", Settings::DefaultBlockMAxSize) <= 1000000)
return InitError("The maxblocksize mining limit is too low, it should be over 1MB. The Hub is shutting down.");
}
else if (Params().NetworkIDString() == CBaseChainParams::REGTEST) { // setup for testing to not use so much disk space.
UnspentOutputDatabase::setSmallLimits();
}
2018-11-21 12:18:32 +01:00
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, hub log
2014-09-25 09:03:30 +02:00
2015-04-22 14:28:26 -07:00
// Initialize elliptic curve code
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
2015-04-22 14:28:26 -07:00
2018-08-10 10:33:34 +03:00
// Initialize SigCache
InitSignatureCache();
// Sanity check
if (!InitSanityCheck())
2017-11-13 23:09:33 +01:00
return InitError(_("Initialization sanity check failed. The Hub is shutting down."));
2012-05-21 16:47:29 +02:00
std::string strDataDir = GetDataDir().string();
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
// Wallet file must be a plain filename without a directory
if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile))
2014-01-16 16:15:27 +01:00
return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir));
2013-11-29 16:04:29 +01:00
#endif
2012-05-21 16:47:29 +02:00
// Make sure only a single Bitcoin process is using the data directory.
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
try {
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
2017-11-13 23:09:33 +01:00
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. The Hub is probably already running."), strDataDir));
} catch(const boost::interprocess::interprocess_exception& e) {
2017-11-13 23:09:33 +01:00
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. The Hub is probably already running.") + " %s.", strDataDir, e.what()));
}
2014-09-20 10:56:25 +02:00
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
if (GetBoolArg("-shrinkdebugfile", true))
2011-05-14 20:10:21 +02:00
ShrinkDebugFile();
2014-05-01 09:44:45 +02:00
#ifdef ENABLE_WALLET
2017-08-29 11:42:11 +02:00
logCritical(Log::Wallet) << "Using BerkeleyDB version" << DbEnv::version(0, 0, 0);
2014-05-01 09:44:45 +02:00
#endif
2017-08-29 11:42:11 +02:00
logCritical(Log::Bitcoin) << "Startup time:" << DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime());
logCritical(Log::Bitcoin) << "Using data directory" << strDataDir;
logCritical(Log::Bitcoin) << "Using config file" << GetConfigFile().string();
2019-02-03 19:48:56 +01:00
logCritical(Log::Bitcoin) << "Using log-config file" << GetConfigFile("logs.conf").string();
2017-08-29 11:42:11 +02:00
logInfo(Log::Net) << "Using at most" << nMaxConnections << "connections.";
logInfo(Log::Internals) << nFD << "file descriptors available";
2012-05-21 16:47:29 +02:00
std::ostringstream strErrors;
// Start the lightweight task scheduler thread
2019-10-10 16:18:53 +02:00
CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
2014-10-29 18:08:31 +01:00
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
* that the server is there and will be ready later). Warmup mode will
* be disabled when initialisation is finished.
*/
if (fServer)
{
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
2017-02-21 13:44:48 +01:00
if (!AppInitServers())
2018-11-21 12:18:32 +01:00
return InitError(_("Unable to start HTTP server. See hub log for details."));
2014-10-29 18:08:31 +01:00
}
Application::instance()->validation()->enableFeeResolveForMetaData(GetBoolArg("-feesmetadata", false));
2018-01-15 15:26:12 +00:00
Application::instance()->validation()->setMempool(&mempool);
2019-09-02 23:28:14 +02:00
scheduler.scheduleEvery(std::bind(&DoubleSpendProofStorage::periodicCleanup, mempool.doubleSpendProofStorage()), 60);
2016-08-16 16:51:22 +02:00
2013-01-11 23:18:00 +01:00
// ********************************************************* Step 5: verify wallet database integrity
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
if (!fDisableWallet) {
2017-08-29 11:42:11 +02:00
logCritical(Log::Wallet) << "Using wallet" << strWalletFile;
uiInterface.InitMessage(_("Verifying wallet..."));
2012-09-18 14:30:47 -04:00
std::string warningString;
std::string errorString;
2015-05-31 15:36:44 +02:00
if (!CWallet::Verify(strWalletFile, warningString, errorString))
return false;
2015-05-31 15:36:44 +02:00
if (!warningString.empty())
InitWarning(warningString);
if (!errorString.empty())
2015-09-11 23:31:30 +02:00
return InitError(errorString);
2015-05-31 15:36:44 +02:00
} // (!fDisableWallet)
2013-11-29 16:04:29 +01:00
#endif // ENABLE_WALLET
2012-05-21 16:47:29 +02:00
2017-02-08 17:17:38 +01:00
2017-08-03 10:38:01 +02:00
// ********************************************************* Step 6: load block chain
2011-05-14 20:10:21 +02:00
2017-02-21 13:44:48 +01:00
bool fReindex = GetBoolArg("-reindex", false);
2013-02-16 17:58:45 +01:00
bool fLoaded = false;
2017-08-29 11:42:11 +02:00
int64_t nStart;
2013-02-16 17:58:45 +01:00
while (!fLoaded) {
bool fReset = fReindex;
std::string strLoadError;
2013-02-16 17:58:45 +01:00
uiInterface.InitMessage(_("Loading block index..."));
2012-07-06 16:33:34 +02:00
2013-02-16 17:58:45 +01:00
nStart = GetTimeMillis();
do {
try {
UnloadBlockIndex();
delete g_utxo;
g_utxo = nullptr;
2019-04-22 20:33:35 +02:00
Blocks::DB::createInstance(40 << 20, fReindex, &scheduler);
const auto utxoDir = GetDataDir() / "unspent";
if (fReindex) {
boost::system::error_code error;
// delete all files under unspent. Don't delete itself, it may be a symlink.
boost::filesystem::directory_iterator iter(utxoDir, error);
while (!error && iter != boost::filesystem::directory_iterator()) {
boost::filesystem::remove_all(*iter, error);
++iter;
}
if (error) {
// then try to delete the utxo dir itself.
boost::filesystem::remove_all(utxoDir, error);
if (error) {
fRequestShutdown = true;
logFatal(Log::Bitcoin) << "Can't remove the unspent dir to do a reindex" << error.message();
break;
}
}
}
g_utxo = new UnspentOutputDatabase(Application::instance()->ioService(), utxoDir);
mempool.setUtxo(g_utxo);
2019-02-25 18:40:33 +01:00
if (fReindex)
2018-01-15 15:26:12 +00:00
Blocks::DB::instance()->setReindexing(Blocks::ScanningFiles);
2020-02-27 13:35:56 +01:00
if (!fReindex && !LoadBlockIndexDB(g_utxo)) {
2013-02-16 17:58:45 +01:00
strLoadError = _("Error loading block database");
break;
}
Application::instance()->validation()->setBlockchain(&chainActive);
2020-02-27 14:48:54 +01:00
while (!fReindex) {
auto tip = Blocks::Index::get(g_utxo->blockId());
// now lets see if the utxo and the block-database like each other
2020-02-27 14:48:54 +01:00
if (tip) {
chainActive.SetTip(tip);
pindexBestHeader = tip;
2020-09-11 13:11:21 +02:00
// Set the chain again after it received a Tip()
Application::instance()->validation()->setBlockchain(&chainActive);
// verify basics
if (!VerifyDB().verifyDB(GetArg("-checklevel", Settings::DefaultCheckLevel),
GetArg("-checkblocks", Settings::DefaultCheckBlocks))) {
// verify failed, go to an older state.
tip = nullptr;
}
} else if (g_utxo->blockId().IsNull()) { // first start.
break;
} else {
logCritical(Log::Bitcoin) << "UTXO has tip which we don't have in the block-index. UTXO best block:"
<< g_utxo->blockId() << g_utxo->blockheight();
}
if (tip) { // yes, lets go!
2020-02-27 14:48:54 +01:00
logCritical(Log::Bitcoin) << "LoadBlockIndexDB: hashBestChain:" << tip->GetBlockHash()
<< "height:" << tip->nHeight
<< "nTx:" << tip->nChainTx
<< "date:" << DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime()).c_str()
<< "header height:" << Blocks::DB::instance()->headerChain().Height();
break;
} else {
// they don't like each other. Try an older UTXO state.
if (!g_utxo->loadOlderState()) {
fRequestShutdown = true;
break;
}
}
}
if (fRequestShutdown)
break;
2017-02-21 13:44:48 +01:00
// Check whether we need to continue reindexing
2018-01-15 15:26:12 +00:00
fReindex = fReindex || Blocks::DB::instance()->reindexing() != Blocks::NoReindex;
2013-01-03 15:29:07 +01:00
2013-05-12 12:03:32 +02:00
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
2018-01-15 15:26:12 +00:00
if (!Blocks::Index::empty() && !Blocks::Index::exists(chainparams.GetConsensus().hashGenesisBlock))
2013-05-12 12:03:32 +02:00
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
2013-02-16 17:58:45 +01:00
// Initialize the block index (no-op if non-empty database was already loaded)
if (!InitBlockIndex(chainparams)) {
2013-02-16 17:58:45 +01:00
strLoadError = _("Error initializing block database");
break;
}
2013-02-23 23:48:02 +01:00
uiInterface.InitMessage(_("Verifying blocks..."));
{
LOCK(cs_main);
CBlockIndex* tip = chainActive.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");
break;
}
}
scheduler.scheduleEvery(std::bind(&UnspentOutputDatabase::saveCaches, g_utxo), 5 * 60);
2014-12-07 13:29:06 +01:00
} catch (const std::exception& e) {
2017-08-03 12:25:46 +02:00
logWarning() << e;
2013-02-16 17:58:45 +01:00
strLoadError = _("Error opening block database");
break;
}
fLoaded = true;
} while(false);
2017-08-02 16:11:30 +02:00
if (fRequestShutdown)
break;
2013-02-16 17:58:45 +01:00
if (!fLoaded) {
// first suggest a reindex
if (!fReset) {
bool fRet = uiInterface.ThreadSafeMessageBox(
strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?"),
2013-02-16 17:58:45 +01:00
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
if (fRet) {
fReindex = true;
2018-01-15 15:26:12 +00:00
Blocks::DB::instance()->setReindexing(Blocks::ScanningFiles);
2013-02-16 17:58:45 +01:00
fRequestShutdown = false;
} else {
2017-08-29 11:42:11 +02:00
logFatal(Log::Bitcoin) << "Aborted block database rebuild. Exiting.";
2013-02-16 17:58:45 +01:00
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 (fRequestShutdown)
{
2017-08-29 11:42:11 +02:00
logFatal(Log::Bitcoin) << "Shutdown requested. Exiting.";
return false;
}
2017-08-29 11:42:11 +02:00
logInfo(Log::Bench).nospace() << "block index load took: " << GetTimeMillis() - nStart << "ms";
2011-05-14 20:10:21 +02:00
if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { // For non-testing setups, keep tracks of disk-space free stats.
auto &dsc = Application::instance()->diskSpaceChecker();
if (!dsc.enoughSpaceAvailable())
return InitError("Not enough disk space available to safely start");
dsc.start(); // keep checking
}
2017-08-03 10:38:01 +02:00
// ********************************************************* Step 7: network initialization
2018-02-12 14:15:24 +01:00
CTxOrphanCache::instance()->setLimit((unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", Settings::DefaultMaxOrphanTransactions)));
2017-08-03 10:38:01 +02:00
RegisterNodeSignals(GetNodeSignals());
if (mapArgs.count("-onlynet")) {
std::set<CNetAddr::Network> nets;
2018-12-30 15:33:11 +01:00
for (const std::string& snet : mapMultiArgs["-onlynet"]) {
2017-08-03 10:38:01 +02:00
CNetAddr::Network net = ParseNetwork(snet);
if (net == CNetAddr::NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
nets.insert(net);
}
for (int n = 0; n < CNetAddr::NET_MAX; n++) {
CNetAddr::Network net = (CNetAddr::Network)n;
if (!nets.count(net))
SetLimited(net);
}
}
if (mapArgs.count("-whitelist")) {
2018-12-30 15:33:11 +01:00
for (const std::string& net : mapMultiArgs["-whitelist"]) {
2017-08-03 10:38:01 +02:00
CSubNet subnet(net);
if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
CNode::AddWhitelistedRange(subnet);
}
}
2018-02-12 14:15:24 +01:00
bool proxyRandomize = GetBoolArg("-proxyrandomize", Settings::DefaultProxyRandomize);
2017-08-03 10:38:01 +02:00
// -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 = GetArg("-proxy", "");
SetLimited(CNetAddr::NET_TOR);
if (proxyArg != "" && proxyArg != "0") {
proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg));
SetProxy(CNetAddr::NET_IPV4, addrProxy);
SetProxy(CNetAddr::NET_IPV6, addrProxy);
SetProxy(CNetAddr::NET_TOR, addrProxy);
SetNameProxy(addrProxy);
SetLimited(CNetAddr::NET_TOR, false); // by default, -proxy sets onion as reachable, unless -noonion later
}
// -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 = GetArg("-onion", "");
if (onionArg != "") {
if (onionArg == "0") { // Handle -noonion/-onion=0
SetLimited(CNetAddr::NET_TOR); // set onions as unreachable
} else {
proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg));
SetProxy(CNetAddr::NET_TOR, addrOnion);
SetLimited(CNetAddr::NET_TOR, false);
}
}
// see Step 2: parameter interactions for more information about these
fListen = GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = GetBoolArg("-discover", true);
2018-02-12 14:15:24 +01:00
fNameLookup = GetBoolArg("-dns", Settings::DefaultNameLookup);
2017-08-03 10:38:01 +02:00
bool fBound = false;
if (fListen) {
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
2018-12-30 15:33:11 +01:00
for (const std::string& strBind : mapMultiArgs["-bind"]) {
2017-08-03 10:38:01 +02:00
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
2018-12-30 15:33:11 +01:00
for (const std::string& strBind : mapMultiArgs["-whitebind"]) {
2017-08-03 10:38:01 +02:00
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false))
return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
}
}
else {
struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY;
fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
}
if (!fBound)
return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
}
if (mapArgs.count("-externalip")) {
2018-12-30 15:33:11 +01:00
for (const std::string& strAddr : mapMultiArgs["-externalip"]) {
2017-08-03 10:38:01 +02:00
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr));
AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
}
}
2018-12-30 15:33:11 +01:00
for (const std::string& strDest : mapMultiArgs["-seednode"])
2017-08-03 10:38:01 +02:00
AddOneShot(strDest);
#if ENABLE_ZMQ
pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
if (pzmqNotificationInterface) {
2018-02-15 18:06:38 +01:00
ValidationNotifier().addListener(pzmqNotificationInterface);
2017-08-03 10:38:01 +02:00
}
#endif
if (mapArgs.count("-maxuploadtarget")) {
2018-02-12 14:15:24 +01:00
CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", Settings::DefaultMaxUploadTarget)*1024*1024);
2017-08-03 10:38:01 +02:00
}
2012-09-18 14:30:47 -04:00
// ********************************************************* Step 8: load wallet
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
if (fDisableWallet) {
pwalletMain = NULL;
2017-08-29 11:42:11 +02:00
logInfo(Log::Wallet) << "Wallet disabled!";
} else {
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
if (GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
pwalletMain = new CWallet(strWalletFile);
DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
return false;
}
delete pwalletMain;
pwalletMain = NULL;
}
uiInterface.InitMessage(_("Loading wallet..."));
2011-05-14 20:10:21 +02:00
nStart = GetTimeMillis();
bool fFirstRun = true;
pwalletMain = new CWallet(strWalletFile);
DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
{
2015-10-22 18:09:19 +02:00
InitWarning(_("Error reading wallet.dat! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."));
}
else if (nLoadWalletRet == DB_TOO_NEW)
2017-11-13 23:09:33 +01:00
strErrors << _("Error loading wallet.dat: Wallet requires newer version of The Hub") << "\n";
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
2017-11-13 23:09:33 +01:00
strErrors << _("Wallet needed to be rewritten: restart The Hub to complete") << "\n";
2017-08-29 11:42:11 +02:00
logFatal(Log::Wallet) << strErrors.str();
return InitError(strErrors.str());
}
else
strErrors << _("Error loading wallet.dat") << "\n";
}
2017-11-15 11:22:32 +01:00
if (fFirstRun) {
pwalletMain->SetMinVersion(FEATURE_LATEST);
// Create new keyUser and set as default key
RandAddSeedPerfmon();
CPubKey newDefaultKey;
if (pwalletMain->GetKeyFromPool(newDefaultKey)) {
pwalletMain->SetDefaultKey(newDefaultKey);
2021-04-19 11:58:00 +02:00
if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.getKeyId(), "", "receive"))
strErrors << _("Cannot write default address") << "\n";
}
2021-02-18 16:03:01 +01:00
pwalletMain->setBestChain(chainActive.GetLocator());
}
2017-08-29 11:42:11 +02:00
if (!strErrors.str().empty())
logFatal(Log::Wallet) << strErrors.str();
logInfo(Log::Wallet).nospace() << "wallet load took: " << GetTimeMillis() - nStart << "ms";
2018-02-15 18:06:38 +01:00
ValidationNotifier().addListener(pwalletMain);
CBlockIndex *pindexRescan = chainActive.Tip();
2017-08-29 11:42:11 +02:00
if (GetBoolArg("-rescan", false)) {
pindexRescan = chainActive.Genesis();
2017-08-29 11:42:11 +02:00
} else {
CWalletDB walletdb(strWalletFile);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
2014-09-03 02:52:01 +02:00
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
else
pindexRescan = chainActive.Genesis();
}
2017-08-29 11:42:11 +02:00
if (chainActive.Tip() && chainActive.Tip() != pindexRescan) {
uiInterface.InitMessage(_("Rescanning..."));
2017-08-29 11:42:11 +02:00
logCritical(Log::Bitcoin) << "Rescanning last" << chainActive.Height() - pindexRescan->nHeight << "blocks. (from block"
<< pindexRescan->nHeight << ")...";
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
2017-08-29 11:42:11 +02:00
logInfo(Log::Bench).nospace() << "rescan took: " << GetTimeMillis() - nStart << "ms";
2021-02-18 16:03:01 +01:00
pwalletMain->setBestChain(chainActive.GetLocator());
nWalletDBUpdated++;
// Restore wallet transaction metadata after -zapwallettxes=1
2017-08-29 11:42:11 +02:00
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") {
CWalletDB walletdb(strWalletFile);
2018-12-30 15:33:11 +01:00
for (const CWalletTx& wtxOld : vWtx) {
uint256 hash = wtxOld.GetHash();
auto mi = pwalletMain->mapWallet.find(hash);
2017-08-29 11:42:11 +02:00
if (mi != pwalletMain->mapWallet.end()) {
const CWalletTx* copyFrom = &wtxOld;
CWalletTx* copyTo = &mi->second;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
copyTo->nTimeReceived = copyFrom->nTimeReceived;
copyTo->nTimeSmart = copyFrom->nTimeSmart;
copyTo->fFromMe = copyFrom->fFromMe;
copyTo->strFromAccount = copyFrom->strFromAccount;
copyTo->nOrderPos = copyFrom->nOrderPos;
copyTo->WriteToDisk(&walletdb);
}
}
}
}
2018-02-12 14:15:24 +01:00
pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", Settings::DefaultWalletBroadcast));
} // (!fDisableWallet)
2013-11-29 16:04:29 +01:00
#else // ENABLE_WALLET
2018-03-19 22:41:13 +01:00
logDebug(Log::Wallet) << "No wallet support compiled in!";
2013-11-29 16:04:29 +01:00
#endif // !ENABLE_WALLET
2019-04-22 19:47:07 +02:00
// ********************************************************* Step 9: import blocks
2012-05-21 16:47:29 +02:00
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
Blocks::DB::startBlockImporter();
2017-08-29 11:42:11 +02:00
if (chainActive.Tip() == nullptr) {
2017-08-31 10:21:09 +02:00
logDebug(Log::Bitcoin) << "Waiting for genesis block to be imported...";
2017-08-29 11:42:11 +02:00
while (!fRequestShutdown && chainActive.Tip() == nullptr)
MilliSleep(10);
}
2018-09-15 22:12:16 +02:00
Application::instance()->validation()->start();
2019-04-22 19:47:07 +02:00
// ********************************************************* Step 10: start node
2012-05-21 16:47:29 +02:00
if (!CheckDiskSpace())
return false;
2013-05-02 12:26:33 -04:00
if (!strErrors.str().empty())
return InitError(strErrors.str());
2012-05-21 16:47:29 +02:00
RandAddSeedPerfmon();
2011-05-14 20:10:21 +02:00
//// debug print
2018-01-15 15:26:12 +00:00
logDebug(Log::DB) << "mapBlockIndex.size() =" << Blocks::Index::size();
2017-08-29 11:42:11 +02:00
logDebug(Log::BlockValidation) << "nBestHeight =" << chainActive.Height();
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
2017-08-29 11:42:11 +02:00
logDebug(Log::Wallet) << "setKeyPool.size() =" << (pwalletMain ? pwalletMain->setKeyPool.size() : 0);
logDebug(Log::Wallet) << "mapWallet.size() =" << (pwalletMain ? pwalletMain->mapWallet.size() : 0);
logDebug(Log::Wallet) << "mapAddressBook.size() =" << (pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
2013-11-29 16:04:29 +01:00
#endif
2011-05-14 20:10:21 +02:00
2018-02-12 14:15:24 +01:00
if (GetBoolArg("-listenonion", Settings::DefaultListenOnion))
StartTorControl(threadGroup, scheduler);
2015-04-02 12:04:59 -04:00
StartNode(threadGroup, scheduler);
2011-05-14 20:10:21 +02:00
// Monitor the chain, and alert if we get blocks much quicker or slower than expected
2020-07-31 16:03:15 +02:00
const int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing;
scheduler.scheduleEvery(std::bind(&Blocks::DB::partitionCheck, Blocks::DB::instance(), nPowTargetSpacing), nPowTargetSpacing);
// Generate coins in the background
2016-10-28 13:52:37 +02:00
try {
2018-02-12 14:15:24 +01:00
Mining::GenerateBitcoins(GetBoolArg("-gen", Settings::DefaultGenerateCoins), GetArg("-genproclimit", Settings::DefaultGenerateThreads),
2016-10-28 13:52:37 +02:00
chainparams, GetArg("-gencoinbase", ""));
} catch (const std::exception &e) {
2017-08-29 11:42:11 +02:00
logCritical(Log::Bitcoin) << "Mining could not be activated. Reason: %s" << e.what();
2016-10-28 13:52:37 +02:00
}
2019-04-22 19:47:07 +02:00
// ********************************************************* Step 11: finished
2012-05-21 16:47:29 +02:00
2014-10-29 18:08:31 +01:00
SetRPCWarmupFinished();
2012-05-21 16:47:29 +02:00
uiInterface.InitMessage(_("Done loading"));
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
if (pwalletMain) {
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain->ReacceptWalletTransactions();
2012-05-21 16:47:29 +02:00
// Run a thread to flush wallet periodically
2019-10-10 16:18:53 +02:00
threadGroup.create_thread(std::bind(&ThreadFlushWalletDB, std::ref(pwalletMain->strWalletFile)));
}
2013-11-29 16:04:29 +01:00
#endif
2011-05-14 20:10:21 +02:00
2013-03-09 12:02:57 -05:00
return !fRequestShutdown;
2011-05-14 20:10:21 +02:00
}