From 5075c1fc438aa94db484538d399d25f252852db8 Mon Sep 17 00:00:00 2001 From: David Nix Date: Fri, 12 May 2023 08:58:49 -0600 Subject: [PATCH 1/4] Refactor rest job factory to single job --- cmd/root.go | 32 +++++++++++++++++--------------- config.example.yaml | 6 ++++++ cosmos/rest_job.go | 18 +++++++----------- cosmos/rest_job_test.go | 39 ++++++++++----------------------------- 4 files changed, 40 insertions(+), 55 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 9ce660b..946f6b3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -125,23 +125,25 @@ 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)) + restJobs := cosmos.NewRestJob(cosmosMets, restClient, cfg.Cosmos) + jobs = append(jobs, toJobs(restJobs)...) + valJobs := cosmos.BuildValidatorJobs(cosmosMets, restClient, cfg.Cosmos) + 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..2830f71 100644 --- a/cosmos/rest_job.go +++ b/cosmos/rest_job.go @@ -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 { @@ -69,7 +65,7 @@ func (job RestJob) Run(ctx context.Context) error { return fmt.Errorf("query /status: %w", 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) From 8fc97fe91d61f812a0cd8ae8501a2784f14042cc Mon Sep 17 00:00:00 2001 From: David Nix Date: Fri, 12 May 2023 09:01:30 -0600 Subject: [PATCH 2/4] Small tweaks --- cosmos/rest_job.go | 8 ++++---- cosmos/validator_job.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cosmos/rest_job.go b/cosmos/rest_job.go index 2830f71..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 { @@ -58,11 +58,11 @@ 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, "job", job.String()) diff --git a/cosmos/validator_job.go b/cosmos/validator_job.go index 67b1f67..8b7281f 100644 --- a/cosmos/validator_job.go +++ b/cosmos/validator_job.go @@ -58,7 +58,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 { From cd71124879c1919e16658e06ee8621b064813511 Mon Sep 17 00:00:00 2001 From: David Nix Date: Fri, 12 May 2023 09:07:27 -0600 Subject: [PATCH 3/4] Refactor val job to take just 1 chain --- cosmos/validator_job.go | 22 ++++++++++------------ cosmos/validator_job_test.go | 24 +++++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cosmos/validator_job.go b/cosmos/validator_job.go index 8b7281f..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 } 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) }) From 227c4166ec9cad11e99ecf37fc0e377650fc3bdc Mon Sep 17 00:00:00 2001 From: David Nix Date: Fri, 12 May 2023 09:09:43 -0600 Subject: [PATCH 4/4] Refactor main for new interfaces --- cmd/root.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 946f6b3..8353d9c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -139,9 +139,8 @@ func buildCosmosJobs(cosmosMets *metrics.Cosmos, refMets *metrics.ReferenceAPI, } restClient := cosmos.NewRestClient(metrics.NewFallbackClient(httpClient, refMets, urls)) - restJobs := cosmos.NewRestJob(cosmosMets, restClient, cfg.Cosmos) - jobs = append(jobs, toJobs(restJobs)...) - valJobs := cosmos.BuildValidatorJobs(cosmosMets, restClient, cfg.Cosmos) + jobs = append(jobs, cosmos.NewRestJob(cosmosMets, restClient, chain)) + valJobs := cosmos.BuildValidatorJobs(cosmosMets, restClient, chain) jobs = append(jobs, toJobs(valJobs)...) }