aboutsummaryrefslogtreecommitdiff
path: root/src/init.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/init.cpp')
-rw-r--r--src/init.cpp137
1 files changed, 96 insertions, 41 deletions
diff --git a/src/init.cpp b/src/init.cpp
index 672ef77e8..0ee828ce9 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -215,6 +215,21 @@ void Shutdown()
fFeeEstimatesInitialized = false;
}
+ // FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
+ if (pcoinsTip != nullptr) {
+ FlushStateToDisk();
+ }
+
+ // After there are no more peers/RPC left to give us new data which may generate
+ // CValidationInterface callbacks, flush them...
+ GetMainSignals().FlushBackgroundCallbacks();
+
+ // Any future callbacks will be dropped. This should absolutely be safe - if
+ // missing a callback results in an unrecoverable situation, unclean shutdown
+ // would too. The only reason to do the above flushes is to let the wallet catch
+ // up with our current chain to avoid any strange pruning edge cases and make
+ // next startup faster by avoiding rescan.
+
{
LOCK(cs_main);
if (pcoinsTip != NULL) {
@@ -251,6 +266,7 @@ void Shutdown()
}
#endif
UnregisterAllValidationInterfaces();
+ GetMainSignals().UnregisterBackgroundSignalScheduler();
#ifdef ENABLE_WALLET
for (CWalletRef pwallet : vpwallets) {
delete pwallet;
@@ -465,7 +481,7 @@ std::string HelpMessage(HelpMessageMode mode)
if (showDebug) {
strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->RequireStandard()));
strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
- strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
+ strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
}
strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
@@ -632,7 +648,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
fReindex = false;
LogPrintf("Reindexing finished\n");
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
- InitBlockIndex(chainparams);
+ LoadGenesisBlock(chainparams);
}
// hardcoded $DATADIR/bootstrap.dat
@@ -1147,6 +1163,8 @@ bool AppInitSanityChecks()
// ********************************************************* Step 4: sanity checks
// Initialize elliptic curve code
+ std::string sha256_algo = SHA256AutoDetect();
+ LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
RandomInit();
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
@@ -1156,13 +1174,13 @@ bool AppInitSanityChecks()
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
// Probe the data directory lock to give an early error message, if possible
+ // We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened,
+ // and a fork will cause weird behavior to it.
return LockDataDirectory(true);
}
-bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
+bool AppInitLockDataDirectory()
{
- const CChainParams& chainparams = Params();
- // ********************************************************* Step 4a: application initialization
// After daemonization get the data directory lock again and hold on to it until exit
// This creates a slight window for a race condition to happen, however this condition is harmless: it
// will at most make us exit without printing a message to console.
@@ -1170,7 +1188,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Detailed error printed inside LockDataDirectory
return false;
}
+ return true;
+}
+bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
+{
+ const CChainParams& chainparams = Params();
+ // ********************************************************* Step 4a: application initialization
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
@@ -1203,6 +1227,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+
/* 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
@@ -1375,23 +1401,19 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
delete pblocktree;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);
- pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
if (fReindex) {
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
CleanupBlockRevFiles();
- } else {
- // If necessary, upgrade from older database format.
- if (!pcoinsdbview->Upgrade()) {
- strLoadError = _("Error upgrading chainstate database");
- break;
- }
}
+
if (fRequestShutdown) break;
+ // LoadBlockIndex will load fTxIndex from the db, or set it if
+ // we're reindexing. It will also load fHavePruned if we've
+ // ever removed a block file from disk.
if (!LoadBlockIndex(chainparams)) {
strLoadError = _("Error loading block database");
break;
@@ -1402,12 +1424,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
- // Initialize the block index (no-op if non-empty database was already loaded)
- if (!InitBlockIndex(chainparams)) {
- strLoadError = _("Error initializing block database");
- break;
- }
-
// Check for changed -txindex state
if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex");
@@ -1421,14 +1437,49 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}
+ // At this point blocktree args are consistent with what's on disk.
+ // If we're not mid-reindex (based on disk + args), add a genesis block on disk.
+ // This is called again in ThreadImport in the reindex completes.
+ if (!fReindex && !LoadGenesisBlock(chainparams)) {
+ strLoadError = _("Error initializing block database");
+ break;
+ }
+
+ // At this point we're either in reindex or we've loaded a useful
+ // block tree into mapBlockIndex!
+
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);
+ pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
+
+ // If necessary, upgrade from older database format.
+ // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
+ if (!pcoinsdbview->Upgrade()) {
+ strLoadError = _("Error upgrading chainstate database");
+ break;
+ }
+
+ // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!ReplayBlocks(chainparams, pcoinsdbview)) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
break;
}
+
+ // The on-disk coinsdb is now in a good state, create the cache
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
- LoadChainTip(chainparams);
- if (!fReindex && chainActive.Tip() != NULL) {
+ if (!fReindex && !fReindexChainState) {
+ // LoadChainTip sets chainActive based on pcoinsTip's best block
+ if (!LoadChainTip(chainparams)) {
+ strLoadError = _("Error initializing block database");
+ break;
+ }
+ assert(chainActive.Tip() != NULL);
+ }
+
+ if (!fReindex) {
+ // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
+ // It both disconnects blocks based on chainActive, and drops block data in
+ // mapBlockIndex based on lack of available witness data.
uiInterface.InitMessage(_("Rewinding blocks..."));
if (!RewindBlockIndex(chainparams)) {
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
@@ -1436,28 +1487,30 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- uiInterface.InitMessage(_("Verifying blocks..."));
- if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
- MIN_BLOCKS_TO_KEEP);
- }
+ if (!fReindex && !fReindexChainState) {
+ uiInterface.InitMessage(_("Verifying blocks..."));
+ if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
+ LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
+ MIN_BLOCKS_TO_KEEP);
+ }
- {
- LOCK(cs_main);
- CBlockIndex* tip = chainActive.Tip();
- RPCNotifyBlockChange(true, 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;
+ {
+ LOCK(cs_main);
+ CBlockIndex* tip = chainActive.Tip();
+ RPCNotifyBlockChange(true, 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;
+ }
}
- }
- if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL),
- GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
- strLoadError = _("Corrupted block database detected");
- break;
+ if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
+ strLoadError = _("Corrupted block database detected");
+ break;
+ }
}
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
@@ -1496,7 +1549,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Shutdown requested. Exiting.\n");
return false;
}
- LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
+ if (fLoaded) {
+ LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
+ }
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);