From 855471e18833d5ea4c3ce1a819f9e7dc38a6fd27 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Thu, 1 Oct 2020 01:25:38 +0200 Subject: [PATCH 1/6] [Cleanup] Static AcceptBlock --- src/validation.cpp | 2 +- src/validation.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index a75f748ec483..f251443f72f0 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3016,7 +3016,7 @@ bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex return true; } -bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp, bool fAlreadyCheckedBlock) +static bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp = nullptr, bool fAlreadyCheckedBlock = false) { AssertLockHeld(cs_main); diff --git a/src/validation.h b/src/validation.h index 37c8dd370203..91772b595104 100644 --- a/src/validation.h +++ b/src/validation.h @@ -340,8 +340,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Store block on disk. If dbp is provided, the file is known to already reside on disk */ -bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** pindex, CDiskBlockPos* dbp = NULL, bool fAlreadyCheckedBlock = false); -bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex** ppindex = NULL); +bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex** ppindex = nullptr); /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ From a0fe01de8720e616ccb7a2299d41b7a63b82a093 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Apr 2016 14:53:36 +0200 Subject: [PATCH 2/6] Make ProcessNewBlock dbp const and update comment --- src/validation.cpp | 4 ++-- src/validation.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index f251443f72f0..f49fa9074dba 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3016,7 +3016,7 @@ bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex return true; } -static bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp = nullptr, bool fAlreadyCheckedBlock = false) +static bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, const CDiskBlockPos* dbp = nullptr, bool fAlreadyCheckedBlock = false) { AssertLockHeld(cs_main); @@ -3328,7 +3328,7 @@ void CBlockIndex::BuildSkip() pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); } -bool ProcessNewBlock(CValidationState& state, CNode* pfrom, const CBlock* pblock, CDiskBlockPos* dbp, bool* fAccepted) +bool ProcessNewBlock(CValidationState& state, CNode* pfrom, const CBlock* pblock, const CDiskBlockPos* dbp, bool* fAccepted) { AssertLockNotHeld(cs_main); diff --git a/src/validation.h b/src/validation.h index 91772b595104..4f2e9698d931 100644 --- a/src/validation.h +++ b/src/validation.h @@ -166,11 +166,11 @@ static const uint64_t nMinDiskSpace = 52428800; * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation. * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. * @param[in] pblock The block we want to process. - * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. + * @param[in] dbp The already known disk position of pblock, or NULL if not yet stored. * @param[out] fAccepted Whether the block is accepted or not * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState& state, CNode* pfrom, const CBlock* pblock, CDiskBlockPos* dbp, bool* fAccepted = nullptr); +bool ProcessNewBlock(CValidationState& state, CNode* pfrom, const CBlock* pblock, const CDiskBlockPos* dbp, bool* fAccepted = nullptr); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ From ec7809a817192bdce5623211ce857938ce9a854c Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Sep 2020 12:50:30 +0200 Subject: [PATCH 3/6] Switch reindexing to AcceptBlock in-loop and ActivateBestChain after >>> backports bitcoin/bitcoin@316623f2c197971db9b5bcb9c84e446254b552c3 --- src/init.cpp | 15 ++++++++------- src/validation.cpp | 13 ++++++++----- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 66163edd868a..d78217fbed55 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -649,10 +649,10 @@ struct CImportingNow { void ThreadImport(std::vector vImportFiles) { util::ThreadRename("pivx-loadblk"); + CImportingNow imp; // -reindex if (fReindex) { - CImportingNow imp; int nFile = 0; while (true) { CDiskBlockPos pos(nFile, 0); @@ -677,7 +677,6 @@ void ThreadImport(std::vector vImportFiles) if (fs::exists(pathBootstrap)) { FILE* file = fsbridge::fopen(pathBootstrap, "rb"); if (file) { - CImportingNow imp; fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); LoadExternalBlockFile(file); @@ -691,7 +690,6 @@ void ThreadImport(std::vector vImportFiles) for (fs::path& path : vImportFiles) { FILE* file = fsbridge::fopen(path, "rb"); if (file) { - CImportingNow imp; LogPrintf("Importing blocks file %s...\n", path.string()); LoadExternalBlockFile(file); } else { @@ -699,6 +697,13 @@ void ThreadImport(std::vector vImportFiles) } } + // scan for better chains in the block chain database, that are not yet connected in the active best chain + CValidationState state; + if (!ActivateBestChain(state)) { + LogPrintf("Failed to connect best block"); + StartShutdown(); + } + if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); StartShutdown(); @@ -1711,10 +1716,6 @@ bool AppInit2() if (mapArgs.count("-blocksizenotify")) uiInterface.NotifyBlockSize.connect(BlockSizeNotifyCallback); - // scan for better chains in the block chain database, that are not yet connected in the active best chain - CValidationState state; - if (!ActivateBestChain(state)) - strErrors << "Failed to connect best block"; // update g_best_block if needed { LOCK(g_best_block_mutex); diff --git a/src/validation.cpp b/src/validation.cpp index f49fa9074dba..e2c721fbd1fb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3020,7 +3020,8 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockInde { AssertLockHeld(cs_main); - CBlockIndex*& pindex = *ppindex; + CBlockIndex* pindexDummy = nullptr; + CBlockIndex*& pindex = ppindex ? *ppindex : pindexDummy; const Consensus::Params& consensus = Params().GetConsensus(); @@ -3828,13 +3829,14 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { + LOCK(cs_main); CValidationState state; - if (ProcessNewBlock(state, nullptr, &block, dbp)) + if (AcceptBlock(block, state, nullptr, dbp)) nLoaded++; if (state.IsError()) break; } else if (hash != Params().GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { - LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); + LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } // Recursively process earlier encountered successors of this block @@ -3847,10 +3849,11 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) while (range.first != range.second) { std::multimap::iterator it = range.first; if (ReadBlockFromDisk(block, it->second)) { - LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), + LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); + LOCK(cs_main); CValidationState dummy; - if (ProcessNewBlock(dummy, nullptr, &block, &it->second)) { + if (AcceptBlock(block, dummy, nullptr, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); } From da9a122cca7a7569472501effc9d2b67ce3572b7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 20 Apr 2016 16:02:19 +0200 Subject: [PATCH 4/6] Optimize ActivateBestChain for long chains --- src/validation.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index e2c721fbd1fb..c3af629fea69 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2149,12 +2149,11 @@ static void PruneBlockIndexCandidates() * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMostWork, const CBlock* pblock, bool fAlreadyChecked, std::list& txConflicted, std::vector>& txChanged) +static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMostWork, const CBlock* pblock, bool fAlreadyChecked, std::list& txConflicted, std::vector>& txChanged, bool& fInvalidFound) { AssertLockHeld(cs_main); if (pblock == NULL) fAlreadyChecked = false; - bool fInvalidFound = false; const CBlockIndex* pindexOldTip = chainActive.Tip(); const CBlockIndex* pindexFork = chainActive.FindFork(pindexMostWork); @@ -2258,15 +2257,23 @@ bool ActivateBestChain(CValidationState& state, const CBlock* pblock, bool fAlre } CBlockIndex *pindexOldTip = chainActive.Tip(); - pindexMostWork = FindMostWorkChain(); + if (pindexMostWork == nullptr) { + pindexMostWork = FindMostWorkChain(); + } // Whether we have anything to do at all. - if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) + if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fAlreadyChecked, txConflicted, txChanged)) + bool fInvalidFound = false; + if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullptr, fAlreadyChecked, txConflicted, txChanged, fInvalidFound)) return false; + if (fInvalidFound) { + // Wipe cache, we may need another branch now. + pindexMostWork = nullptr; + } + pindexNewTip = chainActive.Tip(); pindexFork = chainActive.FindFork(pindexOldTip); fInitialDownload = IsInitialBlockDownload(); From 8f7f31de532e8431ce62eda1e45dffe026b15242 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Sep 2020 13:46:14 +0200 Subject: [PATCH 5/6] Add -reindex-chainstate that does not rebuild block index >>> backports bitcoin/bitcoin@d3d75479115bc3480f163df774ee9dd2f8bd9f54 --- src/init.cpp | 6 ++++-- test/functional/feature_reindex.py | 12 +++++++++--- test/functional/test_runner.py | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index d78217fbed55..1f5eac6303ee 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -417,6 +417,7 @@ std::string HelpMessage(HelpMessageMode mode) #ifndef WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), PIVX_PID_FILENAME)); #endif + strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks")); strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup")); strUsage += HelpMessageOpt("-reindexmoneysupply", strprintf(_("Reindex the %s and z%s money supply statistics"), CURRENCY_UNIT, CURRENCY_UNIT) + " " + _("on startup")); strUsage += HelpMessageOpt("-resync", _("Delete blockchain folders and resync from scratch") + " " + _("on startup")); @@ -1462,6 +1463,7 @@ bool AppInit2() // ********************************************************* Step 7: load block chain fReindex = GetBoolArg("-reindex", false); + bool fReindexChainState = GetBoolArg("-reindex-chainstate", false); // Create blocks directory if it doesn't already exist fs::create_directories(GetDataDir() / "blocks"); @@ -1504,7 +1506,7 @@ bool AppInit2() pSporkDB = new CSporkDB(0, false, false); pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinsTip = new CCoinsViewCache(pcoinscatcher); @@ -1550,7 +1552,7 @@ bool AppInit2() // Check for changed -txindex state if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); + strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex"); break; } diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py index 234d1ad899f3..10cf68c3f3b1 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -19,19 +19,25 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def reindex(self): + def reindex(self, justchainstate=False): self.nodes[0].generate(3) blockcount = self.nodes[0].getblockcount() self.stop_nodes() + self.log.info("Stopping node...") time.sleep(5) - extra_args = [["-reindex", "-checkblockindex=1"]] + extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]] + self.log.info("Reindexing %s [block count: %d]" % ( + "chainstate" if justchainstate else "blocks", blockcount)) self.start_nodes(extra_args) time.sleep(15) wait_until(lambda: self.nodes[0].getblockcount() == blockcount) self.log.info("Success") def run_test(self): - self.reindex() + self.reindex(False) + self.reindex(True) + self.reindex(False) + self.reindex(True) if __name__ == '__main__': ReindexTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index b71a5c3f882a..2ae9e43c7e51 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -61,6 +61,7 @@ # vv Tests less than 5m vv 'wallet_zapwallettxes.py', # ~ 300 sec + 'feature_reindex.py', # ~ 290 sec 'p2p_time_offset.py', # ~ 267 sec 'rpc_fundrawtransaction.py', # ~ 260 sec 'mining_pos_coldStaking.py', # ~ 215 sec @@ -84,7 +85,6 @@ 'p2p_disconnect_ban.py', # ~ 118 sec 'wallet_listreceivedby.py', # ~ 117 sec 'mining_pos_fakestake.py', # ~ 113 sec - 'feature_reindex.py', # ~ 110 sec 'interface_http.py', # ~ 105 sec 'wallet_listtransactions.py', # ~ 97 sec 'mempool_reorg.py', # ~ 92 sec From 2d309330bc93a3e310a8f5cd4912cb80e5579046 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 22 Sep 2020 15:02:59 +0200 Subject: [PATCH 6/6] Report reindexing progress in GUI >>> backports bitcoin@b4d24e142e25a21c78ab74146c3520f2259fd7c2 --- src/guiinterface.h | 3 ++ src/qt/clientmodel.cpp | 17 ++++--- src/qt/clientmodel.h | 2 +- .../settings/settingsinformationwidget.cpp | 5 ++- .../pivx/settings/settingsinformationwidget.h | 2 +- src/qt/pivx/topbar.cpp | 8 ++-- src/qt/pivx/topbar.h | 2 +- src/qt/rpcconsole.cpp | 5 ++- src/qt/rpcconsole.h | 2 +- src/validation.cpp | 44 +++++++++++++++++-- 10 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/guiinterface.h b/src/guiinterface.h index cc1a0cc087f8..2a5f31a92645 100644 --- a/src/guiinterface.h +++ b/src/guiinterface.h @@ -103,6 +103,9 @@ class CClientUIInterface /** New block has been accepted */ boost::signals2::signal NotifyBlockTip; + /** Best header has changed */ + boost::signals2::signal NotifyHeaderTip; + /** New block has been accepted and is over a certain size */ boost::signals2::signal NotifyBlockSize; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 1e8ab4221356..630c9c0e9997 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -29,6 +29,7 @@ static const int64_t nClientStartupTime = GetTime(); // Last tip update notification +static int64_t nLastHeaderTipUpdateNotification = 0; static int64_t nLastBlockTipUpdateNotification = 0; ClientModel::ClientModel(OptionsModel* optionsModel, QObject* parent) : QObject(parent), @@ -250,7 +251,7 @@ void ClientModel::updateBanlist() banTableModel->refresh(); } -static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex) +static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex, bool fHeader) { // lock free async UI updates in case we have a new block tip // during initial sync, only update the UI if the last update @@ -259,15 +260,17 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB if (initialSync) now = GetTimeMillis(); + int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; + // if we are in-sync, update the UI regardless of last update time - if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) { + if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { //pass a async signal to the UI thread clientmodel->setCacheTip(pIndex); clientmodel->setCacheImporting(fImporting); clientmodel->setCacheReindexing(fReindex); clientmodel->setCacheInitialSync(initialSync); - Q_EMIT clientmodel->numBlocksChanged(pIndex->nHeight); - nLastBlockTipUpdateNotification = now; + Q_EMIT clientmodel->numBlocksChanged(pIndex->nHeight, fHeader); + nLastUpdateNotification = now; } } @@ -306,7 +309,8 @@ void ClientModel::subscribeToCoreSignals() uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); + uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false)); + uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true)); } void ClientModel::unsubscribeFromCoreSignals() @@ -316,7 +320,8 @@ void ClientModel::unsubscribeFromCoreSignals() uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); - uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); + uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false)); + uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true)); } bool ClientModel::getTorInfo(std::string& ip_port) const diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 9940aeb40605..adb902c6ede0 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -112,7 +112,7 @@ class ClientModel : public QObject Q_SIGNALS: void numConnectionsChanged(int count); - void numBlocksChanged(int count); + void numBlocksChanged(int count, bool headers); void strMasternodesChanged(const QString& strMasternodes); void alertsChanged(const QString& warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); diff --git a/src/qt/pivx/settings/settingsinformationwidget.cpp b/src/qt/pivx/settings/settingsinformationwidget.cpp index f08a10aa6d0b..2f9733210334 100644 --- a/src/qt/pivx/settings/settingsinformationwidget.cpp +++ b/src/qt/pivx/settings/settingsinformationwidget.cpp @@ -118,7 +118,7 @@ void SettingsInformationWidget::loadClientModel() setNumConnections(clientModel->getNumConnections()); connect(clientModel, &ClientModel::numConnectionsChanged, this, &SettingsInformationWidget::setNumConnections); - setNumBlocks(clientModel->getNumBlocks()); + setNumBlocks(clientModel->getNumBlocks(), false); connect(clientModel, &ClientModel::numBlocksChanged, this, &SettingsInformationWidget::setNumBlocks); connect(clientModel, &ClientModel::strMasternodesChanged, this, &SettingsInformationWidget::setMasternodeCount); @@ -137,8 +137,9 @@ void SettingsInformationWidget::setNumConnections(int count) ui->labelInfoConnections->setText(connections); } -void SettingsInformationWidget::setNumBlocks(int count) +void SettingsInformationWidget::setNumBlocks(int count, bool headers) { + if (headers) return; ui->labelInfoBlockNumber->setText(QString::number(count)); if (clientModel) { ui->labelInfoBlockTime->setText(clientModel->getLastBlockDate().toString()); diff --git a/src/qt/pivx/settings/settingsinformationwidget.h b/src/qt/pivx/settings/settingsinformationwidget.h index 5e071b9bdea4..9a12bb440f83 100644 --- a/src/qt/pivx/settings/settingsinformationwidget.h +++ b/src/qt/pivx/settings/settingsinformationwidget.h @@ -25,7 +25,7 @@ class SettingsInformationWidget : public PWidget private Q_SLOTS: void setNumConnections(int count); - void setNumBlocks(int count); + void setNumBlocks(int count, bool headers); void setMasternodeCount(const QString& strMasternodes); void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; diff --git a/src/qt/pivx/topbar.cpp b/src/qt/pivx/topbar.cpp index 389fa3f25613..9afb4e704d6c 100644 --- a/src/qt/pivx/topbar.cpp +++ b/src/qt/pivx/topbar.cpp @@ -373,7 +373,7 @@ void TopBar::loadClientModel() setNumConnections(clientModel->getNumConnections()); connect(clientModel, &ClientModel::numConnectionsChanged, this, &TopBar::setNumConnections); - setNumBlocks(clientModel->getNumBlocks()); + setNumBlocks(clientModel->getNumBlocks(), false); connect(clientModel, &ClientModel::numBlocksChanged, this, &TopBar::setNumBlocks); timerStakingIcon = new QTimer(ui->pushButtonStack); @@ -420,7 +420,7 @@ void TopBar::setNumConnections(int count) ui->pushButtonConnection->setButtonText(tr("%n active connection(s)", "", count)); } -void TopBar::setNumBlocks(int count) +void TopBar::setNumBlocks(int count, bool headers) { if (!clientModel) return; @@ -430,15 +430,17 @@ void TopBar::setNumBlocks(int count) std::string text = ""; switch (blockSource) { case BLOCK_SOURCE_NETWORK: + if (headers) return; text = "Synchronizing.."; break; case BLOCK_SOURCE_DISK: - text = "Importing blocks from disk.."; + text = headers ? "Indexing blocks from disk..." : "Processing blocks on disk..."; break; case BLOCK_SOURCE_REINDEX: text = "Reindexing blocks on disk.."; break; case BLOCK_SOURCE_NONE: + if (headers) return; // Case: not Importing, not Reindexing and no network connection text = "No block source available.."; ui->pushButtonSync->setChecked(false); diff --git a/src/qt/pivx/topbar.h b/src/qt/pivx/topbar.h index c471cfe240b5..8bff66ca0632 100644 --- a/src/qt/pivx/topbar.h +++ b/src/qt/pivx/topbar.h @@ -47,7 +47,7 @@ public Q_SLOTS: void updateDisplayUnit(); void setNumConnections(int count); - void setNumBlocks(int count); + void setNumBlocks(int count, bool headers); void setStakingStatusActive(bool fActive); void updateStakingStatus(); void updateHDState(const bool& upgraded, const QString& upgradeError); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index bcf1890ee689..bc64d361f45d 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -387,7 +387,7 @@ void RPCConsole::setClientModel(ClientModel* model) setNumConnections(model->getNumConnections()); connect(model, &ClientModel::numConnectionsChanged, this, &RPCConsole::setNumConnections); - setNumBlocks(model->getNumBlocks()); + setNumBlocks(model->getNumBlocks(), false); connect(model, &ClientModel::numBlocksChanged, this, &RPCConsole::setNumBlocks); connect(model, &ClientModel::strMasternodesChanged, this, &RPCConsole::setMasternodeCount); @@ -661,8 +661,9 @@ void RPCConsole::setNumConnections(int count) ui->numberOfConnections->setText(connections); } -void RPCConsole::setNumBlocks(int count) +void RPCConsole::setNumBlocks(int count, bool headers) { + if (headers) return; ui->numberOfBlocks->setText(QString::number(count)); if (clientModel) { ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString()); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index c96a0caa342e..7b528cc0813f 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -88,7 +88,7 @@ public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks shown in the UI */ - void setNumBlocks(int count); + void setNumBlocks(int count, bool headers); /** Set number of masternodes shown in the UI */ void setMasternodeCount(const QString& strMasternodes); /** Go forward or back in history */ diff --git a/src/validation.cpp b/src/validation.cpp index c3af629fea69..695810319440 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2223,6 +2223,29 @@ static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMo return true; } +static void NotifyHeaderTip() +{ + bool fNotify = false; + bool fInitialBlockDownload = false; + static CBlockIndex* pindexHeaderOld = NULL; + CBlockIndex* pindexHeader = NULL; + { + LOCK(cs_main); + if (!setBlockIndexCandidates.empty()) { + pindexHeader = *setBlockIndexCandidates.rbegin(); + } + if (pindexHeader != pindexHeaderOld) { + fNotify = true; + fInitialBlockDownload = IsInitialBlockDownload(); + pindexHeaderOld = pindexHeader; + } + } + // Send block tip changed notifications without cs_main + if (fNotify) { + uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader); + } +} + /** * Make the best chain active, in multiple steps. The result is either failure * or an activated best chain. pblock is either NULL or a pointer to a block @@ -3380,6 +3403,8 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, const CBlock* pblock } } + NotifyHeaderTip(); + if (!ActivateBestChain(state, pblock, checked)) return error("%s : ActivateBestChain failed", __func__); @@ -3781,6 +3806,8 @@ bool InitBlockIndex() bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) { + const Consensus::Params& consensus = Params().GetConsensus(); + // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); @@ -3825,8 +3852,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) nRewind = blkdat.GetPos(); // detect out of order blocks, and store them for later - uint256 hash = block.GetHash(); - if (hash != Params().GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { + const uint256& hash = block.GetHash(); + if (hash != consensus.hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.GetHex(), block.hashPrevBlock.GetHex()); if (dbp) @@ -3842,10 +3869,20 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) nLoaded++; if (state.IsError()) break; - } else if (hash != Params().GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { + } else if (hash != consensus.hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } + // Activate the genesis block so normal node progress can continue + if (hash == consensus.hashGenesisBlock) { + CValidationState state; + if (!ActivateBestChain(state)) { + break; + } + } + + NotifyHeaderTip(); + // Recursively process earlier encountered successors of this block std::deque queue; queue.push_back(hash); @@ -3867,6 +3904,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) } range.first++; mapBlocksUnknownParent.erase(it); + NotifyHeaderTip(); } } } catch (const std::exception& e) {