Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app/peerinfo: add nickname field to peerinfo protocol #3428

Merged
merged 12 commits into from
Jan 8, 2025
10 changes: 7 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
TestnetConfig eth2util.Network
ProcDirectory string
ConsensusProtocol string
Nickname string

TestConfig TestConfig
}
Expand Down Expand Up @@ -257,7 +258,10 @@

sender := new(p2p.Sender)

wirePeerInfo(life, tcpNode, peerIDs, cluster.GetInitialMutationHash(), sender, conf.BuilderAPI)
if len(conf.Nickname) > 32 {
return errors.New("nickname can not exceed 32 characters")
}
wirePeerInfo(life, tcpNode, peerIDs, cluster.GetInitialMutationHash(), sender, conf.BuilderAPI, conf.Nickname)

Check warning on line 264 in app/app.go

View check run for this annotation

Codecov / codecov/patch

app/app.go#L261-L264

Added lines #L261 - L264 were not covered by tests

// seenPubkeys channel to send seen public keys from validatorapi to monitoringapi.
seenPubkeys := make(chan core.PubKey)
Expand Down Expand Up @@ -297,9 +301,9 @@
}

// wirePeerInfo wires the peerinfo protocol.
func wirePeerInfo(life *lifecycle.Manager, tcpNode host.Host, peers []peer.ID, lockHash []byte, sender *p2p.Sender, builderEnabled bool) {
func wirePeerInfo(life *lifecycle.Manager, tcpNode host.Host, peers []peer.ID, lockHash []byte, sender *p2p.Sender, builderEnabled bool, nickname string) {

Check warning on line 304 in app/app.go

View check run for this annotation

Codecov / codecov/patch

app/app.go#L304

Added line #L304 was not covered by tests
gitHash, _ := version.GitCommit()
peerInfo := peerinfo.New(tcpNode, peers, version.Version, lockHash, gitHash, sender.SendReceive, builderEnabled)
peerInfo := peerinfo.New(tcpNode, peers, version.Version, lockHash, gitHash, sender.SendReceive, builderEnabled, nickname)

Check warning on line 306 in app/app.go

View check run for this annotation

Codecov / codecov/patch

app/app.go#L306

Added line #L306 was not covered by tests
life.RegisterStart(lifecycle.AsyncAppCtx, lifecycle.StartPeerInfo, lifecycle.HookFuncCtx(peerInfo.Run))
}

Expand Down
5 changes: 4 additions & 1 deletion app/peerinfo/adhoc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ func TestDoOnce(t *testing.T) {
vers := version.Version
lockHash := []byte("123")
gitHash := "abc"
nickname := "johndoe"

// Register the server handler that either
_ = peerinfo.New(server, []peer.ID{server.ID(), client.ID()}, vers, lockHash, gitHash, p2p.SendReceive, true)
_ = peerinfo.New(server, []peer.ID{server.ID(), client.ID()}, vers, lockHash, gitHash, p2p.SendReceive, true, nickname)

info, _, ok, err := peerinfo.DoOnce(context.Background(), client, server.ID())
require.NoError(t, err)
Expand All @@ -35,4 +37,5 @@ func TestDoOnce(t *testing.T) {
require.Equal(t, gitHash, info.GetGitHash())
require.Equal(t, lockHash, info.GetLockHash())
require.True(t, info.GetBuilderApiEnabled())
require.Equal(t, nickname, info.GetNickname())
}
8 changes: 8 additions & 0 deletions app/peerinfo/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,12 @@ var (
Name: "builder_api_enabled",
Help: "Set to 1 if builder API is enabled on this peer, else 0 if disabled.",
}, []string{"peer"})

peerNickname = promauto.NewResetGaugeVec(prometheus.GaugeOpts{
Namespace: "app",
Subsystem: "peerinfo",
Name: "nickname",
Help: "Constant gauge with nickname label set to peer's charon nickname.",
ConstLabels: nil,
}, []string{"peer", "nickname"})
)
32 changes: 23 additions & 9 deletions app/peerinfo/peerinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,18 @@
type (
tickerProvider func() (<-chan time.Time, func())
nowFunc func() time.Time
metricSubmitter func(peerID peer.ID, clockOffset time.Duration, version, gitHash string, startTime time.Time, builderAPIEnabled bool)
metricSubmitter func(peerID peer.ID, clockOffset time.Duration, version, gitHash string, startTime time.Time, builderAPIEnabled bool, nickname string)
)

