Skip to content

ergo-nipopow: tolerate skipped prefix entries in has_valid_connections#852

Open
mwaddip wants to merge 1 commit into
ergoplatform:developfrom
mwaddip:fix/nipopow-prefix-connection-lookback
Open

ergo-nipopow: tolerate skipped prefix entries in has_valid_connections#852
mwaddip wants to merge 1 commit into
ergoplatform:developfrom
mwaddip:fix/nipopow-prefix-connection-lookback

Conversation

@mwaddip
Copy link
Copy Markdown

@mwaddip mwaddip commented Apr 9, 2026

Rewrites has_valid_connections to walk a use_last_epochs + 2 lookback for each prefix pair, matching JVM NipopowProof.scala:128. The pre-fix immediate-predecessor check rejected every real JVM-built proof — continuous-mode and sparse-superlevel entries naturally skip intermediates.

Adds NipopowAlgos::use_last_epochs (default 8, matching mainnet/testnet).

`NipopowProof::has_valid_connections` was too strict compared to JVM:
it required every adjacent prefix entry to connect to its IMMEDIATE
sorted-by-height neighbour via interlink or parent_id. JVM's
`NipopowProof.scala` (`hasValidConnections`, lines ~128-148) instead
allows each `next` entry to connect to ANY of the preceding
`useLastEpochs + 3` entries (a window of up to 11 with the mainnet
default of 8).

The tolerance is load-bearing for real-world proofs: JVM-built proofs
include continuous-mode difficulty-recalculation headers and
naturally-skipped entries from sparse-superlevel walks. Those entries
do not directly connect to the immediately previous sorted entry but
do connect to a nearby earlier neighbour. The Rust verifier had been
silently rejecting such proofs since `2b69b16a` (the original
`is_better_than` impl), but it went unnoticed until sigma-rust was
deployed as a verifier against live JVM peers.

Changes:
- Add `use_last_epochs: u32` to `NipopowAlgos` (Rust analog of JVM
  `chainSettings.useLastEpochs`). Default `8`, matching mainnet and
  testnet `application.conf`. Manual `Default` impl preserves the
  default-derive call sites in `ergo-chain-generation` and the
  proptest `Arbitrary` impl.
- Rewrite `has_valid_connections` to walk a `[max(0, idx - lookback), idx)`
  window for each prefix entry, exactly matching the Scala range
  semantics. Suffix-tail check is unchanged.
- Add three regression tests:
  1. `accepts_skipped_prefix_entry` — synthesizes a chain whose
     middle prefix entry skips its immediate predecessor but connects
     to a 2-back interlink; tolerant verifier must accept.
  2. `rejects_too_far_skip` — same shape, but with `use_last_epochs`
     squeezed to `0` so the only valid backward link sits outside the
     lookback window; verifier must still reject. Proves the fix is
     not a blanket accept-all.
  3. `rejects_broken_suffix_tail` — sanity check that the
     suffix-side parent_id chain is still strictly enforced.
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.

1 participant