fix(p2p): do not penalize peers that signal a missing block with Fr.ZERO#23672
Merged
Merged
Conversation
Collaborator
Flakey Tests🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry. |
PhilWindle
approved these changes
May 29, 2026
| @@ -1528,6 +1528,16 @@ export class LibP2PService extends WithTracer implements P2PService { | |||
| peerId: PeerId, | |||
| ): Promise<boolean> { | |||
Collaborator
There was a problem hiding this comment.
It looks to me like this functions would be better off returning more infomration than simply true/false. Perhaps ReqRespStatus. The case you have added gets translated to INTERNAL_ERROR. It has the same effect as NOT_FOUND but perhaps this is due a cleanup.
f97be2d to
480af1a
Compare
danielntmd
pushed a commit
to danielntmd/aztec-packages
that referenced
this pull request
Jun 4, 2026
BEGIN_COMMIT_OVERRIDE test(e2e): unskip pipelining related e2e tests (AztecProtocol#23642) fix(archiver): prune blocks without proposed checkpoint by end of build slot (AztecProtocol#23606) test: migrate benchmarks to pipelining setup (AztecProtocol#23647) fix(p2p): fall back to archiver in BLOCK_TXS response validation (AztecProtocol#23624) docs(slashing): align operator and slasher docs with AZIP-7 (AztecProtocol#23494) fix(p2p): do not penalize peers that signal a missing block with Fr.ZERO (AztecProtocol#23672) chore: adjust metrics deployment (AztecProtocol#23676) fix(cheat-codes): warpL2TimeAtLeastBy advances relative to leading clock (AztecProtocol#23675) chore: tighten node pool sizes (AztecProtocol#23678) chore: remove archival nodes (AztecProtocol#23630) chore: merge blob sink duties into RPC node (AztecProtocol#23631) fix: sync avm-transpiler Cargo.lock with noir submodule (AztecProtocol#23683) fix(spartan): set validator lag env vars in tps-scenario (AztecProtocol#23684) fix: make world-state hash queries reorg-aware to close getWorldState race (AztecProtocol#23677) fix: pin noir submodule to next's version on merge-train/spartan (AztecProtocol#23690) fix: ensure image ref is used by bench runner (AztecProtocol#23682) fix(ci): retry aztec-nr nargo dependency clone on transient network flake (AztecProtocol#23653) chore: run one-off jobs on network nodes (AztecProtocol#23701) fix: simulate proposals inside target slot (AztecProtocol#23692) chore: smaller eth-devnet (AztecProtocol#23704) chore: enable testnet autoscaling (AztecProtocol#23705) feat(api)!: redesign node log retrieval API around tag-based queries (AztecProtocol#23625) fix(sequencer): set own proposed checkpoint locally instead of via p2p loopback (AztecProtocol#23659) END_COMMIT_OVERRIDE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on:
[mr/fix-block-txs-validation-archiver-fallback](https://github.com/AztecProtocol/aztec-packages/pull/23624)(the archiver-fallback PR).Summary
A peer that legitimately can't find the requested block in its attestation pool or archiver, but matches the requested hashes against its tx pool and sends those txs back, signals "I don't have the block" by setting
archiveRoot = Fr.ZEROin the response (block_txs_handler.ts:54-58). The requester's validation currently treats that response the same as a malicious archive-root mismatch and applies aMidToleranceErrorpeer penalty. After enough such responses from the same helpful peer, that peer is disconnected by the requester for behaviour the protocol explicitly documents as legitimate.This PR makes the validator recognise
Fr.ZEROas the "I don't have the block" signal and stop penalising peers for it.What's broken
Responder side (correct, intentional)
block_txs_handler.ts:54-58— when the responder lacks the block (no proposal, no archived block) but the request carried full tx hashes, it tries to serve from its pool by hash and signals the "I don't know the block" condition witharchiveRoot = Fr.zero():Requester side (broken)
The validator at
libp2p_service.ts:1525-1530penalizes any archive-root mismatch withMidToleranceError(-10 score points) and throws — includingFr.zero:After 5 such responses from the same helpful peer, that peer is at -50 in the requester's score book → disconnected by
pruneUnhealthyPeers(peer_manager.ts:601-603).Receiver-side code already documented the correct intent
The wrongful penalty contradicts what the receiver-side code explicitly says should happen.
batch_tx_requester.ts:586-600hashandleArchiveRootMismatch, whose docstring spells out exactly the semantic we're restoring:But this function is only reached from
decideIfPeerIsSmart→handleSuccessResponseFromPeer, which only runs when validation returnstrue. The validator's first check (archive-root equality) rejects every archive-mismatched response — includingFr.zero— sohandleArchiveRootMismatchis never actually invoked. The "Fr.zero is legitimate" exemption it encodes has been unreachable since the validator's archive-root check was added.The flow today:
So the receiver side already knew Fr.zero should not be penalised; the decision was just being made at the wrong layer. This PR moves it to the validator, where it can actually fire.
handleArchiveRootMismatchitself remains dead code (separate cleanup candidate, not in this PR).Fix
Special-case
response.archiveRoot.isZero()at the top ofvalidateRequestedBlockTxsConsistencyso the archive-root mismatch path is bypassed forFr.zeroresponses. We still returnfalse(the txs are dropped because we can't verify membership/order without the block) but no peer penalty is applied — matching the intent of theFr.zeroexemption inbatch_tx_requester.ts:593-600.The validator's other checks are unchanged. The early return prevents the bitvector-length and
maxReturnablechecks downstream from firing on a zero-length bitvector response, which would otherwise also wrongly penalise the peer.Tests
Unit —
p2p/src/services/libp2p/libp2p_service.test.tsA new test in the
validateRequestedBlockTxsConsistencydescribe block: "should not penalize a peer that signals lacking the block with Fr.ZERO archive root". Constructs a response witharchiveRoot = Fr.ZEROand asserts thatpeerManager.penalizePeeris not called. Verified red before the fix, green after.Integration —
p2p/src/client/test/p2p_client.integration_block_txs.test.tsA new test in the
p2p client integration block txs protocoldescribe block: "requester does not penalize peer that returns Fr.zero (peer lacks proposal but matched by hash)". Drives a real reqresp BLOCK_TXS request over libp2p between two clients, lets the responder hit theFr.zerobranch inblock_txs_handler, then runs the response through the requester's realvalidateRequestedBlockTxsConsistencyand asserts the requester'speerManager.penalizePeeris not called withMidToleranceErrororLowToleranceError. Verified red before the fix, green after.