Skip to content

Improve block clock rendering and sync state - #803

Open
johnny9 wants to merge 5 commits into
bitcoin-core:qt6from
johnny9:improve/block-clock
Open

Improve block clock rendering and sync state#803
johnny9 wants to merge 5 commits into
bitcoin-core:qt6from
johnny9:improve/block-clock

Conversation

@johnny9

@johnny9 johnny9 commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR fixes how the block clock represents sync/catch-up state and how confirmation history renders in both the full and mini clocks.

  • Keep the UI in sync mode until Core has left IBD and both headers and the active chain have caught up. Near-tip catch-up remains at 99.9% instead of prematurely showing the normal clock.
  • Render rounded confirmation segments without losing confirmation depth when closely spaced block boundaries coalesce, and use one continuous gradient across combined blocks.
  • Correct the mini block clock gradient so clockwise time moves from older, higher-confirmation yellow toward newer, zero-confirmation red.
  • Move timeline ownership from ChainModel to BlockClockModel and stop presentation work while the clock is not visible. Hidden pages or tabs—and hidden or minimized windows—do not schedule dial repaints or run dial, peer-indicator, or estimating animations. The backing model stays current with minute-aligned clock updates and an immediate refresh when a block arrives, so the clock renders the latest state when it becomes visible again.

Visual evidence

Catch-up sync-state bug

The unfixed build briefly shows the normal red clock while the active chain is still rapidly catching up from a stale signet tip. The new sync-state latch keeps the UI in syncing state at 99.9% until both header and block catch-up are complete.

Screencast.from.2026-07-19.17-37-22.mp4

Confirmation segment rendering

Before After
Before: separated confirmation segments After: rounded coalesced segments with a continuous gradient
Every block was drawn individually. When several boundaries landed only a few pixels apart, the segments crowded together and their confirmation-color changes became difficult to see. Rounded segments coalesce when necessary while preserving confirmation depth and a continuous gradient.

Mini block clock gradient

The mini clock now uses the same direction as the full clock: older, higher-confirmation time is yellow, transitioning clockwise toward the newest, zero-confirmation time in red.

Fixed mini block clock gradient

Motivation

verificationProgress > 0.999 can report the normal clock too early. With a saved signet tip at height 313768, Core had already left IBD at 0.999830; once a peer announced height 313904, the UI showed a normal clock while 136 blocks rapidly caught up.

The existing timeline also mixed model data with paint geometry, kept repaint requests, timers, and animations active while views were hidden, and lost confirmation transitions when rounded segments were too close to render separately.

Related issues

Fixes #227.
Fixes #743.
Fixes #785.

Related to #576.
Follow-up to #609.

Testing

  • Built bitcoin-core-app, bitcoinqml_unit_tests, and bitcoinqml_qmltests.
  • Ran QT_QPA_PLATFORM=offscreen QT_QUICK_BACKEND=software LIBGL_ALWAYS_SOFTWARE=1 ctest --test-dir build --output-on-failure (2/2 passed).
  • Built each commit in the branch independently.
  • Ran Bitcoin lint checks for commit messages, tabs/whitespace, and trailing newlines.
  • Ran git diff --check.
  • Verified visibility gating in the C++ and QML tests: inactive clocks stop dial timers, estimating animation, peer-indicator animation, and repaint scheduling while model state remains current for reactivation.
  • Added BlockClockModel coverage for minute alignment and block-triggered time refresh (BlockClockModelTests: 10/10 passed), and reran the QML suite (389/389 passed).
  • Manually reproduced stale-signet catch-up with the unfixed and fixed builds.

@johnny9
johnny9 marked this pull request as ready for review July 19, 2026 22:00
@johnny9 johnny9 changed the title qml: improve block clock rendering and sync state Improve block clock rendering and sync state Jul 22, 2026
johnny9 and others added 5 commits July 30, 2026 13:56
Extract the block clock timeline from ChainModel, keep its data current independently of presentation, and stop dial and QML animation work when the relevant view is inactive. Bound sync-progress estimation work and cover the model, dial lifecycle, page visibility, and QML behavior.
Stop treating verification progress as a completion signal. Keep the clock in
its initial-sync presentation until the node is ready, Core has left IBD,
header sync and presync are inactive, and the active chain has caught the best
known header. Latch completion for the session so a normal header-first block
announcement does not return the clock to IBD.

While sync is pending, drive the dial from active header or block progress.
Display Core's reported percentage, capping only near-complete estimates at
99.9%. Use the same completion state for the full clock, mini clock, and wallet
tooltip. Fit the header presync label inside the dial, and accept an empty
current-period block timeline as valid clock data.

Cover stale-tip catch-up, genesis, late headers, normal new blocks, progress
rendering, labels, empty histories, and tooltip state in NodeModel and QML
tests.
@johnny9
johnny9 force-pushed the improve/block-clock branch from a3d1291 to df9cb11 Compare July 30, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Miniblock clock gradient is backwords Block Clock Header Pre-sync is not showing progress dial Tech Debt: Refactor ChainModel

1 participant