Documentation
¶
Overview ¶
Package chainsync tracks the state of Dingo's block-synchronization sessions with connected peers. It does not speak the Ouroboros chainsync mini-protocol directly — that lives in the ouroboros package — but holds the per-peer tracking state the rest of the node queries and mutates.
The State type tracks which connection is currently the "primary" chainsync client, observed headers per peer, stall detection timestamps, and ingress-eligibility flags. It is thread-safe and is shared by the chain selector, the ouroboros handlers, and the node's stall recycler.
Chainsync clients can enter a stalled state when a peer stops delivering headers while still holding the connection open. The node's stall recycler reads tracked-client status from this package and issues ConnectionRecycleRequestedEvent to recover.
Index ¶
- Constants
- type ChainProvider
- type ChainsyncClientState
- type ClientAddedEvent
- type ClientRemoveRequestedEvent
- type ClientRemovedEvent
- type ClientStalledEvent
- type ClientStatus
- type ClientSyncedEvent
- type Config
- type ForkDetectedEvent
- type HeaderSyncStrategy
- type ObservedHeader
- type State
- func (s *State) AddClient(connId connection.ConnectionId, intersectPoint ocommon.Point) (*ChainsyncClientState, error)
- func (s *State) AddClientConnId(connId ouroboros.ConnectionId) bool
- func (s *State) AdvanceHeaderSyncRotation()
- func (s *State) BlockfetchLatency(connId ouroboros.ConnectionId) (time.Duration, bool)
- func (s *State) BlockfetchLatencyMedian() (time.Duration, int)
- func (s *State) CheckStalledClients() []ouroboros.ConnectionId
- func (s *State) ClearObservedHeaderHistory(connId ouroboros.ConnectionId)
- func (s *State) ClearSeenHeaders()
- func (s *State) ClearSeenHeadersFrom(fromSlot uint64)
- func (s *State) ClientConnCount() int
- func (s *State) ClientObservabilityOnly(connId ouroboros.ConnectionId) (bool, bool)
- func (s *State) ClientStartedAsOutbound(connId ouroboros.ConnectionId) (bool, bool)
- func (s *State) GetClientConnId() *ouroboros.ConnectionId
- func (s *State) GetClientConnIds() []ouroboros.ConnectionId
- func (s *State) GetTrackedClient(connId ouroboros.ConnectionId) *TrackedClient
- func (s *State) GetTrackedClients() []TrackedClient
- func (s *State) HandleClientRemoveRequestedEvent(evt event.Event)
- func (s *State) HasClientConnId(connId ouroboros.ConnectionId) bool
- func (s *State) HeaderPreviouslySeenFromOtherConn(connId ouroboros.ConnectionId, point ocommon.Point) bool
- func (s *State) HeaderSyncStrategy() HeaderSyncStrategy
- func (s *State) LookupObservedHeader(connId ouroboros.ConnectionId, hash []byte) (ObservedHeader, []byte, bool)
- func (s *State) MarkClientSynced(connId ouroboros.ConnectionId)
- func (s *State) MaxClients() int
- func (s *State) PeersWithBlock(origin ouroboros.ConnectionId, point ocommon.Point) []ouroboros.ConnectionId
- func (s *State) PruneSeenHeaders(beforeSlot uint64)
- func (s *State) RecordBlockfetchLatency(connId ouroboros.ConnectionId, latency time.Duration)
- func (s *State) RecordObservedHeader(h ObservedHeader)
- func (s *State) RemoveClient(connId connection.ConnectionId)
- func (s *State) RemoveClientConnId(connId ouroboros.ConnectionId)
- func (s *State) RewindTrackedClientsTo(point ocommon.Point) []ouroboros.ConnectionId
- func (s *State) SeenHeadersLen() int
- func (s *State) SetClientConnId(connId ouroboros.ConnectionId)
- func (s *State) SetClientObservabilityOnly(connId ouroboros.ConnectionId, observabilityOnly bool) bool
- func (s *State) SetClientStartedAsOutbound(connId ouroboros.ConnectionId, startedAsOutbound bool) bool
- func (s *State) ShouldPublishHeader(connId ouroboros.ConnectionId, point ocommon.Point, isNew bool) bool
- func (s *State) TryAddClientConnId(connId ouroboros.ConnectionId, maxClients int) bool
- func (s *State) TryAddClientConnIdWithDirection(connId ouroboros.ConnectionId, maxClients int, startedAsOutbound bool) bool
- func (s *State) TryAddObservedClientConnId(connId ouroboros.ConnectionId) bool
- func (s *State) TryAddObservedClientConnIdWithDirection(connId ouroboros.ConnectionId, startedAsOutbound bool) bool
- func (s *State) UpdateClientTip(connId ouroboros.ConnectionId, point ocommon.Point, tip ochainsync.Tip) bool
- func (s *State) UpdateClientTipWithoutDedup(connId ouroboros.ConnectionId, point ocommon.Point, tip ochainsync.Tip)
- type TrackedClient
Constants ¶
const ( // ClientAddedEventType is emitted when a new chainsync // client is registered. ClientAddedEventType event.EventType = "chainsync.client_added" // ClientRemovedEventType is emitted when a chainsync client // is unregistered (e.g. on disconnect). ClientRemovedEventType event.EventType = "chainsync.client_removed" // ClientSyncedEventType is emitted when a chainsync client // reaches the upstream chain tip. ClientSyncedEventType event.EventType = "chainsync.client_synced" // ClientStalledEventType is emitted when a chainsync client // has not received any headers within the stall timeout. ClientStalledEventType event.EventType = "chainsync.client_stalled" // ForkDetectedEventType is emitted when two clients report // different block hashes for the same slot. ForkDetectedEventType event.EventType = "chainsync.fork_detected" // ClientRemoveRequestedEventType is emitted when another // component requests chainsync to remove a tracked client. ClientRemoveRequestedEventType event.EventType = "chainsync.client_remove_requested" )
const DefaultMaxClients = 3
DefaultMaxClients is the default maximum number of concurrent chainsync clients.
const DefaultStallTimeout = 2 * time.Minute
DefaultStallTimeout is the default duration after which a client with no activity is considered stalled. This value must stay in sync with config.DefaultChainsyncConfig() and the fallback in internal/node/node.go.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ChainProvider ¶ added in v0.55.0
type ChainProvider interface {
GetChainFromPoint(point ocommon.Point, inclusive bool) (*chain.ChainIterator, error)
StabilityWindow() uint64
}
ChainProvider is the minimal interface chainsync requires from the ledger layer: local chain iteration for N2C server clients and the stability-window value used to bound the seen-header deduplication cache.
type ChainsyncClientState ¶
type ChainsyncClientState struct {
ChainIter *chain.ChainIterator
Cursor ocommon.Point
NeedsInitialRollback bool
}
ChainsyncClientState holds per-connection state for a chainsync server-side client (node-to-client connections).
type ClientAddedEvent ¶ added in v0.22.0
type ClientAddedEvent struct {
ConnId ouroboros.ConnectionId
TotalClients int
}
ClientAddedEvent contains details about a newly registered chainsync client.
type ClientRemoveRequestedEvent ¶ added in v0.22.0
type ClientRemoveRequestedEvent struct {
ConnId ouroboros.ConnectionId
ConnKey string
Reason string
}
ClientRemoveRequestedEvent contains the connection details for a requested tracked-client removal.
type ClientRemovedEvent ¶ added in v0.22.0
type ClientRemovedEvent struct {
ConnId ouroboros.ConnectionId
TotalClients int
WasPrimary bool
}
ClientRemovedEvent contains details about a removed chainsync client.
type ClientStalledEvent ¶ added in v0.22.0
type ClientStalledEvent struct {
ConnId ouroboros.ConnectionId
Slot uint64
}
ClientStalledEvent is published when a client exceeds the stall timeout.
type ClientStatus ¶ added in v0.22.0
type ClientStatus int
ClientStatus represents the sync status of a chainsync client.
const ( // ClientStatusSyncing indicates the client is actively // receiving headers. ClientStatusSyncing ClientStatus = iota // ClientStatusSynced indicates the client has reached the // upstream chain tip. ClientStatusSynced // ClientStatusStalled indicates the client has not received // activity within the stall timeout. ClientStatusStalled // ClientStatusFailed indicates the client encountered an // error. ClientStatusFailed )
func (ClientStatus) String ¶ added in v0.22.0
func (s ClientStatus) String() string
String returns a human-readable name for the ClientStatus.
type ClientSyncedEvent ¶ added in v0.22.0
type ClientSyncedEvent struct {
ConnId ouroboros.ConnectionId
Slot uint64
}
ClientSyncedEvent is published when a client reaches the upstream chain tip.
type Config ¶ added in v0.22.0
type Config struct {
MaxClients int
StallTimeout time.Duration
// HeaderSyncStrategy selects how headers from multiple eligible peers
// drive ledger ingress. The zero value is HeaderSyncStrategyPrimary,
// which preserves single-active behavior.
HeaderSyncStrategy HeaderSyncStrategy
// SeenHeadersRetention overrides the retention window, in slots, for
// the header deduplication cache. When zero, the retention window is
// derived from the ledger's current stability window (falling back to
// defaultSeenHeadersRetention when no ledger state is available).
SeenHeadersRetention uint64
// PromRegistry, when non-nil, is used to register chainsync metrics
// such as the current header deduplication cache size.
PromRegistry prometheus.Registerer
}
Config holds configuration for the chainsync State.
func DefaultConfig ¶ added in v0.22.0
func DefaultConfig() Config
DefaultConfig returns the default chainsync configuration.
type ForkDetectedEvent ¶ added in v0.22.0
type ForkDetectedEvent struct {
Slot uint64
HashA []byte
HashB []byte
ConnIdA ouroboros.ConnectionId
ConnIdB ouroboros.ConnectionId
Point ocommon.Point
}
ForkDetectedEvent is published when two clients report different block hashes at the same slot.
type HeaderSyncStrategy ¶ added in v0.55.0
type HeaderSyncStrategy int
HeaderSyncStrategy selects how headers from multiple eligible ChainSync peers drive ledger ingress. Cross-peer deduplication and fork detection apply under every strategy; the strategy only decides which eligible peer is permitted to publish a header into the ledger ingress queue.
const ( // HeaderSyncStrategyPrimary drives ledger ingress from a single active // peer, failing over to another eligible peer when it stalls or // disconnects. A new header from any eligible peer is published, and the // active peer replays a header first observed from another peer so it // stays the contiguous ingress driver. This is the default and preserves // the behavior from before the strategy gate existed. HeaderSyncStrategyPrimary HeaderSyncStrategy = iota // HeaderSyncStrategyParallel lets every eligible peer drive ledger // ingress concurrently. The first peer to report a header drives it; // duplicates from other peers are deduplicated before ledger ingress, so // a header never enters ledger processing twice. HeaderSyncStrategyParallel // HeaderSyncStrategyRoundRobin rotates a single ingress-driving peer // across the eligible peers. The rotation advances via // AdvanceHeaderSyncRotation. HeaderSyncStrategyRoundRobin )
func ParseHeaderSyncStrategy ¶ added in v0.55.0
func ParseHeaderSyncStrategy(s string) (HeaderSyncStrategy, error)
ParseHeaderSyncStrategy parses a header-sync strategy name. An empty string returns the default (primary). Names are case-insensitive and ignore surrounding whitespace; "round-robin", "roundrobin", and "round_robin" are all accepted.
func (HeaderSyncStrategy) String ¶ added in v0.55.0
func (h HeaderSyncStrategy) String() string
String returns the canonical name for the strategy.
type ObservedHeader ¶ added in v0.55.0
type ObservedHeader struct {
ConnectionId ouroboros.ConnectionId
BlockHeader gledger.BlockHeader
Point ocommon.Point
Tip ochainsync.Tip
BlockNumber uint64
Type uint
Rollback bool
}
ObservedHeader is a chainsync-owned record of a header received from a peer before cross-peer deduplication may suppress it. It carries enough context for fork resolution to reconstruct a peer's candidate fragment later.
type State ¶
State manages chainsync client connections and header tracking for both server-side (N2C) and outbound (N2N) connections.
func NewState ¶
func NewState( eventBus *event.EventBus, chainProvider ChainProvider, ) *State
NewState creates a new chainsync State with the given event bus and chain provider using default configuration.
func NewStateWithConfig ¶ added in v0.22.0
func NewStateWithConfig( eventBus *event.EventBus, chainProvider ChainProvider, cfg Config, ) *State
NewStateWithConfig creates a new chainsync State with the given event bus, chain provider, and configuration.
func (*State) AddClient ¶
func (s *State) AddClient( connId connection.ConnectionId, intersectPoint ocommon.Point, ) (*ChainsyncClientState, error)
AddClient registers a server-side (N2C) chainsync client.
func (*State) AddClientConnId ¶ added in v0.21.0
func (s *State) AddClientConnId( connId ouroboros.ConnectionId, ) bool
AddClientConnId adds a connection ID to the set of tracked chainsync clients, enforcing the configured MaxClients limit. Returns true if the client was added, false if rejected (already tracked or at capacity). If no active client exists, this connection is automatically set as the active client. The client is recorded as outbound (StartedAsOutbound=true).
func (*State) AdvanceHeaderSyncRotation ¶ added in v0.55.0
func (s *State) AdvanceHeaderSyncRotation()
AdvanceHeaderSyncRotation advances the round-robin ingress driver to the next eligible peer. It is a no-op unless the round-robin strategy is in use, so it is safe to call unconditionally (e.g. on every stall-check tick).
func (*State) BlockfetchLatency ¶ added in v0.38.0
BlockfetchLatency returns the blockfetch EWMA for the given connection and whether any samples have been recorded.
func (*State) BlockfetchLatencyMedian ¶ added in v0.39.0
BlockfetchLatencyMedian returns the median EWMA latency across all tracked peers that have at least one sample, plus the sample count. Used to adapt thresholds (e.g. shadow blockfetch gating) to the observed peer population rather than a fixed cutoff.
func (*State) CheckStalledClients ¶ added in v0.22.0
func (s *State) CheckStalledClients() []ouroboros.ConnectionId
CheckStalledClients scans all tracked clients and marks any that have exceeded the stall timeout. If the primary client is stalled, a failover to the next best client is triggered. Returns the list of connection IDs that were newly marked as stalled.
func (*State) ClearObservedHeaderHistory ¶ added in v0.27.7
func (s *State) ClearObservedHeaderHistory( connId ouroboros.ConnectionId, )
func (*State) ClearSeenHeaders ¶ added in v0.22.0
func (s *State) ClearSeenHeaders()
ClearSeenHeaders removes all entries from the header deduplication cache. This should be called on rollback to avoid stale entries.
func (*State) ClearSeenHeadersFrom ¶ added in v0.27.4
ClearSeenHeadersFrom removes entries from the header deduplication cache above the specified slot. This allows a restarted chainsync client to replay headers beyond a known-good intersect point after an active-peer switch without discarding older fork-detection history.
func (*State) ClientConnCount ¶ added in v0.21.0
ClientConnCount returns the number of tracked chainsync clients.
func (*State) ClientObservabilityOnly ¶ added in v0.27.5
func (s *State) ClientObservabilityOnly( connId ouroboros.ConnectionId, ) (bool, bool)
ClientObservabilityOnly reports whether a tracked client is currently observability-only. The second return value reports whether the client exists.
func (*State) ClientStartedAsOutbound ¶ added in v0.35.0
func (s *State) ClientStartedAsOutbound( connId ouroboros.ConnectionId, ) (bool, bool)
ClientStartedAsOutbound reports whether a tracked client was registered as an outbound connection. The second return value reports whether the client exists.
func (*State) GetClientConnId ¶
func (s *State) GetClientConnId() *ouroboros.ConnectionId
GetClientConnId returns the active chainsync client connection ID. This is the connection that should be used for block fetching.
func (*State) GetClientConnIds ¶ added in v0.21.0
func (s *State) GetClientConnIds() []ouroboros.ConnectionId
GetClientConnIds returns all tracked chainsync client connection IDs.
func (*State) GetTrackedClient ¶ added in v0.22.0
func (s *State) GetTrackedClient( connId ouroboros.ConnectionId, ) *TrackedClient
GetTrackedClient returns a deep copy of the TrackedClient for the given connection ID, or nil if not found. Byte slices inside Point.Hash are cloned so the caller cannot race with concurrent UpdateClientTip calls.
func (*State) GetTrackedClients ¶ added in v0.22.0
func (s *State) GetTrackedClients() []TrackedClient
GetTrackedClients returns deep copies of all tracked clients.
func (*State) HandleClientRemoveRequestedEvent ¶ added in v0.22.0
HandleClientRemoveRequestedEvent removes a tracked client when a component publishes a client removal request event.
func (*State) HasClientConnId ¶ added in v0.21.0
func (s *State) HasClientConnId( connId ouroboros.ConnectionId, ) bool
HasClientConnId returns true if the connection ID is being tracked.
func (*State) HeaderPreviouslySeenFromOtherConn ¶ added in v0.27.7
func (s *State) HeaderPreviouslySeenFromOtherConn( connId ouroboros.ConnectionId, point ocommon.Point, ) bool
HeaderPreviouslySeenFromOtherConn reports whether the exact header point was already recorded by a different connection. This lets the selected ingress peer replay a header first observed elsewhere without also replaying same-connection duplicates back into the ledger queue.
func (*State) HeaderSyncStrategy ¶ added in v0.55.0
func (s *State) HeaderSyncStrategy() HeaderSyncStrategy
HeaderSyncStrategy returns the configured header-sync strategy.
func (*State) LookupObservedHeader ¶ added in v0.27.7
func (s *State) LookupObservedHeader( connId ouroboros.ConnectionId, hash []byte, ) (ObservedHeader, []byte, bool)
LookupObservedHeader returns a previously observed header for the given connection/hash pair, along with its prev-hash ancestry.
func (*State) MarkClientSynced ¶ added in v0.22.0
func (s *State) MarkClientSynced( connId ouroboros.ConnectionId, )
MarkClientSynced marks a tracked client as synced (at chain tip).
func (*State) MaxClients ¶ added in v0.22.0
MaxClients returns the configured maximum number of chainsync clients.
func (*State) PeersWithBlock ¶ added in v0.38.0
func (s *State) PeersWithBlock( origin ouroboros.ConnectionId, point ocommon.Point, ) []ouroboros.ConnectionId
PeersWithBlock returns all tracked connection IDs — excluding origin — that have a recorded observed header at the given point. Callers use this to identify shadow peers for parallel blockfetch.
func (*State) PruneSeenHeaders ¶ added in v0.22.0
PruneSeenHeaders removes entries from the header deduplication cache for slots older than the given slot.
func (*State) RecordBlockfetchLatency ¶ added in v0.38.0
func (s *State) RecordBlockfetchLatency( connId ouroboros.ConnectionId, latency time.Duration, )
RecordBlockfetchLatency updates the EWMA blockfetch latency for the given connection. Called by the ledger when the first block body arrives after a RequestRange.
func (*State) RecordObservedHeader ¶ added in v0.27.7
func (s *State) RecordObservedHeader(h ObservedHeader)
RecordObservedHeader stores the raw per-connection header ancestry before cross-peer dedup can suppress delivery into the ledger queue. This lets fork resolution reconstruct the selected peer's candidate fragment even when earlier headers were first seen from another peer.
func (*State) RemoveClient ¶
func (s *State) RemoveClient(connId connection.ConnectionId)
RemoveClient unregisters a server-side (N2C) chainsync client.
func (*State) RemoveClientConnId ¶
func (s *State) RemoveClientConnId( connId ouroboros.ConnectionId, )
RemoveClientConnId removes a connection from tracking. If this was the active client, promotes the client with the highest tip slot as the new primary.
func (*State) RewindTrackedClientsTo ¶ added in v0.27.7
func (s *State) RewindTrackedClientsTo( point ocommon.Point, ) []ouroboros.ConnectionId
RewindTrackedClientsTo rewinds tracked client cursors that sit ahead of the provided local ledger point. This keeps chainsync client state aligned with local rollback/recovery so peers do not strand us in AwaitReply on a stale higher cursor.
func (*State) SeenHeadersLen ¶ added in v0.49.0
SeenHeadersLen returns the number of slots currently retained in the header deduplication cache. Primarily useful for metrics and tests.
func (*State) SetClientConnId ¶
func (s *State) SetClientConnId(connId ouroboros.ConnectionId)
SetClientConnId sets the active chainsync client connection ID. This is used when chain selection determines a new best peer.
func (*State) SetClientObservabilityOnly ¶ added in v0.27.5
func (s *State) SetClientObservabilityOnly( connId ouroboros.ConnectionId, observabilityOnly bool, ) bool
SetClientObservabilityOnly toggles whether a tracked client participates in the eligible chainsync pool. Promoting an observability-only client back into the eligible pool respects MaxClients; when the pool is full, the client remains observability-only and this method returns false.
func (*State) SetClientStartedAsOutbound ¶ added in v0.35.0
func (s *State) SetClientStartedAsOutbound( connId ouroboros.ConnectionId, startedAsOutbound bool, ) bool
SetClientStartedAsOutbound updates the recorded connection direction for an existing tracked client. This is used when a ConnectionId collision causes a new physical connection to replace an older tracked connection under the same ID.
func (*State) ShouldPublishHeader ¶ added in v0.55.0
func (s *State) ShouldPublishHeader( connId ouroboros.ConnectionId, point ocommon.Point, isNew bool, ) bool
ShouldPublishHeader reports whether a header from connId — already past peer eligibility and cross-peer deduplication — should be published into the ledger ingress queue under the configured header-sync strategy. isNew is the result returned by UpdateClientTip for this header; point is required to evaluate duplicate replay for the single-driver strategies.
The caller is responsible for the prior ingress-eligibility gate; this method only applies the strategy-specific driver policy.
func (*State) TryAddClientConnId ¶ added in v0.21.0
func (s *State) TryAddClientConnId( connId ouroboros.ConnectionId, maxClients int, ) bool
TryAddClientConnId atomically checks if a connection can be added (not already tracked and under maxClients limit) and adds it if allowed. Returns true if the connection was added, false otherwise.
func (*State) TryAddClientConnIdWithDirection ¶ added in v0.35.0
func (s *State) TryAddClientConnIdWithDirection( connId ouroboros.ConnectionId, maxClients int, startedAsOutbound bool, ) bool
TryAddClientConnIdWithDirection is like TryAddClientConnId but additionally records whether the connection was started as outbound. This is used to stamp each tracked client with its connection direction at registration time, providing a reliable flag that survives ConnectionId collisions.
func (*State) TryAddObservedClientConnId ¶ added in v0.27.5
func (s *State) TryAddObservedClientConnId( connId ouroboros.ConnectionId, ) bool
TryAddObservedClientConnId adds a connection to observability-only tracking. Observability-only clients do not consume the eligible client limit and are never promoted as the active chainsync source.
func (*State) TryAddObservedClientConnIdWithDirection ¶ added in v0.35.0
func (s *State) TryAddObservedClientConnIdWithDirection( connId ouroboros.ConnectionId, startedAsOutbound bool, ) bool
TryAddObservedClientConnIdWithDirection adds a connection to observability-only tracking and records whether it was started as outbound.
func (*State) UpdateClientTip ¶ added in v0.22.0
func (s *State) UpdateClientTip( connId ouroboros.ConnectionId, point ocommon.Point, tip ochainsync.Tip, ) bool
UpdateClientTip updates the cursor, tip, and activity tracking for a tracked client, and performs header deduplication. Returns true if the header at this point is new (not a duplicate).
func (*State) UpdateClientTipWithoutDedup ¶ added in v0.27.5
func (s *State) UpdateClientTipWithoutDedup( connId ouroboros.ConnectionId, point ocommon.Point, tip ochainsync.Tip, )
UpdateClientTipWithoutDedup updates the cursor, tip, and activity tracking for a tracked client without recording the header in the shared dedup cache. This is used for peers that should not drive ledger ingress, so they do not suppress later delivery of the same header from an eligible peer.
type TrackedClient ¶ added in v0.22.0
type TrackedClient struct {
ConnId ouroboros.ConnectionId
Cursor ocommon.Point
Tip ochainsync.Tip
Status ClientStatus
// ObservabilityOnly marks connections that should keep
// tip/activity metrics but must not consume the eligible
// client pool or become active for ledger ingress.
ObservabilityOnly bool
// StartedAsOutbound records whether the connection was
// initiated by us (outbound). This is stamped at
// registration time and can be refreshed only when the
// same ConnectionId is explicitly re-registered after a
// connmanager collision replacement.
StartedAsOutbound bool
LastActivity time.Time
HeadersRecv uint64
// TODO: BytesRecv needs to be wired to the underlying
// connection's byte counter. Currently unused.
BytesRecv uint64
// BlockfetchLatencyEWMA is an exponential moving average
// (alpha=0.2) of the time from RequestRange to first block
// response. Zero means no samples recorded yet.
BlockfetchLatencyEWMA time.Duration
// contains filtered or unexported fields
}
TrackedClient holds per-connection state for a tracked chainsync client (outbound node-to-node connections).