Skip to content

feat(api): expose peer-scoring fields on /eth/v1/node/peers#16794

Draft
barnabasbusa wants to merge 4 commits into
OffchainLabs:developfrom
barnabasbusa:bbusa/peer-scores-beacon-api
Draft

feat(api): expose peer-scoring fields on /eth/v1/node/peers#16794
barnabasbusa wants to merge 4 commits into
OffchainLabs:developfrom
barnabasbusa:bbusa/peer-scores-beacon-api

Conversation

@barnabasbusa
Copy link
Copy Markdown
Contributor

Summary

Extends /eth/v1/node/peers (and /eth/v1/node/peers/{peer_id}) with four optional fields per a simplified beacon-API spec extension currently under discussion:

  • agent_version — from libp2p peerstore (host.Peerstore().Get(id, "AgentVersion"))
  • score — composite via peerStatus.Scorers().Score(id)
  • disconnect_reason — from new LastGoodbye* tracking persisted on peerdata.PeerData
  • downscore_reasons — live-derived from each scorer's IsBadPeer(id) (snapshot of current bad-state flags)

Spec proposal

ethereum/beacon-APIs#606

What's in this PR

  1. structs.Peer (api/server/structs/endpoints_node.go) — adds 4 fields with omitempty JSON tags.
  2. Handler wiring (beacon-chain/rpc/eth/node/handlers_peers.go) — populates the new fields in peerInfo() plus inline controlled-vocab translators (mapGoodbyeCode, mapDownscoreReasons).
  3. Goodbye persistence (beacon-chain/p2p/peers/peerdata/store.go + status.go) — new LastGoodbye{Code, SentByUs, Observed} on PeerData, with SetLastGoodbye() / LastGoodbye() accessors.
  4. Goodbye recording (beacon-chain/sync/rpc_goodbye.go) — records inbound goodbyes in goodbyeRPCHandler and outbound in sendGoodByeMessage.
  5. BUILD.bazel — adds @com_github_libp2p_go_libp2p//core/host dep for the new host.Peerstore() call.

Note on downscore_reasons

Rather than persisting per-event reason history, this derives the current bad-state classification at query time from each scorer:

  • BadResponsesScorer.IsBadPeer(id)rpc_invalid_response
  • PeerStatusScorer.IsBadPeer(id)status_unviable_fork
  • GossipScorer.IsBadPeer(id)behaviour_penalty

Empty array when the peer isn't currently flagged. This sidesteps event-history storage but means downscore_reasons reflects "currently bad for these reasons" rather than "recently downscored for these reasons" — both are valid interpretations of the field; happy to revisit.

Coordinated implementations

Part of a coordinated multi-client effort — see ethereum/beacon-APIs#606 for the other five client PRs.

Status

Draft. go build ./beacon-chain/... + go test ./beacon-chain/p2p/peers/... ./beacon-chain/rpc/eth/node/... pass. Bazel build also clean (required a struct-field reordering on PeerData to satisfy nogo's maligned-struct check).

Adds four optional fields to the beacon-API peer response objects
returned by /eth/v1/node/peers and /eth/v1/node/peers/{peer_id}:

  - agent_version: libp2p identify-protocol agent string
  - score: composite peer score from Prysm's scorer service
  - disconnect_reason: reserved for future per-peer goodbye tracking
  - downscore_reasons: live mapping of bad-peer scorer signals to the
    beacon-API spec's controlled vocabulary

All fields are emitted with omitempty so existing consumers are
unaffected. Disconnect reasons are intentionally left empty pending
per-peer goodbye-code tracking in peers.Status.
…nnect_reason

Adds per-peer tracking of the most recent goodbye code observed for each
peer in peers.Status. Both inbound goodbye RPC messages and outbound
goodbye messages sent by sendGoodByeMessage now record the code, the
direction (sentByUs), and an observation timestamp on the peerdata
store.

The /eth/v1/node/peers handler uses this to populate disconnect_reason,
mapping Prysm's goodbye code values to the beacon-API spec's controlled
vocabulary (client_shutdown, irrelevant_network, io_error, unviable_fork,
too_many_peers, bad_score). Unrecognized codes map to "unknown" so
consumers can still differentiate between "we observed a goodbye" and
"no goodbye seen" (which continues to omit the field).
PeerData's new LastGoodbye* fields needed reordering (uint64, time.Time,
bool) to avoid padding waste flagged by Prysm's nogo maligned-struct
check. Also wire @com_github_libp2p_go_libp2p//core/host into the
beacon-chain/rpc/eth/node BUILD.bazel deps since handlers_peers.go now
fetches AgentVersion via the libp2p host's Peerstore.
Per the proposed beacon-API spec
(ethereum/beacon-APIs#606), `disconnect_reason`
MUST only be populated when the peer's `state` is `disconnected` or
`disconnecting`. Only look up the last goodbye when the (lowercased)
peer state matches one of those values.
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