From 5654732c2aa8bafeb08026f014052ac18fc4c006 Mon Sep 17 00:00:00 2001 From: presstab Date: Mon, 20 Nov 2017 20:28:43 -0700 Subject: [PATCH] Automate database corruption fix caused by out of sync txdb. --- src/chainparams.cpp | 7 +- src/checkpoints.cpp | 14 ++- src/checkpoints.h | 2 +- src/init.cpp | 54 +--------- src/main.cpp | 236 +++++++++++++++++++++++++++++--------------- src/main.h | 1 + 6 files changed, 179 insertions(+), 135 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3b100f125603e..268d8aed36ef8 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -65,11 +65,12 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (867733, uint256("03b26296bf693de5782c76843d2fb649cb66d4b05550c6a79c047ff7e1c3ae15")) (879650, uint256("227e1d2b738b6cd83c46d1d64617934ec899d77cee34336a56e61b71acd10bb2")) (895400, uint256("7796a0274a608fac12d400198174e50beda992c1d522e52e5b95b884bc1beac6"))//block that serial# range is enforced - (895991, uint256("d53013ed7ea5c325b9696c95e07667d6858f8ff7ee13fecfa90827bf3c9ae316"));//network split here + (895991, uint256("d53013ed7ea5c325b9696c95e07667d6858f8ff7ee13fecfa90827bf3c9ae316"))//network split here + (908000, uint256("202708f8c289b676fceb832a079ff6b308a28608339acbf7584de533619d014d")); static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1510187238, // * UNIX timestamp of last checkpoint block - 1816040, // * total number of transactions between genesis and last checkpoint + 1510948627, // * UNIX timestamp of last checkpoint block + 1842739, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 2000 // * estimated number of transactions per day after checkpoint }; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index e4b4371d9d447..4533a8aa66051 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -27,7 +27,7 @@ static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; bool fEnabled = true; -bool CheckBlock(int nHeight, const uint256& hash) +bool CheckBlock(int nHeight, const uint256& hash, bool fMatchesCheckpoint) { if (!fEnabled) return true; @@ -35,7 +35,17 @@ bool CheckBlock(int nHeight, const uint256& hash) const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; MapCheckpoints::const_iterator i = checkpoints.find(nHeight); - if (i == checkpoints.end()) return true; + // If looking for an exact match, then return false + if (i == checkpoints.end()) return !fMatchesCheckpoint; + return hash == i->second; +} + +//! Returns true only when both the height and hash match a checkpoint +bool IsCheckpointedBlock(int nHeight, const uint256& hash) +{ + const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; + MapCheckpoints::const_iterator i = checkpoints.find(nHeight); + if (i == checkpoints.end()) return false; return hash == i->second; } diff --git a/src/checkpoints.h b/src/checkpoints.h index c21294c0bab84..2fdb2c9783e45 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -27,7 +27,7 @@ struct CCheckpointData { }; //! Returns true if block passes checkpoint checks -bool CheckBlock(int nHeight, const uint256& hash); +bool CheckBlock(int nHeight, const uint256& hash, bool fMatchesCheckpoint = false); //! Return conservative estimate of total number of blocks, 0 if unknown int GetTotalBlocksEstimate(); diff --git a/src/init.cpp b/src/init.cpp index 4e9f671a63832..df43113a784b3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1371,59 +1371,13 @@ bool AppInit2(boost::thread_group& threadGroup) } // PIVX: recalculate Accumulator Checkpoints that failed to database properly - if (!listAccCheckpointsNoDB.empty() && chainActive.Tip()->GetBlockHeader().nVersion >= Params().Zerocoin_HeaderVersion()) { + if (!listAccCheckpointsNoDB.empty()) { uiInterface.InitMessage(_("Calculating missing accumulators...")); LogPrintf("%s : finding missing checkpoints\n", __func__); - //search the chain to see when zerocoin started - int nZerocoinStart = 0; - CBlockIndex* pindex = chainActive.Tip(); - while (pindex->pprev) { - if (pindex->GetBlockHeader().nVersion >= Params().Zerocoin_HeaderVersion()) - nZerocoinStart = pindex->nHeight; - else if (nZerocoinStart) - break; - - pindex = pindex->pprev; - } - - // find each checkpoint that is missing - pindex = chainActive[nZerocoinStart]; - while (!listAccCheckpointsNoDB.empty()) { - if (ShutdownRequested()) - break; - - // find checkpoints by iterating through the blockchain beginning with the first zerocoin block - if (pindex->nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint) { - - double dPercent = (pindex->nHeight - nZerocoinStart) / (double)(chainActive.Height() - nZerocoinStart); - uiInterface.ShowProgress(_("Calculating missing accumulators..."), (int)(dPercent * 100)); - if(find(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), pindex->nAccumulatorCheckpoint) != listAccCheckpointsNoDB.end()) { - uint256 nCheckpointCalculated = 0; - if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) { - // GetCheckpoint could have terminated due to a shutdown request. Check this here. - if (ShutdownRequested()) - break; - return InitError(_("Failed to calculate accumulator checkpoint")); - } - - //check that the calculated checkpoint is what is in the index. - if(nCheckpointCalculated != pindex->nAccumulatorCheckpoint) { - LogPrintf("%s : height=%d calculated_checkpoint=%s actual=%s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), pindex->nAccumulatorCheckpoint.GetHex()); - return InitError(_("Calculated accumulator checkpoint is not what is recorded by block index")); - } - - auto it = find(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), pindex->nAccumulatorCheckpoint); - listAccCheckpointsNoDB.erase(it); - } - } - - // if we have iterated to the end of the blockchain, then checkpoints should be in sync - if (pindex->nHeight + 1 <= chainActive.Height()) - pindex = chainActive[pindex->nHeight + 1]; - else - break; - } + string strError; + if (!ReindexAccumulators(listAccCheckpointsNoDB, strError)) + return InitError(strError); } uiInterface.InitMessage(_("Verifying blocks...")); diff --git a/src/main.cpp b/src/main.cpp index decfc1589fbb8..1be44f9e6c909 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2772,7 +2772,7 @@ void PopulateInvalidOutPointMap() } } - if (pindex->nHeight >= Params().Zerocoin_Block_RecalculateAccumulators()) + if (pindex->nHeight > Params().Zerocoin_Block_RecalculateAccumulators()) fListPopulatedAfterLock = true; } } @@ -2903,6 +2903,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsVi bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { + if (pindex->GetBlockHash() != view.GetBestBlock()) + LogPrintf("%s : pindex=%s view=%s\n", __func__, pindex->GetBlockHash().GetHex(), view.GetBestBlock().GetHex()); assert(pindex->GetBlockHash() == view.GetBestBlock()); if (pfClean) @@ -3196,6 +3198,59 @@ bool RecalculatePIVSupply(int nHeightStart) return true; } +bool ReindexAccumulators(list listMissingCheckpoints, string& strError) +{ + // PIVX: recalculate Accumulator Checkpoints that failed to database properly + if (!listMissingCheckpoints.empty() && chainActive.Height() >= Params().Zerocoin_StartHeight()) { + //uiInterface.InitMessage(_("Calculating missing accumulators...")); + LogPrintf("%s : finding missing checkpoints\n", __func__); + + //search the chain to see when zerocoin started + int nZerocoinStart = Params().Zerocoin_StartHeight(); + + // find each checkpoint that is missing + CBlockIndex* pindex = chainActive[nZerocoinStart]; + while (!listMissingCheckpoints.empty()) { + if (ShutdownRequested()) + return false; + + // find checkpoints by iterating through the blockchain beginning with the first zerocoin block + if (pindex->nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint) { + + //double dPercent = (pindex->nHeight - nZerocoinStart) / (double) (chainActive.Height() - nZerocoinStart); + //uiInterface.ShowProgress(_("Calculating missing accumulators..."), (int) (dPercent * 100)); + if (find(listMissingCheckpoints.begin(), listMissingCheckpoints.end(), pindex->nAccumulatorCheckpoint) != listMissingCheckpoints.end()) { + uint256 nCheckpointCalculated = 0; + if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) { + // GetCheckpoint could have terminated due to a shutdown request. Check this here. + if (ShutdownRequested()) + break; + strError = _("Failed to calculate accumulator checkpoint"); + return false; + } + + //check that the calculated checkpoint is what is in the index. + if (nCheckpointCalculated != pindex->nAccumulatorCheckpoint) { + LogPrintf("%s : height=%d calculated_checkpoint=%s actual=%s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), pindex->nAccumulatorCheckpoint.GetHex()); + strError = _("Calculated accumulator checkpoint is not what is recorded by block index"); + return false; + } + + auto it = find(listMissingCheckpoints.begin(), listMissingCheckpoints.end(), pindex->nAccumulatorCheckpoint); + listMissingCheckpoints.erase(it); + } + } + + // if we have iterated to the end of the blockchain, then checkpoints should be in sync + if (pindex->nHeight + 1 <= chainActive.Height()) + pindex = chainActive.Next(pindex); + else + break; + } + } + return true; +} + static int64_t nTimeVerify = 0; static int64_t nTimeConnect = 0; static int64_t nTimeIndex = 0; @@ -3453,17 +3508,42 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // zerocoin accumulator: if a new accumulator checkpoint was generated, check that it is the correct value if (!fVerifyingBlocks && pindex->nHeight >= Params().Zerocoin_StartHeight() && pindex->nHeight % 10 == 0) { uint256 nCheckpointCalculated = 0; - if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) - return state.DoS(100, error("ConnectBlock() : failed to calculate accumulator checkpoint")); + + // if IDB, invalid outpoints must be calculated or else acc checkpoint will be incorrect + if (pindex->nHeight == Params().Zerocoin_Block_RecalculateAccumulators()) + PopulateInvalidOutPointMap(); + + if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) { + //Calculate list of checkpoints that may be missing due to deletion on block 809000, and rewinding back before 809000 + int nStop = Params().Zerocoin_Block_RecalculateAccumulators() + 20; + if (pindex->nHeight < nStop && pindex->nHeight > Params().Zerocoin_Block_LastGoodCheckpoint()) { + LogPrintf("%s : Checkpoint not found for block %d, recalculating accumulators\n", __func__, pindex->nHeight); + CBlockIndex* pindexCheckpoint = chainActive[Params().Zerocoin_Block_LastGoodCheckpoint()]; + list listCheckpoints; + while (pindexCheckpoint->nHeight <= nStop) { + if (!count(listCheckpoints.begin(), listCheckpoints.end(), pindexCheckpoint->nAccumulatorCheckpoint)) + listCheckpoints.emplace_back(pindexCheckpoint->nAccumulatorCheckpoint); + + pindexCheckpoint = chainActive.Next(pindexCheckpoint); + if (!pindexCheckpoint) + break; + } + + string strError; + if (!ReindexAccumulators(listCheckpoints, strError) || !CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) + return state.DoS(100, error("ConnectBlock() : failed to recalculate accumulator checkpoint")); + } else { + return state.DoS(100, error("ConnectBlock() : failed to calculate accumulator checkpoint")); + } + } if (nCheckpointCalculated != block.nAccumulatorCheckpoint) { LogPrintf("%s: block=%d calculated: %s\n block: %s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), block.nAccumulatorCheckpoint.GetHex()); return state.DoS(100, error("ConnectBlock() : accumulator does not match calculated value")); } } else if (!fVerifyingBlocks) { - if (block.nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint) { + if (block.nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint) return state.DoS(100, error("ConnectBlock() : new accumulator checkpoint generated on a block that is not multiple of 10")); - } } if (!control.Wait()) @@ -4635,9 +4715,22 @@ bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex if (mi == mapBlockIndex.end()) return state.DoS(0, error("%s : prev block %s not found", __func__, block.hashPrevBlock.ToString().c_str()), 0, "bad-prevblk"); pindexPrev = (*mi).second; - if (pindexPrev->nStatus & BLOCK_FAILED_MASK) - return state.DoS(100, error("%s : prev block %s is invalid, unable to add block %s", __func__, block.hashPrevBlock.GetHex(), block.GetHash().GetHex()), + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { + //If this "invalid" block is an exact match from the checkpoints, then reconsider it + if (Checkpoints::CheckBlock(pindex->nHeight - 1, block.hashPrevBlock, true)) { + LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); + CValidationState statePrev; + ReconsiderBlock(statePrev, pindexPrev); + if (statePrev.IsValid()) { + ActivateBestChain(statePrev); + return true; + } + } + + return state.DoS(100, error("%s : prev block height=%d hash=%s is invalid, unable to add block %s", __func__, pindexPrev->nHeight, block.hashPrevBlock.GetHex(), block.GetHash().GetHex()), REJECT_INVALID, "bad-prevblk"); + } + } if (!ContextualCheckBlockHeader(block, state, pindexPrev)) @@ -4665,9 +4758,20 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, if (mi == mapBlockIndex.end()) return state.DoS(0, error("%s : prev block %s not found", __func__, block.hashPrevBlock.ToString().c_str()), 0, "bad-prevblk"); pindexPrev = (*mi).second; - if (pindexPrev->nStatus & BLOCK_FAILED_MASK) + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { + //If this "invalid" block is an exact match from the checkpoints, then reconsider it + if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true)) { + LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); + CValidationState statePrev; + ReconsiderBlock(statePrev, pindexPrev); + if (statePrev.IsValid()) { + ActivateBestChain(statePrev); + return true; + } + } return state.DoS(100, error("%s : prev block %s is invalid, unable to add block %s", __func__, block.hashPrevBlock.GetHex(), block.GetHash().GetHex()), REJECT_INVALID, "bad-prevblk"); + } } if (block.GetHash() != Params().HashGenesisBlock() && !CheckWork(block, pindexPrev)) @@ -4981,7 +5085,7 @@ bool static LoadBlockIndexDB() // Calculate nChainWork vector > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); - BOOST_FOREACH (const PAIRTYPE(uint256, CBlockIndex*) & item, mapBlockIndex) { + for (const PAIRTYPE(uint256, CBlockIndex*) & item : mapBlockIndex) { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } @@ -5031,7 +5135,7 @@ bool static LoadBlockIndexDB() // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); set setBlkDataFiles; - BOOST_FOREACH (const PAIRTYPE(uint256, CBlockIndex*) & item, mapBlockIndex) { + for (const PAIRTYPE(uint256, CBlockIndex*) & item : mapBlockIndex) { CBlockIndex* pindex = item.second; if (pindex->nStatus & BLOCK_HAVE_DATA) { setBlkDataFiles.insert(pindex->nFile); @@ -5050,83 +5154,57 @@ bool static LoadBlockIndexDB() LogPrintf("%s: Last shutdown was prepared: %s\n", __func__, fLastShutdownWasPrepared); //Check for inconsistency with block file info and internal state - if (!fLastShutdownWasPrepared && !GetBoolArg("-forcestart", false) && !GetBoolArg("-reindex", false) && (vSortedByHeight.size() != vinfoBlockFile[nLastBlockFile].nHeightLast + 1) && (vinfoBlockFile[nLastBlockFile].nHeightLast != 0)) { - //The database is in a state where a block has been accepted and written to disk, but not - //all of the block has perculated through the code. The block and the index should both be - //intact (although assertions are added if they are not), and the block will be reprocessed - //to ensure all data will be accounted for. - LogPrintf("%s: Inconsistent State Detected mapBlockIndex.size()=%d blockFileBlocks=%d\n", __func__, vSortedByHeight.size(), vinfoBlockFile[nLastBlockFile].nHeightLast + 1); - LogPrintf("%s: lastIndexPos=%d blockFileSize=%d\n", __func__, vSortedByHeight[vSortedByHeight.size() - 1].second->GetBlockPos().nPos, - vinfoBlockFile[nLastBlockFile].nSize); - - //try reading the block from the last index we have - bool isFixed = true; - string strError = ""; - LogPrintf("%s: Attempting to re-add last block that was recorded to disk\n", __func__); - - //get the last block that was properly recorded to the block info file - CBlockIndex* pindexLastMeta = vSortedByHeight[vinfoBlockFile[nLastBlockFile].nHeightLast + 1].second; + if (!fLastShutdownWasPrepared && !GetBoolArg("-forcestart", false) && !GetBoolArg("-reindex", false) && pcoinsTip->GetBestBlock() != vSortedByHeight[vinfoBlockFile[nLastBlockFile].nHeightLast + 1].second->GetBlockHash()) { + //The database is in a state where a block has been accepted and written to disk, but the + //transaction database (pcoinsTip) was not flushed to disk, and is therefore not in sync with + //the block index database. - //fix Assertion `hashPrevBlock == view.GetBestBlock()' failed. By adjusting height to the last recorded by coinsview - CBlockIndex* pindexCoinsView = mapBlockIndex[pcoinsTip->GetBestBlock()]; - for(unsigned int i = vinfoBlockFile[nLastBlockFile].nHeightLast + 1; i < vSortedByHeight.size(); i++) - { - pindexLastMeta = vSortedByHeight[i].second; - if(pindexLastMeta->nHeight > pindexCoinsView->nHeight) + if (!mapBlockIndex.count(pcoinsTip->GetBestBlock())) { + uiInterface.ThreadSafeMessageBox("Transaction database does not match the block database. Restart using -reindex.", "", CClientUIInterface::MSG_ERROR); + abort(); + } + LogPrintf("%s : pcoinstip synced to block height %d, block index height %d\n", __func__, mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, vSortedByHeight.size()); + + //get the index associated with the point in the chain that pcoinsTip is synced to + CBlockIndex* pindexLastMeta = vSortedByHeight[vinfoBlockFile[nLastBlockFile].nHeightLast + 1].second; + CBlockIndex* pindex = vSortedByHeight[0].second; + unsigned int nSortedPos = 0; + for (unsigned int i = 0; i < vSortedByHeight.size(); i++) { + nSortedPos = i; + if (vSortedByHeight[i].first == mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight +1) { + pindex = vSortedByHeight[i].second; break; + } } - LogPrintf("%s: Last block properly recorded: #%d %s\n", __func__, pindexLastMeta->nHeight, pindexLastMeta->GetBlockHash().ToString().c_str()); + CCoinsViewCache view(pcoinsTip); + while (nSortedPos < vSortedByHeight.size()) { + CBlock block; + assert(ReadBlockFromDisk(block, pindex)); + + vector vtxundo; + vtxundo.reserve(block.vtx.size() - 1); + uint256 hashBlock = block.GetHash(); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + CValidationState state; + CTxUndo undoDummy; + if (i > 0) + vtxundo.push_back(CTxUndo()); + UpdateCoins(block.vtx[i], state, view, i == 0 ? undoDummy : vtxundo.back(), pindex->nHeight); + view.SetBestBlock(hashBlock); + } + + if (pindex->nHeight >= pindexLastMeta->nHeight) + break; - CBlock lastMetaBlock; - if (!ReadBlockFromDisk(lastMetaBlock, pindexLastMeta)) { - isFixed = false; - strError = strprintf("failed to read block %d from disk", pindexLastMeta->nHeight); + pindex = vSortedByHeight[++nSortedPos].second; } - //set the chain to the block before lastMeta so that the meta block will be seen as new - chainActive.SetTip(pindexLastMeta->pprev); + if (!view.Flush() || !pcoinsTip->Flush()) + LogPrintf("%s : failed to flush view\n", __func__); - //Process the lastMetaBlock again, using the known location on disk - CDiskBlockPos blockPos = pindexLastMeta->GetBlockPos(); - CValidationState state; - ProcessNewBlock(state, NULL, &lastMetaBlock, &blockPos); - - //ensure that everything is as it should be - if (pcoinsTip->GetBestBlock() != vSortedByHeight[vSortedByHeight.size() - 1].second->GetBlockHash()) { - isFixed = false; - strError = "pcoinsTip best block is not correct"; - } - - //properly account for all of the blocks that were not in the meta data. If this is not done the file - //positioning will be wrong and blocks will be overwritten and later cause serialization errors - CBlockIndex *pindexLast = vSortedByHeight[vSortedByHeight.size() - 1].second; - CBlock lastBlock; - if (!ReadBlockFromDisk(lastBlock, pindexLast)) { - isFixed = false; - strError = strprintf("failed to read block %d from disk", pindexLast->nHeight); - } - vinfoBlockFile[nLastBlockFile].nHeightLast = pindexLast->nHeight; - vinfoBlockFile[nLastBlockFile].nSize = pindexLast->GetBlockPos().nPos + ::GetSerializeSize(lastBlock, SER_DISK, CLIENT_VERSION);; - setDirtyFileInfo.insert(nLastBlockFile); - FlushStateToDisk(state, FLUSH_STATE_ALWAYS); - - //Print out file info again - pblocktree->ReadLastBlockFile(nLastBlockFile); - vinfoBlockFile.resize(nLastBlockFile + 1); - LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); - for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { - pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); - } - LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); - - if (!isFixed) { - strError = "Failed reading from database. " + strError + ". The block database is in an inconsistent state and may cause issues in the future." - "To force start use -forcestart"; - uiInterface.ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR); - abort(); - } - LogPrintf("Passed corruption fix\n"); + LogPrintf("%s: Last block properly recorded: #%d %s\n", __func__, pindexLastMeta->nHeight, pindexLastMeta->GetBlockHash().ToString().c_str()); + LogPrintf("%s : pcoinstip=%d %s\n", __func__, mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, pcoinsTip->GetBestBlock().GetHex()); } // Check whether we need to continue reindexing diff --git a/src/main.h b/src/main.h index cefc413f95dfc..56a3786c6f93a 100644 --- a/src/main.h +++ b/src/main.h @@ -374,6 +374,7 @@ bool ValidOutPoint(const COutPoint out, int nHeight); void RecalculateZPIVSpent(); void RecalculateZPIVMinted(); bool RecalculatePIVSupply(int nHeightStart); +bool ReindexAccumulators(list listMissingCheckpoints, string& strError); /**