Skip to content

fix: reject legacy proofs whose headers commit to uncles/extensions - #293

Merged
quake merged 2 commits into
nervosnetwork:developfrom
eval-exec:fix/legacy-proof-missing-extension-check
Sep 14, 2026
Merged

quake merged 2 commits into
nervosnetwork:developfrom
eval-exec:fix/legacy-proof-missing-extension-check

Conversation

@eval-exec

Copy link
Copy Markdown
Contributor

Problem

A peer can answer a GetBlocksProof / GetTransactionsProof request with a legacy (v0) message that omits the V1 extra fields (blocks_uncles_hash, blocks_extension). The client fabricated None extensions for every proved header without checking whether the header's authenticated extra_hash actually commits to an empty uncle list and no extension. Stored headers then served None from ExtensionProvider, so scripts using the CKB2023 load_extension syscall were evaluated against missing extension data and local verification diverged from consensus.

Refs: sec-reports PENDING-HIGH-0007 ("Peer can omit CKB2023 block extensions").

Fix

For a block without uncles and without an extension, extra_hash is Byte32::zero() (the empty uncles hash is zero, and extra_hash equals the uncles hash when no extension is committed). Any other value commits to data the legacy message cannot carry.

  • send_blocks_proof.rs: new verify_legacy_extra_hash() helper, called in the legacy branch before the MMR proof.
  • send_transactions_proof.rs: same check in its legacy branch.
  • Rejection returns InvalidProof (439), which is ban-eligible through the existing misbehavior rate limiter.

Compatibility

  • Legacy (v0) responses remain accepted for blocks with no uncles and no extension (e.g. pre-V1 servers still work for those blocks).
  • Blocks with uncles and/or extensions now require the V1 fields — which the client needs anyway, since it cannot reconstruct uncle hashes or extensions from a legacy message.

Tests

  • Unit tests for verify_legacy_extra_hash and verify_extra_hash (accept/reject cases).
  • Integration: legacy blocks proof and legacy transactions proof for extension-bearing blocks are rejected; V1 proof with an incorrect extension is rejected.
  • The mock chain's block assembler attaches an extension to every mined block, so the proof-message test harness and the three tx-proof tests now send V1 messages carrying the real uncle hashes and extensions, like an honest server would.
  • Full ckb-light-client-lib suite: 122/122 pass. ckb-light-client bin compiles; clippy clean for the changed code.

A peer can answer a GetBlocksProof/GetTransactionsProof request with a
legacy (v0) message that omits the V1 extra fields (uncle hashes and
block extensions). The client fabricated None extensions for every
proved header without checking whether the header's authenticated
extra_hash actually commits to an empty uncle list and no extension.
Stored headers then served None from ExtensionProvider, so scripts
using the CKB2023 load_extension syscall verified against missing
extension data and local verification diverged from consensus.

For a block without uncles and without an extension, extra_hash is
Byte32::zero() (the empty uncles hash is zero, and extra_hash equals
the uncles hash when no extension is committed). Reject legacy
messages whose headers have any other extra_hash, since such blocks
can only be proved with the V1 fields.

Refs: sec-reports PENDING-HIGH-0007
The mock chain's block assembler attaches an extension to every mined
block, so proof-message tests now send V1 messages carrying the real
uncle hashes and extensions, like an honest server would. Add
regression tests for rejecting legacy (v0) proofs of extension-bearing
blocks, rejecting V1 proofs with incorrect extensions, and unit tests
for the extra-hash verification helpers.
Copilot AI lite review requested due to automatic review settings August 19, 2026 09:07
@eval-exec
eval-exec marked this pull request as draft August 19, 2026 09:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the light-client proof handlers against a legacy (v0) response that omits V1 “extra fields” (uncles hash + extension), preventing the client from accepting headers whose authenticated extra_hash commits to data that the legacy message cannot carry. This closes a consensus-divergence vector for CKB2023 load_extension by ensuring legacy proofs are only accepted for headers that commit to “no uncles, no extension”.

Changes:

  • Add verify_legacy_extra_hash() and invoke it when handling legacy (v0) SendBlocksProof / SendTransactionsProof responses.
  • Update protocol-level tests to send V1 messages with real blocks_uncles_hash and blocks_extension from the snapshot when appropriate.
  • Add unit tests covering accept/reject behavior for legacy extra-hash verification and extension mismatch verification.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
light-client-lib/src/protocols/light_client/components/send_blocks_proof.rs Adds verify_legacy_extra_hash() and enforces it on the legacy branch before continuing proof validation.
light-client-lib/src/protocols/light_client/components/send_transactions_proof.rs Enforces verify_legacy_extra_hash() for legacy tx-proof responses to prevent extension omission.
light-client-lib/src/protocols/light_client/components/mod.rs Re-exports verify_legacy_extra_hash for reuse by components.
light-client-lib/src/protocols/light_client/components/tests/send_blocks_proof.rs Adds focused unit tests for legacy extra-hash acceptance/rejection and V1 extension mismatch behavior.
light-client-lib/src/protocols/light_client/components/tests/mod.rs Registers the new component test module.
light-client-lib/src/tests/protocols/light_client/send_blocks_proof.rs Extends integration-style blocks-proof tests to cover legacy rejection for extension-bearing blocks and V1 incorrect-extension rejection; updates harness to send realistic V1 fields.
light-client-lib/src/tests/protocols/light_client/send_transactions_proof.rs Updates tx-proof tests to send V1 fields in normal cases and adds an integration test ensuring legacy tx-proofs are rejected for extension-bearing blocks.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@eval-exec
eval-exec requested a balanced review from Copilot August 20, 2026 06:45
@eval-exec
eval-exec marked this pull request as ready for review August 20, 2026 06:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

@quake
quake merged commit d8695b5 into nervosnetwork:develop Sep 14, 2026
10 checks passed
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.

3 participants