This repository measures the latency between when a slot is first observed via Solana gossip and when it is confirmed via a Yellowstone gRPC stream.
- Connects to Solana gossip and subscribes to vote messages.
- Simultaneously subscribes to slot updates from a Yellowstone gRPC endpoint.
- For each slot, records the first arrival timestamp from each source.
- When both timestamps are available, logs the latency (
gossip arrival → Yellowstone slot update). - Writes structured JSON logs to stdout and a file via zerolog.
runtime/: executable entrypoint (main.go).services/:TrackerService— coordinates gossip and Yellowstone subscriptions, slot tracking logic..env.example: environment variable template.
- Go
1.25.5(as declared ingo.mod). - A Yellowstone-compatible gRPC endpoint and access token.
- UDP and TCP ports open for gossip traffic.
Copy the example env file and fill in your values:
cp .env.example .env| Variable | Description | Example |
|---|---|---|
ENV |
Solana cluster (mainnet, testnet, devnet) |
mainnet |
GRPC_ENDPOINT |
Yellowstone gRPC endpoint host | yellowstone.eu.fluxrpc.com |
GRPC_TOKEN |
Auth token for the gRPC endpoint | 432d443f-... |
UDP_PORT |
UDP port for gossip traffic | 8001 |
TCP_PORT |
TCP port for gossip IP echo handshake | 8001 |
LOG_LEVEL |
Log verbosity (trace, debug, info, error) |
info |
LOG_FILE |
Path to write the log file | gossip.log |
DISPLAY_SLOTS |
Whether to display slot output | true |
go run ./runtime/main.goOn first start, if id.json is not found, a new keypair is generated and written there automatically.
The tracker keeps a circular ring buffer of the last 1500 slots. For each slot:
- When a gossip vote for that slot arrives, the receive timestamp is stored.
- When a Yellowstone slot update for the same slot arrives, the receive timestamp is stored.
- Once both timestamps are present, the latency is computed as:
latency = yellowstone_arrival − gossip_arrival
The result is a time.Duration and is logged as the latency field on the SLOT LATENCY TRACKED log line.
If Yellowstone is observed before gossip for a slot, that slot is dropped because it does not represent a valid gossip-to-Yellowstone latency.
The gossip dependency (github.com/Gealber/gossip) relies on a forked binary decoder
(github.com/Gealber/binary) to correctly handle Solana's bincode wire format. Because Go only
applies replace directives from the main module, this repo must redeclare the replacement in its
own go.mod:
replace github.com/gagliardetto/binary => github.com/Gealber/binary v0.0.0-20260419181258-89e8fe42e32c
Without this, gossip packet decoding will fail with unknown CrdsData discriminant errors caused
by byte-offset drift in the upstream library.
This is a narrow observability utility focused on measuring gossip-to-confirmation latency on Solana. It is not a full gossip node and does not persist or re-broadcast any state.