Skip to content

p2p/protocols/eth, p2p/sentry: EIP-8159 eth/71 handler + sentry dispatch (PR 2/3)#20794

Merged
yperbasis merged 3 commits intomainfrom
feat/eip-8159/handler-sentry
Apr 27, 2026
Merged

p2p/protocols/eth, p2p/sentry: EIP-8159 eth/71 handler + sentry dispatch (PR 2/3)#20794
yperbasis merged 3 commits intomainfrom
feat/eip-8159/handler-sentry

Conversation

@mh0lt
Copy link
Copy Markdown
Contributor

@mh0lt mh0lt commented Apr 24, 2026

Summary

Second of three stacked PRs implementing EIP-8159. Adds the server-side answer handler and wires eth/71 message dispatch into the sentry.

Depends on #20793 — review/merge that one first.

What lands

  • AnswerGetBlockAccessListsQuery in p2p/protocols/eth/handlers.go:
    • Iterates request hashes, resolves block number via HeaderReader.HeaderNumber.
    • Calls rawdb.ReadBlockAccessListBytes and appends RLP to response.
    • Returns empty RLP list (0xc0) for any hash not in local rawdb — EIP-8159's "not available" signal.
    • Enforces a soft-size limit (default 2 MiB per EIP recommendation) by truncating the response rather than padding.
  • Sentry dispatch in sentry_grpc_server.go for the two new message codes.
  • libsentry/protocol.goETH71 added to ethProtocolsByVersion, ProtoIds whitelist extended; MinProtocol(GET_BLOCK_ACCESS_LISTS_71) returns ETH71 so only eth/71 peers are queried.
  • Tests in p2p/protocols/eth/handlers_test.go:
    • TestAnswerGetBlockAccessListsQuery_OrderedResponseWithMissing — asserts positional ordering, plus unknown-block and known-block-no-BAL both return 0xc0 in the correct slot.
    • TestAnswerGetBlockAccessListsQuery_SoftSizeLimit — seeds 5 oversized BALs, asserts truncation (no partial payloads in the response).

What's NOT here

No consumer-side fetcher yet — peers that speak eth/71 can answer our queries, but we don't send any. That's PR 3.

Stack

  1. p2p/protocols/eth: EIP-8159 eth/71 wire protocol (PR 1/3) #20793 — wire protocol constants + packet types.
  2. This PR — handler + sentry dispatch.
  3. #TBD (fetcher + downloader + devnet skill) — depends on this one.

Test plan

  • go test -short ./p2p/protocols/eth/... ./p2p/sentry/...
  • make lint (0 issues)
  • make erigon integration
  • PR 3 builds and tests cleanly on top.

mh0lt and others added 3 commits April 26, 2026 11:56
…59 Phase 3)

Server-side handler for the eth/71 GetBlockAccessLists message. Returns
positionally-aligned RLP-encoded BALs sourced from rawdb.ReadBlockAccessListBytes,
with 0xc0 (empty RLP list) as the "not available" sentinel — same convention
the spec specifies. Disambiguation between "peer doesn't have it" and
"block genuinely has an empty BAL" happens at the caller via
keccak256(payload) == header.BlockAccessListHash; the handler does not
distinguish the cases.

Changes:

- p2p/protocols/eth/handler.go: add MaxBlockAccessListsServe = 1024 limit
  constant (alongside MaxBodiesServe, maxReceiptsServe).

- p2p/protocols/eth/handlers.go: add AnswerGetBlockAccessListsQuery. Mirrors
  AnswerGetBlockBodiesQuery — iterates requested hashes, resolves block
  number via blockReader.HeaderNumber, fetches BAL via
  rawdb.ReadBlockAccessListBytes, appends the RLP bytes (or 0xc0 when
  missing). Respects softResponseLimit (2 MiB) and the BAL-specific
  MaxBlockAccessListsServe cap. Truncates on limit hit; never pads.

