diff --git a/cmd/root.go b/cmd/root.go index 9ce660b..8353d9c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -125,23 +125,24 @@ func logFatal(msg string, err error) { os.Exit(1) } -func buildCosmosJobs(cosmosMets *metrics.Cosmos, refMets *metrics.ReferenceAPI, cfg Config) (jobs []metrics.Job) { - // TODO(nix): Need different rest clients per chain. This hack prevents > 1 chain. - var urls []url.URL - for _, rest := range cfg.Cosmos[0].Rest { - u, err := url.Parse(rest.URL) - if err != nil { - logFatal("Failed to parse rest url", err) - } - urls = append(urls, *u) - } +func buildCosmosJobs(cosmosMets *metrics.Cosmos, refMets *metrics.ReferenceAPI, cfg Config) []metrics.Job { + var jobs []metrics.Job - restClient := cosmos.NewRestClient(metrics.NewFallbackClient(httpClient, refMets, urls)) + for _, chain := range cfg.Cosmos { + var urls []url.URL + for _, rest := range chain.Rest { + u, err := url.Parse(rest.URL) + if err != nil { + logFatal("Failed to parse cosmos rest url", err) + } + urls = append(urls, *u) + } - restJobs := cosmos.BuildRestJobs(cosmosMets, restClient, cfg.Cosmos) - jobs = append(jobs, toJobs(restJobs)...) - valJobs := cosmos.BuildValidatorJobs(cosmosMets, restClient, cfg.Cosmos) - jobs = append(jobs, toJobs(valJobs)...) + restClient := cosmos.NewRestClient(metrics.NewFallbackClient(httpClient, refMets, urls)) + jobs = append(jobs, cosmos.NewRestJob(cosmosMets, restClient, chain)) + valJobs := cosmos.BuildValidatorJobs(cosmosMets, restClient, chain) + jobs = append(jobs, toJobs(valJobs)...) + } return jobs } diff --git a/config.example.yaml b/config.example.yaml index abcb531..edf31a1 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -30,3 +30,9 @@ cosmos: validators: # The consensus address of a validator. - consaddress: cosmosvalcons164q2kq3q3psj436t9p7swmdlh39rw73wpy6qx6 + - chainID: osmosis-1 + rest: + - url: https://osmosis-api.polkachu.com + - url: https://lcd.osmosis.zone + validators: + - consaddress: osmovalcons1zw8an2m6hc96a52v5l2pmzzm0qzj5j4p9mnvva diff --git a/cosmos/rest_job.go b/cosmos/rest_job.go index 44ea2d0..d1f5c61 100644 --- a/cosmos/rest_job.go +++ b/cosmos/rest_job.go @@ -10,8 +10,8 @@ import ( ) const ( - defaultInterval = 15 * time.Second - defaultRestTimeout = 5 * time.Second + defaultInterval = 15 * time.Second + defaultRequestTimeout = 5 * time.Second ) func intervalOrDefault(dur time.Duration) time.Duration { @@ -38,17 +38,13 @@ type RestJob struct { metrics Metrics } -func BuildRestJobs(metrics Metrics, client Client, chains []Chain) []RestJob { - var jobs []RestJob - for _, chain := range chains { - jobs = append(jobs, RestJob{ - chainID: chain.ChainID, - client: client, - interval: intervalOrDefault(chain.Interval), - metrics: metrics, - }) +func NewRestJob(metrics Metrics, client Client, chain Chain) RestJob { + return RestJob{ + chainID: chain.ChainID, + client: client, + interval: intervalOrDefault(chain.Interval), + metrics: metrics, } - return jobs } func (job RestJob) String() string { @@ -62,14 +58,14 @@ func (job RestJob) Interval() time.Duration { // Run queries the Endpoint server for data and records various metrics. func (job RestJob) Run(ctx context.Context) error { - cctx, cancel := context.WithTimeout(ctx, defaultRestTimeout) + cctx, cancel := context.WithTimeout(ctx, defaultRequestTimeout) defer cancel() block, err := job.client.LatestBlock(cctx) if err != nil { - return fmt.Errorf("query /status: %w", err) + return err } if chainID := block.Block.Header.ChainID; chainID != job.chainID { - slog.Warn("Mismatched chain id", "expected", job.chainID, "actual", chainID) + slog.Warn("Mismatched chain id", "expected", job.chainID, "actual", chainID, "job", job.String()) } height, err := strconv.ParseFloat(block.Block.Header.Height, 64) if err != nil { diff --git a/cosmos/rest_job_test.go b/cosmos/rest_job_test.go index 693408c..6e72d67 100644 --- a/cosmos/rest_job_test.go +++ b/cosmos/rest_job_test.go @@ -33,28 +33,19 @@ func (m *mockRestClient) LatestBlock(ctx context.Context) (Block, error) { func TestRestJob_Interval(t *testing.T) { t.Parallel() - chains := []Chain{ - {Interval: time.Second}, - {}, - } - - jobs := BuildRestJobs(nil, nil, chains) + job := NewRestJob(nil, nil, Chain{Interval: time.Second}) + require.Equal(t, time.Second, job.Interval()) - require.Len(t, jobs, 2) - require.Equal(t, time.Second, jobs[0].Interval()) - require.Equal(t, 15*time.Second, jobs[1].Interval()) + job = NewRestJob(nil, nil, Chain{}) + require.Equal(t, defaultInterval, job.Interval()) } func TestRestJob_String(t *testing.T) { t.Parallel() - chains := []Chain{ - {ChainID: "cosmoshub-4"}, - } - - jobs := BuildRestJobs(nil, nil, chains) + job := NewRestJob(nil, nil, Chain{ChainID: "cosmoshub-4"}) - require.Equal(t, "Cosmos REST cosmoshub-4", jobs[0].String()) + require.Equal(t, "Cosmos REST cosmoshub-4", job.String()) } func TestRestJob_Run(t *testing.T) { @@ -70,23 +61,13 @@ func TestRestJob_Run(t *testing.T) { blk.Block.Header.ChainID = "cosmoshub-4" client.StubBlock = blk - chains := []Chain{ - { - ChainID: "cosmoshub-4", - Rest: []Endpoint{{URL: "http://cosmos.example.com"}, {}}, - }, - { - ChainID: "akash-1234", - Rest: []Endpoint{{URL: "http://akash.example.com"}}, - }, + chain := Chain{ + ChainID: "cosmoshub-4", + Rest: []Endpoint{{URL: "http://cosmos.example.com"}, {}}, } var metrics mockCosmosMetrics - jobs := BuildRestJobs(&metrics, &client, chains) - - require.Len(t, jobs, 2) - - job := jobs[0] + job := NewRestJob(&metrics, &client, chain) err := job.Run(ctx) require.NoError(t, err) diff --git a/cosmos/validator_job.go b/cosmos/validator_job.go index 67b1f67..e40fb8e 100644 --- a/cosmos/validator_job.go +++ b/cosmos/validator_job.go @@ -34,18 +34,16 @@ type ValidatorJob struct { metrics ValidatorMetrics } -func BuildValidatorJobs(metrics ValidatorMetrics, client ValidatorClient, chains []Chain) []ValidatorJob { - var jobs []ValidatorJob - for _, chain := range chains { - for _, val := range chain.Validators { - jobs = append(jobs, ValidatorJob{ - chainID: chain.ChainID, - client: client, - consaddress: val.ConsAddress, - interval: intervalOrDefault(chain.Interval), - metrics: metrics, - }) - } +func BuildValidatorJobs(metrics ValidatorMetrics, client ValidatorClient, chain Chain) []*ValidatorJob { + var jobs []*ValidatorJob + for _, val := range chain.Validators { + jobs = append(jobs, &ValidatorJob{ + chainID: chain.ChainID, + client: client, + consaddress: val.ConsAddress, + interval: intervalOrDefault(chain.Interval), + metrics: metrics, + }) } return jobs } @@ -58,7 +56,7 @@ func (job ValidatorJob) Interval() time.Duration { return job.interval } // Run executes the job gathering a variety of metrics for cosmos validators. func (job ValidatorJob) Run(ctx context.Context) error { - ctx, cancel := context.WithTimeout(ctx, defaultRestTimeout) + ctx, cancel := context.WithTimeout(ctx, defaultRequestTimeout) defer cancel() resp, err := job.client.SigningStatus(ctx, job.consaddress) if err != nil { diff --git a/cosmos/validator_job_test.go b/cosmos/validator_job_test.go index 63e076b..529c951 100644 --- a/cosmos/validator_job_test.go +++ b/cosmos/validator_job_test.go @@ -37,17 +37,19 @@ func (m *mockValMetrics) SetValJailStatus(chain, consaddress string, status Jail func TestValidatorJob_Interval(t *testing.T) { t.Parallel() - chains := []Chain{ - {Interval: time.Second, Validators: []Validator{{ConsAddress: "1"}, {ConsAddress: "2"}}}, - {Validators: []Validator{{ConsAddress: "3"}}}, // empty chain - } + chain := Chain{Interval: time.Second, Validators: []Validator{{ConsAddress: "1"}, {ConsAddress: "2"}}} - jobs := BuildValidatorJobs(nil, nil, chains) + jobs := BuildValidatorJobs(nil, nil, chain) - require.Len(t, jobs, 3) + require.Len(t, jobs, 2) require.Equal(t, time.Second, jobs[0].Interval()) require.Equal(t, time.Second, jobs[1].Interval()) - require.Equal(t, defaultInterval, jobs[2].Interval()) + + chain = Chain{Validators: []Validator{{ConsAddress: "1"}}} + jobs = BuildValidatorJobs(nil, nil, chain) + + require.Len(t, jobs, 1) + require.Equal(t, defaultInterval, jobs[0].Interval()) } func TestValidatorJob_String(t *testing.T) { @@ -64,13 +66,13 @@ func TestValidatorJob_String(t *testing.T) { {ConsAddress: "cosmosvalcons567"}, }, } - jobs := BuildValidatorJobs(nil, nil, []Chain{chain}) + jobs := BuildValidatorJobs(nil, nil, chain) require.Len(t, jobs, 2) require.Equal(t, "Cosmos validator cosmosvalcons123: cosmoshub-4", jobs[0].String()) } -func TestValdatorJob_Run(t *testing.T) { +func TestValidatorJob_Run(t *testing.T) { t.Parallel() chain := Chain{ @@ -106,7 +108,7 @@ func TestValdatorJob_Run(t *testing.T) { var metrics mockValMetrics - jobs := BuildValidatorJobs(&metrics, &client, []Chain{chain}) + jobs := BuildValidatorJobs(&metrics, &client, chain) require.Len(t, jobs, 1) err := jobs[0].Run(context.Background()) @@ -121,7 +123,7 @@ func TestValdatorJob_Run(t *testing.T) { }) t.Run("zero state", func(t *testing.T) { - jobs := BuildValidatorJobs(nil, nil, nil) + jobs := BuildValidatorJobs(nil, nil, Chain{}) require.Empty(t, jobs) })