diff --git a/QORTIUM-CHANGELOG.md b/QORTIUM-CHANGELOG.md index 4e888a382..439b7c6cd 100644 --- a/QORTIUM-CHANGELOG.md +++ b/QORTIUM-CHANGELOG.md @@ -34,6 +34,10 @@ own chain. ## Change Entries +### 2026-06-02 - Refresh tray sync progress from peer height + +Changed the tray tooltip so its syncing percentage and blocks-remaining count use the same current peer-height progress calculation as the node status API. This keeps the desktop tooltip moving while a preview node catches up, instead of leaving an older remaining-block estimate visible after the local height has advanced. + ### 2026-06-02 - Expose preview peer reachability diagnostics Added inbound and outbound peer counts plus P2P and QDN reachability flags to the node status response so preview testers can tell the difference between outbound-only connectivity and public reachability. Preview participants now target four outbound chain peers when enough reachable peers are available, and the preview docs explain how firewall or router forwarding affects peer counts. diff --git a/src/main/java/org/qortium/controller/Controller.java b/src/main/java/org/qortium/controller/Controller.java index fb7f8a6b4..e6c0e00d3 100644 --- a/src/main/java/org/qortium/controller/Controller.java +++ b/src/main/java/org/qortium/controller/Controller.java @@ -8,6 +8,7 @@ import org.qortium.api.ApiService; import org.qortium.api.DomainMapService; import org.qortium.api.GatewayService; +import org.qortium.api.model.NodeStatus; import org.qortium.api.resource.TransactionsResource; import org.qortium.block.Block; import org.qortium.block.BlockChain; @@ -1104,7 +1105,8 @@ public void updateSysTray() { return; } - final int numberOfPeers = Network.getInstance().getImmutableHandshakedPeers().size(); + final List handshakedPeers = Network.getInstance().getImmutableHandshakedPeers(); + final int numberOfPeers = handshakedPeers.size(); final int height = getChainHeight(); @@ -1117,9 +1119,14 @@ public void updateSysTray() { // Any block in the last 2 hours is considered "up to date" for the purposes of displaying statuses. // This also aligns with the time interval required for continued online account submission. final Long minLatestBlockTimestamp = NTP.getTime() - (2 * 60 * 60 * 1000L); + final boolean isUpToDate = this.isUpToDate(minLatestBlockTimestamp); + final NodeStatus.SyncProgress syncProgress = NodeStatus.calculateSyncProgress(height, + Synchronizer.getInstance().getSyncTargetHeight(), Synchronizer.getInstance().isSynchronizing(), + getBestPeerHeight(handshakedPeers), isUpToDate, Settings.getInstance().isLite(), numberOfPeers, + Settings.getInstance().getMinBlockchainPeers()); // Only show sync percent if it's less than 100, to avoid confusion - final Integer syncPercent = Synchronizer.getInstance().getSyncPercent(); + final Integer syncPercent = syncProgress.syncPercent; final boolean isSyncing = (syncPercent != null && syncPercent < 100); synchronized (Synchronizer.getInstance().syncLock) { @@ -1131,11 +1138,11 @@ else if (numberOfPeers < Settings.getInstance().getMinBlockchainPeers()) { actionText = Translator.INSTANCE.translate("SysTray", "CONNECTING"); nodeTray.setTrayIcon(TrayIconState.SYNCHRONIZING); } - else if (!this.isUpToDate(minLatestBlockTimestamp) && isSyncing) { - actionText = String.format("%s - %d%%", Translator.INSTANCE.translate("SysTray", "SYNCHRONIZING_BLOCKCHAIN"), Synchronizer.getInstance().getSyncPercent()); + else if (!isUpToDate && isSyncing) { + actionText = String.format("%s - %d%%", Translator.INSTANCE.translate("SysTray", "SYNCHRONIZING_BLOCKCHAIN"), syncPercent); nodeTray.setTrayIcon(TrayIconState.SYNCHRONIZING); } - else if (!this.isUpToDate(minLatestBlockTimestamp)) { + else if (!isUpToDate) { actionText = String.format("%s", Translator.INSTANCE.translate("SysTray", "SYNCHRONIZING_BLOCKCHAIN")); nodeTray.setTrayIcon(TrayIconState.SYNCHRONIZING); } @@ -1153,7 +1160,7 @@ else if (OnlineAccountsManager.getInstance().hasActiveOnlineAccountSignatures()) if (!Settings.getInstance().isLite()) { tooltip = tooltip.concat(String.format(" - %s %d", heightText, height)); - final Integer blocksRemaining = Synchronizer.getInstance().getBlocksRemaining(); + final Integer blocksRemaining = syncProgress.syncBlocksRemaining; if (blocksRemaining != null && blocksRemaining > 0) { String blocksRemainingText = Translator.INSTANCE.translate("SysTray", "BLOCKS_REMAINING"); tooltip = tooltip.concat(String.format(" - %d %s", blocksRemaining, blocksRemainingText)); @@ -1167,6 +1174,21 @@ else if (OnlineAccountsManager.getInstance().hasActiveOnlineAccountSignatures()) }); } + private static Integer getBestPeerHeight(List peers) { + Integer bestPeerHeight = null; + + for (Peer peer : peers) { + BlockSummaryData chainTipData = peer.getChainTipData(); + if (chainTipData == null) + continue; + + if (bestPeerHeight == null || chainTipData.getHeight() > bestPeerHeight) + bestPeerHeight = chainTipData.getHeight(); + } + + return bestPeerHeight; + } + public void deleteExpiredTransactions() { final Long now = NTP.getTime(); if (now == null)