…of forcing a re-sync
The Ironwood history-tree upgrade rebuilds the tip ZIP-221 tree from finalized
blocks. A node pruned before the Ironwood bump no longer has those blocks, so the
upgrade fails with a fatal "delete the cache directory and re-sync" error.
The on-disk failure is purely a buffer-width change: adding V3 (Ironwood) node
data grew the history-tree Entry from 253 to 326 bytes. A pre-Ironwood tip's
V1/V2 node data is consensus-fixed and still present in the stored entry. This
adds an in-place re-encode fallback: when the from-blocks rebuild reports
MissingData, read the stored old-format tip entry, widen each peak's buffer to
the current size (padding only), and write it back -- no blocks required.
The inner reader consumes only the meaningful node-data prefix and ignores the
trailing zero padding, and version dispatch keys on the tip height, so a
pre-NU6.3 tip's peaks are parsed as V1/V2 exactly as written. The re-encoded tree
is therefore byte-for-byte equal (same peaks, same size, same MMR root) to what
the from-blocks rebuild and a fresh sync produce. The archive from-blocks path is
unchanged; the re-encode runs only on the previously-fatal pruned path, and a
genuinely unreadable entry still fails loudly.
Summary
The Ironwood history-tree upgrade rebuilds the tip ZIP-221 tree from finalized blocks. A node pruned before the Ironwood bump no longer has those blocks, so the upgrade fails with a fatal "delete the cache directory and re-sync from genesis" error — including for pruned snapshots upgrading to Ironwood.
The on-disk failure is purely a buffer-width change: adding V3 (Ironwood) node data grew the history-tree
Entryfrom 253 to 326 bytes. A pre-Ironwood tip's V1/V2 node data is consensus-fixed and still present in the stored entry. This adds an in-place re-encode fallback: when the from-blocks rebuild reportsMissingData, read the stored old-format tip entry, widen each peak's buffer to the current size (padding only), and write it back — no blocks required.Why it's consensus-safe
The inner
zcash_historyreader consumes only the meaningful node-data prefix and ignores trailing zero padding, and version dispatch keys on the tip height — so a pre-NU6.3 tip's peaks are parsed as V1/V2 exactly as written. The re-encoded tree is therefore byte-for-byte equal (same peaks, samesize, same MMR root) to what the from-blocks rebuild and a fresh sync produce. Sync-time block-commitment validation already guarantees the stored tree equals the canonical tree, so reusing it cannot diverge.The merged archive (from-blocks) path is unchanged: the fallback runs only on the previously-fatal pruned path, and a genuinely unreadable entry still fails loudly with the re-sync message.