diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3b100f125603e..776377943d185 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 }; @@ -139,6 +140,7 @@ class CMainParams : public CChainParams nBlockRecalculateAccumulators = 908000; //Trigger a recalculation of accumulators nBlockFirstFraudulent = 891737; //First block that bad serials emerged nBlockLastGoodCheckpoint = 891730; //Last valid accumulator checkpoint + nBlockEnforceInvalidUTXO = 902850; //Start enforcing the invalid UTXO's /** * Build the genesis block. Note that the output of the genesis coinbase cannot @@ -256,6 +258,7 @@ class CTestNetParams : public CMainParams nBlockRecalculateAccumulators = 9908000; //Trigger a recalculation of accumulators nBlockFirstFraudulent = 9891737; //First block that bad serials emerged nBlockLastGoodCheckpoint = 9891730; //Last valid accumulator checkpoint + nBlockEnforceInvalidUTXO = 9902850; //Start enforcing the invalid UTXO's //! Modify the testnet genesis block so the timestamp is valid for a later start. genesis.nTime = 1454124731; diff --git a/src/chainparams.h b/src/chainparams.h index bf46680b004c7..13501d19c1b81 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -116,6 +116,7 @@ class CChainParams int Zerocoin_Block_FirstFraudulent() const { return nBlockFirstFraudulent; } int Zerocoin_Block_LastGoodCheckpoint() const { return nBlockLastGoodCheckpoint; } int Zerocoin_StartTime() const { return nZerocoinStartTime; } + int Block_Enforce_Invalid() const { return nBlockEnforceInvalidUTXO; } protected: CChainParams() {} @@ -173,6 +174,7 @@ class CChainParams int nBlockRecalculateAccumulators; int nBlockFirstFraudulent; int nBlockLastGoodCheckpoint; + int nBlockEnforceInvalidUTXO; }; /** diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index e4b4371d9d447..3ac8d29b465e9 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,8 @@ 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; } 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..2c5bb05f6f153 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1326,8 +1326,10 @@ bool AppInit2(boost::thread_group& threadGroup) LoadSporksFromDB(); uiInterface.InitMessage(_("Loading block index...")); - if (!LoadBlockIndex()) { + string strBlockIndexError = ""; + if (!LoadBlockIndex(strBlockIndexError)) { strLoadError = _("Error loading block database"); + strLoadError = strprintf("%s : %s", strLoadError, strBlockIndexError); break; } @@ -1371,59 +1373,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..d2fdaf567789a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2468,7 +2468,7 @@ int64_t GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCou bool IsInitialBlockDownload() { LOCK(cs_main); - if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) + if (fImporting || fReindex || fVerifyingBlocks || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) return true; static bool lockIBDState = false; if (lockIBDState) @@ -2772,14 +2772,14 @@ void PopulateInvalidOutPointMap() } } - if (pindex->nHeight >= Params().Zerocoin_Block_RecalculateAccumulators()) + if (pindex->nHeight > Params().Zerocoin_Block_RecalculateAccumulators()) fListPopulatedAfterLock = true; } } bool ValidOutPoint(const COutPoint out, int nHeight) { - bool isInvalid = nHeight >= GetSporkValue(SPORK_11_LOCK_INVALID_UTXO) && mapInvalidOutPoints.count(out); + bool isInvalid = nHeight >= Params().Block_Enforce_Invalid() && mapInvalidOutPoints.count(out); return !isInvalid; } @@ -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 (pindex && 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)) @@ -4971,7 +5075,7 @@ CBlockIndex* InsertBlockIndex(uint256 hash) return pindexNew; } -bool static LoadBlockIndexDB() +bool static LoadBlockIndexDB(string& strError) { if (!pblocktree->LoadBlockIndexGuts()) return false; @@ -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,63 @@ 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) - break; + if (!mapBlockIndex.count(pcoinsTip->GetBestBlock())) { + strError = "The wallet has been not been closed gracefully, causing the transaction database to be out of sync with the block database"; + return false; } + LogPrintf("%s : pcoinstip synced to block height %d, block index height %d\n", __func__, mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, vSortedByHeight.size()); - LogPrintf("%s: Last block properly recorded: #%d %s\n", __func__, pindexLastMeta->nHeight, pindexLastMeta->GetBlockHash().ToString().c_str()); - - CBlock lastMetaBlock; - if (!ReadBlockFromDisk(lastMetaBlock, pindexLastMeta)) { - isFixed = false; - strError = strprintf("failed to read block %d from disk", pindexLastMeta->nHeight); + //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; + } } - //set the chain to the block before lastMeta so that the meta block will be seen as new - chainActive.SetTip(pindexLastMeta->pprev); + // Start at the last block that was successfully added to the txdb (pcoinsTip) and manually add all transactions that occurred for each block up until + // the best known block from the block index db. + CCoinsViewCache view(pcoinsTip); + while (nSortedPos < vSortedByHeight.size()) { + CBlock block; + if (!ReadBlockFromDisk(block, pindex)) { + strError = "The wallet has been not been closed gracefully and has caused corruption of blocks stored to disk. Data directory is in an unusable state"; + return false; + } - //Process the lastMetaBlock again, using the known location on disk - CDiskBlockPos blockPos = pindexLastMeta->GetBlockPos(); - CValidationState state; - ProcessNewBlock(state, NULL, &lastMetaBlock, &blockPos); + 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); + } - //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"; - } + if (pindex->nHeight >= pindexLastMeta->nHeight) + break; - //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); + pindex = vSortedByHeight[++nSortedPos].second; } - 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()); + // Save the updates to disk + if (!view.Flush() || !pcoinsTip->Flush()) + LogPrintf("%s : failed to flush view\n", __func__); - 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 @@ -5252,10 +5336,10 @@ void UnloadBlockIndex() pindexBestInvalid = NULL; } -bool LoadBlockIndex() +bool LoadBlockIndex(string& strError) { // Load block index from databases - if (!fReindex && !LoadBlockIndexDB()) + if (!fReindex && !LoadBlockIndexDB(strError)) return false; return true; } @@ -5898,6 +5982,7 @@ void static ProcessGetData(CNode* pfrom) } } +bool fRequestedSporksIDB = false; bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { RandAddSeedPerfmon(); @@ -5918,11 +6003,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // PIVX: We use certain sporks during IBD, so check to see if they are // available. If not, ask the first peer connected for them. - if (!pSporkDB->SporkExists(SPORK_14_NEW_PROTOCOL_ENFORCEMENT) && - !pSporkDB->SporkExists(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) && - !pSporkDB->SporkExists(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { - LogPrintf("Required sporks not found, asking peer to send them\n"); + bool fMissingSporks = !pSporkDB->SporkExists(SPORK_14_NEW_PROTOCOL_ENFORCEMENT) && + !pSporkDB->SporkExists(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) && + !pSporkDB->SporkExists(SPORK_16_ZEROCOIN_MAINTENANCE_MODE); + + if (fMissingSporks || !fRequestedSporksIDB){ + LogPrintf("asking peer for sporks\n"); pfrom->PushMessage("getsporks"); + fRequestedSporksIDB = true; } int64_t nTime; diff --git a/src/main.h b/src/main.h index cefc413f95dfc..0d6445e4f32c3 100644 --- a/src/main.h +++ b/src/main.h @@ -205,7 +205,7 @@ 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 */ -bool LoadBlockIndex(); +bool LoadBlockIndex(std::string& strError); /** Unload database information */ void UnloadBlockIndex(); /** See whether the protocol update is enforced for connected nodes */ @@ -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); /** diff --git a/src/spork.cpp b/src/spork.cpp index d9a3f85854601..a29427699ec02 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -124,7 +124,6 @@ int64_t GetSporkValue(int nSporkID) if (nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT; if (nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT; if (nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT; - if (nSporkID == SPORK_11_LOCK_INVALID_UTXO) r = SPORK_11_LOCK_INVALID_UTXO_DEFAULT; if (nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT; if (nSporkID == SPORK_14_NEW_PROTOCOL_ENFORCEMENT) r = SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT; if (nSporkID == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) r = SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT; @@ -264,7 +263,6 @@ int CSporkManager::GetSporkIDByName(std::string strName) if (strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT; if (strName == "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT") return SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT; if (strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES; - if (strName == "SPORK_11_LOCK_INVALID_UTXO") return SPORK_11_LOCK_INVALID_UTXO; if (strName == "SPORK_13_ENABLE_SUPERBLOCKS") return SPORK_13_ENABLE_SUPERBLOCKS; if (strName == "SPORK_14_NEW_PROTOCOL_ENFORCEMENT") return SPORK_14_NEW_PROTOCOL_ENFORCEMENT; if (strName == "SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2") return SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2; @@ -282,7 +280,6 @@ std::string CSporkManager::GetSporkNameByID(int id) if (id == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT"; if (id == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) return "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT"; if (id == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES"; - if (id == SPORK_11_LOCK_INVALID_UTXO) return "SPORK_11_LOCK_INVALID_UTXO"; if (id == SPORK_13_ENABLE_SUPERBLOCKS) return "SPORK_13_ENABLE_SUPERBLOCKS"; if (id == SPORK_14_NEW_PROTOCOL_ENFORCEMENT) return "SPORK_14_NEW_PROTOCOL_ENFORCEMENT"; if (id == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) return "SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2"; diff --git a/src/spork.h b/src/spork.h index 6add73e7b8ed5..a74ae69c1a65c 100644 --- a/src/spork.h +++ b/src/spork.h @@ -36,7 +36,7 @@ using namespace boost; #define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT 10007 #define SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT 10008 #define SPORK_10_MASTERNODE_PAY_UPDATED_NODES 10009 -#define SPORK_11_LOCK_INVALID_UTXO 10010 +//#define SPORK_11_LOCK_INVALID_UTXO 10010 //#define SPORK_12_RECONSIDER_BLOCKS 10011 #define SPORK_13_ENABLE_SUPERBLOCKS 10012 #define SPORK_14_NEW_PROTOCOL_ENFORCEMENT 10013 @@ -50,7 +50,7 @@ using namespace boost; #define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT 4070908800 //OFF #define SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT 4070908800 //OFF #define SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT 4070908800 //OFF -#define SPORK_11_LOCK_INVALID_UTXO_DEFAULT 4070908800 //OFF - NOTE: this is block height not time! +//#define SPORK_11_LOCK_INVALID_UTXO_DEFAULT 4070908800 //OFF - NOTE: this is block height not time! #define SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT 4070908800 //OFF #define SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT 4070908800 //OFF #define SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT 4070908800 //OFF