// New returns a new peer info protocol instance.
func New(tcpNode host.Host, peers []peer.ID, version version.SemVer, lockHash []byte, gitHash string,
sendFunc p2p.SendReceiveFunc, builderEnabled bool,
sendFunc p2p.SendReceiveFunc, builderEnabled bool, nickname string,
) *PeerInfo {
// Set own version and git hash and start time metrics.
// Set own version, git hash and nickname and start time and metrics.
name := p2p.PeerName(tcpNode.ID())
peerVersion.WithLabelValues(name, version.String()).Set(1)
peerGitHash.WithLabelValues(name, gitHash).Set(1)
peerNickname.WithLabelValues(name, nickname).Set(1)
peerStartGauge.WithLabelValues(name).Set(float64(time.Now().Unix()))

if builderEnabled {
Expand All @@ -68,24 +69,24 @@
}

return newInternal(tcpNode, peers, version, lockHash, gitHash, sendFunc, p2p.RegisterHandler,
tickerProvider, time.Now, newMetricsSubmitter(), builderEnabled)
tickerProvider, time.Now, newMetricsSubmitter(), builderEnabled, nickname)
}

// NewForT returns a new peer info protocol instance for testing only.
func NewForT(_ *testing.T, tcpNode host.Host, peers []peer.ID, version version.SemVer, lockHash []byte, gitHash string,
sendFunc p2p.SendReceiveFunc, registerHandler p2p.RegisterHandlerFunc,
tickerProvider tickerProvider, nowFunc nowFunc, metricSubmitter metricSubmitter,
builderAPIEnabled bool,
builderAPIEnabled bool, nickname string,
) *PeerInfo {
return newInternal(tcpNode, peers, version, lockHash, gitHash, sendFunc, registerHandler,
tickerProvider, nowFunc, metricSubmitter, builderAPIEnabled)
tickerProvider, nowFunc, metricSubmitter, builderAPIEnabled, nickname)
}

// newInternal returns a new instance for New or NewForT.
func newInternal(tcpNode host.Host, peers []peer.ID, version version.SemVer, lockHash []byte, gitHash string,
sendFunc p2p.SendReceiveFunc, registerHandler p2p.RegisterHandlerFunc,
tickerProvider tickerProvider, nowFunc nowFunc, metricSubmitter metricSubmitter,
builderAPIEnabled bool,
builderAPIEnabled bool, nickname string,
) *PeerInfo {
startTime := timestamppb.New(nowFunc())

Expand All @@ -100,10 +101,14 @@
SentAt: timestamppb.New(nowFunc()),
StartedAt: startTime,
BuilderApiEnabled: builderAPIEnabled,
Nickname: nickname,
}, true, nil
},
)

// Maps peers to their nickname
nicknames := map[string]string{p2p.PeerName(tcpNode.ID()): nickname}

// Create log filters
lockHashFilters := make(map[peer.ID]z.Field)
versionFilters := make(map[peer.ID]z.Field)
Expand All @@ -125,6 +130,7 @@
nowFunc: nowFunc,
lockHashFilters: lockHashFilters,
versionFilters: versionFilters,
nicknames: nicknames,
}
}

Expand All @@ -142,6 +148,7 @@
nowFunc func() time.Time
lockHashFilters map[peer.ID]z.Field
versionFilters map[peer.ID]z.Field
nicknames map[string]string
}

// Run runs the peer info protocol until the context is cancelled.
Expand Down Expand Up @@ -175,6 +182,7 @@
SentAt: timestamppb.New(now),
StartedAt: p.startTime,
BuilderApiEnabled: p.builderAPIEnabled,
Nickname: p.nicknames[p2p.PeerName(p.tcpNode.ID())],
}

