Skip to content

fix(p2p)!: fix BLOCK_TXS response under proposer equivocation#23786

Open
fcarreiro wants to merge 1 commit into
merge-train/spartanfrom
fc/fix-block-txs-equivocation
Open

fix(p2p)!: fix BLOCK_TXS response under proposer equivocation#23786
fcarreiro wants to merge 1 commit into
merge-train/spartanfrom
fc/fix-block-txs-equivocation

Conversation

@fcarreiro
Copy link
Copy Markdown
Contributor

@fcarreiro fcarreiro commented Jun 1, 2026

Summary

Fixes A-1070: a malicious proposer who sends two different proposals with the same archive root but different tx sets could make two honest nodes fail the BLOCK_TXS exchange and penalize each other.

In the BLOCK_TXS protocol the requester asks for txs by their index within a block (proposal), identified only by its archive root. If an equivocating proposer gives node A and node B two proposals that share an archive root but differ in their tx list, then:

  • Node A (requester) asks node B for txs at indices [i, j, …] of "the block with this archive root".
  • Node B (responder) resolves those indices against its version of the proposal and returns txs that, from A's perspective, are not part of the block.
  • A's validateRequestedBlockTxsConsistency rejects the response and penalizes B — an honest node punished for honest behavior.

Fix

The request now carries a commitment to the full set of block tx hashes (blockTxHashesCommitment, a SHA-256 over the serialized tx hashes) alongside the archive root. The responder only serves txs by index (and advertises availability via the bitvector) when its own block's tx-hash commitment matches the request's. Otherwise it treats the request as "I don't have that block" — returning an empty bitvector and only servicing any explicitly-requested tx hashes — so neither side is penalized for an equivocation it didn't cause.

This closes the gap that the archive root alone could not: identical archive roots no longer imply identical tx sets.

Why not use proposal hash?

That would work when the BLOCK_TXS request is from a proposal, but it cannot be used when it's done from a block (e.g., in the prover node).

Changes

  • BlockTxsRequest gains a blockTxHashesCommitment field and a computeBlockTxHashesCommitment helper; serialization and fromTxsSourceAndMissingTxs updated accordingly.
  • reqRespBlockTxsHandler verifies the commitment before serving txs by index; on mismatch it falls back to the "block not available" path instead of returning indexed txs.
  • This builds on the preceding BLOCK_TXS validation revamp commit (consistency checks on the requester side, response no longer echoes the archive root).
  • Tests adapted across block_txs, block_txs_handler, and libp2p_service, plus a new handler test covering the equivocation case (different proposal under the same archive root → responder refuses to serve by index).

Closes https://linear.app/aztec-labs/issue/A-1070/malicious-proposer-can-make-honest-nodes-to-fail-tx-validation .

@fcarreiro fcarreiro changed the base branch from merge-train/spartan to fc/fix-block-txs-validation June 1, 2026 21:55
@fcarreiro fcarreiro changed the title fix(p2p): fix BLOCK_TXS response under proposer equivocation fix(p2p)!: fix BLOCK_TXS response under proposer equivocation Jun 1, 2026
Comment on lines 73 to +74
const responseTxs = (await txPool.getTxsByHash(requestedTxsHashes)).filter(tx => !!tx);
const response = new BlockTxsResponse(new TxArray(...responseTxs), responseBitVector);
const response = new BlockTxsResponse(new TxArray(...responseTxs), availableIndicesBitVector);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't we check if requestedTxHashes is non-empty before this, and if it is, return NOT_FOUND?

Base automatically changed from fc/fix-block-txs-validation to merge-train/spartan June 2, 2026 01:56
@spalladino spalladino force-pushed the fc/fix-block-txs-equivocation branch from 12c4d5c to c8f703b Compare June 2, 2026 01:58
@spalladino spalladino enabled auto-merge (squash) June 2, 2026 02:00
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