Skip to content

Commit 5c2f39a

Browse files
authored
chore(sensor): move oldest and head block to Conns (#761)
* feat(sensor): use LRU with TTL for requests cache * docs: make gen-doc * fix: rename requests cache variables * fix: comment * fix: requests cache opts name * feat(sensor): use cache to track seen blocks * docs: make gen-doc * feat: global blocks cache * fix: rename method * fix: conditional sends? * fix: flags * chore: use conns opts * fix: revert request spelling * fix: remove wrong check * fix: logic issues * feat: store entire blocks * chore: runAsync refactor * feat: optimizations * feat(sensor): track if block headers are fetched as parents * docs: make gen-doc * chore: refactor to use CacheOptions struct * chore(sensor): move oldest and head block to Conns * chore: remove HeadBlock struct in favor of eth.NewBlockPacket * chore: add ToBlock to rpc block type * fix: only log if value was changed * chore: use ReplaceAll instead of Replace * chore: clean up oldest logic * feat: add head and oldest block to the api * feat: add promtheus metrics * docs: metrics generation * docs: update examples * chore: lint * fix: rename methods to be more idiomatic * fix: nil checks
1 parent f200a99 commit 5c2f39a

22 files changed

+682
-218
lines changed

cmd/p2p/crawl/crawl.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package crawl
22

33
import (
4+
_ "embed"
45
"fmt"
56
"time"
67

@@ -32,6 +33,8 @@ type (
3233
)
3334

3435
var (
36+
//go:embed usage.md
37+
crawlUsage string
3538
inputCrawlParams crawlParams
3639
)
3740

@@ -40,7 +43,7 @@ var (
4043
var CrawlCmd = &cobra.Command{
4144
Use: "crawl [nodes file]",
4245
Short: "Crawl a network on the devp2p layer and generate a nodes JSON file.",
43-
Long: "If no nodes.json file exists, it will be created.",
46+
Long: crawlUsage,
4447
Args: cobra.MinimumNArgs(1),
4548
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
4649
inputCrawlParams.NodesFile = args[0]

cmd/p2p/crawl/usage.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
To crawl the network for nodes and write the output json to a file. This will
2+
not engage in block or transaction propagation, but it can give a good indicator
3+
of network size, and the output json can be used to quick start other nodes.
4+
5+
## Example
6+
7+
```bash
8+
polycli p2p crawl nodes.json \
9+
--bootnodes "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303,enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303,enode://4be7248c3a12c5f95d4ef5fff37f7c44ad1072fdb59701b2e5987c5f3846ef448ce7eabc941c5575b13db0fb016552c1fa5cca0dda1a8008cf6d63874c0f3eb7@3.93.224.197:30303,enode://32dd20eaf75513cf84ffc9940972ab17a62e88ea753b0780ea5eca9f40f9254064dacb99508337043d944c2a41b561a17deaad45c53ea0be02663e55e6a302b2@3.212.183.151:30303" \
10+
--network-id 137
11+
```

cmd/p2p/p2p.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,16 @@ package p2p
33
import (
44
"github.com/spf13/cobra"
55

6-
_ "embed"
7-
86
"github.com/0xPolygon/polygon-cli/cmd/p2p/crawl"
97
"github.com/0xPolygon/polygon-cli/cmd/p2p/nodelist"
108
"github.com/0xPolygon/polygon-cli/cmd/p2p/ping"
119
"github.com/0xPolygon/polygon-cli/cmd/p2p/query"
1210
"github.com/0xPolygon/polygon-cli/cmd/p2p/sensor"
1311
)
1412

15-
//go:embed usage.md
16-
var usage string
17-
1813
var P2pCmd = &cobra.Command{
1914
Use: "p2p",
2015
Short: "Set of commands related to devp2p.",
21-
Long: usage,
2216
}
2317

2418
func init() {

cmd/p2p/ping/ping.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ping
22

33
import (
44
"crypto/ecdsa"
5+
_ "embed"
56
"net"
67
"sync"
78
"time"
@@ -30,19 +31,16 @@ type (
3031
)
3132

3233
var (
34+
//go:embed usage.md
35+
pingUsage string
3336
inputPingParams pingParams
3437
)
3538

3639
var PingCmd = &cobra.Command{
3740
Use: "ping [enode/enr or nodes file]",
3841
Short: "Ping node(s) and return the output.",
39-
Long: `Ping nodes by either giving a single enode/enr or an entire nodes file.
40-
41-
This command will establish a handshake and status exchange to get the Hello and
42-
Status messages and output JSON. If providing a enode/enr rather than a nodes
43-
file, then the connection will remain open by default (--listen=true), and you
44-
can see other messages the peer sends (e.g. blocks, transactions, etc.).`,
45-
Args: cobra.MinimumNArgs(1),
42+
Long: pingUsage,
43+
Args: cobra.MinimumNArgs(1),
4644
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
4745
inputPingParams.privateKey, err = p2p.ParsePrivateKey(inputPingParams.KeyFile, inputPingParams.PrivateKey)
4846
if err != nil {

cmd/p2p/ping/usage.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Pinging a peer is useful to determine information about the peer and retrieving
2+
the `Hello` and `Status` messages. By default, it will listen to the peer after
3+
the status exchange for blocks and transactions. To disable this behavior, set
4+
the `--listen` flag.
5+
6+
## Example
7+
8+
```bash
9+
polycli p2p ping <enode/enr or nodes.json file>
10+
```

cmd/p2p/sensor/api.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/0xPolygon/polygon-cli/p2p"
11+
"github.com/ethereum/go-ethereum/core/types"
1112
"github.com/ethereum/go-ethereum/eth/protocols/eth"
1213
ethp2p "github.com/ethereum/go-ethereum/p2p"
1314
"github.com/prometheus/client_golang/prometheus"
@@ -27,12 +28,33 @@ type peerData struct {
2728
DurationSeconds float64 `json:"duration_seconds"`
2829
}
2930

31+
// blockInfo represents basic block information.
32+
type blockInfo struct {
33+
Hash string `json:"hash"`
34+
Number uint64 `json:"number"`
35+
}
36+
37+
// newBlockInfo creates a blockInfo from a types.Header.
38+
// Returns nil if the header is nil.
39+
func newBlockInfo(header *types.Header) *blockInfo {
40+
if header == nil {
41+
return nil
42+
}
43+
44+
return &blockInfo{
45+
Hash: header.Hash().Hex(),
46+
Number: header.Number.Uint64(),
47+
}
48+
}
49+
3050
// apiData represents all sensor information including node info and peer data.
3151
type apiData struct {
3252
ENR string `json:"enr"`
3353
URL string `json:"enode"`
3454
PeerCount int `json:"peer_count"`
3555
Peers map[string]peerData `json:"peers"`
56+
Head *blockInfo `json:"head_block"`
57+
Oldest *blockInfo `json:"oldest_block"`
3658
}
3759

3860
// handleAPI sets up the API for interacting with the sensor. All endpoints
@@ -54,7 +76,7 @@ func handleAPI(server *ethp2p.Server, counter *prometheus.CounterVec, conns *p2p
5476
url := peer.Node().URLv4()
5577
peerID := peer.Node().ID().String()
5678
name := peer.Fullname()
57-
connectedAt := conns.GetPeerConnectedAt(peerID)
79+
connectedAt := conns.PeerConnectedAt(peerID)
5880
if connectedAt.IsZero() {
5981
continue
6082
}
@@ -71,11 +93,21 @@ func handleAPI(server *ethp2p.Server, counter *prometheus.CounterVec, conns *p2p
7193
peers[url] = msgs
7294
}
7395

96+
head := conns.HeadBlock()
97+
oldest := conns.OldestBlock()
98+
99+
var headHeader *types.Header
100+
if head.Block != nil {
101+
headHeader = head.Block.Header()
102+
}
103+
74104
data := apiData{
75105
ENR: server.NodeInfo().ENR,
76106
URL: server.Self().URLv4(),
77107
PeerCount: len(peers),
78108
Peers: peers,
109+
Head: newBlockInfo(headHeader),
110+
Oldest: newBlockInfo(oldest),
79111
}
80112

81113
if err := json.NewEncoder(w).Encode(data); err != nil {

cmd/p2p/sensor/sensor.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package sensor
33
import (
44
"context"
55
"crypto/ecdsa"
6+
_ "embed"
67
"errors"
78
"fmt"
89
"os"
910
"os/signal"
10-
"sync"
1111
"syscall"
1212
"time"
1313

@@ -17,6 +17,7 @@ import (
1717
"github.com/ethereum/go-ethereum/common"
1818
"github.com/ethereum/go-ethereum/core/forkid"
1919
"github.com/ethereum/go-ethereum/crypto"
20+
"github.com/ethereum/go-ethereum/eth/protocols/eth"
2021
ethp2p "github.com/ethereum/go-ethereum/p2p"
2122
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
2223
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -82,6 +83,8 @@ type (
8283
)
8384

8485
var (
86+
//go:embed usage.md
87+
sensorUsage string
8588
inputSensorParams sensorParams
8689
)
8790

@@ -90,7 +93,7 @@ var (
9093
var SensorCmd = &cobra.Command{
9194
Use: "sensor [nodes file]",
9295
Short: "Start a devp2p sensor that discovers other peers and will receive blocks and transactions.",
93-
Long: "If no nodes.json file exists, it will be created.",
96+
Long: sensorUsage,
9497
Args: cobra.MinimumNArgs(1),
9598
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
9699
inputSensorParams.NodesFile = args[0]
@@ -170,14 +173,14 @@ var SensorCmd = &cobra.Command{
170173
// Fetch the latest block which will be used later when crafting the status
171174
// message. This call will only be made once and stored in the head field
172175
// until the sensor receives a new block it can overwrite it with.
173-
block, err := getLatestBlock(inputSensorParams.RPC)
176+
rpcBlock, err := getLatestBlock(inputSensorParams.RPC)
174177
if err != nil {
175178
return err
176179
}
177-
head := p2p.HeadBlock{
178-
Hash: block.Hash.ToHash(),
179-
TotalDifficulty: block.TotalDifficulty.ToBigInt(),
180-
Number: block.Number.ToUint64(),
180+
181+
head := eth.NewBlockPacket{
182+
Block: rpcBlock.ToBlock(),
183+
TD: rpcBlock.TotalDifficulty.ToBigInt(),
181184
}
182185

183186
peersGauge := promauto.NewGauge(prometheus.GaugeOpts{
@@ -192,10 +195,13 @@ var SensorCmd = &cobra.Command{
192195
Help: "The number and type of messages the sensor has sent and received",
193196
}, []string{"message", "url", "name", "direction"})
194197

198+
metrics := p2p.NewBlockMetrics(head.Block)
199+
195200
// Create peer connection manager for broadcasting transactions
196201
// and managing the global blocks cache
197202
conns := p2p.NewConns(p2p.ConnsOptions{
198203
BlocksCache: inputSensorParams.BlocksCache,
204+
Head: head,
199205
})
200206

201207
opts := p2p.EthProtocolOptions{
@@ -206,8 +212,6 @@ var SensorCmd = &cobra.Command{
206212
SensorID: inputSensorParams.SensorID,
207213
NetworkID: inputSensorParams.NetworkID,
208214
Conns: conns,
209-
Head: &head,
210-
HeadMutex: &sync.RWMutex{},
211215
ForkID: forkid.ID{Hash: [4]byte(inputSensorParams.ForkID)},
212216
MsgCounter: msgCounter,
213217
RequestsCache: inputSensorParams.RequestsCache,
@@ -280,6 +284,8 @@ var SensorCmd = &cobra.Command{
280284
peersGauge.Set(float64(server.PeerCount()))
281285
db.WritePeers(cmd.Context(), server.Peers(), time.Now())
282286

287+
metrics.Update(conns.HeadBlock().Block, conns.OldestBlock())
288+
283289
urls := []string{}
284290
for _, peer := range server.Peers() {
285291
urls = append(urls, peer.Node().URLv4())

cmd/p2p/sensor/usage.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Running the sensor will do peer discovery and continue to watch for blocks and
2+
transactions from those peers. This is useful for observing the network for
3+
forks and reorgs without the need to run the entire full node infrastructure.
4+
5+
The sensor can persist data to various backends including Google Cloud Datastore
6+
or JSON output. If no nodes.json file exists at the specified path, it will be
7+
created automatically.
8+
9+
The bootnodes may change, so refer to the [Polygon Knowledge Layer][bootnodes]
10+
if the sensor is not discovering peers.
11+
12+
## Metrics
13+
14+
The sensor exposes Prometheus metrics at `http://localhost:2112/metrics`
15+
(configurable via `--prom-port`). For a complete list of available metrics, see
16+
[polycli_p2p_sensor_metrics.md](polycli_p2p_sensor_metrics.md).
17+
18+
## Examples
19+
20+
### Mainnet
21+
22+
To run a Polygon Mainnet sensor, copy the `genesis.json` from [here][mainnet-genesis].
23+
24+
```bash
25+
polycli p2p sensor nodes.json \
26+
--bootnodes "enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303,enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303" \
27+
--network-id 137 \
28+
--sensor-id "sensor" \
29+
--write-blocks=true \
30+
--write-block-events=true \
31+
--write-txs=true \
32+
--write-tx-events=true \
33+
--genesis-hash "0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b" \
34+
--fork-id "22d523b2" \
35+
--rpc "https://polygon-rpc.com" \
36+
--discovery-dns "enrtree://AKUEZKN7PSKVNR65FZDHECMKOJQSGPARGTPPBI7WS2VUL4EGR6XPC@pos.polygon-peers.io" \
37+
--pprof \
38+
--verbosity 700 \
39+
--pretty-logs=true \
40+
--database "json"
41+
```
42+
43+
### Amoy
44+
45+
To run a Polygon Amoy sensor, copy the `genesis.json` from [here][amoy-genesis].
46+
47+
```bash
48+
polycli p2p sensor amoy-nodes.json \
49+
--bootnodes "enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303,enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303" \
50+
--network-id 80002 \
51+
--sensor-id "sensor-amoy" \
52+
--write-blocks=true \
53+
--write-block-events=true \
54+
--write-txs=true \
55+
--write-tx-events=true \
56+
--genesis-hash "0x7202b2b53c5a0836e773e319d18922cc756dd67432f9a1f65352b61f4406c697" \
57+
--fork-id "8b7e4175" \
58+
--rpc "https://rpc-amoy.polygon.technology" \
59+
--discovery-dns "enrtree://AKUEZKN7PSKVNR65FZDHECMKOJQSGPARGTPPBI7WS2VUL4EGR6XPC@amoy.polygon-peers.io" \
60+
--pprof \
61+
--verbosity 700 \
62+
--pretty-logs=true \
63+
--database "json"
64+
```
65+
66+
[mainnet-genesis]: https://github.com/0xPolygon/bor/blob/master/builder/files/genesis-mainnet-v1.json
67+
[amoy-genesis]: https://github.com/0xPolygon/bor/blob/master/builder/files/genesis-amoy.json
68+
[bootnodes]: https://docs.polygon.technology/pos/reference/seed-and-bootnodes/

cmd/p2p/usage.md

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)