- p2p/protocols/eth/handlers_test.go:
  - balHeaderReader: minimal services.HeaderReader stub (only HeaderNumber
    is exercised by the handler; other methods panic).
  - TestAnswerGetBlockAccessListsQuery_OrderedResponseWithMissing: verifies
    positional ordering is preserved and that both "unknown block" and
    "known block, no BAL" cases return 0xc0 in the correct slot.
  - TestAnswerGetBlockAccessListsQuery_SoftSizeLimit: seeds five oversized
    BALs and asserts the response is truncated rather than padded, and
    that every returned entry is the full BAL (no partial payloads).

No sentry dispatch yet — Phase 4 wires the message codes into
sentry_grpc_server.go and libsentry protocol negotiation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hase 4)

Wires the wire-protocol substrate (PR Phase 1+2) into the runtime sentry
layer so inbound BAL requests and responses reach subscribers, and so
eth/71 participates in capability negotiation and MinProtocol lookups.

Changes:

- p2p/sentry/libsentry/protocol.go:
  - ethProtocolsByVersion: append Protocol_ETH71 so MinProtocol can find
    it when resolving a message id to its minimum supporting version.
  - ProtoIds: add a Protocol_ETH71 entry cloned from Protocol_ETH70 plus
    the two new eth/71 message ids (GET_BLOCK_ACCESS_LISTS_71,
    BLOCK_ACCESS_LISTS_71). Peers that advertise eth/71 will have these
    message ids in scope for negotiation.

- p2p/sentry/sentry_grpc_server.go:
  - Inbound dispatch switch: add cases for GetBlockAccessListsMsg and
    BlockAccessListsMsg. Pattern mirrors GetBlockBodiesMsg / BlockBodiesMsg
    exactly: no-op when no subscribers, read msg bytes, forward to the
    mapped MessageId via send(). The response path (BlockAccessListsMsg)
    sets givePermit=true since it completes an in-flight request.

After this commit:
- eth/71 appears in capability negotiation when both peers support it.
- GetBlockAccessLists(0x12) and BlockAccessLists(0x13) inbound messages
  are de-multiplexed to the correct subscriber stream via the sentry
  Messages gRPC.
- The server-side answer handler added in the previous commit
  (AnswerGetBlockAccessListsQuery) can be wired to respond by
  subscribing to GET_BLOCK_ACCESS_LISTS_71.

Tested: short tests pass in p2p/sentry, p2p/sentry/libsentry,
p2p/sentry/sentry_multi_client, p2p/protocols/eth; make lint clean;
make erigon builds.

