From 8df54fe3557a6e7d1d027b986d377f53fdb3b30d Mon Sep 17 00:00:00 2001
From: jarolrod <jarolrod@tutanota.com>
Date: Tue, 28 Feb 2023 02:34:16 -0500
Subject: [PATCH 1/2] qml: handle pre & header sync, move verification progress
 along

This connects us to the header tip signal so that we can handle when the
node is in pre & or headers sync. This calculates the progress of the
pre or headers sync and adds it to our verification progress. Pre and
headers sync take up 1% of verification progress each, then IBD begins
at 2% progress as displayed on the block clock.
---
 src/qml/models/nodemodel.cpp | 78 ++++++++++++++++++++++++++++++++++--
 src/qml/models/nodemodel.h   | 22 ++++++++++
 2 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/src/qml/models/nodemodel.cpp b/src/qml/models/nodemodel.cpp
index a699376d1a..1bf1049f91 100644
--- a/src/qml/models/nodemodel.cpp
+++ b/src/qml/models/nodemodel.cpp
@@ -20,6 +20,7 @@ NodeModel::NodeModel(interfaces::Node& node)
     : m_node{node}
 {
     ConnectToBlockTipSignal();
+    ConnectToHeaderTipSignal();
     ConnectToNumConnectionsChangedSignal();
 }
 
@@ -39,6 +40,47 @@ void NodeModel::setNumOutboundPeers(int new_num)
     }
 }
 
+void NodeModel::setInHeaderSync(bool new_in_header_sync)
+{
+    if (new_in_header_sync != m_in_header_sync) {
+        m_in_header_sync = new_in_header_sync;
+        Q_EMIT inHeaderSyncChanged();
+    }
+}
+
+void NodeModel::setHeaderSyncProgress(int64_t header_height, const QDateTime& block_date)
+{
+    int estimated_headers_left = block_date.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
+    double new_header_sync_progress = (100.0 / (header_height + estimated_headers_left) * header_height) / 10000;
+
+    if (new_header_sync_progress != m_header_sync_progress) {
+        m_header_sync_progress = new_header_sync_progress;
+        setVerificationProgress(0.0);
+        Q_EMIT headerSyncProgressChanged();
+    }
+}
+
+void NodeModel::setInPreHeaderSync(bool new_in_pre_header_sync)
+{
+    if (new_in_pre_header_sync != m_in_pre_header_sync) {
+        m_in_pre_header_sync = new_in_pre_header_sync;
+        Q_EMIT inPreHeaderSyncChanged();
+    }
+}
+
+void NodeModel::setPreHeaderSyncProgress(int64_t header_height, const QDateTime& block_date)
+{
+    int estimated_headers_left = block_date.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
+    double new_pre_header_sync_progress = (100.0 / (header_height + estimated_headers_left) * header_height) / 10000;
+
+    if (new_pre_header_sync_progress != m_pre_header_sync_progress) {
+        m_pre_header_sync_progress = new_pre_header_sync_progress;
+        setVerificationProgress(0.0);
+        Q_EMIT preHeaderSyncProgressChanged();
+
+    }
+}
+
 void NodeModel::setRemainingSyncTime(double new_progress)
 {
     int currentTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
@@ -74,12 +116,19 @@ void NodeModel::setRemainingSyncTime(double new_progress)
         }
     }
 }
+
 void NodeModel::setVerificationProgress(double new_progress)
 {
-    if (new_progress != m_verification_progress) {
-        setRemainingSyncTime(new_progress);
+    double header_progress = m_header_sync_progress + m_pre_header_sync_progress;
+    if (!m_in_header_sync && !m_in_pre_header_sync) {
+       if (new_progress != m_verification_progress) {
+            setRemainingSyncTime(new_progress);
 
-        m_verification_progress = new_progress;
+            m_verification_progress = header_progress + (new_progress - header_progress);
+            Q_EMIT verificationProgressChanged();
+        }
+    } else {
+        m_verification_progress = header_progress;
         Q_EMIT verificationProgressChanged();
     }
 }
@@ -140,12 +189,33 @@ void NodeModel::ConnectToBlockTipSignal()
             QMetaObject::invokeMethod(this, [=] {
                 setBlockTipHeight(tip.block_height);
                 setVerificationProgress(verification_progress);
-
+                setInHeaderSync(false);
+                setInPreHeaderSync(false);
                 Q_EMIT setTimeRatioList(tip.block_time);
             });
         });
 }
 
