Skip to content

Commit 79807d5

Browse files
committed
chore(sync/stats): migrate stats packages for EVM state sync from coreth
- Migrate sync/handlers/stats and sync/client/stats to vms/evm/sync/stats package in avalanchego. resolves #4368 Signed-off-by: Tsvetan Dimitrov (tsvetan.dimitrov@avalabs.org)
1 parent ede1a7e commit 79807d5

File tree

2 files changed

+379
-0
lines changed

2 files changed

+379
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package stats
5+
6+
import (
7+
"time"
8+
9+
"github.com/ava-labs/libevm/metrics"
10+
)
11+
12+
// HandlerStats reports prometheus metrics for the state sync handlers
13+
type HandlerStats interface {
14+
BlockRequestHandlerStats
15+
CodeRequestHandlerStats
16+
LeafsRequestHandlerStats
17+
}
18+
19+
type BlockRequestHandlerStats interface {
20+
IncBlockRequest()
21+
IncMissingBlockHash()
22+
UpdateBlocksReturned(num uint16)
23+
UpdateBlockRequestProcessingTime(duration time.Duration)
24+
}
25+
26+
type CodeRequestHandlerStats interface {
27+
IncCodeRequest()
28+
IncMissingCodeHash()
29+
IncTooManyHashesRequested()
30+
IncDuplicateHashesRequested()
31+
UpdateCodeReadTime(duration time.Duration)
32+
UpdateCodeBytesReturned(bytes uint32)
33+
}
34+
35+
type LeafsRequestHandlerStats interface {
36+
IncLeafsRequest()
37+
IncInvalidLeafsRequest()
38+
UpdateLeafsReturned(numLeafs uint16)
39+
UpdateLeafsRequestProcessingTime(duration time.Duration)
40+
UpdateReadLeafsTime(duration time.Duration)
41+
UpdateSnapshotReadTime(duration time.Duration)
42+
UpdateGenerateRangeProofTime(duration time.Duration)
43+
UpdateRangeProofValsReturned(numProofVals int64)
44+
IncMissingRoot()
45+
IncTrieError()
46+
IncProofError()
47+
IncSnapshotReadError()
48+
IncSnapshotReadAttempt()
49+
IncSnapshotReadSuccess()
50+
IncSnapshotSegmentValid()
51+
IncSnapshotSegmentInvalid()
52+
}
53+
54+
type handlerStats struct {
55+
// BlockRequestHandler metrics
56+
blockRequest metrics.Counter
57+
missingBlockHash metrics.Counter
58+
blocksReturned metrics.Histogram
59+
blockRequestProcessingTime metrics.Timer
60+
61+
// CodeRequestHandler stats
62+
codeRequest metrics.Counter
63+
missingCodeHash metrics.Counter
64+
tooManyHashesRequested metrics.Counter
65+
duplicateHashesRequested metrics.Counter
66+
codeBytesReturned metrics.Histogram
67+
codeReadDuration metrics.Timer
68+
69+
// LeafsRequestHandler stats
70+
leafsRequest metrics.Counter
71+
invalidLeafsRequest metrics.Counter
72+
leafsReturned metrics.Histogram
73+
leafsRequestProcessingTime metrics.Timer
74+
leafsReadTime metrics.Timer
75+
snapshotReadTime metrics.Timer
76+
generateRangeProofTime metrics.Timer
77+
proofValsReturned metrics.Histogram
78+
missingRoot metrics.Counter
79+
trieError metrics.Counter
80+
proofError metrics.Counter
81+
snapshotReadError metrics.Counter
82+
snapshotReadAttempt metrics.Counter
83+
snapshotReadSuccess metrics.Counter
84+
snapshotSegmentValid metrics.Counter
85+
snapshotSegmentInvalid metrics.Counter
86+
}
87+
88+
func (h *handlerStats) IncBlockRequest() {
89+
h.blockRequest.Inc(1)
90+
}
91+
92+
func (h *handlerStats) IncMissingBlockHash() {
93+
h.missingBlockHash.Inc(1)
94+
}
95+
96+
func (h *handlerStats) UpdateBlocksReturned(num uint16) {
97+
h.blocksReturned.Update(int64(num))
98+
}
99+
100+
func (h *handlerStats) UpdateBlockRequestProcessingTime(duration time.Duration) {
101+
h.blockRequestProcessingTime.Update(duration)
102+
}
103+
104+
func (h *handlerStats) IncCodeRequest() {
105+
h.codeRequest.Inc(1)
106+
}
107+
108+
func (h *handlerStats) IncMissingCodeHash() {
109+
h.missingCodeHash.Inc(1)
110+
}
111+
112+
func (h *handlerStats) IncTooManyHashesRequested() {
113+
h.tooManyHashesRequested.Inc(1)
114+
}
115+
116+
func (h *handlerStats) IncDuplicateHashesRequested() {
117+
h.duplicateHashesRequested.Inc(1)
118+
}
119+
120+
func (h *handlerStats) UpdateCodeReadTime(duration time.Duration) {
121+
h.codeReadDuration.Update(duration)
122+
}
123+
124+
func (h *handlerStats) UpdateCodeBytesReturned(bytesLen uint32) {
125+
h.codeBytesReturned.Update(int64(bytesLen))
126+
}
127+
128+
func (h *handlerStats) IncLeafsRequest() {
129+
h.leafsRequest.Inc(1)
130+
}
131+
132+
func (h *handlerStats) IncInvalidLeafsRequest() {
133+
h.invalidLeafsRequest.Inc(1)
134+
}
135+
136+
func (h *handlerStats) UpdateLeafsRequestProcessingTime(duration time.Duration) {
137+
h.leafsRequestProcessingTime.Update(duration)
138+
}
139+
140+
func (h *handlerStats) UpdateLeafsReturned(numLeafs uint16) {
141+
h.leafsReturned.Update(int64(numLeafs))
142+
}
143+
144+
func (h *handlerStats) UpdateReadLeafsTime(duration time.Duration) {
145+
h.leafsReadTime.Update(duration)
146+
}
147+
148+
func (h *handlerStats) UpdateSnapshotReadTime(duration time.Duration) {
149+
h.snapshotReadTime.Update(duration)
150+
}
151+
152+
func (h *handlerStats) UpdateGenerateRangeProofTime(duration time.Duration) {
153+
h.generateRangeProofTime.Update(duration)
154+
}
155+
156+
func (h *handlerStats) UpdateRangeProofValsReturned(numProofVals int64) {
157+
h.proofValsReturned.Update(numProofVals)
158+
}
159+
160+
func (h *handlerStats) IncMissingRoot() { h.missingRoot.Inc(1) }
161+
func (h *handlerStats) IncTrieError() { h.trieError.Inc(1) }
162+
func (h *handlerStats) IncProofError() { h.proofError.Inc(1) }
163+
func (h *handlerStats) IncSnapshotReadError() { h.snapshotReadError.Inc(1) }
164+
func (h *handlerStats) IncSnapshotReadAttempt() { h.snapshotReadAttempt.Inc(1) }
165+
func (h *handlerStats) IncSnapshotReadSuccess() { h.snapshotReadSuccess.Inc(1) }
166+
func (h *handlerStats) IncSnapshotSegmentValid() { h.snapshotSegmentValid.Inc(1) }
167+
func (h *handlerStats) IncSnapshotSegmentInvalid() { h.snapshotSegmentInvalid.Inc(1) }
168+
169+
// GetOrRegisterHandlerStats returns a [HandlerStats] to track state sync handler metrics.
170+
// If `enabled` is false, a no-op implementation is returned.
171+
// if `enabled` is true, calling this multiple times will return the same registered metrics.
172+
func GetOrRegisterHandlerStats(enabled bool) HandlerStats {
173+
if !enabled {
174+
return NewNoopHandlerStats()
175+
}
176+
return &handlerStats{
177+
// initialize block request stats
178+
blockRequest: metrics.GetOrRegisterCounter("block_request_count", nil),
179+
missingBlockHash: metrics.GetOrRegisterCounter("block_request_missing_block_hash", nil),
180+
blocksReturned: metrics.GetOrRegisterHistogram("block_request_total_blocks", nil, metrics.NewExpDecaySample(1028, 0.015)),
181+
blockRequestProcessingTime: metrics.GetOrRegisterTimer("block_request_processing_time", nil),
182+
183+
// initialize code request stats
184+
codeRequest: metrics.GetOrRegisterCounter("code_request_count", nil),
185+
missingCodeHash: metrics.GetOrRegisterCounter("code_request_missing_code_hash", nil),
186+
tooManyHashesRequested: metrics.GetOrRegisterCounter("code_request_too_many_hashes", nil),
187+
duplicateHashesRequested: metrics.GetOrRegisterCounter("code_request_duplicate_hashes", nil),
188+
codeReadDuration: metrics.GetOrRegisterTimer("code_request_read_time", nil),
189+
codeBytesReturned: metrics.GetOrRegisterHistogram("code_request_bytes_returned", nil, metrics.NewExpDecaySample(1028, 0.015)),
190+
191+
// initialize leafs request stats
192+
leafsRequest: metrics.GetOrRegisterCounter("leafs_request_count", nil),
193+
invalidLeafsRequest: metrics.GetOrRegisterCounter("leafs_request_invalid", nil),
194+
leafsRequestProcessingTime: metrics.GetOrRegisterTimer("leafs_request_processing_time", nil),
195+
leafsReturned: metrics.GetOrRegisterHistogram("leafs_request_total_leafs", nil, metrics.NewExpDecaySample(1028, 0.015)),
196+
leafsReadTime: metrics.GetOrRegisterTimer("leafs_request_read_time", nil),
197+
snapshotReadTime: metrics.GetOrRegisterTimer("leafs_request_snapshot_read_time", nil),
198+
generateRangeProofTime: metrics.GetOrRegisterTimer("leafs_request_generate_range_proof_time", nil),
199+
proofValsReturned: metrics.GetOrRegisterHistogram("leafs_request_proof_vals_returned", nil, metrics.NewExpDecaySample(1028, 0.015)),
200+
missingRoot: metrics.GetOrRegisterCounter("leafs_request_missing_root", nil),
201+
trieError: metrics.GetOrRegisterCounter("leafs_request_trie_error", nil),
202+
proofError: metrics.GetOrRegisterCounter("leafs_request_proof_error", nil),
203+
snapshotReadError: metrics.GetOrRegisterCounter("leafs_request_snapshot_read_error", nil),
204+
snapshotReadAttempt: metrics.GetOrRegisterCounter("leafs_request_snapshot_read_attempt", nil),
205+
snapshotReadSuccess: metrics.GetOrRegisterCounter("leafs_request_snapshot_read_success", nil),
206+
snapshotSegmentValid: metrics.GetOrRegisterCounter("leafs_request_snapshot_segment_valid", nil),
207+
snapshotSegmentInvalid: metrics.GetOrRegisterCounter("leafs_request_snapshot_segment_invalid", nil),
208+
}
209+
}
210+
211+
// no op implementation
212+
type noopHandlerStats struct{}
213+
214+
func NewNoopHandlerStats() HandlerStats {
215+
return &noopHandlerStats{}
216+
}
217+
218+
// all operations are no-ops
219+
func (*noopHandlerStats) IncBlockRequest() {}
220+
func (*noopHandlerStats) IncMissingBlockHash() {}
221+
func (*noopHandlerStats) UpdateBlocksReturned(uint16) {}
222+
func (*noopHandlerStats) UpdateBlockRequestProcessingTime(time.Duration) {}
223+
func (*noopHandlerStats) IncCodeRequest() {}
224+
func (*noopHandlerStats) IncMissingCodeHash() {}
225+
func (*noopHandlerStats) IncTooManyHashesRequested() {}
226+
func (*noopHandlerStats) IncDuplicateHashesRequested() {}
227+
func (*noopHandlerStats) UpdateCodeReadTime(time.Duration) {}
228+
func (*noopHandlerStats) UpdateCodeBytesReturned(uint32) {}
229+
func (*noopHandlerStats) IncLeafsRequest() {}
230+
func (*noopHandlerStats) IncInvalidLeafsRequest() {}
231+
func (*noopHandlerStats) UpdateLeafsRequestProcessingTime(time.Duration) {}
232+
func (*noopHandlerStats) UpdateLeafsReturned(uint16) {}
233+
func (*noopHandlerStats) UpdateReadLeafsTime(_ time.Duration) {}
234+
func (*noopHandlerStats) UpdateSnapshotReadTime(_ time.Duration) {}
235+
func (*noopHandlerStats) UpdateGenerateRangeProofTime(_ time.Duration) {}
236+
func (*noopHandlerStats) UpdateRangeProofValsReturned(_ int64) {}
237+
func (*noopHandlerStats) IncMissingRoot() {}
238+
func (*noopHandlerStats) IncTrieError() {}
239+
func (*noopHandlerStats) IncProofError() {}
240+
func (*noopHandlerStats) IncSnapshotReadError() {}
241+
func (*noopHandlerStats) IncSnapshotReadAttempt() {}
242+
func (*noopHandlerStats) IncSnapshotReadSuccess() {}
243+
func (*noopHandlerStats) IncSnapshotSegmentValid() {}
244+
func (*noopHandlerStats) IncSnapshotSegmentInvalid() {}

