Skip to content

Commit

Permalink
Fix some LoadChainTip-related init-order bugs.
Browse files Browse the repository at this point in the history
>>> adapts bitcoin/bitcoin@eda888e

* 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.
  • Loading branch information
random-zebra committed Mar 2, 2021
1 parent 99f478b commit 9bcc942
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ void ThreadImport(const 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();
LoadGenesisBlock();
}

// hardcoded $DATADIR/bootstrap.dat
Expand Down Expand Up @@ -1620,7 +1620,7 @@ bool AppInitMain()
return UIError(_("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()) {
if (!LoadGenesisBlock()) {
strLoadError = _("Error initializing block database");
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/test_pivx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ TestingSetup::TestingSetup()
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
InitBlockIndex();
LoadGenesisBlock();
{
CValidationState state;
bool ok = ActivateBestChain(state);
Expand Down
71 changes: 41 additions & 30 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3743,45 +3743,56 @@ void UnloadBlockIndex()

bool LoadBlockIndex(std::string& strError)
{
// Load block index from databases
if (!fReindex && !LoadBlockIndexDB(strError))
return false;
bool needs_init = fReindex;
if (!fReindex) {
if (!LoadBlockIndexDB(strError))
return false;
needs_init = mapBlockIndex.empty();
}

if (needs_init) {
// Everything here is for *new* reindex/DBs. Thus, though
// LoadBlockIndexDB may have set fReindex if we shut down
// mid-reindex previously, we don't check fReindex and
// instead only check it prior to LoadBlockIndexDB to set
// needs_init.

LogPrintf("Initializing databases...\n");
// Use the provided setting for -txindex in the new database
fTxIndex = gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX);
pblocktree->WriteFlag("txindex", fTxIndex);
}
return true;
}


bool InitBlockIndex()
bool LoadGenesisBlock()
{
LOCK(cs_main);

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

// Use the provided setting for -txindex in the new database
fTxIndex = gArgs.GetBoolArg("-txindex", true);
pblocktree->WriteFlag("txindex", fTxIndex);
LogPrintf("Initializing databases...\n");

// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
if (!fReindex) {
try {
CBlock& block = const_cast<CBlock&>(Params().GenesisBlock());
// Start new block file
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize + 8, 0, block.GetBlockTime()))
return error("LoadBlockIndex() : FindBlockPos failed");
if (!WriteBlockToDisk(block, blockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed");
CBlockIndex* pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
} catch (const std::runtime_error& e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
}
}
try {
CBlock& block = const_cast<CBlock&>(Params().GenesisBlock());
// Start new block file
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize + 8, 0, block.GetBlockTime()))
return error("%s: FindBlockPos failed", __func__);
if (!WriteBlockToDisk(block, blockPos))
return error("%s: writing genesis block to disk failed", __func__);
CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("%s: genesis block not accepted", __func__);
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
}

return true;
}
Expand Down
7 changes: 4 additions & 3 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,10 @@ FILE* OpenUndoFile(const CDiskBlockPos& pos, bool fReadOnly = false);
fs::path GetBlockPosFilename(const CDiskBlockPos& pos, const char* prefix);
/** Import blocks from an external file */
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp = NULL);
/** Initialize a new block tree database + block data on disk */
bool InitBlockIndex();
/** Load the block tree and coins database from disk */
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
bool LoadGenesisBlock();
/** Load the block tree and coins database from disk,
* initializing state if we're running with -reindex. */
bool LoadBlockIndex(std::string& strError);
/** Update the chain tip based on database information. */
void LoadChainTip(const CChainParams& chainparams);
Expand Down

0 comments on commit 9bcc942

Please sign in to comment.