Skip to content

ergo-nipopow: validate the initial proof before selection - #914

Merged
kushti merged 1 commit into
ergoplatform:v0.30.0from
a-shannon:fix/nipopow-validate-initial-proof
Aug 3, 2026
Merged

ergo-nipopow: validate the initial proof before selection#914
kushti merged 1 commit into
ergoplatform:v0.30.0from
a-shannon:fix/nipopow-validate-initial-proof

Conversation

@a-shannon

Copy link
Copy Markdown

Merge dependency

This PR is ready for code review, but it must not merge before #852 and #866.
The current structural predicate rejects real JVM-node proofs until #852 fixes
prefix lookback semantics and #866 fixes canonical interlink-key encoding.
Neither prerequisite's diff is included here.

A manual replay of a mainnet proof ending at block 1,784,124 confirmed the
boundary: the proof is rejected by the candidate on standalone develop and
selected when the same candidate is stacked on the exact #852 and #866 heads.
The current #852 head also needs formatting cleanup, and the current #866 head
trips the crate's clippy::expect_used denial.

Summary

  • require a genesis-anchored initial proof to pass the verifier's existing
    structural validity predicate before it can become best_proof
  • reject interlink vectors that cannot be represented by the one-byte run
    length and canonical first-occurrence key position before validation calls
    the unchecked packer
  • keep invalid-proof handling and the public process() API unchanged
  • add isolated regression coverage for invalid connections, heights, interlink
    proofs and encoding bounds, genesis anchoring, valid admission, and recovery

Why

NipopowVerifier::process previously stored the first genesis-anchored proof
without calling the predicate used during later proof comparisons. A
structurally invalid first proof could therefore become observable through
best_proof() and best_chain().

This PR applies the existing predicate to that initial state transition. It
also makes interlink validation reject an empty-vector/proof mismatch, a run
longer than 255 entries, or a run beginning after position 255 before reaching
pack_interlinks.

Invalid proofs continue to be ignored with Ok(()), leaving the verifier empty
so that a later valid proof can be accepted.

Validation

Candidate on the #863 dependency-repair head:

  • focused verifier tests: 12/12 in debug and 12/12 in release
  • ergo-chain-generation library tests: 28/28
  • cargo fmt --all -- --check
  • cargo clippy -p ergo-nipopow -p ergo-chain-generation --all-targets -- -D warnings

Candidate stacked on #852, #866, #863, and #903:

  • focused verifier tests: 12/12 in debug and 12/12 in release
  • ergo-chain-generation library tests: 28/28
  • ergo-nipopow library tests: 2/2
  • mainnet block-1,784,124 proof: all interlink proofs valid, connections valid,
    and initial proof selected

The RED phases separately demonstrated the initial-selection bypass, three
unchecked-packer panics, and acceptance of a sparse run beginning at position
256. All focused cases pass with the complete change.

Fresh develop currently cannot resolve the yanked core2 dependency, so
Cargo validation used #863. The isolated JSON target additionally used #903.
Those build repairs are not included in this PR.

Scope

This PR does not add proof-of-work, m/k, or continuous-mode difficulty
validation, and it does not claim complete JVM parity, deployed exploitation,
or established funds impact.

@kushti
kushti changed the base branch from develop to v0.30.0 August 3, 2026 08:58
@kushti
kushti merged commit 3d53c36 into ergoplatform:v0.30.0 Aug 3, 2026
2 of 28 checks passed
@kushti kushti mentioned this pull request Aug 3, 2026
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.

2 participants