vms/evm/sync/stats/syncer_stats.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package stats
5+
6+
import (
7+
"fmt"
8+
"time"
9+
10+
"github.com/ava-labs/libevm/metrics"
11+
12+
"github.com/ava-labs/avalanchego/vms/evm/sync/message"
13+
)
14+
15+
var (
16+
_ ClientSyncerStats = (*clientSyncerStats)(nil)
17+
_ ClientSyncerStats = (*noopStats)(nil)
18+
)
19+
20+
type ClientSyncerStats interface {
21+
GetMetric(message.Request) (MessageMetric, error)
22+
}
23+
24+
type MessageMetric interface {
25+
IncRequested()
26+
IncSucceeded()
27+
IncFailed()
28+
IncInvalidResponse()
29+
IncReceived(int64)
30+
UpdateRequestLatency(time.Duration)
31+
}
32+
33+
type messageMetric struct {
34+
requested metrics.Counter // Number of times a request has been sent
35+
succeeded metrics.Counter // Number of times a request has succeeded
36+
failed metrics.Counter // Number of times a request failed (does not include invalid responses)
37+
invalidResponse metrics.Counter // Number of times a request failed due to an invalid response
38+
received metrics.Counter // Number of items that have been received
39+
40+
requestLatency metrics.Timer // Latency for this request
41+
}
42+
43+
func NewMessageMetric(name string) MessageMetric {
44+
return &messageMetric{
45+
requested: metrics.GetOrRegisterCounter(name+"_requested", nil),
46+
succeeded: metrics.GetOrRegisterCounter(name+"_succeeded", nil),
47+
failed: metrics.GetOrRegisterCounter(name+"_failed", nil),
48+
invalidResponse: metrics.GetOrRegisterCounter(name+"_invalid_response", nil),
49+
received: metrics.GetOrRegisterCounter(name+"_received", nil),
50+
requestLatency: metrics.GetOrRegisterTimer(name+"_request_latency", nil),
51+
}
52+
}
53+
54+
func (m *messageMetric) IncRequested() {
55+
m.requested.Inc(1)
56+
}
57+
58+
func (m *messageMetric) IncSucceeded() {
59+
m.succeeded.Inc(1)
60+
}
61+
62+
func (m *messageMetric) IncFailed() {
63+
m.failed.Inc(1)
64+
}
65+
66+
func (m *messageMetric) IncInvalidResponse() {
67+
m.invalidResponse.Inc(1)
68+
}
69+
70+
func (m *messageMetric) IncReceived(size int64) {
71+
m.received.Inc(size)
72+
}
73+
74+
func (m *messageMetric) UpdateRequestLatency(duration time.Duration) {
75+
m.requestLatency.Update(duration)
76+
}
77+
78+
type clientSyncerStats struct {
79+
leafMetrics map[message.NodeType]MessageMetric
80+
codeRequestMetric,
81+
blockRequestMetric MessageMetric
82+
}
83+
84+
// NewClientSyncerStats returns stats for the client syncer
85+
func NewClientSyncerStats(leafMetricNames map[message.NodeType]string) *clientSyncerStats {
86+
leafMetrics := make(map[message.NodeType]MessageMetric, len(leafMetricNames))
87+
for nodeType, name := range leafMetricNames {
88+
leafMetrics[nodeType] = NewMessageMetric(name)
89+
}
90+
return &clientSyncerStats{
91+
leafMetrics: leafMetrics,
92+
codeRequestMetric: NewMessageMetric("sync_code"),
93+
blockRequestMetric: NewMessageMetric("sync_blocks"),
94+
}
95+
}
96+
97+
// GetMetric returns the appropriate messaage metric for the given request
98+
func (c *clientSyncerStats) GetMetric(msgIntf message.Request) (MessageMetric, error) {
99+
switch msg := msgIntf.(type) {
100+
case message.BlockRequest:
101+
return c.blockRequestMetric, nil
102+
case message.CodeRequest:
103+
return c.codeRequestMetric, nil
104+
case message.LeafsRequest:
105+
metric, ok := c.leafMetrics[msg.NodeType]
106+
if !ok {
107+
return nil, fmt.Errorf("invalid leafs request for node type: %T", msg.NodeType)
108+
}
109+
return metric, nil
110+
default:
111+
return nil, fmt.Errorf("attempted to get metric for invalid request with type %T", msg)
112+
}
113+
}
114+
115+
// no-op implementation of ClientSyncerStats
116+
type noopStats struct {
117+
noop noopMsgMetric
118+
}
119+
120+
type noopMsgMetric struct{}
121+
122+
func (noopMsgMetric) IncRequested() {}
123+
func (noopMsgMetric) IncSucceeded() {}
124+
func (noopMsgMetric) IncFailed() {}
125+
func (noopMsgMetric) IncInvalidResponse() {}
126+
func (noopMsgMetric) IncReceived(int64) {}
127+
func (noopMsgMetric) UpdateRequestLatency(time.Duration) {}
128+
129+
func NewNoOpStats() ClientSyncerStats {
130+
return &noopStats{}
131+
}
132+
133+
func (n noopStats) GetMetric(_ message.Request) (MessageMetric, error) {
134+
return n.noop, nil
135+
}

0 commit comments

Comments
 (0)