To check whether a Base (OP-Stack) node is fully synced, you must inspect both the op-node consensus client and the execution engine (op-reth, op-geth, or op-erigon) via the Engine API and admin RPC. Query op-node's admin RPC for unsafe, safe, and finalized head heights, and compare them with the execution engine's canonical head. A healthy node shows the unsafe head advancing with the sequencer, the safe head catching up from L1, and the engine head matching the unsafe target. If any head stalls or the engine reports syncing, the node is not live.
Direct Answer: How to Verify Your Base Node Is Synced
To verify that your Base node is fully synced, you need to check both the op-node (consensus/rollup client) and the execution engine (op-reth, op-geth, or op-erigon). The op-node exposes an admin RPC that reports the current unsafe head (the latest sequencer block), safe head (derived from L1), and finalized head. The execution engine exposes its own sync status and head height. A healthy node shows the unsafe head advancing with the sequencer, the safe head catching up from L1, and the engine head matching the unsafe target. If any head stalls or the engine reports syncing, the node is not live.
This guide is for node operators who run their own Base node and need to diagnose sync issues. It complements the Base finality and safe/finalized block tags article, which is written for RPC consumers reading those tags, not for node operators inspecting their own node's sync state.
Architecture: op-node and the Execution Engine
Base is an OP-Stack rollup. The node consists of two main components: op-node (the rollup consensus client) and an execution engine (op-reth, op-geth, or op-erigon). They communicate over the Engine API, an Ethereum JSON-RPC namespace (engine_*) that allows the consensus client to drive the execution engine's fork choice and block production.
The op-node tracks three head states:
- Unsafe head: The latest block from the sequencer, learned via the Engine API's forkchoice updates. This is the tip of the chain as produced by the sequencer.
- Safe head: The latest block that has been derived from finalized L1 data. This advances as the op-node processes L1 batches.
- Finalized head: The latest block that is final on L1 and thus final on Base.
The execution engine maintains its own canonical chain and exposes its head via the eth_blockNumber or eth_getBlockByNumber methods. The op-node's unsafe head should match the engine's head when the node is fully synced.
For authoritative details, refer to the Base documentation on running a node and the Optimism op-node documentation.
Accessing op-node Admin RPC and Engine API
The op-node exposes an admin RPC on a separate port (default 9545) that provides node-specific methods. To enable it, you must start op-node with the --admin.rpc.enabled flag and optionally set --admin.rpc.port. The admin RPC includes methods like admin_health, admin_logs, and admin_sync (depending on version).
The execution engine exposes the Engine API on its JSON-RPC port (default 8545 for op-reth). To query engine methods, you need to authenticate using a JWT secret, which is passed via the --authrpc.jwtsecret flag on both op-node and the execution engine.
Important: These admin and engine namespaces are operator-only and must not be exposed publicly. They can reveal sensitive information and allow control of the node. Always bind them to localhost or a private network.
For the exact method names and arguments, consult the documentation for your specific OP-Stack version, as they may vary.
Step-by-Step: Querying Sync Status
The following commands assume you have curl and jq installed, and that your op-node admin RPC is available at http://localhost:9545 and your execution engine's Engine API at http://localhost:8551 (with JWT). Replace the ports and paths as needed.
First, check the op-node's health endpoint:
This returns a JSON object with a healthy boolean and details about the unsafe head, safe head, and finalized head. A healthy node should show "healthy": true and the heads should be advancing.
Next, query the op-node's admin RPC for sync status. The method name may be admin_sync or optimism_syncStatus depending on version. For example:
This returns an object with unsafe_l2, safe_l2, and finalized_l2 blocks, each containing a block number and hash.
Now check the execution engine's head. Use the Engine API method engine_getPayloadV2 or simply eth_blockNumber (if enabled). For example:
Compare the engine's head block number with the op-node's unsafe head. They should be equal or very close (within a few blocks).
curl -s http://localhost:9545/health | jq .
curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"admin_sync","params":[],"id":1}' http://localhost:9545 | jq .
curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' http://localhost:8545 | jq -r '.result' | xargs printf "%d\n"Interpreting the Output: Healthy vs Degraded
A healthy node shows the following:
- The op-node health endpoint returns
"healthy": true.
- The unsafe head is advancing at the expected rate (typically every 2 seconds on Base).
- The safe head is also advancing, though it may lag behind the unsafe head by a few minutes as it waits for L1 confirmations.
- The execution engine's head matches the unsafe head.
A degraded node might show:
- The health endpoint returns
"healthy": falsewith a reason such as"unsafe head is behind"or"engine sync not progressing".
- The unsafe head is not advancing, indicating the sequencer feed is down or the node is in fallback mode.
- The safe head is stuck, meaning L1 derivation is not progressing.
- The execution engine's head is far behind the unsafe head, indicating the engine is still syncing or is stuck.
If the node is in safe mode (sequencer feed unavailable), it will only derive blocks from L1, which is slower. The unsafe head may not advance, but the safe head should still progress. This is not necessarily an error, but it means the node is not at the tip.
Detecting Stuck Sync and Pruning Issues
A common failure is a node that appears to be running but is stuck in initial sync or behind a stale snapshot. For example, an archive node started from a snapshot may not reach the tip because the snapshot is outdated. Similarly, op-node may hang while op-reth is pruning, as reported in GitHub issues.
To detect these issues:
- Check the op-node logs for errors like
"engine sync not progressing"or"unsafe head is behind".
- Check the execution engine's sync status. For op-reth, you can use the
reth_syncmethod (if enabled) or inspect the logs for sync progress.
- If the engine is still syncing, it will report a
syncingstatus in the Engine API. You can queryengine_getPayloadV2and check thelatestValidHashandfinalizedBlockHash.
- If the node is stuck behind a stale snapshot, you may need to resync from a more recent snapshot or use a checkpoint sync.
For example, to check op-reth's sync status:
This returns an object with current_block, highest_block, and stage fields. If current_block is not increasing, the sync is stuck.
curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"reth_sync","params":[],"id":1}' http://localhost:8545 | jq .Operator Troubleshooting Checklist
Use this checklist to diagnose and fix sync issues on your Base node:
- Check op-node health: Run
curl -s http://localhost:9545/health | jq .and verifyhealthyis true.
- Check op-node sync status: Query
admin_syncand note the unsafe, safe, and finalized block numbers.
- Check execution engine head: Query
eth_blockNumberand compare with the unsafe head.
- Check engine sync status: For op-reth, query
reth_syncand ensurecurrent_blockis advancing.
- Inspect logs: Look for errors in op-node and op-reth logs. Common errors include
"engine sync not progressing","unsafe head is behind", and"pruning"messages.
- Verify sequencer feed: If the unsafe head is not advancing, check if the sequencer feed is reachable. You may need to restart op-node with the correct
--l1.beaconand--l1.rpcendpoints.
- Check L1 connection: Ensure op-node can reach the L1 node and that L1 is synced.
- Restart services: If all else fails, restart op-node and the execution engine. Sometimes a simple restart resolves transient issues.
- Resync if necessary: If the node is stuck behind a stale snapshot, consider resyncing from a more recent snapshot or using a checkpoint sync.
Reproducible Measurement Script
The following script queries both op-node and the execution engine and prints a table of head heights. Run it twice with a delay to see if the heads are advancing.
Fill in the results in the table below after running the script twice with a 30-second interval:
| Head type | First run | Second run | Delta |
|---|---|---|---|
| Unsafe | |||
| Safe | |||
| Finalized | |||
| Engine |
If the deltas are zero for unsafe and engine, the node is not syncing. If the safe head is also zero, L1 derivation is stuck.
#!/bin/bash
# Save as check_sync.sh and run with: bash check_sync.sh
OP_NODE_ADMIN="http://localhost:9545"
ENGINE_RPC="http://localhost:8551"
# Get op-node sync status
sync_status=$(curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"admin_sync","params":[],"id":1}' $OP_NODE_ADMIN)
unsafe=$(echo $sync_status | jq -r '.result.unsafe_l2.number')
safe=$(echo $sync_status | jq -r '.result.safe_l2.number')
finalized=$(echo $sync_status | jq -r '.result.finalized_l2.number')
# Get engine head (assuming eth_blockNumber is enabled)
engine_hex=$(curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' $ENGINE_RPC | jq -r '.result')
engine=$((16#${engine_hex#0x}))
# Print table
echo "Head type | Block number"
echo "----------|--------------"
echo "Unsafe | $unsafe"
echo "Safe | $safe"
echo "Finalized | $finalized"
echo "Engine | $engine"Limitations and Tradeoffs
The methods described require operator-level access to the node's admin RPC and Engine API. These endpoints are not available on public RPC providers like OnFinality's Base RPC node. If you are using a managed node, you cannot directly query these namespaces; instead, you can monitor sync status via public endpoints like eth_blockNumber and compare with the latest block from a block explorer.
Exact method names and arguments may vary between OP-Stack versions and execution clients. Always consult the documentation for your specific version. For example, op-node's admin RPC method might be admin_sync or optimism_syncStatus, and op-reth's sync method might be reth_sync or admin_peerInfo.
Exposing admin or engine RPC endpoints publicly is a security risk. They can allow attackers to control your node or extract sensitive information. Always bind them to localhost or use a firewall.
For more on monitoring node health, see Monitoring RPC endpoints and node health.
Next Steps and Further Reading
Now that you can check your Base node's sync status, you may want to explore related topics:
- Base RPC latency – understand latency expectations for your node.
- Running and querying Base archive nodes – if you need historical data.
- Base finality and safe/finalized block tags – for consumers reading these tags.
- OnFinality Learn hub – more guides for node operators and developers.
- API service – if you prefer a managed RPC service.
- RPC pricing – understand costs if you scale.
If you are using OnFinality's managed Base node, you do not need to perform these checks yourself; our infrastructure handles sync and health monitoring. For more information, see Base RPC node (RPC Assistant).