Skip to content

fix(sync): enforce end-of-input on header receive (match the reload path and sibling sinks) - #347

Open
cafebedouin wants to merge 1 commit into
arkadianet:mainfrom
cafebedouin:fix/header-receive-eof-guard
Open

cafebedouin wants to merge 1 commit into
arkadianet:mainfrom
cafebedouin:fix/header-receive-eof-guard

Conversation

@cafebedouin

Copy link
Copy Markdown

This change was prepared with AI assistance (Claude, model Claude Opus 4.8); every claim below was verified against the source and the fix is covered by the included regression test.

pre_validate_header (ergo-sync/src/header_proc.rs) parses an inbound header with read_header but does not check that the parse consumed all of the payload bytes. Two consequences:

  1. A header delivered as canonical_bytes ++ trailing_junk is accepted — read_header stops at the end of the header and ignores the trailing bytes.
  2. The header id is blake2b256(header_bytes) over the raw received bytes, so the same block content entering with different trailing bytes is stored under different, non-canonical ids.

This is looser than the node's own reload path (ergo-validation/src/header/mod.rs), which already rejects consumed != header_bytes.len() (with a comment noting the same gap), and looser than the sibling receive sinks — the transaction deserializer (ergo-validation/src/tx/mod.rs, !r.is_empty()), block-section verify (ergo-sync/src/coordinator/section_verify.rs, r.remaining() != 0), and deserialize_nipopow_proof (ergo-ser/src/popow_proof.rs, r.remaining() != 0) all reject trailing bytes. The Ergo reference node also rejects a trailing-byte header at parse.

Fix: enforce end-of-input in pre_validate_header immediately after read_header, matching the reload path. Because trailing bytes are then rejected, header_bytes is canonical and its blake2b256 id is the canonical id — closing both the trailing-byte acceptance and the raw-vs-canonical-id divergence in one check. read_header already consumes a header's own unparsed_bytes field, so a canonical header (including v5+ headers carrying real unparsed_bytes) lands exactly at end-of-input and is not affected.

Test: ergo-sync/tests/header_receive_eof.rs — a canonical mainnet header is accepted; the same header with trailing bytes appended is rejected. Existing header_proc unit tests (7) and the header_sync_integration suite (23) pass unchanged.

🤖 Generated with Claude Code

pre_validate_header parsed an inbound header but did not check that read_header
consumed all the payload bytes, unlike the reload path
(ergo-validation/src/header/mod.rs) and the sibling receive sinks (transaction,
block-section, and NiPoPoW-proof deserializers all reject trailing bytes).

Consequences: a header delivered as `canonical ++ trailing` was accepted, and
because the id is blake2b256(header_bytes) over the raw bytes, the same block
content could enter under a non-canonical id. Adds the missing EOF check right
after read_header (matching the reload path), plus a regression test: a canonical
header is accepted and a trailing-byte header is rejected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 485f5886-964e-4855-9277-ce963560e995


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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