Lesson 3 of 4

Check How Far a Node Has Synced

When you run Dolos (or any Cardano node) from a fresh database, it takes hours to reach the live chain tip. Before your code submits transactions or starts reading fresh blocks, you want to confirm the node is actually caught up. This lesson shows you two ways to check, both from the starter-kit, and explains when each is the right answer.


Two Questions, Two Tools

"Has my node finished syncing?" splits into two slightly different questions:

Question

Tool

Mini-protocol

"What slot does the node think is the tip?"

cmd/chain-tip

ChainSync GetCurrentTip

"What slot, era, epoch, and block number is the tip?"

cmd/state-query tip

LocalStateQuery

chain-tip is the cheapest way to ask "are you still moving?" state-query tip gives you richer structured data in the same round-trip and is what you'd use in an application's health-check endpoint.

Both use Node-to-Client over the Unix socket you set up in 101.1.


Prerequisites

  • Completed 101.1 (starter-kit cloned, CARDANO_NODE_SOCKET_PATH and CARDANO_NODE_MAGIC exported)
  • Dolos running in the background

Approach 1: chain-tip

You already ran this in 101.1. One slot number, one block hash, exits.

go run ./cmd/chain-tip
Chain Tip:
Slot: 56123456  Block Hash: e3f1a2...

The implementation is just:

tip, err := o.ChainSync().Client.GetCurrentTip()
// tip is ocommon.Tip{ Point: { Slot uint64; Hash []byte }, BlockNumber uint64 }
fmt.Printf("Chain Tip:\nSlot: %-10d Block Hash: %x\n", tip.Point.Slot, tip.Point.Hash)

When you'd use this in real code: before streaming with chain-sync, to pick a sensible starting point. Or inside a liveness check that only needs to confirm the node is responding.


Approach 2: state-query tip

A richer view, accessed via LocalStateQuery. From the starter-kit:

go run ./cmd/state-query tip

Output:

Era: Conway (7)
Epoch: 432
Block Number: 2834721
Slot Number: 56123456
Block Hash: e3f1a2...

The program calls multiple queries in sequence:

// inside state-query/main.go
era, _      := o.LocalStateQuery().Client.GetCurrentEra()
tip, _      := o.ChainSync().Client.GetCurrentTip()
epochNo, _  := o.LocalStateQuery().Client.GetEpochNo()
// ...

The state-query command also accepts other subcommands — protocol-params, stake-distribution, utxos-by-address, etc. See go run ./cmd/state-query --help for the full list. You'll use several of these in Modules 202 and 301.


Confirming Dolos Is Caught Up

Run both commands, then compare to a public source:

# Our view (via Dolos)
go run ./cmd/state-query tip

# Public view
curl -s https://preprod.cardanoscan.io/ | grep -o 'Slot [0-9]*' | head -1
# or visit https://preprod.cardanoscan.io/ in the browser

If the two slot numbers are within a few blocks of each other, Dolos is synced. If yours is thousands of slots behind, Dolos is still catching up — leave dolos daemon running and re-check in a few minutes.

A Quick Watch Loop

while true; do
  go run ./cmd/chain-tip
  sleep 10
done

The slot should advance by about 20 each iteration on preprod (one slot per second, ~one block every ~20 slots).


Two Things Worth Knowing

  • Tip moves even when synced. A synced node is not frozen — it's producing new tips every slot. "Synced" means "tracking the live chain at the same pace as everyone else," not "stopped."
  • Syncing vs. caught up. During initial sync, the slot number in the tip rises as fast as the network can deliver blocks — much faster than wall-clock. Once caught up, the slot number advances in line with real time.

Common Issues

Slot is a long way behind wall-clock

Dolos is still catching up. Watch the dolos daemon log — you should see it replaying blocks. Initial sync from Mithril snapshot is faster than syncing from genesis but can still take 15–30 minutes on preprod.

state-query fails with unsupported query or similar

Some LocalStateQuery queries need a fully-synced node or only work on certain eras. Tip queries work across all eras. If you hit this on a specific subcommand, check the gOuroboros feature matrix in its README.

Slot prints 0

Node is up but hasn't intersected the chain yet — very early in startup. Wait 10–20 seconds and retry.


You'll Know You're Successful When

  • chain-tip and state-query tip both return a slot close to the current preprod slot on Cardanoscan
  • The slot advances between runs
  • You understand which command you'd use for a quick liveness ping vs. a structured status report

Practice Tasks

  • Run both commands and note the wall-clock time between completing each. Which is faster and why?
  • Stop Dolos (Ctrl+C in its terminal), then run chain-tip. Observe the error. Restart Dolos and re-run.
  • Run go run ./cmd/state-query --help and identify two other queries you'd want for a production health dashboard.

What's Next

  • 101.4 — look at pending transactions in the mempool
  • 102.4 — submit a transaction back into this same node you've been querying