Sync and reindex
Three modes: initial sync, steady state, and rebuild. The third is always available, which is what makes the first two safe.
- Which height to start from, and why
/readyhas to keep failing until the first sync finishes. - How to spot a reorg from your stored block hashes, and the six steps back to steady state.
- The five situations that force a full reindex, and the two that look like they should and do not.
- How to rebuild alongside a live index and compare state roots at a shared height before you swap.
- Why a rebuild never loses anything, and why hand editing the store is never the answer.
Initial sync
Four things to get right on the first pass. The fourth is the one people skip, and it is the one that makes a reorg detectable later.
- Start at the deployment start height. Earlier blocks contain nothing.
- Process blocks in order, applying the rules and recording invalid events.
- Keep
/readyfailing throughout. An indexer that answers during initial sync gives correct answers for a height nobody asked about. - Record block hashes per height as you go. Without them you cannot detect a reorg later.
watch -n 10 "curl -s http://localhost:PORT/patina/status \
| grep -o '\"indexed_height\":[0-9]*'"
Steady state
- Follow the node's tip. Apply each new block as it arrives.
- Compare the incoming block's previous hash with your stored hash for that height. A mismatch is a reorg.
- Keep the gap between
indexed_heightandtip_heightsmall, and alert when it is not. - Nothing needs to happen per block per artifact. Depth is computed at query time, so a block with no PATINA activity costs almost nothing.
Reorg handling
- Detect a mismatch between your stored hash and the node's block at that height.
- Walk back to the last height where hashes agree. That is the fork point.
- Roll state back to the fork point.
- Fail
/readywhile rolling back and replaying. - Replay forward, applying the same rules.
- Return to steady state.
Rules and requirements on Reorg behavior. The critical property is that rolling back to height H and replaying to H reproduces the same state root. Test it deliberately, not only when it happens.
When to reindex from scratch
Rebuild when the rules that produced the state changed, or when you cannot say what produced it. Slowness is not on that list, and the last two rows are there because they are the ones people most often get wrong.
| Situation | Reindex | Why |
|---|---|---|
| Upgrading to a build with a parser change | Yes | Old state was produced by different rules |
spec_sha256 changed | Yes | The specification is different, so the state may be too |
| A state root mismatch against another implementation | Yes, after the bug is understood | Rebuilding on a fixed parser is the only way to trust the result |
| Storage corruption, or an unclean shutdown you cannot reason about | Yes | Rebuild is cheap compared with serving wrong state |
| A reorg deeper than your rollback history | Yes | You cannot reach the fork point |
| A performance problem | No | Fix the query path. Reindexing does not make wrong data fast or fast data right. |
| Bug fix in serving code only | No | The state is unaffected |
Reindex procedure
-
Announce it if you serve others
Say what you are rebuilding and why. A silent rebuild looks like an outage.
-
Build into a new store
Do not destroy the old index first. Rebuild alongside it, so you can compare the two and so a failed rebuild is not an outage.
-
Run the golden vectors on the new build
Before it touches a real chain.
-
Index to a height the old store also reached
Then compare state roots at that exact height. Identical roots mean the rebuild changed nothing, which is the expected result unless you were fixing a bug.
-
Swap and keep the old store
Keep it until the new one has been correct for long enough that you would not want to go back.
The entire index is derived from the blockchain. There is no user data in it, no state that exists only in your database, and nothing that cannot be recomputed. That is why reindex is always a safe answer, and why an operator should never be tempted to hand edit the store.
Upgrades
- Read the release notes for parser changes. Any parser change means a reindex.
- Run the vectors on the new build.
- If the parser is unchanged, a rolling restart is enough. Confirm
indexed_heightresumes from where it stopped. - If the parser changed, follow the reindex procedure and compare roots before serving.
- Publish the new
spec_sha256andparser_versionthroughstatus.
What never happens during any of this
- No artifact is created, moved, or destroyed by anything an operator does. Only the chain does that.
- No depth is affected by downtime. Depth is measured from block heights, not from uptime, which the public site shows moving block by block on the depth page.
- No holder needs to act because an indexer restarted.