# Week 18 — Update ## TL;DR Implemented the ping protocol in zig-libp2p. PR: https://github.com/zen-eth/eth-p2p-z/pull/85 --- ## Wire behavior (protocol semantics) - A Ping message must include a unique identifier (ping_id) that the responder reflects back in the Pong. - On receiving a Ping, the peer must immediately (or as soon as possible) send a Pong with the same ping_id. - On receiving a Pong, the originator matches the pong's ping_id with the outstanding Ping and computes RTT = now - ping_sent_time. - Duplicate or stale Pong: if ping_id is unknown or already matched/expired, safely ignore. - Ping to self: if the node receives a Ping from itself via looped connection, handle gracefully (respond with Pong) but do not count it as a measurement for peer health. --- ## Per-peer state & invariants For each connected peer maintain a PingState: - last_rtt: most recent RTT sample (ms). - rtt_ema: exponentially-weighted moving average of RTT (for smoothing). - outstanding: map ping_id -> sent_timestamp (only one outstanding ping per peer is simplest; implementations may allow a small window). - consecutive_timeouts: integer count of sequential ping timeouts. - next_ping_deadline: scheduled time for next proactive ping. Invariants: - outstanding count <= configured window (recommended 1). - consecutive_timeouts resets to 0 on any successful Pong. - If consecutive_timeouts > ping_retries threshold, mark peer unhealthy and take configured action (log, deprioritize, attempt reconnect, or disconnect). --- ## Internal APIs - peer_ping.init(config) - peer_ping.schedule_ping(peer_id) // schedule next ping per ping_interval - peer_ping.send_ping(peer_id) -> ping_id - records sent_timestamp in outstanding[ping_id] - sends Ping RPC/frame on wire - peer_ping.handle_pong(peer_id, ping_id) -> RTT - lookup outstanding ping_id, compute RTT, update last_rtt and rtt_ema, clear outstanding, reset consecutive_timeouts - peer_ping.on_ping_timeout(peer_id, ping_id) -> void - if outstanding still present and timed out, increment consecutive_timeouts and either retry or escalate per policy - peer_ping.handle_incoming_ping(peer_id, ping_id) - immediately send Pong(peer_id, ping_id) Configuration knobs: - ping_interval (seconds) - ping_timeout (seconds) - ping_retries (count) - rtt_ema_alpha (0..1) smoothing factor --- ## Example pseudocode ```pseudo // Periodic worker or per-peer timer function tick_peer_ping(peer): if now >= peer.next_ping_deadline and peer.outstanding.is_empty(): ping_id = send_ping(peer) peer.outstanding[ping_id] = now schedule_timeout(peer, ping_id, ping_timeout) peer.next_ping_deadline = now + ping_interval function handle_pong(peer, ping_id): if ping_id not in peer.outstanding: return // stale or duplicate sent = peer.outstanding[ping_id] rtt = now() - sent peer.last_rtt = rtt peer.rtt_ema = alpha * rtt + (1-alpha) * peer.rtt_ema delete peer.outstanding[ping_id] peer.consecutive_timeouts = 0 function on_ping_timeout(peer, ping_id): if ping_id not in peer.outstanding: return // already handled delete peer.outstanding[ping_id] peer.consecutive_timeouts += 1 if peer.consecutive_timeouts > ping_retries: mark_peer_unhealthy(peer) else: // optionally retry immediately, or wait until next tick ``` --- ## Message format & transport - Use existing libp2p RPC/subprotocol framing (match repo conventions). - Ping message payload: { ping_id: [u8; N] } (N = 8 or 16 bytes nonce is sufficient). - Pong message payload: { ping_id: same as Ping }. - Ensure endianness and canonical encoding (if using protobuf/CBOR/bytes) match interop expectations. - Respect per-message size limits; pings are tiny. --- ## Sequence diagram ```mermaid sequenceDiagram participant A as local participant B as remote A->>B: Ping(ping_id) Note right of B: store recv time if needed B->>A: Pong(ping_id) Note left of A: compute RTT = now - sent_time ``` --- ## Next Integrate the ping health signals with the peer manager (connection scoring / eviction), wire metrics to the monitoring stack, and add the interop tests against other libp2p implementations. Monitor canary nodes to validate behavior in the wild and adjust ping_interval/ping_timeout/ping_retries if needed. --- ## References - PR: https://github.com/zen-eth/eth-p2p-z/pull/85 - libp2p ping protocol (reference implementations for interop): go-libp2p / js-libp2p ping examples