go func(peerID peer.ID) {
Expand All @@ -194,6 +202,9 @@

name := p2p.PeerName(peerID)

p.nicknames[name] = resp.Nickname
log.Info(ctx, "Peer name to nickname mappings", z.Any("nicknames", p.nicknames))

// Validator git hash with regex.
if !gitHashMatch.MatchString(resp.GetGitHash()) {
log.Warn(ctx, "Invalid peer git hash", nil, z.Str("peer", name))
Expand Down Expand Up @@ -221,7 +232,7 @@
// Set peer compatibility to true.
peerCompatibleGauge.WithLabelValues(name).Set(1)

p.metricSubmitter(peerID, clockOffset, resp.GetCharonVersion(), resp.GetGitHash(), resp.GetStartedAt().AsTime(), resp.GetBuilderApiEnabled())
p.metricSubmitter(peerID, clockOffset, resp.GetCharonVersion(), resp.GetGitHash(), resp.GetStartedAt().AsTime(), resp.GetBuilderApiEnabled(), resp.GetNickname())

// Log unexpected lock hash
if !bytes.Equal(resp.GetLockHash(), p.lockHash) {
Expand Down Expand Up @@ -269,10 +280,13 @@
// newMetricsSubmitter returns a prometheus metric submitter.
func newMetricsSubmitter() metricSubmitter {
return func(peerID peer.ID, clockOffset time.Duration, version string, gitHash string,
startTime time.Time, builderAPIEnabled bool,
startTime time.Time, builderAPIEnabled bool, nickname string,
) {
peerName := p2p.PeerName(peerID)

peerNickname.Reset(peerName)
peerNickname.WithLabelValues(peerName, nickname).Set(1)

Check warning on line 289 in app/peerinfo/peerinfo.go

View check run for this annotation

Codecov / codecov/patch

app/peerinfo/peerinfo.go#L287-L289

Added lines #L287 - L289 were not covered by tests
// Limit range of possible values
if clockOffset < -time.Hour {
clockOffset = -time.Hour
Expand Down
3 changes: 2 additions & 1 deletion app/peerinfo/peerinfo_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func TestPeerBuilderAPIEnabledGauge(t *testing.T) {
lockHash := []byte("123")
gitHash := "abc"
peerName := p2p.PeerName(server.ID())
peerNickname := "johndoe"

tests := []struct {
name string
Expand All @@ -84,7 +85,7 @@ func TestPeerBuilderAPIEnabledGauge(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_ = New(server, []peer.ID{server.ID(), client.ID()}, version.Version, lockHash, gitHash, nil, test.builderEnabled)
_ = New(server, []peer.ID{server.ID(), client.ID()}, version.Version, lockHash, gitHash, nil, test.builderEnabled, peerNickname)

expectedMetric := fmt.Sprintf(`
# HELP app_peerinfo_builder_api_enabled Set to 1 if builder API is enabled on this peer, else 0 if disabled.
Expand Down
10 changes: 6 additions & 4 deletions app/peerinfo/peerinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
func TestPeerInfo(t *testing.T) {
now := time.Now()
const gitCommit = "1234567"
baseNickname := "john-"

// when a major release happens, charon will only be compatible with a single version
versions := version.Supported()
Expand Down Expand Up @@ -49,7 +50,7 @@ func TestPeerInfo(t *testing.T) {
Offset: time.Minute,
},
{
Version: semver(t, "v0.0"),
Version: semver(t, "v1.0"),
Ignore: true,
},
}
Expand Down Expand Up @@ -92,7 +93,7 @@ func TestPeerInfo(t *testing.T) {
tickProvider := func() (<-chan time.Time, func()) {
return nil, func() {}
}
metricSubmitter := func(peer.ID, time.Duration, string, string, time.Time, bool) {
metricSubmitter := func(peer.ID, time.Duration, string, string, time.Time, bool, string) {
panic("unexpected metric submitted")
}

Expand All @@ -107,7 +108,7 @@ func TestPeerInfo(t *testing.T) {

var submittedMutex sync.Mutex
var submitted int
metricSubmitter = func(peerID peer.ID, clockOffset time.Duration, version, gitHash string, startTime time.Time, builderEnabled bool) {
metricSubmitter = func(peerID peer.ID, clockOffset time.Duration, version, gitHash string, startTime time.Time, builderEnabled bool, nickname string) {
for i, tcpNode := range tcpNodes {
if tcpNode.ID() != peerID {
continue
Expand All @@ -117,6 +118,7 @@ func TestPeerInfo(t *testing.T) {
require.Equal(t, gitCommit, gitHash)
require.Equal(t, nowFunc(i)().Unix(), startTime.Unix())
require.True(t, builderEnabled)
require.Equal(t, baseNickname+p2p.PeerName(peerID), nickname)

submittedMutex.Lock()
submitted++
Expand All @@ -132,7 +134,7 @@ func TestPeerInfo(t *testing.T) {
}

peerInfo := peerinfo.NewForT(t, tcpNodes[i], peers, node.Version, node.LockHash, gitCommit, p2p.SendReceive, p2p.RegisterHandler,
tickProvider, nowFunc(i), metricSubmitter, true)
tickProvider, nowFunc(i), metricSubmitter, true, baseNickname+p2p.PeerName(peers[i]))

peerInfos = append(peerInfos, peerInfo)
}
Expand Down
26 changes: 18 additions & 8 deletions app/peerinfo/peerinfopb/v1/peerinfo.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/peerinfo/peerinfopb/v1/peerinfo.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ message PeerInfo {
string git_hash = 4;
optional google.protobuf.Timestamp started_at = 5;
bool builder_api_enabled = 6;
string nickname = 7;

// NOTE: Always populate timestamps when sending, then make them required after subsequent release.
}
4 changes: 4 additions & 0 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,15 @@
cmd.Flags().StringVar(&config.TestnetConfig.CapellaHardFork, "testnet-capella-hard-fork", "", "Capella hard fork version of the custom test network.")
cmd.Flags().StringVar(&config.ProcDirectory, "proc-directory", "", "Directory to look into in order to detect other stack components running on the host.")
cmd.Flags().StringVar(&config.ConsensusProtocol, "consensus-protocol", "", "Preferred consensus protocol name for the node. Selected automatically when not specified.")
cmd.Flags().StringVar(&config.Nickname, "nickname", "", "Human friendly peer nickname. Maximum 32 characters.")

wrapPreRunE(cmd, func(*cobra.Command, []string) error {
if len(config.BeaconNodeAddrs) == 0 && !config.SimnetBMock {
return errors.New("either flag 'beacon-node-endpoints' or flag 'simnet-beacon-mock=true' must be specified")
}
if len(config.Nickname) > 32 {
return errors.New("flag 'nickname' can not exceed 32 characters")
}

Check warning on line 104 in cmd/run.go

View check run for this annotation

Codecov / codecov/patch

cmd/run.go#L103-L104

Added lines #L103 - L104 were not covered by tests

return nil
})
Expand Down
3 changes: 2 additions & 1 deletion dkg/dkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,8 @@ func setupP2P(ctx context.Context, key *k1.PrivateKey, conf Config, peers []p2p.

// Register peerinfo server handler for identification to relays (but do not run peerinfo client).
gitHash, _ := version.GitCommit()
_ = peerinfo.New(tcpNode, peerIDs, version.Version, defHash, gitHash, nil, false)

_ = peerinfo.New(tcpNode, peerIDs, version.Version, defHash, gitHash, nil, false, "")

return tcpNode, func() {
_ = tcpNode.Close()
Expand Down
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ Flags:
--loki-service string Service label sent with logs to Loki. (default "charon")
--manifest-file string The path to the cluster manifest file. If both cluster manifest and cluster lock files are provided, the cluster manifest file takes precedence. (default ".charon/cluster-manifest.pb")
--monitoring-address string Listening address (ip and port) for the monitoring API (prometheus). (default "127.0.0.1:3620")
--nickname string Human friendly peer nickname. Maximum 32 characters.
--no-verify Disables cluster definition and lock file verification.
--p2p-disable-reuseport Disables TCP port reuse for outgoing libp2p connections.
--p2p-external-hostname string The DNS hostname advertised by libp2p. This may be used to advertise an external DNS.
Expand Down
1 change: 1 addition & 0 deletions docs/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ when storing metrics from multiple nodes or clusters in one Prometheus instance.
| `app_peerinfo_clock_offset_seconds` | Gauge | Peer clock offset in seconds | `peer` |
| `app_peerinfo_git_commit` | Gauge | Constant gauge with git_hash label set to peer`s git commit hash. | `peer, git_hash` |
| `app_peerinfo_index` | Gauge | Constant gauge set to the peer index in the cluster definition | `peer` |
| `app_peerinfo_nickname` | Gauge | Constant gauge with nickname label set to peer`s charon nickname. | `peer, nickname` |
| `app_peerinfo_start_time_secs` | Gauge | Constant gauge set to the peer start time of the binary in unix seconds | `peer` |
| `app_peerinfo_version` | Gauge | Constant gauge with version label set to peer`s charon version. | `peer, version` |
| `app_peerinfo_version_support` | Gauge | Set to 1 if the peer`s version is supported by (compatible with) the current version, else 0 if unsupported. | `peer` |
Expand Down
Loading