From 225c949014603d34e9ed6ceaaf4720206a12eacc Mon Sep 17 00:00:00 2001 From: avalkov Date: Mon, 8 Aug 2022 13:51:45 +0300 Subject: [PATCH] Exposed /stats endpoint --- cmd/stats-service/main.go | 1 + config.yaml | 4 ++ internal/config/config.go | 3 + internal/handlers/handlers.go | 112 ++++++++++++++++++++++++++-------- internal/storage/storage.go | 13 ++++ internal/tasks/apr.go | 4 ++ internal/tasks/inflation.go | 8 +++ internal/tasks/tasks.go | 1 + 8 files changed, 122 insertions(+), 24 deletions(-) diff --git a/cmd/stats-service/main.go b/cmd/stats-service/main.go index 31525fb..73768b0 100644 --- a/cmd/stats-service/main.go +++ b/cmd/stats-service/main.go @@ -68,6 +68,7 @@ func main() { http.HandleFunc("/cosmos/bank/v1beta1/supply", handlers.GetSupplyHandler(cfg, keyValueStorage)) http.HandleFunc("/circulating-supply", handlers.GetCircSupplyTextHandler(cfg, keyValueStorage)) http.HandleFunc("/json/circulating-supply", handlers.GetCircSupplyJSONHandler(cfg, keyValueStorage)) + http.HandleFunc("/stats", handlers.GetStatsHandler(cfg, keyValueStorage)) log.Info().Msg(fmt.Sprintf("Listening on port: %d", cfg.Port)) diff --git a/config.yaml b/config.yaml index 8fe3c8f..70f3fc0 100644 --- a/config.yaml +++ b/config.yaml @@ -30,7 +30,11 @@ calculation: inflation_since_days: 50 storage: apr_key: apr + apr_height_key: apr_height annual_provisions_key: annual_provisions inflation_key: inflation + inflation_height_key: inflation_height all_tokens_supply_key: all_tokens_supply supply_key: supply + supply_height_key: supply_height + diff --git a/internal/config/config.go b/internal/config/config.go index 14bbc4a..50c8beb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -50,9 +50,12 @@ type Config struct { } `yaml:"calculation"` Storage struct { APRKey string `yaml:"apr_key"` + APRHeightKey string `yaml:"apr_height_key"` AnnualProvisionsKey string `yaml:"annual_provisions"` InflationKey string `yaml:"inflation_key"` + InflationHeightKey string `yaml:"inflation_height_key"` AllTokensSupplyKey string `yaml:"all_tokens_supply_key"` SupplyKey string `yaml:"supply_key"` + SupplyHeightKey string `yaml:"supply_height_key"` } `yaml:"storage"` } diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 1313583..515ab8a 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -14,15 +14,13 @@ func GetCircSupplyTextHandler(cfg config.Config, storage keyValueStorage) func(h return func(w http.ResponseWriter, r *http.Request) { supply, err := storage.GetValue(cfg.Storage.SupplyKey) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } formattedSupply, err := formatSupply(supply) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } @@ -30,8 +28,7 @@ func GetCircSupplyTextHandler(cfg config.Config, storage keyValueStorage) func(h w.WriteHeader(http.StatusOK) if _, err := w.Write([]byte(formattedSupply)); err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } } @@ -41,22 +38,76 @@ func GetCircSupplyJSONHandler(cfg config.Config, storage keyValueStorage) func(h return func(w http.ResponseWriter, r *http.Request) { supply, err := storage.GetValue(cfg.Storage.SupplyKey) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } formattedSupply, err := formatSupply(supply) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } setHeaders(w) if err := json.NewEncoder(w).Encode(supplyResponse{Supply: formattedSupply}); err != nil { - log.Error().Err(err).Send() + badRequest(w, err) + } + } +} + +func GetStatsHandler(cfg config.Config, storage keyValueStorage) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + supply, err := storage.GetValue(cfg.Storage.SupplyKey) + if err != nil { + badRequest(w, err) + return + } + + formattedSupply, err := formatSupply(supply) + if err != nil { + badRequest(w, err) + return + } + + supplyHeight, err := storage.GetInt64Value(cfg.Storage.SupplyHeightKey) + if err != nil { + badRequest(w, err) + return + } + + inflation, err := storage.GetValue(cfg.Storage.InflationKey) + if err != nil { + badRequest(w, err) + return + } + + inflationHeight, err := storage.GetInt64Value(cfg.Storage.InflationHeightKey) + if err != nil { + badRequest(w, err) + return + } + + apr, err := storage.GetValue(cfg.Storage.APRKey) + if err != nil { + badRequest(w, err) + return + } + + aprHeight, err := storage.GetInt64Value(cfg.Storage.APRHeightKey) + if err != nil { + badRequest(w, err) + return + } + + setHeaders(w) + + if err := json.NewEncoder(w).Encode(statsResponse{ + Inflation: valueAtHeight{Value: inflation, Height: inflationHeight}, + APR: valueAtHeight{Value: apr, Height: aprHeight}, + Supply: valueAtHeight{Value: formattedSupply, Height: supplyHeight}, + }); err != nil { + badRequest(w, err) } } } @@ -65,15 +116,14 @@ func GetSupplyHandler(cfg config.Config, storage keyValueStorage) func(http.Resp return func(w http.ResponseWriter, r *http.Request) { supply, err := storage.GetValue(cfg.Storage.AllTokensSupplyKey) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } setHeaders(w) if _, err := w.Write([]byte(supply)); err != nil { - log.Error().Err(err).Send() + badRequest(w, err) } } } @@ -82,15 +132,14 @@ func GetAPRHandler(cfg config.Config, storage keyValueStorage) func(http.Respons return func(w http.ResponseWriter, r *http.Request) { apr, err := storage.GetValue(cfg.Storage.APRKey) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } setHeaders(w) if err := json.NewEncoder(w).Encode(aprResponse{APR: apr}); err != nil { - log.Error().Err(err).Send() + badRequest(w, err) } } } @@ -99,15 +148,14 @@ func GetAnnualProvisionsHandler(cfg config.Config, storage keyValueStorage) func return func(w http.ResponseWriter, r *http.Request) { annualProvisions, err := storage.GetValue(cfg.Storage.AnnualProvisionsKey) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } setHeaders(w) if err := json.NewEncoder(w).Encode(annualProvisionsResponse{AnnualProvisions: annualProvisions}); err != nil { - log.Error().Err(err).Send() + badRequest(w, err) } } } @@ -116,15 +164,14 @@ func GetInflationHandler(cfg config.Config, storage keyValueStorage) func(http.R return func(w http.ResponseWriter, r *http.Request) { inflation, err := storage.GetValue(cfg.Storage.InflationKey) if err != nil { - log.Error().Err(err).Send() - w.WriteHeader(http.StatusBadRequest) + badRequest(w, err) return } setHeaders(w) if err := json.NewEncoder(w).Encode(inflationResponse{Inflation: inflation}); err != nil { - log.Error().Err(err).Send() + badRequest(w, err) } } } @@ -143,7 +190,7 @@ func GetParamsHandler(cfg config.Config) func(http.ResponseWriter, *http.Request BlocksPerYear: cfg.Genesis.BlocksPerDay, }, }); err != nil { - log.Error().Err(err).Send() + badRequest(w, err) } } } @@ -161,6 +208,11 @@ func formatSupply(supply string) (string, error) { return formattedSupply.String(), nil } +func badRequest(w http.ResponseWriter, err error) { + log.Error().Err(err).Send() + w.WriteHeader(http.StatusBadRequest) +} + func setHeaders(w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -195,7 +247,19 @@ type supplyResponse struct { Supply string `json:"supply"` } +type statsResponse struct { + Inflation valueAtHeight `json:"inflation"` + APR valueAtHeight `json:"apr"` + Supply valueAtHeight `json:"supply"` +} + +type valueAtHeight struct { + Value string `json:"value"` + Height int64 `json:"height"` +} + type keyValueStorage interface { SetValue(key, value string) error GetValue(key string) (string, error) + GetInt64Value(key string) (int64, error) } diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 6b63e4e..bf67e3c 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -2,6 +2,7 @@ package storage import ( "errors" + "strconv" ) type storage struct { @@ -36,3 +37,15 @@ func (s *storage) GetOrDefaultValue(key, defaultValue string) (string, error) { } return value, err } + +func (s *storage) SetInt64Value(key string, value int64) error { + return s.SetValue(key, strconv.FormatInt(value, 10)) +} + +func (s *storage) GetInt64Value(key string) (int64, error) { + value, err := s.GetValue(key) + if err != nil { + return 0, err + } + return strconv.ParseInt(value, 10, 64) +} diff --git a/internal/tasks/apr.go b/internal/tasks/apr.go index b3f31d6..48bf9e6 100644 --- a/internal/tasks/apr.go +++ b/internal/tasks/apr.go @@ -46,6 +46,10 @@ func getCalculateAPRHandler(genesisState cudoMintTypes.GenesisState, cfg config. return fmt.Errorf("failed to set value %s for key %s", apr.String(), cfg.Storage.APRKey) } + if err := storage.SetInt64Value(cfg.Storage.APRHeightKey, latestBlockHeight); err != nil { + return fmt.Errorf("failed to set value %d for key %s", latestBlockHeight, cfg.Storage.APRHeightKey) + } + annualProvisions := mintAmountInt.ToDec().MulInt64(12) if err := storage.SetValue(cfg.Storage.AnnualProvisionsKey, annualProvisions.String()); err != nil { diff --git a/internal/tasks/inflation.go b/internal/tasks/inflation.go index 17ba2bf..739325f 100644 --- a/internal/tasks/inflation.go +++ b/internal/tasks/inflation.go @@ -73,6 +73,10 @@ func getCalculateInflationHandler(genesisState cudoMintTypes.GenesisState, cfg c return fmt.Errorf("failed to set value %s for key %s", inflation.String(), cfg.Storage.InflationKey) } + if err := storage.SetInt64Value(cfg.Storage.InflationHeightKey, latestCudosBlock); err != nil { + return fmt.Errorf("failed to set value %d for key %s", latestCudosBlock, cfg.Storage.InflationHeightKey) + } + ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*10) defer cancelFunc() @@ -100,6 +104,10 @@ func getCalculateInflationHandler(genesisState cudoMintTypes.GenesisState, cfg c return fmt.Errorf("failed to set value %s for key %s", currentTotalSupply.String(), cfg.Storage.SupplyKey) } + if err := storage.SetInt64Value(cfg.Storage.SupplyHeightKey, latestCudosBlock); err != nil { + return fmt.Errorf("failed to set value %d for key %s", latestCudosBlock, cfg.Storage.SupplyHeightKey) + } + return nil } } diff --git a/internal/tasks/tasks.go b/internal/tasks/tasks.go index b03205d..21b4c41 100644 --- a/internal/tasks/tasks.go +++ b/internal/tasks/tasks.go @@ -204,6 +204,7 @@ const maxSupply = "10000000000000000000000000000" // 10 billion type keyValueStorage interface { SetValue(key, value string) error + SetInt64Value(key string, value int64) error GetOrDefaultValue(key, defaultValue string) (string, error) }