No consumer-side fetcher yet — Phase 5 adds the client that subscribes
to BLOCK_ACCESS_LISTS_71, validates payloads against header-committed
BAL hashes, and applies the bad-peer penalty tracks described in the plan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…159 update (#11553)

ethereum/EIPs#11553 corrected EIP-8159: the positional "not available"
sentinel in a BlockAccessLists response is now 0x80 (empty RLP string),
not 0xc0 (empty RLP list). Reason: 0xc0 is the canonical RLP encoding
of an empty access-list list, so on a chain without system contracts a
genuinely empty BAL collides with "I don't have it" — making the two
indistinguishable on the wire. 0x80 keeps them distinct.

- AnswerGetBlockAccessListsQuery now returns 0x80 for both "unknown
  block" and "known block, no BAL stored" cases.
- Comment + variable rename: emptyRLPList → notAvailableSentinel.
- Test asserts 0x80 in those slots.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mh0lt mh0lt force-pushed the feat/eip-8159/handler-sentry branch from 6a4a70c to ffb034d Compare April 26, 2026 11:57
@yperbasis yperbasis requested a review from Copilot April 26, 2026 15:17
@yperbasis yperbasis added Glamsterdam https://eips.ethereum.org/EIPS/eip-7773 Networking labels Apr 26, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements the server-side eth/71 (EIP-8159) Block Access List response handler and wires the new eth/71 message codes through the sentry dispatch layer, enabling peers to request/serve BAL sidecars over p2p.

Changes:

  • Add AnswerGetBlockAccessListsQuery to serve per-hash BAL responses with a soft size limit and positional “not available” signaling.
  • Extend sentry inbound dispatch to forward GetBlockAccessLists / BlockAccessLists messages and release request permits on responses.
  • Add ETH71 to libsentry protocol/version whitelisting and add handler tests covering ordering, missing entries, and truncation.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
p2p/sentry/sentry_grpc_server.go Dispatch inbound eth/71 BAL request/response messages to subscribers and manage permits for responses.
p2p/sentry/libsentry/protocol.go Register ETH71 and whitelist the eth/71 BAL message IDs for sentry routing/min-protocol selection.
p2p/protocols/eth/handlers.go Implement BAL query answering logic with sentinel behavior and soft response size truncation.
p2p/protocols/eth/handler.go Introduce a per-request disk-lookup cap constant for BAL serving.
p2p/protocols/eth/handlers_test.go Add unit tests validating ordering/missing semantics and soft-size-limit truncation for BAL responses.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +62 to +67
// MaxBlockAccessListsServe is the maximum number of block access lists to
// serve for an eth/71 GetBlockAccessLists request (EIP-8159). The spec
// recommends a per-response cap of 2 MiB, which softResponseLimit already
// enforces; this cap limits the number of disk lookups even when
// individual BALs are small.
MaxBlockAccessListsServe = 1024
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

MaxBlockAccessListsServe is exported, but its usage appears to be internal to the eth package (only referenced in handlers.go). Exporting it increases the public API surface unnecessarily; consider making it unexported (e.g., maxBlockAccessListsServe) unless it’s needed by other packages.

Suggested change
// MaxBlockAccessListsServe is the maximum number of block access lists to
// serve for an eth/71 GetBlockAccessLists request (EIP-8159). The spec
// recommends a per-response cap of 2 MiB, which softResponseLimit already
// enforces; this cap limits the number of disk lookups even when
// individual BALs are small.
MaxBlockAccessListsServe = 1024
// maxBlockAccessListsServe is the maximum number of block access lists to
// serve for an eth/71 GetBlockAccessLists request (EIP-8159). The spec
// recommends a per-response cap of 2 MiB, which softResponseLimit already
// enforces; this cap limits the number of disk lookups even when
// individual BALs are small.
maxBlockAccessListsServe = 1024

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +66
// MaxBlockAccessListsServe is the maximum number of block access lists to
// serve for an eth/71 GetBlockAccessLists request (EIP-8159). The spec
// recommends a per-response cap of 2 MiB, which softResponseLimit already
// enforces; this cap limits the number of disk lookups even when
// individual BALs are small.
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

The comment on softResponseLimit says it’s “Used by all protocol versions (eth/68–70)”, but this PR introduces an eth/71 handler that also relies on softResponseLimit. Please update the comment to reflect the new protocol range so the documentation stays accurate.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +180
// notAvailableSentinel is the RLP encoding of an empty string (0x80). EIP-8159
// (post ethereum/EIPs#11553) uses this as the positional "not available"
// sentinel in a BlockAccessLists response. Earlier drafts used 0xc0 (empty
// RLP list), but that collides with a genuinely empty BAL — 0xc0 is the
// canonical encoding of an empty access-list list — so "unavailable" and
// "valid empty BAL" were indistinguishable on the wire. Using 0x80 keeps
// the two distinct: 0x80 = "I don't have it", 0xc0 = "the BAL really is
// empty (e.g. a chain without system contracts)".
var notAvailableSentinel = rlp.RawValue{0x80}
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

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

PR description says the “not available” signal is 0xc0 (empty RLP list), but the implementation and tests use 0x80 (empty RLP string) as the sentinel. Please update the PR description (or adjust the code) so the documented behavior matches what’s actually implemented.

Copilot uses AI. Check for mistakes.
@yperbasis yperbasis added this pull request to the merge queue Apr 27, 2026
Merged via the queue into main with commit c568a38 Apr 27, 2026
41 of 43 checks passed
@yperbasis yperbasis deleted the feat/eip-8159/handler-sentry branch April 27, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Glamsterdam https://eips.ethereum.org/EIPS/eip-7773 Networking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants