Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2016-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <bitcoin-build-config.h> // IWYU pragma: keep7#include <qt/modaloverlay.h>8#include <qt/forms/ui_modaloverlay.h>10#include <chainparams.h>11#include <qt/guiutil.h>13#include <QEasingCurve>14#include <QPropertyAnimation>15#include <QResizeEvent>17ModalOverlay::ModalOverlay(bool enable_wallet, QWidget* parent)18: QWidget(parent),19ui(new Ui::ModalOverlay),20bestHeaderDate(QDateTime())21{22ui->setupUi(this);23connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);24if (parent) {25parent->installEventFilter(this);26raise();27}28ui->closeButton->installEventFilter(this);30blockProcessTime.clear();31setVisible(false);32if (!enable_wallet) {33ui->infoText->setVisible(false);34ui->infoTextStrong->setText(tr("%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.").arg(CLIENT_NAME));35}37m_animation.setTargetObject(this);38m_animation.setPropertyName("pos");39m_animation.setDuration(300 /* ms */);40m_animation.setEasingCurve(QEasingCurve::OutQuad);41}43ModalOverlay::~ModalOverlay()44{45delete ui;46}48bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {49if (obj == parent()) {50if (ev->type() == QEvent::Resize) {51QResizeEvent * rev = static_cast<QResizeEvent*>(ev);52resize(rev->size());53if (!layerIsVisible)54setGeometry(0, height(), width(), height());56if (m_animation.endValue().toPoint().y() > 0) {57m_animation.setEndValue(QPoint(0, height()));58}59}60else if (ev->type() == QEvent::ChildAdded) {61raise();62}63}65if (obj == ui->closeButton && ev->type() == QEvent::FocusOut && layerIsVisible) {66ui->closeButton->setFocus(Qt::OtherFocusReason);67}69return QWidget::eventFilter(obj, ev);70}72//! Tracks parent widget changes73bool ModalOverlay::event(QEvent* ev) {74if (ev->type() == QEvent::ParentAboutToChange) {75if (parent()) parent()->removeEventFilter(this);76}77else if (ev->type() == QEvent::ParentChange) {78if (parent()) {79parent()->installEventFilter(this);80raise();81}82}83return QWidget::event(ev);84}86void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate, bool presync)87{88if (!presync && count > bestHeaderHeight) {89bestHeaderHeight = count;90bestHeaderDate = blockDate;91UpdateHeaderSyncLabel();92}93if (presync) {94UpdateHeaderPresyncLabel(count, blockDate);95}96}98void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)99{100QDateTime currentDate = QDateTime::currentDateTime();102// keep a vector of samples of verification progress at height103blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));105// show progress speed if we have more than one sample106if (blockProcessTime.size() >= 2) {107double progressDelta = 0;108double progressPerHour = 0;109qint64 timeDelta = 0;110qint64 remainingMSecs = 0;111double remainingProgress = 1.0 - nVerificationProgress;112for (int i = 1; i < blockProcessTime.size(); i++) {113QPair<qint64, double> sample = blockProcessTime[i];115// take first sample after 500 seconds or last available one116if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {117progressDelta = blockProcessTime[0].second - sample.second;118timeDelta = blockProcessTime[0].first - sample.first;119progressPerHour = (progressDelta > 0) ? progressDelta / (double)timeDelta * 1000 * 3600 : 0;120remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;121break;122}123}124// show progress increase per hour125ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");127// show expected remaining time128if(remainingMSecs >= 0) {129ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));130} else {131ui->expectedTimeLeft->setText(QObject::tr("unknown"));132}134static const int MAX_SAMPLES = 5000;135if (blockProcessTime.count() > MAX_SAMPLES) {136blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);137}138}140// show the last block date141ui->newestBlockDate->setText(blockDate.toString());143// show the percentage done according to nVerificationProgress144ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");146if (!bestHeaderDate.isValid())147// not syncing148return;150// estimate the number of headers left based on nPowTargetSpacing151// and check if the gui is not aware of the best header (happens rarely)152int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;153bool hasBestHeader = bestHeaderHeight >= count;155// show remaining number of blocks156if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {157ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));158} else {159UpdateHeaderSyncLabel();160ui->expectedTimeLeft->setText(tr("Unknown…"));161}162}164void ModalOverlay::UpdateHeaderSyncLabel() {165int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;166ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)…").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));167}169void ModalOverlay::UpdateHeaderPresyncLabel(int height, const QDateTime& blockDate) {170int est_headers_left = blockDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;171ui->numberOfBlocksLeft->setText(tr("Unknown. Pre-syncing Headers (%1, %2%)…").arg(height).arg(QString::number(100.0 / (height + est_headers_left) * height, 'f', 1)));172}174void ModalOverlay::toggleVisibility()175{176showHide(layerIsVisible, true);177if (!layerIsVisible)178userClosed = true;179}181void ModalOverlay::showHide(bool hide, bool userRequested)182{183if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))184return;186Q_EMIT triggered(hide);188if (!isVisible() && !hide)189setVisible(true);191m_animation.setStartValue(QPoint(0, hide ? 0 : height()));192// The eventFilter() updates the endValue if it is required for QEvent::Resize.193m_animation.setEndValue(QPoint(0, hide ? height() : 0));194m_animation.start(QAbstractAnimation::KeepWhenStopped);195layerIsVisible = !hide;197if (layerIsVisible) {198ui->closeButton->setFocus(Qt::OtherFocusReason);199}200}202void ModalOverlay::closeClicked()203{204showHide(true);205userClosed = true;206}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.