diff --git a/pkg/beacon/metrics_spec.go b/pkg/beacon/metrics_spec.go index 28095ca..0513cc2 100644 --- a/pkg/beacon/metrics_spec.go +++ b/pkg/beacon/metrics_spec.go @@ -327,7 +327,12 @@ func (s *SpecMetrics) observeSpec(ctx context.Context, spec *state.Spec) error { divided := new(big.Int).Div(&spec.TerminalTotalDifficulty, trillion) asFloat, _ := new(big.Float).SetInt(divided).Float64() s.TerminalTotalDifficultyTrillions.Set(asFloat) - s.TerminalTotalDifficulty.Set(float64(spec.TerminalTotalDifficulty.Uint64())) + + // big.Int.Uint64 is undefined when the value doesn't fit in 64 bits, + // which mainnet's TTD doesn't. Go through big.Float instead so the + // gauge reports the real value rather than a silently wrapped one. + ttdAsFloat, _ := new(big.Float).SetInt(&spec.TerminalTotalDifficulty).Float64() + s.TerminalTotalDifficulty.Set(ttdAsFloat) return nil } diff --git a/pkg/beacon/metrics_spec_test.go b/pkg/beacon/metrics_spec_test.go new file mode 100644 index 0000000..ab76f2b --- /dev/null +++ b/pkg/beacon/metrics_spec_test.go @@ -0,0 +1,51 @@ +package beacon + +import ( + "context" + "math/big" + "testing" + + "github.com/ethpandaops/beacon/pkg/beacon/state" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/sirupsen/logrus" +) + +func gaugeValue(t *testing.T, g prometheus.Gauge) float64 { + t.Helper() + + metricDTO := &dto.Metric{} + if err := g.Write(metricDTO); err != nil { + t.Fatalf("failed to read gauge: %v", err) + } + + return metricDTO.Gauge.GetValue() +} + +func TestObserveSpec_TerminalTotalDifficulty(t *testing.T) { + prometheus.DefaultRegisterer = prometheus.NewRegistry() + + log := logrus.New() + log.SetLevel(logrus.PanicLevel) + + job := NewSpecJob(nil, log, "test_ttd_gauge", map[string]string{}) + + mainnetTTD, ok := new(big.Int).SetString("58750000000000000000000", 10) + if !ok { + t.Fatal("failed to parse mainnet TTD constant") + } + + s := &state.Spec{TerminalTotalDifficulty: *mainnetTTD} + + if err := job.observeSpec(context.Background(), s); err != nil { + t.Fatalf("observeSpec returned error: %v", err) + } + + got := gaugeValue(t, job.TerminalTotalDifficulty) + + want, _ := new(big.Float).SetInt(mainnetTTD).Float64() + + if got != want { + t.Fatalf("expected beacon_spec_terminal_total_difficulty to report the real TTD %v, got %v", want, got) + } +}