Changeset View
Changeset View
Standalone View
Standalone View
src/init.cpp
Show First 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | NODISCARD static bool CreatePidFile() { | ||||
if (file) { | if (file) { | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
tfm::format(file, "%d\n", GetCurrentProcessId()); | tfm::format(file, "%d\n", GetCurrentProcessId()); | ||||
#else | #else | ||||
tfm::format(file, "%d\n", getpid()); | tfm::format(file, "%d\n", getpid()); | ||||
#endif | #endif | ||||
return true; | return true; | ||||
} else { | } else { | ||||
return InitError(strprintf(_("Unable to create the PID file '%s': %s"), | return InitError( | ||||
GetPidFile().string(), | strprintf(_("Unable to create the PID file '%s': %s").translated, | ||||
std::strerror(errno))); | GetPidFile().string(), std::strerror(errno))); | ||||
} | } | ||||
} | } | ||||
////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||
// | // | ||||
// Shutdown | // Shutdown | ||||
// | // | ||||
Show All 23 Lines | |||||
public: | public: | ||||
explicit CCoinsViewErrorCatcher(CCoinsView *view) | explicit CCoinsViewErrorCatcher(CCoinsView *view) | ||||
: CCoinsViewBacked(view) {} | : CCoinsViewBacked(view) {} | ||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override { | bool GetCoin(const COutPoint &outpoint, Coin &coin) const override { | ||||
try { | try { | ||||
return CCoinsViewBacked::GetCoin(outpoint, coin); | return CCoinsViewBacked::GetCoin(outpoint, coin); | ||||
} catch (const std::runtime_error &e) { | } catch (const std::runtime_error &e) { | ||||
uiInterface.ThreadSafeMessageBox( | uiInterface.ThreadSafeMessageBox( | ||||
_("Error reading from database, shutting down."), "", | _("Error reading from database, shutting down.").translated, "", | ||||
CClientUIInterface::MSG_ERROR); | CClientUIInterface::MSG_ERROR); | ||||
LogPrintf("Error reading from database: %s\n", e.what()); | LogPrintf("Error reading from database: %s\n", e.what()); | ||||
// Starting the shutdown sequence and returning false to the caller | // Starting the shutdown sequence and returning false to the caller | ||||
// would be interpreted as 'entry not found' (as opposed to unable | // would be interpreted as 'entry not found' (as opposed to unable | ||||
// to read data), and could lead to invalid interpretation. Just | // to read data), and could lead to invalid interpretation. Just | ||||
// exit immediately, as we can't continue anyway, and all writes | // exit immediately, as we can't continue anyway, and all writes | ||||
// should be atomic. | // should be atomic. | ||||
abort(); | abort(); | ||||
▲ Show 20 Lines • Show All 965 Lines • ▼ Show 20 Lines | #endif | ||||
gArgs.AddHiddenArgs(hidden_args); | gArgs.AddHiddenArgs(hidden_args); | ||||
} | } | ||||
std::string LicenseInfo() { | std::string LicenseInfo() { | ||||
const std::string URL_SOURCE_CODE = | const std::string URL_SOURCE_CODE = | ||||
"<https://github.com/Bitcoin-ABC/bitcoin-abc>"; | "<https://github.com/Bitcoin-ABC/bitcoin-abc>"; | ||||
const std::string URL_WEBSITE = "<https://www.bitcoinabc.org>"; | const std::string URL_WEBSITE = "<https://www.bitcoinabc.org>"; | ||||
return CopyrightHolders( | return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009, | ||||
strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + | COPYRIGHT_YEAR) + | ||||
" ") + | " ") + | ||||
"\n" + "\n" + | "\n" + "\n" + | ||||
strprintf(_("Please contribute if you find %s useful. " | strprintf(_("Please contribute if you find %s useful. " | ||||
"Visit %s for further information about the software."), | "Visit %s for further information about the software.") | ||||
.translated, | |||||
PACKAGE_NAME, URL_WEBSITE) + | PACKAGE_NAME, URL_WEBSITE) + | ||||
"\n" + | "\n" + | ||||
strprintf(_("The source code is available from %s."), | strprintf(_("The source code is available from %s.").translated, | ||||
URL_SOURCE_CODE) + | URL_SOURCE_CODE) + | ||||
"\n" + "\n" + _("This is experimental software.") + "\n" + | "\n" + "\n" + _("This is experimental software.").translated + "\n" + | ||||
strprintf(_("Distributed under the MIT software license, see the " | strprintf(_("Distributed under the MIT software license, see the " | ||||
"accompanying file %s or %s"), | "accompanying file %s or %s") | ||||
.translated, | |||||
"COPYING", "<https://opensource.org/licenses/MIT>") + | "COPYING", "<https://opensource.org/licenses/MIT>") + | ||||
"\n" + "\n" + | "\n" + "\n" + | ||||
strprintf(_("This product includes software developed by the " | strprintf(_("This product includes software developed by the " | ||||
"OpenSSL Project for use in the OpenSSL Toolkit %s and " | "OpenSSL Project for use in the OpenSSL Toolkit %s and " | ||||
"cryptographic software written by Eric Young and UPnP " | "cryptographic software written by Eric Young and UPnP " | ||||
"software written by Thomas Bernard."), | "software written by Thomas Bernard.") | ||||
.translated, | |||||
"<https://www.openssl.org>") + | "<https://www.openssl.org>") + | ||||
"\n"; | "\n"; | ||||
} | } | ||||
static void BlockNotifyCallback(bool initialSync, | static void BlockNotifyCallback(bool initialSync, | ||||
const CBlockIndex *pBlockIndex) { | const CBlockIndex *pBlockIndex) { | ||||
if (initialSync || !pBlockIndex) { | if (initialSync || !pBlockIndex) { | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { | ||||
"setting -whitelistrelay=1\n", | "setting -whitelistrelay=1\n", | ||||
__func__); | __func__); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static std::string ResolveErrMsg(const char *const optname, | static std::string ResolveErrMsg(const char *const optname, | ||||
const std::string &strBind) { | const std::string &strBind) { | ||||
return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); | return strprintf(_("Cannot resolve -%s address: '%s'").translated, optname, | ||||
strBind); | |||||
} | } | ||||
/** | /** | ||||
* Initialize global loggers. | * Initialize global loggers. | ||||
* | * | ||||
* Note that this is called very early in the process lifetime, so you should be | * Note that this is called very early in the process lifetime, so you should be | ||||
* careful about what global state you rely on here. | * careful about what global state you rely on here. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | bool AppInitParameterInteraction(Config &config) { | ||||
// also see: InitParameterInteraction() | // also see: InitParameterInteraction() | ||||
// Warn if network-specific options (-addnode, -connect, etc) are | // Warn if network-specific options (-addnode, -connect, etc) are | ||||
// specified in default section of config file, but not overridden | // specified in default section of config file, but not overridden | ||||
// on the command line or in this network's section of the config file. | // on the command line or in this network's section of the config file. | ||||
std::string network = gArgs.GetChainName(); | std::string network = gArgs.GetChainName(); | ||||
for (const auto &arg : gArgs.GetUnsuitableSectionOnlyArgs()) { | for (const auto &arg : gArgs.GetUnsuitableSectionOnlyArgs()) { | ||||
return InitError(strprintf(_("Config setting for %s only applied on %s " | return InitError(strprintf(_("Config setting for %s only applied on %s " | ||||
"network when in [%s] section."), | "network when in [%s] section.") | ||||
.translated, | |||||
arg, network, network)); | arg, network, network)); | ||||
} | } | ||||
// Warn if unrecognized section name are present in the config file. | // Warn if unrecognized section name are present in the config file. | ||||
for (const auto §ion : gArgs.GetUnrecognizedSections()) { | for (const auto §ion : gArgs.GetUnrecognizedSections()) { | ||||
InitWarning(strprintf("%s:%i " + _("Section [%s] is not recognized."), | InitWarning(strprintf( | ||||
"%s:%i " + _("Section [%s] is not recognized.").translated, | |||||
section.m_file, section.m_line, section.m_name)); | section.m_file, section.m_line, section.m_name)); | ||||
} | } | ||||
if (!fs::is_directory(GetBlocksDir())) { | if (!fs::is_directory(GetBlocksDir())) { | ||||
return InitError( | return InitError(strprintf( | ||||
strprintf(_("Specified blocks directory \"%s\" does not exist."), | _("Specified blocks directory \"%s\" does not exist.").translated, | ||||
gArgs.GetArg("-blocksdir", ""))); | gArgs.GetArg("-blocksdir", ""))); | ||||
} | } | ||||
// if using block pruning, then disallow txindex | // if using block pruning, then disallow txindex | ||||
if (gArgs.GetArg("-prune", 0)) { | if (gArgs.GetArg("-prune", 0)) { | ||||
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { | if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { | ||||
return InitError(_("Prune mode is incompatible with -txindex.")); | return InitError( | ||||
_("Prune mode is incompatible with -txindex.").translated); | |||||
} | } | ||||
} | } | ||||
// -bind and -whitebind can't be set when not listening | // -bind and -whitebind can't be set when not listening | ||||
size_t nUserBind = | size_t nUserBind = | ||||
gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size(); | gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size(); | ||||
if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) { | if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) { | ||||
return InitError( | return InitError( | ||||
Show All 10 Lines | bool AppInitParameterInteraction(Config &config) { | ||||
nMaxConnections = | nMaxConnections = | ||||
std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - | std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - | ||||
MIN_CORE_FILEDESCRIPTORS - | MIN_CORE_FILEDESCRIPTORS - | ||||
MAX_ADDNODE_CONNECTIONS), | MAX_ADDNODE_CONNECTIONS), | ||||
0); | 0); | ||||
nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + | nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + | ||||
MAX_ADDNODE_CONNECTIONS); | MAX_ADDNODE_CONNECTIONS); | ||||
if (nFD < MIN_CORE_FILEDESCRIPTORS) { | if (nFD < MIN_CORE_FILEDESCRIPTORS) { | ||||
return InitError(_("Not enough file descriptors available.")); | return InitError( | ||||
_("Not enough file descriptors available.").translated); | |||||
} | } | ||||
nMaxConnections = | nMaxConnections = | ||||
std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, | std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, | ||||
nMaxConnections); | nMaxConnections); | ||||
if (nMaxConnections < nUserMaxConnections) { | if (nMaxConnections < nUserMaxConnections) { | ||||
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, " | InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, " | ||||
"because of system limitations."), | "because of system limitations.") | ||||
.translated, | |||||
nUserMaxConnections, nMaxConnections)); | nUserMaxConnections, nMaxConnections)); | ||||
} | } | ||||
// Step 3: parameter-to-internal-flags | // Step 3: parameter-to-internal-flags | ||||
if (gArgs.IsArgSet("-debug")) { | if (gArgs.IsArgSet("-debug")) { | ||||
// Special-case: if -debug=0/-nodebug is set, turn off debugging | // Special-case: if -debug=0/-nodebug is set, turn off debugging | ||||
// messages | // messages | ||||
const std::vector<std::string> &categories = gArgs.GetArgs("-debug"); | const std::vector<std::string> &categories = gArgs.GetArgs("-debug"); | ||||
if (std::none_of( | if (std::none_of( | ||||
categories.begin(), categories.end(), | categories.begin(), categories.end(), | ||||
[](std::string cat) { return cat == "0" || cat == "none"; })) { | [](std::string cat) { return cat == "0" || cat == "none"; })) { | ||||
for (const auto &cat : categories) { | for (const auto &cat : categories) { | ||||
if (!LogInstance().EnableCategory(cat)) { | if (!LogInstance().EnableCategory(cat)) { | ||||
InitWarning( | InitWarning(strprintf( | ||||
strprintf(_("Unsupported logging category %s=%s."), | _("Unsupported logging category %s=%s.").translated, | ||||
"-debug", cat)); | "-debug", cat)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Now remove the logging categories which were explicitly excluded | // Now remove the logging categories which were explicitly excluded | ||||
for (const std::string &cat : gArgs.GetArgs("-debugexclude")) { | for (const std::string &cat : gArgs.GetArgs("-debugexclude")) { | ||||
if (!LogInstance().DisableCategory(cat)) { | if (!LogInstance().DisableCategory(cat)) { | ||||
InitWarning(strprintf(_("Unsupported logging category %s=%s."), | InitWarning( | ||||
strprintf(_("Unsupported logging category %s=%s.").translated, | |||||
"-debugexclude", cat)); | "-debugexclude", cat)); | ||||
} | } | ||||
} | } | ||||
// Checkmempool and checkblockindex default to true in regtest mode | // Checkmempool and checkblockindex default to true in regtest mode | ||||
int ratio = std::min<int>( | int ratio = std::min<int>( | ||||
std::max<int>( | std::max<int>( | ||||
gArgs.GetArg("-checkmempool", | gArgs.GetArg("-checkmempool", | ||||
chainparams.DefaultConsistencyChecks() ? 1 : 0), | chainparams.DefaultConsistencyChecks() ? 1 : 0), | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | bool AppInitParameterInteraction(Config &config) { | ||||
// mempool limits | // mempool limits | ||||
int64_t nMempoolSizeMax = | int64_t nMempoolSizeMax = | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | ||||
int64_t nMempoolSizeMin = | int64_t nMempoolSizeMin = | ||||
gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * | gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * | ||||
1000 * 40; | 1000 * 40; | ||||
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) { | if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) { | ||||
return InitError(strprintf(_("-maxmempool must be at least %d MB"), | return InitError( | ||||
strprintf(_("-maxmempool must be at least %d MB").translated, | |||||
std::ceil(nMempoolSizeMin / 1000000.0))); | std::ceil(nMempoolSizeMin / 1000000.0))); | ||||
} | } | ||||
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency | // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency | ||||
nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); | nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); | ||||
if (nScriptCheckThreads <= 0) { | if (nScriptCheckThreads <= 0) { | ||||
nScriptCheckThreads += GetNumCores(); | nScriptCheckThreads += GetNumCores(); | ||||
} | } | ||||
if (nScriptCheckThreads <= 1) { | if (nScriptCheckThreads <= 1) { | ||||
nScriptCheckThreads = 0; | nScriptCheckThreads = 0; | ||||
} else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) { | } else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) { | ||||
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; | nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; | ||||
} | } | ||||
// Configure excessive block size. | // Configure excessive block size. | ||||
const uint64_t nProposedExcessiveBlockSize = | const uint64_t nProposedExcessiveBlockSize = | ||||
gArgs.GetArg("-excessiveblocksize", DEFAULT_MAX_BLOCK_SIZE); | gArgs.GetArg("-excessiveblocksize", DEFAULT_MAX_BLOCK_SIZE); | ||||
if (!config.SetMaxBlockSize(nProposedExcessiveBlockSize)) { | if (!config.SetMaxBlockSize(nProposedExcessiveBlockSize)) { | ||||
return InitError( | return InitError( | ||||
_("Excessive block size must be > 1,000,000 bytes (1MB)")); | _("Excessive block size must be > 1,000,000 bytes (1MB)") | ||||
.translated); | |||||
} | } | ||||
// Check blockmaxsize does not exceed maximum accepted block size. | // Check blockmaxsize does not exceed maximum accepted block size. | ||||
const uint64_t nProposedMaxGeneratedBlockSize = | const uint64_t nProposedMaxGeneratedBlockSize = | ||||
gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE); | gArgs.GetArg("-blockmaxsize", DEFAULT_MAX_GENERATED_BLOCK_SIZE); | ||||
if (nProposedMaxGeneratedBlockSize > config.GetMaxBlockSize()) { | if (nProposedMaxGeneratedBlockSize > config.GetMaxBlockSize()) { | ||||
auto msg = _("Max generated block size (blockmaxsize) cannot exceed " | auto msg = _("Max generated block size (blockmaxsize) cannot exceed " | ||||
"the excessive block size (excessiveblocksize)"); | "the excessive block size (excessiveblocksize)") | ||||
.translated; | |||||
return InitError(msg); | return InitError(msg); | ||||
} | } | ||||
// block pruning; get the amount of disk space (in MiB) to allot for block & | // block pruning; get the amount of disk space (in MiB) to allot for block & | ||||
// undo files | // undo files | ||||
int64_t nPruneArg = gArgs.GetArg("-prune", 0); | int64_t nPruneArg = gArgs.GetArg("-prune", 0); | ||||
if (nPruneArg < 0) { | if (nPruneArg < 0) { | ||||
return InitError( | return InitError( | ||||
_("Prune cannot be configured with a negative value.")); | _("Prune cannot be configured with a negative value.").translated); | ||||
} | } | ||||
nPruneTarget = (uint64_t)nPruneArg * 1024 * 1024; | nPruneTarget = (uint64_t)nPruneArg * 1024 * 1024; | ||||
if (nPruneArg == 1) { | if (nPruneArg == 1) { | ||||
// manual pruning: -prune=1 | // manual pruning: -prune=1 | ||||
LogPrintf("Block pruning enabled. Use RPC call " | LogPrintf("Block pruning enabled. Use RPC call " | ||||
"pruneblockchain(height) to manually prune block and undo " | "pruneblockchain(height) to manually prune block and undo " | ||||
"files.\n"); | "files.\n"); | ||||
nPruneTarget = std::numeric_limits<uint64_t>::max(); | nPruneTarget = std::numeric_limits<uint64_t>::max(); | ||||
fPruneMode = true; | fPruneMode = true; | ||||
} else if (nPruneTarget) { | } else if (nPruneTarget) { | ||||
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { | if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { | ||||
return InitError( | return InitError( | ||||
strprintf(_("Prune configured below the minimum of %d MiB. " | strprintf(_("Prune configured below the minimum of %d MiB. " | ||||
"Please use a higher number."), | "Please use a higher number.") | ||||
.translated, | |||||
MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); | MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); | ||||
} | } | ||||
LogPrintf("Prune configured to target %uMiB on disk for block and undo " | LogPrintf("Prune configured to target %uMiB on disk for block and undo " | ||||
"files.\n", | "files.\n", | ||||
nPruneTarget / 1024 / 1024); | nPruneTarget / 1024 / 1024); | ||||
fPruneMode = true; | fPruneMode = true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | bool AppInitParameterInteraction(Config &config) { | ||||
return true; | return true; | ||||
} | } | ||||
static bool LockDataDirectory(bool probeOnly) { | static bool LockDataDirectory(bool probeOnly) { | ||||
// Make sure only a single Bitcoin process is using the data directory. | // Make sure only a single Bitcoin process is using the data directory. | ||||
fs::path datadir = GetDataDir(); | fs::path datadir = GetDataDir(); | ||||
if (!DirIsWritable(datadir)) { | if (!DirIsWritable(datadir)) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Cannot write to data directory '%s'; check permissions."), | _("Cannot write to data directory '%s'; check permissions.") | ||||
.translated, | |||||
datadir.string())); | datadir.string())); | ||||
} | } | ||||
if (!LockDirectory(datadir, ".lock", probeOnly)) { | if (!LockDirectory(datadir, ".lock", probeOnly)) { | ||||
return InitError(strprintf(_("Cannot obtain a lock on data directory " | return InitError(strprintf(_("Cannot obtain a lock on data directory " | ||||
"%s. %s is probably already running."), | "%s. %s is probably already running.") | ||||
.translated, | |||||
datadir.string(), PACKAGE_NAME)); | datadir.string(), PACKAGE_NAME)); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool AppInitSanityChecks() { | bool AppInitSanityChecks() { | ||||
// Step 4: sanity checks | // Step 4: sanity checks | ||||
// Initialize elliptic curve code | // Initialize elliptic curve code | ||||
std::string sha256_algo = SHA256AutoDetect(); | std::string sha256_algo = SHA256AutoDetect(); | ||||
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); | LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); | ||||
RandomInit(); | RandomInit(); | ||||
ECC_Start(); | ECC_Start(); | ||||
globalVerifyHandle.reset(new ECCVerifyHandle()); | globalVerifyHandle.reset(new ECCVerifyHandle()); | ||||
// Sanity check | // Sanity check | ||||
if (!InitSanityCheck()) { | if (!InitSanityCheck()) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Initialization sanity check failed. %s is shutting down."), | _("Initialization sanity check failed. %s is shutting down.") | ||||
.translated, | |||||
PACKAGE_NAME)); | PACKAGE_NAME)); | ||||
} | } | ||||
// Probe the data directory lock to give an early error message, if possible | // 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() | // 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. | // hasn't yet happened, and a fork will cause weird behavior to it. | ||||
return LockDataDirectory(true); | return LockDataDirectory(true); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | bool AppInitMain(Config &config, RPCServer &rpcServer, | ||||
// Only log conf file usage message if conf file actually exists. | // Only log conf file usage message if conf file actually exists. | ||||
fs::path config_file_path = | fs::path config_file_path = | ||||
GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)); | GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)); | ||||
if (fs::exists(config_file_path)) { | if (fs::exists(config_file_path)) { | ||||
LogPrintf("Config file: %s\n", config_file_path.string()); | LogPrintf("Config file: %s\n", config_file_path.string()); | ||||
} else if (gArgs.IsArgSet("-conf")) { | } else if (gArgs.IsArgSet("-conf")) { | ||||
// Warn if no conf file exists at path provided by user | // Warn if no conf file exists at path provided by user | ||||
InitWarning( | InitWarning(strprintf( | ||||
strprintf(_("The specified config file %s does not exist\n"), | _("The specified config file %s does not exist\n").translated, | ||||
config_file_path.string())); | config_file_path.string())); | ||||
} else { | } else { | ||||
// Not categorizing as "Warning" because it's the default behavior | // Not categorizing as "Warning" because it's the default behavior | ||||
LogPrintf("Config file: %s (not found, skipping)\n", | LogPrintf("Config file: %s (not found, skipping)\n", | ||||
config_file_path.string()); | config_file_path.string()); | ||||
} | } | ||||
// Log the config arguments to debug.log | // Log the config arguments to debug.log | ||||
gArgs.LogArgs(); | gArgs.LogArgs(); | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | #endif | ||||
* process calls yet (but it will verify that the server is there and will | * 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 | * be ready later). Warmup mode will be completed when initialisation is | ||||
* finished. | * finished. | ||||
*/ | */ | ||||
if (gArgs.GetBoolArg("-server", false)) { | if (gArgs.GetBoolArg("-server", false)) { | ||||
uiInterface.InitMessage_connect(SetRPCWarmupStatus); | uiInterface.InitMessage_connect(SetRPCWarmupStatus); | ||||
if (!AppInitServers(config, httpRPCRequestProcessor)) { | if (!AppInitServers(config, httpRPCRequestProcessor)) { | ||||
return InitError( | return InitError( | ||||
_("Unable to start HTTP server. See debug log for details.")); | _("Unable to start HTTP server. See debug log for details.") | ||||
.translated); | |||||
} | } | ||||
} | } | ||||
// Step 5: verify wallet database integrity | // Step 5: verify wallet database integrity | ||||
for (const auto &client : interfaces.chain_clients) { | for (const auto &client : interfaces.chain_clients) { | ||||
if (!client->verify(chainparams)) { | if (!client->verify(chainparams)) { | ||||
return false; | return false; | ||||
} | } | ||||
Show All 20 Lines | peerLogic = std::make_unique<PeerLogicValidation>( | ||||
gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)); | gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)); | ||||
RegisterValidationInterface(peerLogic.get()); | RegisterValidationInterface(peerLogic.get()); | ||||
// sanitize comments per BIP-0014, format user agent and check total size | // sanitize comments per BIP-0014, format user agent and check total size | ||||
std::vector<std::string> uacomments; | std::vector<std::string> uacomments; | ||||
for (const std::string &cmt : gArgs.GetArgs("-uacomment")) { | for (const std::string &cmt : gArgs.GetArgs("-uacomment")) { | ||||
if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) { | if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("User Agent comment (%s) contains unsafe characters."), cmt)); | _("User Agent comment (%s) contains unsafe characters.") | ||||
.translated, | |||||
cmt)); | |||||
} | } | ||||
uacomments.push_back(cmt); | uacomments.push_back(cmt); | ||||
} | } | ||||
const std::string strSubVersion = | const std::string strSubVersion = | ||||
FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); | FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); | ||||
if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { | if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Total length of network version string (%i) exceeds maximum " | _("Total length of network version string (%i) exceeds maximum " | ||||
"length (%i). Reduce the number or size of uacomments."), | "length (%i). Reduce the number or size of uacomments.") | ||||
.translated, | |||||
strSubVersion.size(), MAX_SUBVERSION_LENGTH)); | strSubVersion.size(), MAX_SUBVERSION_LENGTH)); | ||||
} | } | ||||
if (gArgs.IsArgSet("-onlynet")) { | if (gArgs.IsArgSet("-onlynet")) { | ||||
std::set<enum Network> nets; | std::set<enum Network> nets; | ||||
for (const std::string &snet : gArgs.GetArgs("-onlynet")) { | for (const std::string &snet : gArgs.GetArgs("-onlynet")) { | ||||
enum Network net = ParseNetwork(snet); | enum Network net = ParseNetwork(snet); | ||||
if (net == NET_UNROUTABLE) { | if (net == NET_UNROUTABLE) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Unknown network specified in -onlynet: '%s'"), snet)); | _("Unknown network specified in -onlynet: '%s'").translated, | ||||
snet)); | |||||
} | } | ||||
nets.insert(net); | nets.insert(net); | ||||
} | } | ||||
for (int n = 0; n < NET_MAX; n++) { | for (int n = 0; n < NET_MAX; n++) { | ||||
enum Network net = (enum Network)n; | enum Network net = (enum Network)n; | ||||
if (!nets.count(net)) { | if (!nets.count(net)) { | ||||
SetReachable(net, false); | SetReachable(net, false); | ||||
} | } | ||||
Show All 10 Lines | #endif | ||||
// -noproxy (or -proxy=0) as well as the empty string can be used to not set | // -noproxy (or -proxy=0) as well as the empty string can be used to not set | ||||
// a proxy, this is the default | // a proxy, this is the default | ||||
std::string proxyArg = gArgs.GetArg("-proxy", ""); | std::string proxyArg = gArgs.GetArg("-proxy", ""); | ||||
SetReachable(NET_ONION, false); | SetReachable(NET_ONION, false); | ||||
if (proxyArg != "" && proxyArg != "0") { | if (proxyArg != "" && proxyArg != "0") { | ||||
CService proxyAddr; | CService proxyAddr; | ||||
if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { | if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Invalid -proxy address or hostname: '%s'"), proxyArg)); | _("Invalid -proxy address or hostname: '%s'").translated, | ||||
proxyArg)); | |||||
} | } | ||||
proxyType addrProxy = proxyType(proxyAddr, proxyRandomize); | proxyType addrProxy = proxyType(proxyAddr, proxyRandomize); | ||||
if (!addrProxy.IsValid()) { | if (!addrProxy.IsValid()) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Invalid -proxy address or hostname: '%s'"), proxyArg)); | _("Invalid -proxy address or hostname: '%s'").translated, | ||||
proxyArg)); | |||||
} | } | ||||
SetProxy(NET_IPV4, addrProxy); | SetProxy(NET_IPV4, addrProxy); | ||||
SetProxy(NET_IPV6, addrProxy); | SetProxy(NET_IPV6, addrProxy); | ||||
SetProxy(NET_ONION, addrProxy); | SetProxy(NET_ONION, addrProxy); | ||||
SetNameProxy(addrProxy); | SetNameProxy(addrProxy); | ||||
// by default, -proxy sets onion as reachable, unless -noonion later | // by default, -proxy sets onion as reachable, unless -noonion later | ||||
SetReachable(NET_ONION, true); | SetReachable(NET_ONION, true); | ||||
} | } | ||||
// -onion can be used to set only a proxy for .onion, or override normal | // -onion can be used to set only a proxy for .onion, or override normal | ||||
// proxy for .onion addresses. | // proxy for .onion addresses. | ||||
// -noonion (or -onion=0) disables connecting to .onion entirely. An empty | // -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 | // string is used to not override the onion proxy (in which case it defaults | ||||
// to -proxy set above, or none) | // to -proxy set above, or none) | ||||
std::string onionArg = gArgs.GetArg("-onion", ""); | std::string onionArg = gArgs.GetArg("-onion", ""); | ||||
if (onionArg != "") { | if (onionArg != "") { | ||||
if (onionArg == "0") { | if (onionArg == "0") { | ||||
// Handle -noonion/-onion=0 | // Handle -noonion/-onion=0 | ||||
SetReachable(NET_ONION, false); | SetReachable(NET_ONION, false); | ||||
} else { | } else { | ||||
CService onionProxy; | CService onionProxy; | ||||
if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { | if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Invalid -onion address or hostname: '%s'"), onionArg)); | _("Invalid -onion address or hostname: '%s'").translated, | ||||
onionArg)); | |||||
} | } | ||||
proxyType addrOnion = proxyType(onionProxy, proxyRandomize); | proxyType addrOnion = proxyType(onionProxy, proxyRandomize); | ||||
if (!addrOnion.IsValid()) { | if (!addrOnion.IsValid()) { | ||||
return InitError(strprintf( | return InitError(strprintf( | ||||
_("Invalid -onion address or hostname: '%s'"), onionArg)); | _("Invalid -onion address or hostname: '%s'").translated, | ||||
onionArg)); | |||||
} | } | ||||
SetProxy(NET_ONION, addrOnion); | SetProxy(NET_ONION, addrOnion); | ||||
SetReachable(NET_ONION, true); | SetReachable(NET_ONION, true); | ||||
} | } | ||||
} | } | ||||
// see Step 2: parameter interactions for more information about these | // see Step 2: parameter interactions for more information about these | ||||
fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); | fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of " | ||||
nMempoolSizeMax * (1.0 / 1024 / 1024)); | nMempoolSizeMax * (1.0 / 1024 / 1024)); | ||||
int64_t nStart = 0; | int64_t nStart = 0; | ||||
bool fLoaded = false; | bool fLoaded = false; | ||||
while (!fLoaded && !ShutdownRequested()) { | while (!fLoaded && !ShutdownRequested()) { | ||||
bool fReset = fReindex; | bool fReset = fReindex; | ||||
std::string strLoadError; | std::string strLoadError; | ||||
uiInterface.InitMessage(_("Loading block index...")); | uiInterface.InitMessage(_("Loading block index...").translated); | ||||
nStart = GetTimeMillis(); | nStart = GetTimeMillis(); | ||||
do { | do { | ||||
try { | try { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
UnloadBlockIndex(); | UnloadBlockIndex(); | ||||
pcoinsTip.reset(); | pcoinsTip.reset(); | ||||
pcoinsdbview.reset(); | pcoinsdbview.reset(); | ||||
pcoinscatcher.reset(); | pcoinscatcher.reset(); | ||||
Show All 14 Lines | while (!fLoaded && !ShutdownRequested()) { | ||||
} | } | ||||
// LoadBlockIndex will load fHavePruned if we've ever removed a | // LoadBlockIndex will load fHavePruned if we've ever removed a | ||||
// block file from disk. | // block file from disk. | ||||
// Note that it also sets fReindex based on the disk flag! | // Note that it also sets fReindex based on the disk flag! | ||||
// From here on out fReindex and fReset mean something | // From here on out fReindex and fReset mean something | ||||
// different! | // different! | ||||
if (!LoadBlockIndex(config)) { | if (!LoadBlockIndex(config)) { | ||||
strLoadError = _("Error loading block database"); | strLoadError = _("Error loading block database").translated; | ||||
break; | break; | ||||
} | } | ||||
// If the loaded chain has a wrong genesis, bail out immediately | // If the loaded chain has a wrong genesis, bail out immediately | ||||
// (we're likely using a testnet datadir, or the other way | // (we're likely using a testnet datadir, or the other way | ||||
// around). | // around). | ||||
if (!mapBlockIndex.empty() && | if (!mapBlockIndex.empty() && | ||||
!LookupBlockIndex( | !LookupBlockIndex( | ||||
chainparams.GetConsensus().hashGenesisBlock)) { | chainparams.GetConsensus().hashGenesisBlock)) { | ||||
return InitError(_("Incorrect or no genesis block found. " | return InitError(_("Incorrect or no genesis block found. " | ||||
"Wrong datadir for network?")); | "Wrong datadir for network?") | ||||
.translated); | |||||
} | } | ||||
// Check for changed -prune state. What we are concerned about | // Check for changed -prune state. What we are concerned about | ||||
// is a user who has pruned blocks in the past, but is now | // is a user who has pruned blocks in the past, but is now | ||||
// trying to run unpruned. | // trying to run unpruned. | ||||
if (fHavePruned && !fPruneMode) { | if (fHavePruned && !fPruneMode) { | ||||
strLoadError = | strLoadError = | ||||
_("You need to rebuild the database using -reindex to " | _("You need to rebuild the database using -reindex to " | ||||
"go back to unpruned mode. This will redownload the " | "go back to unpruned mode. This will redownload the " | ||||
"entire blockchain"); | "entire blockchain") | ||||
.translated; | |||||
break; | break; | ||||
} | } | ||||
// At this point blocktree args are consistent with what's on | // At this point blocktree args are consistent with what's on | ||||
// disk. If we're not mid-reindex (based on disk + args), add a | // disk. If we're not mid-reindex (based on disk + args), add a | ||||
// genesis block on disk (otherwise we use the one already on | // genesis block on disk (otherwise we use the one already on | ||||
// disk). | // disk). | ||||
// This is called again in ThreadImport after the reindex | // This is called again in ThreadImport after the reindex | ||||
// completes. | // completes. | ||||
if (!fReindex && !LoadGenesisBlock(chainparams)) { | if (!fReindex && !LoadGenesisBlock(chainparams)) { | ||||
strLoadError = _("Error initializing block database"); | strLoadError = | ||||
_("Error initializing block database").translated; | |||||
break; | break; | ||||
} | } | ||||
// At this point we're either in reindex or we've loaded a | // At this point we're either in reindex or we've loaded a | ||||
// useful block tree into mapBlockIndex! | // useful block tree into mapBlockIndex! | ||||
pcoinsdbview.reset(new CCoinsViewDB( | pcoinsdbview.reset(new CCoinsViewDB( | ||||
nCoinDBCache, false, fReset || fReindexChainState)); | nCoinDBCache, false, fReset || fReindexChainState)); | ||||
pcoinscatcher.reset( | pcoinscatcher.reset( | ||||
new CCoinsViewErrorCatcher(pcoinsdbview.get())); | new CCoinsViewErrorCatcher(pcoinsdbview.get())); | ||||
// If necessary, upgrade from older database format. | // If necessary, upgrade from older database format. | ||||
// This is a no-op if we cleared the coinsviewdb with -reindex | // This is a no-op if we cleared the coinsviewdb with -reindex | ||||
// or -reindex-chainstate | // or -reindex-chainstate | ||||
if (!pcoinsdbview->Upgrade()) { | if (!pcoinsdbview->Upgrade()) { | ||||
strLoadError = _("Error upgrading chainstate database"); | strLoadError = | ||||
_("Error upgrading chainstate database").translated; | |||||
break; | break; | ||||
} | } | ||||
// ReplayBlocks is a no-op if we cleared the coinsviewdb with | // ReplayBlocks is a no-op if we cleared the coinsviewdb with | ||||
// -reindex or -reindex-chainstate | // -reindex or -reindex-chainstate | ||||
if (!ReplayBlocks(chainparams.GetConsensus(), | if (!ReplayBlocks(chainparams.GetConsensus(), | ||||
pcoinsdbview.get())) { | pcoinsdbview.get())) { | ||||
strLoadError = | strLoadError = | ||||
_("Unable to replay blocks. You will need to rebuild " | _("Unable to replay blocks. You will need to rebuild " | ||||
"the database using -reindex-chainstate."); | "the database using -reindex-chainstate.") | ||||
.translated; | |||||
break; | break; | ||||
} | } | ||||
// The on-disk coinsdb is now in a good state, create the cache | // The on-disk coinsdb is now in a good state, create the cache | ||||
pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get())); | pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get())); | ||||
bool is_coinsview_empty = fReset || fReindexChainState || | bool is_coinsview_empty = fReset || fReindexChainState || | ||||
pcoinsTip->GetBestBlock().IsNull(); | pcoinsTip->GetBestBlock().IsNull(); | ||||
if (!is_coinsview_empty) { | if (!is_coinsview_empty) { | ||||
// LoadChainTip sets ::ChainActive() based on pcoinsTip's | // LoadChainTip sets ::ChainActive() based on pcoinsTip's | ||||
// best block | // best block | ||||
if (!LoadChainTip(config)) { | if (!LoadChainTip(config)) { | ||||
strLoadError = _("Error initializing block database"); | strLoadError = | ||||
_("Error initializing block database").translated; | |||||
break; | break; | ||||
} | } | ||||
assert(::ChainActive().Tip() != nullptr); | assert(::ChainActive().Tip() != nullptr); | ||||
uiInterface.InitMessage(_("Verifying blocks...")); | uiInterface.InitMessage( | ||||
_("Verifying blocks...").translated); | |||||
if (fHavePruned && | if (fHavePruned && | ||||
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > | gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > | ||||
MIN_BLOCKS_TO_KEEP) { | MIN_BLOCKS_TO_KEEP) { | ||||
LogPrintf( | LogPrintf( | ||||
"Prune: pruned datadir may not have more than %d " | "Prune: pruned datadir may not have more than %d " | ||||
"blocks; only checking available blocks\n", | "blocks; only checking available blocks\n", | ||||
MIN_BLOCKS_TO_KEEP); | MIN_BLOCKS_TO_KEEP); | ||||
} | } | ||||
CBlockIndex *tip = ::ChainActive().Tip(); | CBlockIndex *tip = ::ChainActive().Tip(); | ||||
RPCNotifyBlockChange(true, tip); | RPCNotifyBlockChange(true, tip); | ||||
if (tip && tip->nTime > | if (tip && tip->nTime > | ||||
GetAdjustedTime() + MAX_FUTURE_BLOCK_TIME) { | GetAdjustedTime() + MAX_FUTURE_BLOCK_TIME) { | ||||
strLoadError = _( | strLoadError = | ||||
"The block database contains a block which appears " | _("The block database contains a block which " | ||||
"to be from the future. This may be due to your " | "appears to be from the future. This may be due " | ||||
"computer's date and time being set incorrectly. " | "to your computer's date and time being set " | ||||
"Only rebuild the block database if you are sure " | "incorrectly. Only rebuild the block database if " | ||||
"that your computer's date and time are correct"); | "you are sure that your computer's date and time " | ||||
"are correct") | |||||
.translated; | |||||
break; | break; | ||||
} | } | ||||
if (!CVerifyDB().VerifyDB( | if (!CVerifyDB().VerifyDB( | ||||
config, pcoinsdbview.get(), | config, pcoinsdbview.get(), | ||||
gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), | gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), | ||||
gArgs.GetArg("-checkblocks", | gArgs.GetArg("-checkblocks", | ||||
DEFAULT_CHECKBLOCKS))) { | DEFAULT_CHECKBLOCKS))) { | ||||
strLoadError = _("Corrupted block database detected"); | strLoadError = | ||||
_("Corrupted block database detected").translated; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
LogPrintf("%s\n", e.what()); | LogPrintf("%s\n", e.what()); | ||||
strLoadError = _("Error opening block database"); | strLoadError = _("Error opening block database").translated; | ||||
break; | break; | ||||
} | } | ||||
fLoaded = true; | fLoaded = true; | ||||
} while (false); | } while (false); | ||||
if (!fLoaded && !ShutdownRequested()) { | if (!fLoaded && !ShutdownRequested()) { | ||||
// first suggest a reindex | // first suggest a reindex | ||||
if (!fReset) { | if (!fReset) { | ||||
bool fRet = uiInterface.ThreadSafeQuestion( | bool fRet = uiInterface.ThreadSafeQuestion( | ||||
strLoadError + ".\n\n" + | strLoadError + ".\n\n" + | ||||
_("Do you want to rebuild the block database now?"), | _("Do you want to rebuild the block database now?") | ||||
.translated, | |||||
strLoadError + ".\nPlease restart with -reindex or " | strLoadError + ".\nPlease restart with -reindex or " | ||||
"-reindex-chainstate to recover.", | "-reindex-chainstate to recover.", | ||||
"", | "", | ||||
CClientUIInterface::MSG_ERROR | | CClientUIInterface::MSG_ERROR | | ||||
CClientUIInterface::BTN_ABORT); | CClientUIInterface::BTN_ABORT); | ||||
if (fRet) { | if (fRet) { | ||||
fReindex = true; | fReindex = true; | ||||
AbortShutdown(); | AbortShutdown(); | ||||
Show All 39 Lines | #endif | ||||
// Step 10: data directory maintenance | // Step 10: data directory maintenance | ||||
// if pruning, unset the service bit and perform the initial blockstore | // if pruning, unset the service bit and perform the initial blockstore | ||||
// prune after any wallet rescanning has taken place. | // prune after any wallet rescanning has taken place. | ||||
if (fPruneMode) { | if (fPruneMode) { | ||||
LogPrintf("Unsetting NODE_NETWORK on prune mode\n"); | LogPrintf("Unsetting NODE_NETWORK on prune mode\n"); | ||||
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK); | nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK); | ||||
if (!fReindex) { | if (!fReindex) { | ||||
uiInterface.InitMessage(_("Pruning blockstore...")); | uiInterface.InitMessage(_("Pruning blockstore...").translated); | ||||
::ChainstateActive().PruneAndFlush(); | ::ChainstateActive().PruneAndFlush(); | ||||
} | } | ||||
} | } | ||||
// Step 11: import blocks | // Step 11: import blocks | ||||
if (!CheckDiskSpace(GetDataDir())) { | if (!CheckDiskSpace(GetDataDir())) { | ||||
InitError( | InitError(strprintf(_("Error: Disk space is low for %s").translated, | ||||
strprintf(_("Error: Disk space is low for %s"), GetDataDir())); | GetDataDir())); | ||||
return false; | return false; | ||||
} | } | ||||
if (!CheckDiskSpace(GetBlocksDir())) { | if (!CheckDiskSpace(GetBlocksDir())) { | ||||
InitError( | InitError(strprintf(_("Error: Disk space is low for %s").translated, | ||||
strprintf(_("Error: Disk space is low for %s"), GetBlocksDir())); | GetBlocksDir())); | ||||
return false; | return false; | ||||
} | } | ||||
// Either install a handler to notify us when genesis activates, or set | // Either install a handler to notify us when genesis activates, or set | ||||
// fHaveGenesis directly. | // fHaveGenesis directly. | ||||
// No locking, as this happens before any background thread is started. | // No locking, as this happens before any background thread is started. | ||||
if (::ChainActive().Tip() == nullptr) { | if (::ChainActive().Tip() == nullptr) { | ||||
uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait); | uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait); | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (!g_connman->Start(scheduler, connOptions)) { | if (!g_connman->Start(scheduler, connOptions)) { | ||||
return false; | return false; | ||||
} | } | ||||
// Step 13: finished | // Step 13: finished | ||||
SetRPCWarmupFinished(); | SetRPCWarmupFinished(); | ||||
uiInterface.InitMessage(_("Done loading")); | uiInterface.InitMessage(_("Done loading").translated); | ||||
for (const auto &client : interfaces.chain_clients) { | for (const auto &client : interfaces.chain_clients) { | ||||
client->start(scheduler); | client->start(scheduler); | ||||
} | } | ||||
scheduler.scheduleEvery( | scheduler.scheduleEvery( | ||||
[] { | [] { | ||||
g_banman->DumpBanlist(); | g_banman->DumpBanlist(); | ||||
Show All 9 Lines |