Skip to content

Commit eda888e

Browse files
committed
Fix some LoadChainTip-related init-order bugs.
* Move the writing of fTxIndex to LoadBlockIndex - this fixes a bug introduced in d6af06d where InitBlockIndex was writing to fTxIndex which had not yet been checked (because LoadChainTip hadn't yet initialized the chainActive, which would otherwise have resulted in InitBlockIndex being a NOP), allowing you to modify -txindex without reindex, potentially corrupting your chainstate! * Rename InitBlockIndex to LoadGenesisBlock, which is now a more natural name for it. Also check mapBlockIndex instead of chainActive, fixing a bug where we'd write the genesis block out on every start.
1 parent 5cfdda2 commit eda888e

File tree

4 files changed

+47
-33
lines changed

4 files changed

+47
-33
lines changed

src/init.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
646646
fReindex = false;
647647
LogPrintf("Reindexing finished\n");
648648
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
649-
InitBlockIndex(chainparams);
649+
LoadGenesisBlock(chainparams);
650650
}
651651

652652
// hardcoded $DATADIR/bootstrap.dat
@@ -1419,7 +1419,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
14191419
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
14201420

14211421
// Initialize the block index (no-op if non-empty database was already loaded)
1422-
if (!InitBlockIndex(chainparams)) {
1422+
if (!fReindex && !LoadGenesisBlock(chainparams)) {
14231423
strLoadError = _("Error initializing block database");
14241424
break;
14251425
}

src/test/test_bitcoin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
7272
pblocktree = new CBlockTreeDB(1 << 20, true);
7373
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
7474
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
75-
if (!InitBlockIndex(chainparams)) {
75+
if (!LoadGenesisBlock(chainparams)) {
7676
throw std::runtime_error("InitBlockIndex failed.");
7777
}
7878
{

src/validation.cpp

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3864,42 +3864,55 @@ void UnloadBlockIndex()
38643864
bool LoadBlockIndex(const CChainParams& chainparams)
38653865
{
38663866
// Load block index from databases
3867-
if (!fReindex && !LoadBlockIndexDB(chainparams))
3868-
return false;
3867+
bool needs_init = fReindex;
3868+
if (!fReindex) {
3869+
bool ret = LoadBlockIndexDB(chainparams);
3870+
if (!ret) return false;
3871+
needs_init = mapBlockIndex.empty();
3872+
}
3873+
3874+
if (needs_init) {
3875+
// Everything here is for *new* reindex/DBs. Thus, though
3876+
// LoadBlockIndexDB may have set fReindex if we shut down
3877+
// mid-reindex previously, we don't check fReindex and
3878+
// instead only check it prior to LoadBlockIndexDB to set
3879+
// needs_init.
3880+
3881+
LogPrintf("Initializing databases...\n");
3882+
// Use the provided setting for -txindex in the new database
3883+
fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX);
3884+
pblocktree->WriteFlag("txindex", fTxIndex);
3885+
}
38693886
return true;
38703887
}
38713888

3872-
bool InitBlockIndex(const CChainParams& chainparams)
3889+
bool LoadGenesisBlock(const CChainParams& chainparams)
38733890
{
38743891
LOCK(cs_main);
38753892

3876-
// Check whether we're already initialized
3877-
if (chainActive.Genesis() != NULL)
3893+
// Check whether we're already initialized by checking for genesis in
3894+
// mapBlockIndex. Note that we can't use chainActive here, since it is
3895+
// set based on the coins db, not the block index db, which is the only
3896+
// thing loaded at this point.
3897+
if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash()))
38783898
return true;
38793899

3880-
// Use the provided setting for -txindex in the new database
3881-
fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX);
3882-
pblocktree->WriteFlag("txindex", fTxIndex);
3883-
LogPrintf("Initializing databases...\n");
3884-
38853900
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
3886-
if (!fReindex) {
3887-
try {
3888-
CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
3889-
// Start new block file
3890-
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
3891-
CDiskBlockPos blockPos;
3892-
CValidationState state;
3893-
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
3894-
return error("LoadBlockIndex(): FindBlockPos failed");
3895-
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
3896-
return error("LoadBlockIndex(): writing genesis block to disk failed");
3897-
CBlockIndex *pindex = AddToBlockIndex(block);
3898-
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
3899-
return error("LoadBlockIndex(): genesis block not accepted");
3900-
} catch (const std::runtime_error& e) {
3901-
return error("LoadBlockIndex(): failed to initialize block database: %s", e.what());
3902-
}
3901+
try {
3902+
CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
3903+
// Start new block file
3904+
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
3905+
CDiskBlockPos blockPos;
3906+
CValidationState state;
3907+
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
3908+
return error("%s: FindBlockPos failed", __func__);
3909+
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
3910+
return error("%s: writing genesis block to disk failed", __func__);
3911+
CBlockIndex *pindex = AddToBlockIndex(block);
3912+
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
3913+
return error("%s: genesis block not accepted", __func__);
3914+
} catch (const std::runtime_error& e) {
3915+
return error("%s: failed to write genesis block: %s", __func__, e.what());
39033916
}
39043917

39053918
return true;

src/validation.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,10 @@ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
256256
fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
257257
/** Import blocks from an external file */
258258
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL);
259-
/** Initialize a new block tree database + block data on disk */
260-
bool InitBlockIndex(const CChainParams& chainparams);
261-
/** Load the block tree and coins database from disk */
259+
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
260+
bool LoadGenesisBlock(const CChainParams& chainparams);
261+
/** Load the block tree and coins database from disk,
262+
* initializing state if we're running with -reindex. */
262263
bool LoadBlockIndex(const CChainParams& chainparams);
263264
/** Update the chain tip based on database information. */
264265
void LoadChainTip(const CChainParams& chainparams);

0 commit comments

Comments
 (0)