diff --git a/testutil/promrated/metrics.go b/testutil/promrated/metrics.go index cdd901de8..414a076f4 100644 --- a/testutil/promrated/metrics.go +++ b/testutil/promrated/metrics.go @@ -8,45 +8,13 @@ import ( "github.com/obolnetwork/charon/app/promauto" ) -var ( - validatorLabels = []string{"pubkey_full", "cluster_name", "cluster_hash", "cluster_network"} - networkLabels = []string{"cluster_network"} - - uptime = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: "promrated", - Name: "validator_uptime", - Help: "Uptime of a validation key.", - }, validatorLabels) - - correctness = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: "promrated", - Name: "validator_correctness", - Help: "Average correctness of a validation key.", - }, validatorLabels) - - inclusionDelay = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: "promrated", - Name: "validator_inclusion_delay", - Help: "Average inclusion delay of a validation key.", - }, validatorLabels) - - attester = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: "promrated", - Name: "validator_attester_effectiveness", - Help: "Attester effectiveness of a validation key.", - }, validatorLabels) - - proposer = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: "promrated", - Name: "validator_proposer_effectiveness", - Help: "Proposer effectiveness of a validation key.", - }, validatorLabels) +const ( + clusterNetworkLabel = "cluster_network" + nodeOperatorLabel = "node_operator" +) - effectiveness = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Namespace: "promrated", - Name: "validator_effectiveness", - Help: "Effectiveness of a validation key.", - }, validatorLabels) +var ( + networkLabels = []string{clusterNetworkLabel, nodeOperatorLabel} networkUptime = promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: "promrated", @@ -72,6 +40,18 @@ var ( Help: "Effectiveness of the network.", }, networkLabels) + networkProposerEffectiveness = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "promrated", + Name: "network_proposer_effectiveness", + Help: "Proposer Effectiveness of the network.", + }, networkLabels) + + networkAttesterEffectiveness = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "promrated", + Name: "network_attester_effectiveness", + Help: "Attester Effectiveness of the network.", + }, networkLabels) + ratedErrors = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: "promrated", Name: "api_error_total", diff --git a/testutil/promrated/prometheus.go b/testutil/promrated/prometheus.go index f8c88bc4c..f0f781905 100644 --- a/testutil/promrated/prometheus.go +++ b/testutil/promrated/prometheus.go @@ -3,32 +3,15 @@ package promrated import ( - "context" - "encoding/json" - "fmt" - "io" "net/http" - "net/url" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/obolnetwork/charon/app/errors" - "github.com/obolnetwork/charon/app/z" ) -const ( - promQuery = "group by (cluster_name, cluster_hash, cluster_network, pubkey_full) (core_scheduler_validator_balance_gwei)" -) - -type validator struct { - PubKey string `json:"pubkey_full"` - ClusterName string `json:"cluster_name"` - ClusterHash string `json:"cluster_hash"` - ClusterNetwork string `json:"cluster_network"` -} - // serveMonitoring creates a liveness endpoint and serves metrics to prometheus. func serveMonitoring(addr string, registry *prometheus.Registry) error { mux := http.NewServeMux() @@ -50,69 +33,6 @@ func serveMonitoring(addr string, registry *prometheus.Registry) error { return errors.Wrap(server.ListenAndServe(), "failed to serve prometheus metrics") } -// getValidators queries prometheus and returns a list of validators with associated cluster and pubkey. -func getValidators(ctx context.Context, promEndpoint string, promAuth string) ([]validator, error) { - client := new(http.Client) - - url, err := url.ParseRequestURI(promEndpoint) - if err != nil { - return nil, errors.Wrap(err, "parse prometheus endpoint") - } - - query := url.Query() - query.Add("query", promQuery) - url.RawQuery = query.Encode() - - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil) - if err != nil { - return nil, errors.Wrap(err, "new prometheus request") - } - - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", promAuth)) - - res, err := client.Do(req) - if err != nil { - return nil, errors.Wrap(err, "requesting prom metrics") - } - defer res.Body.Close() - - body, err := io.ReadAll(res.Body) - if err != nil { - return nil, errors.Wrap(err, "reading body") - } - - if res.StatusCode/100 != 2 { - return nil, errors.New("not ok http response", z.Str("body", string(body))) - } - - return parseValidators(body) -} - -// parseValidators reads prometheus response and returns a list of validators. -func parseValidators(body []byte) ([]validator, error) { - var result struct { - Data struct { - Result []struct { - Labels validator `json:"metric"` - } `json:"result"` - } `json:"data"` - } - - if err := json.Unmarshal(body, &result); err != nil { - return nil, errors.Wrap(err, "deserializing json") - } - - var validators []validator - for _, datum := range result.Data.Result { - if datum.Labels.ClusterName == "" || datum.Labels.ClusterNetwork == "" || datum.Labels.PubKey == "" { - continue - } - validators = append(validators, datum.Labels) - } - - return validators, nil -} - func writeResponse(w http.ResponseWriter, status int, msg string) { w.WriteHeader(status) _, _ = w.Write([]byte(msg)) diff --git a/testutil/promrated/prometheus_internal_test.go b/testutil/promrated/prometheus_internal_test.go deleted file mode 100644 index 5c7398adb..000000000 --- a/testutil/promrated/prometheus_internal_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright © 2022-2024 Obol Labs Inc. Licensed under the terms of a Business Source License 1.1 - -package promrated - -import ( - "context" - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/obolnetwork/charon/testutil" -) - -//go:generate go test . -update -clean - -func TestGetValidators(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, promQuery, r.URL.Query()["query"][0]) - require.Equal(t, "Bearer test", r.Header.Get("Authorization")) - _, _ = w.Write([]byte(fixture)) - })) - defer ts.Close() - - vals, err := getValidators(context.Background(), ts.URL, "test") - assert.NoError(t, err) - testutil.RequireGoldenJSON(t, vals) -} - -const fixture = ` -{ - "status": "success", - "isPartial": false, - "data": { - "resultType": "vector", - "result": [ - { - "metric": { - "cluster_hash": "hash1", - "cluster_name": "cluster1", - "cluster_network": "network1", - "pubkey_full": "0x96c85da36a35123aa17ace6588e56e948b1f7fe320f53163015f144541b65645a7aa4df44e5638a00467aff16666629c" - }, - "value": [ - 1671108542, - "1" - ] - }, - { - "metric": { - "cluster_hash": "hash2", - "cluster_name": "cluster2", - "cluster_network": "network2", - "pubkey_full": "0x800a9a1c9f6cd9fbe30a3759070646bc8bf17a1da26bbcd5b72c696396ec2dd40265fd7174231dffe9f19cfc6e64df54" - }, - "value": [ - 1671108542, - "1" - ] - } - ] - } -}` diff --git a/testutil/promrated/promrated.go b/testutil/promrated/promrated.go index 42514fd82..92c03492d 100644 --- a/testutil/promrated/promrated.go +++ b/testutil/promrated/promrated.go @@ -19,16 +19,17 @@ import ( type Config struct { RatedEndpoint string RatedAuth string - PromEndpoint string PromAuth string MonitoringAddr string Networks []string + NodeOperators []string } // Run blocks running the promrated program until the context is canceled or a fatal error occurs. func Run(ctx context.Context, config Config) error { log.Info(ctx, "Promrated started", z.Str("rated_endpoint", redactURL(config.RatedEndpoint)), + z.Str("prom_auth", config.PromAuth), z.Str("monitoring_addr", config.MonitoringAddr), ) @@ -42,7 +43,8 @@ func Run(ctx context.Context, config Config) error { serverErr <- serveMonitoring(config.MonitoringAddr, promRegistry) }() - ticker := time.NewTicker(12 * time.Hour) + // Metrics are produced daily so can preserve Rated CUs + ticker := time.NewTicker(24 * time.Hour) defer ticker.Stop() onStartup := make(chan struct{}, 1) @@ -65,45 +67,10 @@ func Run(ctx context.Context, config Config) error { // report the validator effectiveness metrics for prometheus. func reportMetrics(ctx context.Context, config Config) { - validators, err := getValidators(ctx, config.PromEndpoint, config.PromAuth) - if err != nil { - log.Error(ctx, "Failed fetching validators from prometheus", err) - return - } - - for _, validator := range validators { - log.Info(ctx, "Fetched validator from prometheus", - z.Str("pubkey", validator.PubKey), - z.Str("cluster_name", validator.ClusterName), - z.Str("cluster_network", validator.ClusterNetwork), - ) - - if contains(config.Networks, validator.ClusterNetwork) { - stats, err := getValidatorStatistics(ctx, config.RatedEndpoint, config.RatedAuth, validator) - if err != nil { - log.Error(ctx, "Getting validator statistics", err, z.Str("pubkey", validator.PubKey)) - continue - } - - clusterLabels := prometheus.Labels{ - "pubkey_full": validator.PubKey, - "cluster_name": validator.ClusterName, - "cluster_hash": validator.ClusterHash, - "cluster_network": validator.ClusterNetwork, - } - - uptime.With(clusterLabels).Set(stats.Uptime) - correctness.With(clusterLabels).Set(stats.AvgCorrectness) - inclusionDelay.With(clusterLabels).Set(stats.AvgInclusionDelay) - attester.With(clusterLabels).Set(stats.AttesterEffectiveness) - proposer.With(clusterLabels).Set(stats.ProposerEffectiveness) - effectiveness.With(clusterLabels).Set(stats.ValidatorEffectiveness) - } - } - for _, network := range config.Networks { networkLabels := prometheus.Labels{ - "cluster_network": network, + clusterNetworkLabel: network, + nodeOperatorLabel: "all", } stats, err := getNetworkStatistics(ctx, config.RatedEndpoint, config.RatedAuth, network) @@ -112,24 +79,32 @@ func reportMetrics(ctx context.Context, config Config) { continue } - networkUptime.With(networkLabels).Set(stats.AvgUptime) - networkCorrectness.With(networkLabels).Set(stats.AvgCorrectness) - networkInclusionDelay.With(networkLabels).Set(stats.AvgInclusionDelay) - networkEffectiveness.With(networkLabels).Set(stats.ValidatorEffectiveness) - } -} + setMetrics(networkLabels, stats) + + for _, nodeOperator := range config.NodeOperators { + nodeOperatorLabels := prometheus.Labels{ + clusterNetworkLabel: network, + nodeOperatorLabel: nodeOperator, + } -// contains checks if array contains a string s. -func contains(arr []string, s string) bool { - result := false - for _, x := range arr { - if x == s { - result = true - break + stats, err = getNodeOperatorStatistics(ctx, config.RatedEndpoint, config.RatedAuth, nodeOperator, network) + if err != nil { + log.Error(ctx, "Getting node operator statistics", err, z.Str("network", network), z.Str("node_operator", nodeOperator)) + continue + } + + setMetrics(nodeOperatorLabels, stats) } } +} - return result +func setMetrics(labels prometheus.Labels, stats networkEffectivenessData) { + networkUptime.With(labels).Set(stats.AvgUptime) + networkCorrectness.With(labels).Set(stats.AvgCorrectness) + networkInclusionDelay.With(labels).Set(stats.AvgInclusionDelay) + networkEffectiveness.With(labels).Set(stats.AvgValidatorEffectiveness) + networkProposerEffectiveness.With(labels).Set(stats.AvgProposerEffectiveness) + networkAttesterEffectiveness.With(labels).Set(stats.AvgAttesterEffectiveness) } // redactURL returns a redacted version of the given URL. diff --git a/testutil/promrated/promrated/main.go b/testutil/promrated/promrated/main.go index 923ddc121..ee94cdb50 100644 --- a/testutil/promrated/promrated/main.go +++ b/testutil/promrated/promrated/main.go @@ -41,8 +41,8 @@ func newRootCmd(runFunc func(context.Context, promrated.Config) error) *cobra.Co func bindPromratedFlag(flags *pflag.FlagSet, config *promrated.Config) { flags.StringVar(&config.RatedEndpoint, "rated-endpoint", "https://api.rated.network", "Rated API endpoint to poll for validator metrics.") flags.StringVar(&config.RatedAuth, "rated-auth-token", "token", "[REQUIRED] Token for Rated API.") - flags.StringVar(&config.MonitoringAddr, "monitoring-address", "127.0.0.1:9100", "Listening address (ip and port) for the prometheus monitoring http server.") - flags.StringVar(&config.PromEndpoint, "prom-endpoint", "https://vm.monitoring.gcp.obol.tech/query", "Endpoint for VMetrics Prometheus API.") + flags.StringVar(&config.MonitoringAddr, "monitoring-address", "127.0.0.1:9200", "Listening address (ip and port) for the prometheus monitoring http server.") flags.StringVar(&config.PromAuth, "prom-auth-token", "token", "[REQUIRED] Token for VMetrics Promtetheus API.") flags.StringSliceVar(&config.Networks, "networks", nil, "Comma separated list of one or networks to monitor.") + flags.StringSliceVar(&config.NodeOperators, "node-operators", nil, "Comma separated list of one or node operators to monitor.") } diff --git a/testutil/promrated/rated.go b/testutil/promrated/rated.go index 235ab0485..dcd8d46a2 100644 --- a/testutil/promrated/rated.go +++ b/testutil/promrated/rated.go @@ -18,61 +18,53 @@ import ( "github.com/obolnetwork/charon/app/z" ) -type validatorEffectivenessData struct { - Uptime float64 `json:"uptime"` - AvgCorrectness float64 `json:"avgCorrectness"` - AvgInclusionDelay float64 `json:"avgInclusionDelay"` - AttesterEffectiveness float64 `json:"attesterEffectiveness"` - ProposerEffectiveness float64 `json:"proposerEffectiveness"` - ValidatorEffectiveness float64 `json:"validatorEffectiveness"` -} - type networkEffectivenessData struct { - AvgUptime float64 `json:"avgUptime"` - AvgCorrectness float64 `json:"avgCorrectness"` - AvgInclusionDelay float64 `json:"avgInclusionDelay"` - ValidatorEffectiveness float64 `json:"avgValidatorEffectiveness"` + AvgUptime float64 `json:"avgUptime"` + AvgCorrectness float64 `json:"avgCorrectness"` + AvgInclusionDelay float64 `json:"avgInclusionDelay"` + AvgValidatorEffectiveness float64 `json:"avgValidatorEffectiveness"` + AvgProposerEffectiveness float64 `json:"avgProposerEffectiveness"` + AvgAttesterEffectiveness float64 `json:"avgAttesterEffectiveness"` } -// getValidatorStatistics queries rated for a pubkey and returns rated data about the pubkey -// See https://api.rated.network/docs#/default/get_effectiveness_v0_eth_validators__validator_index_or_pubkey__effectiveness_get -func getValidatorStatistics(ctx context.Context, ratedEndpoint string, ratedAuth string, validator validator) (validatorEffectivenessData, error) { +// getNetworkStatistics queries rated for the network and returns the network 1d average +// See https://api.rated.network/docs#/Network/get_network_overview_v0_eth_network_overview_get +func getNetworkStatistics(ctx context.Context, ratedEndpoint string, ratedAuth string, network string) (networkEffectivenessData, error) { url, err := url.Parse(ratedEndpoint) if err != nil { - return validatorEffectivenessData{}, errors.Wrap(err, "parse rated endpoint") + return networkEffectivenessData{}, errors.Wrap(err, "parse rated endpoint") } - url.Path = fmt.Sprintf("/v0/eth/validators/%s/effectiveness", validator.PubKey) - - // Adding size=1 will get only the latest day of data - query := url.Query() - query.Add("size", "1") - url.RawQuery = query.Encode() + url.Path = "/v0/eth/network/stats" - body, err := queryRatedAPI(ctx, url, ratedAuth, validator.ClusterNetwork) + body, err := queryRatedAPI(ctx, url, ratedAuth, network) if err != nil { - return validatorEffectivenessData{}, err + return networkEffectivenessData{}, err } - return parseValidatorMetrics(body) + return parseNetworkMetrics(body) } -// getNetworkStatistics queries rated for the network and returns the network 1d average -// See https://api.rated.network/docs#/Network/get_network_overview_v0_eth_network_overview_get -func getNetworkStatistics(ctx context.Context, ratedEndpoint string, ratedAuth string, network string) (networkEffectivenessData, error) { +// getNodeOperatorStatistics queries rated for the node operator and returns the 1d average +// See https://api.rated.network/docs#/Operators/get_effectiveness_v0_eth_operators__operator_id__effectiveness_get +func getNodeOperatorStatistics(ctx context.Context, ratedEndpoint string, ratedAuth string, operator string, network string) (networkEffectivenessData, error) { url, err := url.Parse(ratedEndpoint) if err != nil { return networkEffectivenessData{}, errors.Wrap(err, "parse rated endpoint") } - url.Path = "/v0/eth/network/stats" + url.Path = fmt.Sprintf("/v0/eth/operators/%s/effectiveness", operator) + + query := url.Query() + query.Add("size", "1") + url.RawQuery = query.Encode() body, err := queryRatedAPI(ctx, url, ratedAuth, network) if err != nil { return networkEffectivenessData{}, err } - return parseNetworkMetrics(body) + return parseNodeOperatorMetrics(body) } // queryRatedAPI queries rated url and returns effectiveness data. @@ -126,38 +118,38 @@ func queryRatedAPI(ctx context.Context, url *url.URL, ratedAuth string, network return nil, errors.New("max retries exceeded fetching validator data", z.Int("max", maxRetries)) } -// parseValidatorMetrics reads the validator rated response and returns the validator effectiveness data. -func parseValidatorMetrics(body []byte) (validatorEffectivenessData, error) { - var result struct { - Data []validatorEffectivenessData `json:"data"` - } +// parseNetworkMetrics reads the network rated response and returns the network effectiveness data. +func parseNetworkMetrics(body []byte) (networkEffectivenessData, error) { + var result []networkEffectivenessData err := json.Unmarshal(body, &result) if err != nil { - return validatorEffectivenessData{}, errors.Wrap(err, "deserializing json") + return networkEffectivenessData{}, errors.Wrap(err, "deserializing json") } - if len(result.Data) != 1 { - return validatorEffectivenessData{}, errors.New("unexpected data response from rated network") + if len(result) == 0 { + return networkEffectivenessData{}, errors.New("unexpected data response from rated network") } - return result.Data[0], nil + return result[0], nil } -// parseNetworkMetrics reads the network rated response and returns the network effectiveness data. -func parseNetworkMetrics(body []byte) (networkEffectivenessData, error) { - var result []networkEffectivenessData +// parseNodeOperatorMetrics reads the operator rated response and returns the effectiveness data. +func parseNodeOperatorMetrics(body []byte) (networkEffectivenessData, error) { + var result struct { + Data []networkEffectivenessData `json:"data"` + } err := json.Unmarshal(body, &result) if err != nil { return networkEffectivenessData{}, errors.Wrap(err, "deserializing json") } - if len(result) == 0 { + if len(result.Data) != 1 { return networkEffectivenessData{}, errors.New("unexpected data response from rated network") } - return result[0], nil + return result.Data[0], nil } func extractBody(res *http.Response) ([]byte, error) { diff --git a/testutil/promrated/rated_internal_test.go b/testutil/promrated/rated_internal_test.go index a1c71223a..cd3553736 100644 --- a/testutil/promrated/rated_internal_test.go +++ b/testutil/promrated/rated_internal_test.go @@ -16,67 +16,58 @@ import ( //go:generate go test . -update -clean -func TestGetValidatorStatistics(t *testing.T) { +func TestGetNetworkStatistics(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/v0/eth/validators/0xA/effectiveness", r.URL.Path) - require.Equal(t, "1", r.URL.Query()["size"][0]) + require.Equal(t, "/v0/eth/network/stats", r.URL.Path) require.Equal(t, "Bearer auth", r.Header.Get("Authorization")) require.Equal(t, "prater", r.Header.Get("X-Rated-Network")) - _, _ = w.Write([]byte(ratedValidatorFixture)) + _, _ = w.Write([]byte(ratedNetworkFixture)) })) defer ts.Close() - validator := validator{ClusterName: "test-cluster", ClusterHash: "hash", ClusterNetwork: "goerli", PubKey: "0xA"} - - vals, err := getValidatorStatistics(context.Background(), ts.URL, "auth", validator) + vals, err := getNetworkStatistics(context.Background(), ts.URL, "auth", "goerli") assert.NoError(t, err) testutil.RequireGoldenJSON(t, vals) } -func TestGetNetworkStatistics(t *testing.T) { +func TestGetNodeOperatorStatistics(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/v0/eth/network/stats", r.URL.Path) + require.Equal(t, "/v0/eth/operators/Lido/effectiveness", r.URL.Path) require.Equal(t, "Bearer auth", r.Header.Get("Authorization")) require.Equal(t, "prater", r.Header.Get("X-Rated-Network")) - _, _ = w.Write([]byte(ratedNetworkFixture)) + _, _ = w.Write([]byte(ratedNodeOperatorFixture)) })) defer ts.Close() - vals, err := getNetworkStatistics(context.Background(), ts.URL, "auth", "goerli") + vals, err := getNodeOperatorStatistics(context.Background(), ts.URL, "auth", "Lido", "goerli") assert.NoError(t, err) testutil.RequireGoldenJSON(t, vals) } -const ratedValidatorFixture = ` -{ - "page": { - "from": null, - "size": 1, - "granularity": "day", - "filterType": "day" - }, - "total": 115, - "data": [ - { - "avgInclusionDelay": 1.4330357142857142, - "uptime": 0.9955555555555555, - "avgCorrectness": 0.9300595238095238, - "attesterEffectiveness": 64.61289950386524, - "proposerEffectiveness": null, - "validatorEffectiveness": 64.61289950386524 - } - ], - "next": "/v0/eth/validators/379356/effectiveness?size=1&from=629&granularity=day&filterType=day" -}` - const ratedNetworkFixture = ` [ { "avgUptime": 0.9964608763093223, "avgInclusionDelay": 1.0147019732112206, - "avgCorrectness": 0.9914412918384125, - "avgValidatorEffectiveness": 97.6838307968488 + "avgCorrectness": 0.982182918384125, + "avgValidatorEffectiveness": 45.6838307968488, + "avgProposerEffectiveness": 12.68383072342342, + "avgAttesterEffectiveness": 67.2343240993498 } ]` + +const ratedNodeOperatorFixture = ` +{ + "data": [ + { + "avgUptime": 0.352353432111, + "avgInclusionDelay": 1.0147019732112206, + "avgCorrectness": 0.3452333554125, + "avgValidatorEffectiveness": 45.6838307968488, + "avgProposerEffectiveness": 54.68383072342342, + "avgAttesterEffectiveness": 21.2343240993498 + } + ] +}` diff --git a/testutil/promrated/testdata/TestGetNetworkStatistics.golden b/testutil/promrated/testdata/TestGetNetworkStatistics.golden index 39e19d2ef..531ce795a 100644 --- a/testutil/promrated/testdata/TestGetNetworkStatistics.golden +++ b/testutil/promrated/testdata/TestGetNetworkStatistics.golden @@ -1,6 +1,8 @@ { "avgUptime": 0.9964608763093223, - "avgCorrectness": 0.9914412918384125, + "avgCorrectness": 0.982182918384125, "avgInclusionDelay": 1.0147019732112206, - "avgValidatorEffectiveness": 97.6838307968488 + "avgValidatorEffectiveness": 45.6838307968488, + "avgProposerEffectiveness": 12.68383072342342, + "avgAttesterEffectiveness": 67.2343240993498 } \ No newline at end of file diff --git a/testutil/promrated/testdata/TestGetNodeOperatorStatistics.golden b/testutil/promrated/testdata/TestGetNodeOperatorStatistics.golden new file mode 100644 index 000000000..41f01c44c --- /dev/null +++ b/testutil/promrated/testdata/TestGetNodeOperatorStatistics.golden @@ -0,0 +1,8 @@ +{ + "avgUptime": 0.352353432111, + "avgCorrectness": 0.3452333554125, + "avgInclusionDelay": 1.0147019732112206, + "avgValidatorEffectiveness": 45.6838307968488, + "avgProposerEffectiveness": 54.68383072342342, + "avgAttesterEffectiveness": 21.2343240993498 +} \ No newline at end of file diff --git a/testutil/promrated/testdata/TestGetValidatorStatistics.golden b/testutil/promrated/testdata/TestGetValidatorStatistics.golden deleted file mode 100644 index 9cfae5bf2..000000000 --- a/testutil/promrated/testdata/TestGetValidatorStatistics.golden +++ /dev/null @@ -1,8 +0,0 @@ -{ - "uptime": 0.9955555555555555, - "avgCorrectness": 0.9300595238095238, - "avgInclusionDelay": 1.4330357142857142, - "attesterEffectiveness": 64.61289950386524, - "proposerEffectiveness": 0, - "validatorEffectiveness": 64.61289950386524 -} \ No newline at end of file diff --git a/testutil/promrated/testdata/TestGetValidators.golden b/testutil/promrated/testdata/TestGetValidators.golden deleted file mode 100644 index 43e895b2c..000000000 --- a/testutil/promrated/testdata/TestGetValidators.golden +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "pubkey_full": "0x96c85da36a35123aa17ace6588e56e948b1f7fe320f53163015f144541b65645a7aa4df44e5638a00467aff16666629c", - "cluster_name": "cluster1", - "cluster_hash": "hash1", - "cluster_network": "network1" - }, - { - "pubkey_full": "0x800a9a1c9f6cd9fbe30a3759070646bc8bf17a1da26bbcd5b72c696396ec2dd40265fd7174231dffe9f19cfc6e64df54", - "cluster_name": "cluster2", - "cluster_hash": "hash2", - "cluster_network": "network2" - } -] \ No newline at end of file