+void NodeModel::ConnectToHeaderTipSignal()
+{
+    assert(!m_handler_notify_header_tip);
+
+    m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(
+        [this](SynchronizationState sync_state, interfaces::BlockTip tip, bool presync) {
+            QMetaObject::invokeMethod(this, [=] {
+                if (presync) {
+                    setInHeaderSync(false);
+                    setInPreHeaderSync(true);
+                    setPreHeaderSyncProgress(tip.block_height, QDateTime::fromSecsSinceEpoch(tip.block_time));
+                } else {
+                    setInHeaderSync(true);
+                    setInPreHeaderSync(false);
+                    setHeaderSyncProgress(tip.block_height, QDateTime::fromSecsSinceEpoch(tip.block_time));
+                }
+            });
+        });
+}
+
 void NodeModel::ConnectToNumConnectionsChangedSignal()
 {
     assert(!m_handler_notify_num_peers_changed);
diff --git a/src/qml/models/nodemodel.h b/src/qml/models/nodemodel.h
index 442a0becf3..dc63156e2a 100644
--- a/src/qml/models/nodemodel.h
+++ b/src/qml/models/nodemodel.h
@@ -30,6 +30,10 @@ class NodeModel : public QObject
     Q_PROPERTY(QString fullClientVersion READ fullClientVersion CONSTANT)
     Q_PROPERTY(int numOutboundPeers READ numOutboundPeers NOTIFY numOutboundPeersChanged)
     Q_PROPERTY(int maxNumOutboundPeers READ maxNumOutboundPeers CONSTANT)
+    Q_PROPERTY(bool inHeaderSync READ inHeaderSync WRITE setInHeaderSync NOTIFY inHeaderSyncChanged)
+    Q_PROPERTY(double headerSyncProgress READ headerSyncProgress NOTIFY headerSyncProgressChanged)
+    Q_PROPERTY(bool inPreHeaderSync READ inPreHeaderSync WRITE setInPreHeaderSync NOTIFY inPreHeaderSyncChanged)
+    Q_PROPERTY(double preHeaderSyncProgress READ preHeaderSyncProgress NOTIFY preHeaderSyncProgressChanged)
     Q_PROPERTY(int remainingSyncTime READ remainingSyncTime NOTIFY remainingSyncTimeChanged)
     Q_PROPERTY(double verificationProgress READ verificationProgress NOTIFY verificationProgressChanged)
     Q_PROPERTY(bool pause READ pause WRITE setPause NOTIFY pauseChanged)
@@ -43,6 +47,14 @@ class NodeModel : public QObject
     int numOutboundPeers() const { return m_num_outbound_peers; }
     void setNumOutboundPeers(int new_num);
     int maxNumOutboundPeers() const { return m_max_num_outbound_peers; }
+    bool inHeaderSync() const { return m_in_header_sync; }
+    void setInHeaderSync(bool new_in_header_sync);
+    double headerSyncProgress() const { return m_header_sync_progress; }
+    void setHeaderSyncProgress(int64_t header_height, const QDateTime& block_date);
+    bool inPreHeaderSync() const { return m_in_pre_header_sync; }
+    void setInPreHeaderSync(bool new_in_pre_header_sync);
+    double preHeaderSyncProgress() const { return m_pre_header_sync_progress; }
+    void setPreHeaderSyncProgress(int64_t header_height, const QDateTime& block_date);
     int remainingSyncTime() const { return m_remaining_sync_time; }
     void setRemainingSyncTime(double new_progress);
     double verificationProgress() const { return m_verification_progress; }
@@ -65,6 +77,10 @@ public Q_SLOTS:
 Q_SIGNALS:
     void blockTipHeightChanged();
     void numOutboundPeersChanged();
+    void inHeaderSyncChanged();
+    void headerSyncProgressChanged();
+    void inPreHeaderSyncChanged();
+    void preHeaderSyncProgressChanged();
     void remainingSyncTimeChanged();
     void requestedInitialize();
     void requestedShutdown();
@@ -82,6 +98,10 @@ public Q_SLOTS:
     int m_block_tip_height{0};
     int m_num_outbound_peers{0};
     static constexpr int m_max_num_outbound_peers{MAX_OUTBOUND_FULL_RELAY_CONNECTIONS + MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
+    bool m_in_header_sync;
+    double m_header_sync_progress;
+    bool m_in_pre_header_sync;
+    double m_pre_header_sync_progress;
     int m_remaining_sync_time{0};
     double m_verification_progress{0.0};
     bool m_pause{false};
@@ -92,9 +112,11 @@ public Q_SLOTS:
 
     interfaces::Node& m_node;
     std::unique_ptr<interfaces::Handler> m_handler_notify_block_tip;
+    std::unique_ptr<interfaces::Handler> m_handler_notify_header_tip;
     std::unique_ptr<interfaces::Handler> m_handler_notify_num_peers_changed;
 
     void ConnectToBlockTipSignal();
+    void ConnectToHeaderTipSignal();
     void ConnectToNumConnectionsChangedSignal();
 };
 

From f6bb1b1c39bb87940846eba65408025fabc672f3 Mon Sep 17 00:00:00 2001
From: Jarol Rodriguez <jarolrod@tutanota.com>
Date: Tue, 28 Feb 2023 23:40:43 -0500
Subject: [PATCH 2/2] qml: set synced to whether node is in IBD or not

This changes when we consider to be synced within the block clock's
perspective from a check on if verificationProgress is large enough to
a query on the node to see if it is in ibd or not
---
 src/qml/components/BlockClock.qml |  4 ++--
 src/qml/models/nodemodel.cpp      | 11 +++++++++++
 src/qml/models/nodemodel.h        |  5 +++++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/src/qml/components/BlockClock.qml b/src/qml/components/BlockClock.qml
index f7210aa534..8397180ee5 100644
--- a/src/qml/components/BlockClock.qml
+++ b/src/qml/components/BlockClock.qml
@@ -24,7 +24,7 @@ Item {
     property alias subText: subText.text
     property int headerSize: 32
     property bool connected: nodeModel.numOutboundPeers > 0
-    property bool synced: nodeModel.verificationProgress > 0.999
+    property bool synced: !nodeModel.inIBD
     property string syncProgress: formatProgressPercentage(nodeModel.verificationProgress * 100)
     property bool paused: false
     property var syncState: formatRemainingSyncTime(nodeModel.remainingSyncTime)
@@ -49,7 +49,7 @@ Item {
         verificationProgress: nodeModel.verificationProgress
         paused: root.paused
         connected: root.connected
-        synced: nodeModel.verificationProgress > 0.999
+        synced: root.synced
         backgroundColor: Theme.color.neutral2
         timeTickColor: Theme.color.neutral5
         confirmationColors: Theme.color.confirmationColors
diff --git a/src/qml/models/nodemodel.cpp b/src/qml/models/nodemodel.cpp
index 1bf1049f91..2ef402067c 100644
--- a/src/qml/models/nodemodel.cpp
+++ b/src/qml/models/nodemodel.cpp
@@ -32,6 +32,15 @@ void NodeModel::setBlockTipHeight(int new_height)
     }
 }
 
+
+void NodeModel::setInIBD(bool new_ibd)
+{
+    if (new_ibd != m_in_ibd) {
+        m_in_ibd = new_ibd;
+        Q_EMIT inIBDChanged();
+    }
+}
+
 void NodeModel::setNumOutboundPeers(int new_num)
 {
     if (new_num != m_num_outbound_peers) {
@@ -188,6 +197,7 @@ void NodeModel::ConnectToBlockTipSignal()
         [this](SynchronizationState state, interfaces::BlockTip tip, double verification_progress) {
             QMetaObject::invokeMethod(this, [=] {
                 setBlockTipHeight(tip.block_height);
+                setInIBD(m_node.isInitialBlockDownload());
                 setVerificationProgress(verification_progress);
                 setInHeaderSync(false);
                 setInPreHeaderSync(false);
@@ -202,6 +212,7 @@ void NodeModel::ConnectToHeaderTipSignal()
 
     m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(
         [this](SynchronizationState sync_state, interfaces::BlockTip tip, bool presync) {
+            setInIBD(m_node.isInitialBlockDownload());
             QMetaObject::invokeMethod(this, [=] {
                 if (presync) {
                     setInHeaderSync(false);
diff --git a/src/qml/models/nodemodel.h b/src/qml/models/nodemodel.h
index dc63156e2a..3c7f2b5006 100644
--- a/src/qml/models/nodemodel.h
+++ b/src/qml/models/nodemodel.h
@@ -28,6 +28,7 @@ class NodeModel : public QObject
     Q_OBJECT
     Q_PROPERTY(int blockTipHeight READ blockTipHeight NOTIFY blockTipHeightChanged)
     Q_PROPERTY(QString fullClientVersion READ fullClientVersion CONSTANT)
+    Q_PROPERTY(bool inIBD READ inIBD NOTIFY inIBDChanged)
     Q_PROPERTY(int numOutboundPeers READ numOutboundPeers NOTIFY numOutboundPeersChanged)
     Q_PROPERTY(int maxNumOutboundPeers READ maxNumOutboundPeers CONSTANT)
     Q_PROPERTY(bool inHeaderSync READ inHeaderSync WRITE setInHeaderSync NOTIFY inHeaderSyncChanged)
@@ -44,6 +45,8 @@ class NodeModel : public QObject
     int blockTipHeight() const { return m_block_tip_height; }
     void setBlockTipHeight(int new_height);
     QString fullClientVersion() const { return QString::fromStdString(FormatFullVersion()); }
+    bool inIBD() const { return m_in_ibd; }
+    void setInIBD(bool new_ibd);
     int numOutboundPeers() const { return m_num_outbound_peers; }
     void setNumOutboundPeers(int new_num);
     int maxNumOutboundPeers() const { return m_max_num_outbound_peers; }
@@ -76,6 +79,7 @@ public Q_SLOTS:
 
 Q_SIGNALS:
     void blockTipHeightChanged();
+    void inIBDChanged();
     void numOutboundPeersChanged();
     void inHeaderSyncChanged();
     void headerSyncProgressChanged();
@@ -96,6 +100,7 @@ public Q_SLOTS:
 private:
     // Properties that are exposed to QML.
     int m_block_tip_height{0};
+    bool m_in_ibd;
     int m_num_outbound_peers{0};
     static constexpr int m_max_num_outbound_peers{MAX_OUTBOUND_FULL_RELAY_CONNECTIONS + MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
     bool m_in_header_sync;