Skip to content

Commit 617eee0

Browse files
authored
feat(sensor): transaction broadcast metrics (#890)
* refactor: remove global metrics, pass as dependencies * chore: refactor metric initialization * chore: make gen * chore: go fmt * feat: more flags and refactor metrics * fix: comment * fix: protocol.go comment
1 parent 936ec0c commit 617eee0

10 files changed

Lines changed: 210 additions & 164 deletions

File tree

cmd/p2p/sensor/rpc.go

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"github.com/ethereum/go-ethereum/eth/protocols/eth"
1616
"github.com/ethereum/go-ethereum/rlp"
1717
"github.com/prometheus/client_golang/prometheus"
18-
"github.com/prometheus/client_golang/prometheus/promauto"
1918
"github.com/rs/zerolog/log"
2019
)
2120

@@ -50,11 +49,11 @@ type rpcProxy struct {
5049

5150
// rpcParams holds shared parameters for processing JSON-RPC requests.
5251
type rpcParams struct {
53-
conns *p2p.Conns
54-
chainID *big.Int
55-
gpo *p2p.GasPriceOracle
56-
proxy *rpcProxy
57-
counter *prometheus.CounterVec
52+
conns *p2p.Conns
53+
chainID *big.Int
54+
gpo *p2p.GasPriceOracle
55+
proxy *rpcProxy
56+
requests *prometheus.CounterVec
5857
}
5958

6059
// handleRPC sets up the JSON-RPC server for receiving and broadcasting transactions.
@@ -67,21 +66,11 @@ func handleRPC(conns *p2p.Conns, networkID uint64) {
6766
chainID := new(big.Int).SetUint64(networkID)
6867
gpo := p2p.NewGasPriceOracle(conns)
6968

70-
counter := promauto.NewCounterVec(
71-
prometheus.CounterOpts{
72-
Namespace: "sensor",
73-
Subsystem: "rpc",
74-
Name: "calls",
75-
Help: "The number of RPC calls made",
76-
},
77-
[]string{"method", "proxied"},
78-
)
79-
8069
params := &rpcParams{
81-
conns: conns,
82-
chainID: chainID,
83-
gpo: gpo,
84-
counter: counter,
70+
conns: conns,
71+
chainID: chainID,
72+
gpo: gpo,
73+
requests: p2p.NewRPCRequestsCounter(),
8574
}
8675

8776
if inputSensorParams.ProxyRPC {
@@ -132,12 +121,12 @@ func handleRPC(conns *p2p.Conns, networkID uint64) {
132121

133122
// If method not found and proxy is enabled, forward to upstream
134123
if isMethodNotFound(resp) && params.proxy != nil {
135-
params.counter.WithLabelValues(req.Method, "true").Inc()
124+
params.requests.WithLabelValues(req.Method, "true").Inc()
136125
proxyRPCRequest(w, r, body, params.proxy)
137126
return
138127
}
139128

140-
params.counter.WithLabelValues(req.Method, "false").Inc()
129+
params.requests.WithLabelValues(req.Method, "false").Inc()
141130

142131
// Enqueue transactions for async broadcast
143132
if len(txs) > 0 {
@@ -281,9 +270,9 @@ func handleBatchRequest(w http.ResponseWriter, r *http.Request, body []byte, par
281270
if params.proxy != nil {
282271
indices = append(indices, i)
283272
}
284-
params.counter.WithLabelValues(req.Method, "true").Inc()
273+
params.requests.WithLabelValues(req.Method, "true").Inc()
285274
} else {
286-
params.counter.WithLabelValues(req.Method, "false").Inc()
275+
params.requests.WithLabelValues(req.Method, "false").Inc()
287276
}
288277
}
289278

cmd/p2p/sensor/sensor.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import (
2222
"github.com/ethereum/go-ethereum/p2p/enode"
2323
"github.com/ethereum/go-ethereum/p2p/nat"
2424
"github.com/ethereum/go-ethereum/rpc"
25-
"github.com/prometheus/client_golang/prometheus"
26-
"github.com/prometheus/client_golang/prometheus/promauto"
2725
"github.com/prometheus/client_golang/prometheus/promhttp"
2826
"github.com/rs/zerolog/log"
2927
"github.com/spf13/cobra"
@@ -60,6 +58,8 @@ type (
6058
BroadcastWorkers int
6159
TxBatchTimeout time.Duration
6260
TxBroadcastQueueSize int
61+
MaxTxPacketSize int
62+
MaxQueuedTxs int
6363
ShouldRunPprof bool
6464
PprofPort uint
6565
ShouldRunPrometheus bool
@@ -200,12 +200,7 @@ var SensorCmd = &cobra.Command{
200200
TD: rpcBlock.TotalDifficulty.ToBigInt(),
201201
}
202202

203-
peersGauge := promauto.NewGauge(prometheus.GaugeOpts{
204-
Namespace: "sensor",
205-
Name: "peers",
206-
Help: "The number of peers the sensor is connected to",
207-
})
208-
203+
peersGauge := p2p.NewPeersGauge()
209204
metrics := p2p.NewBlockMetrics(head.Block)
210205

211206
// Create peer connection manager for broadcasting transactions
@@ -223,6 +218,8 @@ var SensorCmd = &cobra.Command{
223218
BroadcastWorkers: inputSensorParams.BroadcastWorkers,
224219
TxBatchTimeout: inputSensorParams.TxBatchTimeout,
225220
TxBroadcastQueueSize: inputSensorParams.TxBroadcastQueueSize,
221+
MaxTxPacketSize: inputSensorParams.MaxTxPacketSize,
222+
MaxQueuedTxs: inputSensorParams.MaxQueuedTxs,
226223
})
227224

228225
opts := p2p.EthProtocolOptions{
@@ -499,7 +496,9 @@ will result in less chance of missing data but can significantly increase memory
499496
f.BoolVar(&inputSensorParams.ShouldBroadcastBlockHashes, "broadcast-block-hashes", false, "broadcast block hashes to peers")
500497
f.IntVar(&inputSensorParams.BroadcastWorkers, "broadcast-workers", 4, "number of concurrent broadcast workers")
501498
f.DurationVar(&inputSensorParams.TxBatchTimeout, "tx-batch-timeout", 500*time.Millisecond, "timeout for batching transactions before broadcast")
502-
f.IntVar(&inputSensorParams.TxBroadcastQueueSize, "tx-broadcast-queue-size", 100000, "capacity of transaction broadcast queue")
499+
f.IntVar(&inputSensorParams.TxBroadcastQueueSize, "tx-broadcast-queue-size", 100_000, "capacity of transaction broadcast queue")
500+
f.IntVar(&inputSensorParams.MaxTxPacketSize, "max-tx-packet-size", 100*1024, "target size in bytes for transaction broadcast packets")
501+
f.IntVar(&inputSensorParams.MaxQueuedTxs, "max-queued-txs", 4096, "maximum transaction announcements to queue per peer")
503502
f.BoolVar(&inputSensorParams.ShouldRunPprof, "pprof", false, "run pprof server")
504503
f.UintVar(&inputSensorParams.PprofPort, "pprof-port", 6060, "port pprof runs on")
505504
f.BoolVar(&inputSensorParams.ShouldRunPrometheus, "prom", true, "run Prometheus server")

cmd/pos/exitproof/cmd.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,6 @@ func run(ctx context.Context) error {
250250
return nil
251251
}
252252

253-
254253
// getBlockReceipts calls eth_getBlockReceipts for the given block number.
255254
func getBlockReceipts(ctx context.Context, rpc *ethrpc.Client, blockNum *big.Int) ([]*types.Receipt, error) {
256255
var receipts []*types.Receipt
@@ -614,10 +613,10 @@ func fetchBlockHashesBatched(ctx context.Context, rpc *ethrpc.Client, start, end
614613
hashes := make([]common.Hash, count)
615614

616615
type blockHeader struct {
617-
Number hexutil.Big `json:"number"`
618-
Timestamp hexutil.Big `json:"timestamp"`
619-
TransactionsRoot common.Hash `json:"transactionsRoot"`
620-
ReceiptsRoot common.Hash `json:"receiptsRoot"`
616+
Number hexutil.Big `json:"number"`
617+
Timestamp hexutil.Big `json:"timestamp"`
618+
TransactionsRoot common.Hash `json:"transactionsRoot"`
619+
ReceiptsRoot common.Hash `json:"receiptsRoot"`
621620
}
622621

623622
for batchStart := uint64(0); batchStart < count; batchStart += headerFetchBatchSize {
@@ -702,7 +701,7 @@ func merkleProof(leaves []common.Hash, leafIdx uint64) []byte {
702701
// The Polygon contracts (ExitPayloadReader.toExitPayload) RLP-decode the payload, so it must
703702
// be an RLP list — not ABI-encoded. The format matches the matic-js buildReferenceTxPayload:
704703
// [headerNumber, blockProof, blockNumber, blockTimestamp, txRoot, receiptRoot, receipt,
705-
// receiptParentNodes, branchMask, logIndex]
704+
// receiptParentNodes, branchMask, logIndex]
706705
func encodeExitPayload(
707706
headerNumber *big.Int,
708707
blockProof []byte,

cmd/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ import (
2828
"github.com/0xPolygon/polygon-cli/cmd/nodekey"
2929
"github.com/0xPolygon/polygon-cli/cmd/p2p"
3030
"github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data"
31-
"github.com/0xPolygon/polygon-cli/cmd/pos"
3231
"github.com/0xPolygon/polygon-cli/cmd/parseethwallet"
3332
"github.com/0xPolygon/polygon-cli/cmd/plot"
33+
"github.com/0xPolygon/polygon-cli/cmd/pos"
3434
"github.com/0xPolygon/polygon-cli/cmd/publish"
3535
"github.com/0xPolygon/polygon-cli/cmd/report"
3636
"github.com/0xPolygon/polygon-cli/cmd/retest"

doc/polycli_p2p_sensor.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ polycli p2p sensor amoy-nodes.json \
149149
--max-known-blocks int maximum block hashes to track per peer (0 for no limit) (default 1024)
150150
--max-parents int maximum parent block hashes to track per peer (0 for no limit) (default 1024)
151151
-m, --max-peers int maximum number of peers to connect to (default 2000)
152+
--max-queued-txs int maximum transaction announcements to queue per peer (default 4096)
152153
--max-requests int maximum request IDs to track per peer (0 for no limit) (default 2048)
154+
--max-tx-packet-size int target size in bytes for transaction broadcast packets (default 102400)
153155
--max-txs int maximum transactions to cache for serving to peers (0 for no limit) (default 32768)
154156
--nat string NAT port mapping mechanism (any|none|upnp|pmp|pmp:<IP>|extip:<IP>) (default "any")
155157
-n, --network-id uint filter discovered nodes by this network ID

doc/polycli_p2p_sensor_metrics.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@ Difference between head and oldest block numbers
88
Metric Type: Gauge
99

1010

11+
### sensor_broadcast_batch_size
12+
Number of transactions per broadcast batch
13+
14+
Metric Type: Histogram
15+
16+
17+
### sensor_broadcast_queue_depth
18+
Number of transaction batches in broadcast queue
19+
20+
Metric Type: Gauge
21+
22+
23+
### sensor_broadcast_send_errors
24+
Number of failed broadcast sends
25+
26+
Metric Type: Counter
27+
28+
1129
### sensor_head_block_age
1230
Time since head block was received (in seconds)
1331

@@ -27,7 +45,7 @@ Metric Type: Gauge
2745

2846

2947
### sensor_messages
30-
The number and type of messages the sensor has sent and received
48+
Number and type of messages the sensor has sent and received
3149

3250
Metric Type: CounterVec
3351

@@ -43,7 +61,17 @@ Metric Type: Gauge
4361

4462

4563
### sensor_peers
46-
The number of peers the sensor is connected to
64+
Number of peers the sensor is connected to
4765

4866
Metric Type: Gauge
4967

68+
69+
### sensor_rpc_requests
70+
Number of RPC requests made
71+
72+
Metric Type: CounterVec
73+
74+
Variable Labels:
75+
- method
76+
- proxied
77+

docutil/metrics.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,33 @@ import (
1515
type metricInfo struct {
1616
Name string
1717
Namespace string
18+
Subsystem string
1819
Help string
1920
Type string // Gauge, Counter, Histogram, Summary, GaugeVec, CounterVec, etc.
2021
Labels []string
2122
File string
2223
}
2324

24-
// fullName returns the complete metric name with namespace.
25+
// fullName returns the complete metric name with namespace and subsystem.
2526
func (m metricInfo) fullName() string {
27+
parts := []string{}
2628
if m.Namespace != "" {
27-
return m.Namespace + "_" + m.Name
29+
parts = append(parts, m.Namespace)
2830
}
29-
return m.Name
31+
if m.Subsystem != "" {
32+
parts = append(parts, m.Subsystem)
33+
}
34+
parts = append(parts, m.Name)
35+
return strings.Join(parts, "_")
3036
}
3137

3238
// genMetricsDoc generates a METRICS.md file documenting all Prometheus metrics.
3339
func genMetricsDoc(outputPath string) error {
34-
metrics := []metricInfo{}
35-
36-
// Parse p2p package metrics
37-
p2pMetrics, err := parseMetricsFile("p2p/metrics.go")
40+
// All sensor metrics are defined in p2p/metrics.go
41+
metrics, err := parseMetricsFile("p2p/metrics.go")
3842
if err != nil {
3943
return fmt.Errorf("failed to parse p2p/metrics.go: %w", err)
4044
}
41-
metrics = append(metrics, p2pMetrics...)
42-
43-
// Parse sensor command metrics
44-
sensorMetrics, err := parseMetricsFile("cmd/p2p/sensor/sensor.go")
45-
if err != nil {
46-
return fmt.Errorf("failed to parse cmd/p2p/sensor/sensor.go: %w", err)
47-
}
48-
metrics = append(metrics, sensorMetrics...)
4945

5046
// Sort metrics by full name
5147
sort.Slice(metrics, func(i, j int) bool {
@@ -114,6 +110,10 @@ func parseMetricsFile(filePath string) ([]metricInfo, error) {
114110
if lit, ok := kv.Value.(*ast.BasicLit); ok {
115111
metric.Namespace = strings.Trim(lit.Value, `"`)
116112
}
113+
case "Subsystem":
114+
if lit, ok := kv.Value.(*ast.BasicLit); ok {
115+
metric.Subsystem = strings.Trim(lit.Value, `"`)
116+
}
117117
case "Help":
118118
if lit, ok := kv.Value.(*ast.BasicLit); ok {
119119
metric.Help = strings.Trim(lit.Value, `"`)

0 commit comments

Comments
 (0)