From 171d3111603a5e22f0a1355f427c1db48aa0eb0e Mon Sep 17 00:00:00 2001 From: Marius C Date: Fri, 17 Feb 2023 15:14:05 +0200 Subject: [PATCH 1/6] FEAT: Add AuctionList api interfaces --- README.md | 1 + api/groups/baseValidatorGroup.go | 11 +++++++++++ api/groups/interface.go | 1 + api/mock/facadeStub.go | 5 +++++ cmd/proxy/config/apiConfig/v1_0.toml | 3 ++- cmd/proxy/config/apiConfig/v_next.toml | 3 ++- data/auctionList.go | 17 +++++++++++++++++ facade/baseFacade.go | 5 +++++ facade/interface.go | 1 + facade/mock/accountProccessorStub.go | 5 +++++ facade/mock/validatorStatisticsProcessorStub.go | 5 +++++ process/validatorStatisticsProcessor.go | 4 ++++ 12 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 data/auctionList.go diff --git a/README.md b/README.md index be3f5439..234dec93 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ For more details, go [here](https://docs.multiversx.com/sdk-and-tools/proxy/). ### validator - `/v1.0/validator/statistics` (GET) --> returns the validator statistics data from an observer from any shard. Has a cache to avoid many requests +- `/v1.0/validator/auction` (GET) --> returns the validator auction list data from an observer from metachain. Has a cache to avoid many requests ### block diff --git a/api/groups/baseValidatorGroup.go b/api/groups/baseValidatorGroup.go index cb1a6409..c3d7a200 100644 --- a/api/groups/baseValidatorGroup.go +++ b/api/groups/baseValidatorGroup.go @@ -27,6 +27,7 @@ func NewValidatorGroup(facadeHandler data.FacadeHandler) (*validatorGroup, error baseRoutesHandlers := []*data.EndpointHandlerData{ {Path: "/statistics", Handler: vg.statistics, Method: http.MethodGet}, + {Path: "/auction", Handler: vg.auctionList, Method: http.MethodGet}, } vg.baseGroup.endpoints = baseRoutesHandlers @@ -43,3 +44,13 @@ func (group *validatorGroup) statistics(c *gin.Context) { shared.RespondWith(c, http.StatusOK, gin.H{"statistics": validatorStatistics}, "", data.ReturnCodeSuccess) } + +func (group *validatorGroup) auctionList(c *gin.Context) { + auctionList, err := group.facade.ValidatorStatistics() + if err != nil { + shared.RespondWith(c, http.StatusBadRequest, nil, err.Error(), data.ReturnCodeRequestError) + return + } + + shared.RespondWith(c, http.StatusOK, gin.H{"auction": auctionList}, "", data.ReturnCodeSuccess) +} diff --git a/api/groups/interface.go b/api/groups/interface.go index 1af0fac5..a64ec0ca 100644 --- a/api/groups/interface.go +++ b/api/groups/interface.go @@ -116,6 +116,7 @@ type ProofFacadeHandler interface { // ValidatorFacadeHandler interface defines methods that can be used from the facade type ValidatorFacadeHandler interface { ValidatorStatistics() (map[string]*data.ValidatorApiResponse, error) + AuctionList() ([]*data.AuctionListValidatorAPIResponse, error) } // VmValuesFacadeHandler interface defines methods that can be used from the facade diff --git a/api/mock/facadeStub.go b/api/mock/facadeStub.go index c8c1355c..ef83d2b3 100644 --- a/api/mock/facadeStub.go +++ b/api/mock/facadeStub.go @@ -247,6 +247,11 @@ func (f *FacadeStub) ValidatorStatistics() (map[string]*data.ValidatorApiRespons return f.ValidatorStatisticsHandler() } +// AuctionList - +func (f *FacadeStub) AuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { + return nil, nil +} + // GetAccount - func (f *FacadeStub) GetAccount(address string, options common.AccountQueryOptions) (*data.AccountModel, error) { return f.GetAccountHandler(address, options) diff --git a/cmd/proxy/config/apiConfig/v1_0.toml b/cmd/proxy/config/apiConfig/v1_0.toml index 89d384d2..da29b3f8 100644 --- a/cmd/proxy/config/apiConfig/v1_0.toml +++ b/cmd/proxy/config/apiConfig/v1_0.toml @@ -73,7 +73,8 @@ Routes = [ [APIPackages.validator] Routes = [ - { Name = "/statistics", Open = true, Secured = false, RateLimit = 0 } + { Name = "/statistics", Open = true, Secured = false, RateLimit = 0 }, + { Name = "/auction", Open = true, Secured = false, RateLimit = 0 } ] [APIPackages.vm-values] diff --git a/cmd/proxy/config/apiConfig/v_next.toml b/cmd/proxy/config/apiConfig/v_next.toml index d18d693c..acf54938 100644 --- a/cmd/proxy/config/apiConfig/v_next.toml +++ b/cmd/proxy/config/apiConfig/v_next.toml @@ -73,7 +73,8 @@ Routes = [ [APIPackages.validator] Routes = [ - { Name = "/statistics", Open = true, Secured = false, RateLimit = 0 } + { Name = "/statistics", Open = true, Secured = false, RateLimit = 0 }, + { Name = "/auction", Open = true, Secured = false, RateLimit = 0 } ] [APIPackages.vm-values] diff --git a/data/auctionList.go b/data/auctionList.go new file mode 100644 index 00000000..cd64e807 --- /dev/null +++ b/data/auctionList.go @@ -0,0 +1,17 @@ +package data + +// AuctionNode holds data needed for a node in auction to respond to API calls +type AuctionNode struct { + BlsKey string `json:"blsKey"` + Qualified bool `json:"qualified"` +} + +// AuctionListValidatorAPIResponse holds the data needed for an auction node validator for responding to API calls +type AuctionListValidatorAPIResponse struct { + Owner string `json:"owner"` + NumStakedNodes int64 `json:"numStakedNodes"` + TotalTopUp string `json:"totalTopUp"` + TopUpPerNode string `json:"topUpPerNode"` + QualifiedTopUp string `json:"qualifiedTopUp"` + AuctionList []*AuctionNode `json:"auctionList"` +} diff --git a/facade/baseFacade.go b/facade/baseFacade.go index 131cf5f9..59628cec 100644 --- a/facade/baseFacade.go +++ b/facade/baseFacade.go @@ -396,6 +396,11 @@ func (epf *ProxyFacade) ValidatorStatistics() (map[string]*data.ValidatorApiResp return valStats.Statistics, nil } +// AuctionList will return the auction list +func (epf *ProxyFacade) AuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { + return epf.valStatsProc.GetAuctionList() +} + // GetAtlasBlockByShardIDAndNonce returns block by shardID and nonce in a BlockAtlas-friendly-format func (epf *ProxyFacade) GetAtlasBlockByShardIDAndNonce(shardID uint32, nonce uint64) (data.AtlasBlock, error) { return epf.blockProc.GetAtlasBlockByShardIDAndNonce(shardID, nonce) diff --git a/facade/interface.go b/facade/interface.go index 7de8652d..87ce559e 100644 --- a/facade/interface.go +++ b/facade/interface.go @@ -71,6 +71,7 @@ type NodeGroupProcessor interface { // ValidatorStatisticsProcessor defines what a validator statistics processor should do type ValidatorStatisticsProcessor interface { GetValidatorStatistics() (*data.ValidatorStatisticsResponse, error) + GetAuctionList() ([]*data.AuctionListValidatorAPIResponse, error) } // ESDTSupplyProcessor defines what an esdt supply processor should do diff --git a/facade/mock/accountProccessorStub.go b/facade/mock/accountProccessorStub.go index 20b2bb28..9e41b7c2 100644 --- a/facade/mock/accountProccessorStub.go +++ b/facade/mock/accountProccessorStub.go @@ -90,3 +90,8 @@ func (aps *AccountProcessorStub) GetCodeHash(address string, options common.Acco func (aps *AccountProcessorStub) ValidatorStatistics() (map[string]*data.ValidatorApiResponse, error) { return aps.ValidatorStatisticsCalled() } + +// AuctionList - +func (aps *AccountProcessorStub) AuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { + return nil, nil +} diff --git a/facade/mock/validatorStatisticsProcessorStub.go b/facade/mock/validatorStatisticsProcessorStub.go index 7d65c22b..b2914322 100644 --- a/facade/mock/validatorStatisticsProcessorStub.go +++ b/facade/mock/validatorStatisticsProcessorStub.go @@ -11,3 +11,8 @@ type ValidatorStatisticsProcessorStub struct { func (v *ValidatorStatisticsProcessorStub) GetValidatorStatistics() (*data.ValidatorStatisticsResponse, error) { return v.GetValidatorStatisticsCalled() } + +// GetAuctionList - +func (v *ValidatorStatisticsProcessorStub) GetAuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { + return nil, nil +} diff --git a/process/validatorStatisticsProcessor.go b/process/validatorStatisticsProcessor.go index b9fe2d8c..64db056c 100644 --- a/process/validatorStatisticsProcessor.go +++ b/process/validatorStatisticsProcessor.go @@ -119,6 +119,10 @@ func (vsp *ValidatorStatisticsProcessor) handleCacheUpdate() { } } +func (vsp *ValidatorStatisticsProcessor) GetAuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { + return nil, nil +} + // Close will handle the closing of the cache update go routine func (vsp *ValidatorStatisticsProcessor) Close() error { if vsp.cancelFunc != nil { From df49f9861cb32497378f3e78160983eee7c86cb9 Mon Sep 17 00:00:00 2001 From: Marius C Date: Fri, 17 Feb 2023 17:40:37 +0200 Subject: [PATCH 2/6] FEAT: Get AuctionList from observers without cache --- api/groups/baseValidatorGroup.go | 2 +- data/auctionList.go | 12 +++++++ facade/baseFacade.go | 7 +++- facade/interface.go | 2 +- .../mock/validatorStatisticsProcessorStub.go | 2 +- process/errors.go | 3 ++ process/validatorStatisticsProcessor.go | 5 +-- .../validatorStatisticsProcessorAuction.go | 32 +++++++++++++++++++ 8 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 process/validatorStatisticsProcessorAuction.go diff --git a/api/groups/baseValidatorGroup.go b/api/groups/baseValidatorGroup.go index c3d7a200..1535d597 100644 --- a/api/groups/baseValidatorGroup.go +++ b/api/groups/baseValidatorGroup.go @@ -46,7 +46,7 @@ func (group *validatorGroup) statistics(c *gin.Context) { } func (group *validatorGroup) auctionList(c *gin.Context) { - auctionList, err := group.facade.ValidatorStatistics() + auctionList, err := group.facade.AuctionList() if err != nil { shared.RespondWith(c, http.StatusBadRequest, nil, err.Error(), data.ReturnCodeRequestError) return diff --git a/data/auctionList.go b/data/auctionList.go index cd64e807..76d33e14 100644 --- a/data/auctionList.go +++ b/data/auctionList.go @@ -15,3 +15,15 @@ type AuctionListValidatorAPIResponse struct { QualifiedTopUp string `json:"qualifiedTopUp"` AuctionList []*AuctionNode `json:"auctionList"` } + +// AuctionListResponse respects the format the auction list api response received from the observers +type AuctionListResponse struct { + AuctionListValidators []*AuctionListValidatorAPIResponse `json:"auctionList"` +} + +// AuctionListAPIResponse respects the format the auction list received from the observers +type AuctionListAPIResponse struct { + Data AuctionListResponse `json:"data"` + Error string `json:"error"` + Code string `json:"code"` +} diff --git a/facade/baseFacade.go b/facade/baseFacade.go index 59628cec..6b6fff22 100644 --- a/facade/baseFacade.go +++ b/facade/baseFacade.go @@ -398,7 +398,12 @@ func (epf *ProxyFacade) ValidatorStatistics() (map[string]*data.ValidatorApiResp // AuctionList will return the auction list func (epf *ProxyFacade) AuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { - return epf.valStatsProc.GetAuctionList() + auctionList, err := epf.valStatsProc.GetAuctionList() + if err != nil { + return nil, err + } + + return auctionList.AuctionListValidators, nil } // GetAtlasBlockByShardIDAndNonce returns block by shardID and nonce in a BlockAtlas-friendly-format diff --git a/facade/interface.go b/facade/interface.go index 87ce559e..47dd99ec 100644 --- a/facade/interface.go +++ b/facade/interface.go @@ -71,7 +71,7 @@ type NodeGroupProcessor interface { // ValidatorStatisticsProcessor defines what a validator statistics processor should do type ValidatorStatisticsProcessor interface { GetValidatorStatistics() (*data.ValidatorStatisticsResponse, error) - GetAuctionList() ([]*data.AuctionListValidatorAPIResponse, error) + GetAuctionList() (*data.AuctionListResponse, error) } // ESDTSupplyProcessor defines what an esdt supply processor should do diff --git a/facade/mock/validatorStatisticsProcessorStub.go b/facade/mock/validatorStatisticsProcessorStub.go index b2914322..9a0b8e52 100644 --- a/facade/mock/validatorStatisticsProcessorStub.go +++ b/facade/mock/validatorStatisticsProcessorStub.go @@ -13,6 +13,6 @@ func (v *ValidatorStatisticsProcessorStub) GetValidatorStatistics() (*data.Valid } // GetAuctionList - -func (v *ValidatorStatisticsProcessorStub) GetAuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { +func (v *ValidatorStatisticsProcessorStub) GetAuctionList() (*data.AuctionListResponse, error) { return nil, nil } diff --git a/process/errors.go b/process/errors.go index e5f1ddbc..b43f0f16 100644 --- a/process/errors.go +++ b/process/errors.go @@ -38,6 +38,9 @@ var ErrNilEconomicMetricsCacher = errors.New("nil economic metrics cacher") // ErrValidatorStatisticsNotAvailable signals that the validator statistics data is not found var ErrValidatorStatisticsNotAvailable = errors.New("validator statistics data not found at any observer") +// ErrAuctionListNotAvailable signals that the auction list data is not found +var ErrAuctionListNotAvailable = errors.New("auction list data not found at any observer") + // ErrInvalidCacheValidityDuration signals that the given validity duration for cache data is invalid var ErrInvalidCacheValidityDuration = errors.New("invalid cache validity duration") diff --git a/process/validatorStatisticsProcessor.go b/process/validatorStatisticsProcessor.go index 64db056c..85f41a92 100644 --- a/process/validatorStatisticsProcessor.go +++ b/process/validatorStatisticsProcessor.go @@ -11,6 +11,7 @@ import ( // ValidatorStatisticsPath represents the path where an observer exposes his validator statistics data const ValidatorStatisticsPath = "/validator/statistics" +const auctionListPath = "/validator/auction" // ValidatorStatisticsProcessor is able to process validator statistics data requests type ValidatorStatisticsProcessor struct { @@ -119,10 +120,6 @@ func (vsp *ValidatorStatisticsProcessor) handleCacheUpdate() { } } -func (vsp *ValidatorStatisticsProcessor) GetAuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { - return nil, nil -} - // Close will handle the closing of the cache update go routine func (vsp *ValidatorStatisticsProcessor) Close() error { if vsp.cancelFunc != nil { diff --git a/process/validatorStatisticsProcessorAuction.go b/process/validatorStatisticsProcessorAuction.go new file mode 100644 index 00000000..6d91e286 --- /dev/null +++ b/process/validatorStatisticsProcessorAuction.go @@ -0,0 +1,32 @@ +package process + +import ( + "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-proxy-go/data" +) + +func (vsp *ValidatorStatisticsProcessor) GetAuctionList() (*data.AuctionListResponse, error) { + // TODO: Here, in next PR, add cacher and get list from cache + + return vsp.getAuctionListFromApi() +} + +func (vsp *ValidatorStatisticsProcessor) getAuctionListFromApi() (*data.AuctionListResponse, error) { + observers, errFetchObs := vsp.proc.GetObservers(core.MetachainShardId) + if errFetchObs != nil { + return nil, errFetchObs + } + + var valStatsResponse data.AuctionListAPIResponse + for _, observer := range observers { + _, err := vsp.proc.CallGetRestEndPoint(observer.Address, auctionListPath, &valStatsResponse) + if err == nil { + log.Info("auction list fetched from API", "observer", observer.Address) + return &valStatsResponse.Data, nil + } + + log.Error("auction list", "observer", observer.Address, "error", "no response") + } + + return nil, ErrAuctionListNotAvailable +} From a9c1d3306d8756a0d67f24ca5a0c956958d17c1c Mon Sep 17 00:00:00 2001 From: Marius C Date: Mon, 20 Feb 2023 12:08:22 +0200 Subject: [PATCH 3/6] FEAT: Full branch coverage unit tests in validatorAuctionProcessor_test.go --- ...uction.go => validatorAuctionProcessor.go} | 2 +- process/validatorAuctionProcessor_test.go | 118 ++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) rename process/{validatorStatisticsProcessorAuction.go => validatorAuctionProcessor.go} (90%) create mode 100644 process/validatorAuctionProcessor_test.go diff --git a/process/validatorStatisticsProcessorAuction.go b/process/validatorAuctionProcessor.go similarity index 90% rename from process/validatorStatisticsProcessorAuction.go rename to process/validatorAuctionProcessor.go index 6d91e286..c331d339 100644 --- a/process/validatorStatisticsProcessorAuction.go +++ b/process/validatorAuctionProcessor.go @@ -25,7 +25,7 @@ func (vsp *ValidatorStatisticsProcessor) getAuctionListFromApi() (*data.AuctionL return &valStatsResponse.Data, nil } - log.Error("auction list", "observer", observer.Address, "error", "no response") + log.Error("getAuctionListFromApi", "observer", observer.Address, "error", "no response") } return nil, ErrAuctionListNotAvailable diff --git a/process/validatorAuctionProcessor_test.go b/process/validatorAuctionProcessor_test.go new file mode 100644 index 00000000..5c26f30d --- /dev/null +++ b/process/validatorAuctionProcessor_test.go @@ -0,0 +1,118 @@ +package process + +import ( + "encoding/json" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-proxy-go/data" + "github.com/multiversx/mx-chain-proxy-go/process/mock" + "github.com/stretchr/testify/require" +) + +func TestValidatorStatisticsProcessor_GetAuctionList(t *testing.T) { + t.Parallel() + + t.Run("should work", func(t *testing.T) { + t.Parallel() + + node := &data.NodeData{ + Address: "addr", + ShardId: core.MetachainShardId, + } + expectedResp := &data.AuctionListAPIResponse{ + Data: data.AuctionListResponse{ + AuctionListValidators: []*data.AuctionListValidatorAPIResponse{ + { + Owner: "owner", + NumStakedNodes: 4, + TotalTopUp: "100", + TopUpPerNode: "50", + QualifiedTopUp: "50", + }, + }, + }, + Error: "", + Code: "ok", + } + expectedRespMarshalled, err := json.Marshal(expectedResp) + require.Nil(t, err) + + processor := &mock.ProcessorStub{ + GetObserversCalled: func(shardId uint32) ([]*data.NodeData, error) { + require.Equal(t, core.MetachainShardId, shardId) + + return []*data.NodeData{node}, nil + }, + CallGetRestEndPointCalled: func(address string, path string, value interface{}) (int, error) { + require.Equal(t, node.Address, address) + require.Equal(t, auctionListPath, path) + + err = json.Unmarshal(expectedRespMarshalled, value) + require.Nil(t, err) + return 0, nil + }, + } + vsp, _ := NewValidatorStatisticsProcessor(processor, &mock.ValStatsCacherMock{}, time.Second) + resp, err := vsp.GetAuctionList() + require.Nil(t, err) + require.Equal(t, expectedResp.Data, *resp) + }) + + t.Run("get observers failed, should return error", func(t *testing.T) { + t.Parallel() + + errGetObservers := errors.New("err getting observers") + callGetRestEndPointCalledCt := int32(0) + + processor := &mock.ProcessorStub{ + GetObserversCalled: func(shardId uint32) ([]*data.NodeData, error) { + require.Equal(t, core.MetachainShardId, shardId) + return nil, errGetObservers + }, + CallGetRestEndPointCalled: func(address string, path string, value interface{}) (int, error) { + atomic.AddInt32(&callGetRestEndPointCalledCt, 1) + + return 0, nil + }, + } + vsp, _ := NewValidatorStatisticsProcessor(processor, &mock.ValStatsCacherMock{}, time.Second) + + resp, err := vsp.GetAuctionList() + require.Equal(t, errGetObservers, err) + require.Nil(t, resp) + require.Equal(t, int32(0), callGetRestEndPointCalledCt) + }) + + t.Run("could not get auction list from observer, should return error", func(t *testing.T) { + t.Parallel() + + node := &data.NodeData{ + Address: "addr", + ShardId: core.MetachainShardId, + } + + errCallEndpoint := errors.New("error call endpoint") + processor := &mock.ProcessorStub{ + GetObserversCalled: func(shardId uint32) ([]*data.NodeData, error) { + require.Equal(t, core.MetachainShardId, shardId) + + return []*data.NodeData{node}, nil + }, + CallGetRestEndPointCalled: func(address string, path string, value interface{}) (int, error) { + require.Equal(t, node.Address, address) + require.Equal(t, auctionListPath, path) + + return 0, errCallEndpoint + }, + } + vsp, _ := NewValidatorStatisticsProcessor(processor, &mock.ValStatsCacherMock{}, time.Second) + + resp, err := vsp.GetAuctionList() + require.Equal(t, ErrAuctionListNotAvailable, err) + require.Nil(t, resp) + }) +} From 3bf3d1a38c89b766a15a7e88c0f571e07a522d31 Mon Sep 17 00:00:00 2001 From: Marius C Date: Mon, 20 Feb 2023 13:08:23 +0200 Subject: [PATCH 4/6] FEAT: Unit tests for baseValidatorGroup.go --- api/groups/baseValidatorGroup.go | 2 +- api/groups/baseValidatorGroup_test.go | 70 +++++++++++++++++++++++++ api/mock/facadeStub.go | 11 +++- process/validatorStatisticsProcessor.go | 8 +-- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/api/groups/baseValidatorGroup.go b/api/groups/baseValidatorGroup.go index 1535d597..97017d8a 100644 --- a/api/groups/baseValidatorGroup.go +++ b/api/groups/baseValidatorGroup.go @@ -52,5 +52,5 @@ func (group *validatorGroup) auctionList(c *gin.Context) { return } - shared.RespondWith(c, http.StatusOK, gin.H{"auction": auctionList}, "", data.ReturnCodeSuccess) + shared.RespondWith(c, http.StatusOK, gin.H{"auctionList": auctionList}, "", data.ReturnCodeSuccess) } diff --git a/api/groups/baseValidatorGroup_test.go b/api/groups/baseValidatorGroup_test.go index e56bdbfc..02790a46 100644 --- a/api/groups/baseValidatorGroup_test.go +++ b/api/groups/baseValidatorGroup_test.go @@ -99,3 +99,73 @@ func TestValidatorStatistics_ShouldWork(t *testing.T) { assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, response.Data.Statistics["statistics"], valStatsMap["statistics"]) } + +func TestValidatorGroup_GetAuctionList(t *testing.T) { + t.Parallel() + + t.Run("should work", func(t *testing.T) { + t.Parallel() + + auctionList := []*data.AuctionListValidatorAPIResponse{ + { + Owner: "owner", + NumStakedNodes: 1, + TotalTopUp: "100", + TopUpPerNode: "100", + QualifiedTopUp: "50", + }, + } + facade := &mock.FacadeStub{ + AuctionListHandler: func() ([]*data.AuctionListValidatorAPIResponse, error) { + return auctionList, nil + }, + } + + validatorGroup, _ := groups.NewValidatorGroup(facade) + ws := startProxyServer(validatorGroup, validatorPath) + + req, _ := http.NewRequest("GET", "/validator/auction", nil) + resp := httptest.NewRecorder() + ws.ServeHTTP(resp, req) + + response := data.AuctionListAPIResponse{} + loadResponse(resp.Body, &response) + + require.Equal(t, http.StatusOK, resp.Code) + require.Equal(t, data.AuctionListAPIResponse{ + Data: data.AuctionListResponse{ + AuctionListValidators: auctionList, + }, + Error: "", + Code: string(data.ReturnCodeSuccess), + }, response) + }) + + t.Run("cannot get auction list from facade, should return error", func(t *testing.T) { + t.Parallel() + + errFacade := errors.New("error getting auction list") + facade := &mock.FacadeStub{ + AuctionListHandler: func() ([]*data.AuctionListValidatorAPIResponse, error) { + return nil, errFacade + }, + } + + validatorGroup, _ := groups.NewValidatorGroup(facade) + ws := startProxyServer(validatorGroup, validatorPath) + + req, _ := http.NewRequest("GET", "/validator/auction", nil) + resp := httptest.NewRecorder() + ws.ServeHTTP(resp, req) + + response := data.GenericAPIResponse{} + loadResponse(resp.Body, &response) + + require.Equal(t, http.StatusBadRequest, resp.Code) + require.Equal(t, data.GenericAPIResponse{ + Data: nil, + Error: errFacade.Error(), + Code: data.ReturnCodeRequestError, + }, response) + }) +} diff --git a/api/mock/facadeStub.go b/api/mock/facadeStub.go index ef83d2b3..1cb30a07 100644 --- a/api/mock/facadeStub.go +++ b/api/mock/facadeStub.go @@ -36,6 +36,7 @@ type FacadeStub struct { ExecuteSCQueryHandler func(query *data.SCQuery) (*vm.VMOutputApi, error) GetHeartbeatDataHandler func() (*data.HeartbeatResponse, error) ValidatorStatisticsHandler func() (map[string]*data.ValidatorApiResponse, error) + AuctionListHandler func() ([]*data.AuctionListValidatorAPIResponse, error) TransactionCostRequestHandler func(tx *data.Transaction) (*data.TxCostResponseData, error) GetTransactionStatusHandler func(txHash string, sender string) (string, error) GetConfigMetricsHandler func() (*data.GenericAPIResponse, error) @@ -244,11 +245,19 @@ func (f *FacadeStub) GetESDTSupply(token string) (*data.ESDTSupplyResponse, erro // ValidatorStatistics - func (f *FacadeStub) ValidatorStatistics() (map[string]*data.ValidatorApiResponse, error) { - return f.ValidatorStatisticsHandler() + if f.ValidatorStatisticsHandler != nil { + return f.ValidatorStatisticsHandler() + } + + return nil, nil } // AuctionList - func (f *FacadeStub) AuctionList() ([]*data.AuctionListValidatorAPIResponse, error) { + if f.AuctionListHandler != nil { + return f.AuctionListHandler() + } + return nil, nil } diff --git a/process/validatorStatisticsProcessor.go b/process/validatorStatisticsProcessor.go index 85f41a92..e98a56b6 100644 --- a/process/validatorStatisticsProcessor.go +++ b/process/validatorStatisticsProcessor.go @@ -9,9 +9,11 @@ import ( "github.com/multiversx/mx-chain-proxy-go/data" ) -// ValidatorStatisticsPath represents the path where an observer exposes his validator statistics data -const ValidatorStatisticsPath = "/validator/statistics" -const auctionListPath = "/validator/auction" +const ( + // ValidatorStatisticsPath represents the path where an observer exposes his validator statistics data + ValidatorStatisticsPath = "/validator/statistics" + auctionListPath = "/validator/auction" +) // ValidatorStatisticsProcessor is able to process validator statistics data requests type ValidatorStatisticsProcessor struct { From c25e3727b2fa20b1066a0d30df25d0fa989b3785 Mon Sep 17 00:00:00 2001 From: Marius C Date: Mon, 20 Feb 2023 13:24:26 +0200 Subject: [PATCH 5/6] FIX: Remove todo --- process/validatorAuctionProcessor.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/process/validatorAuctionProcessor.go b/process/validatorAuctionProcessor.go index c331d339..ac77ba20 100644 --- a/process/validatorAuctionProcessor.go +++ b/process/validatorAuctionProcessor.go @@ -6,12 +6,6 @@ import ( ) func (vsp *ValidatorStatisticsProcessor) GetAuctionList() (*data.AuctionListResponse, error) { - // TODO: Here, in next PR, add cacher and get list from cache - - return vsp.getAuctionListFromApi() -} - -func (vsp *ValidatorStatisticsProcessor) getAuctionListFromApi() (*data.AuctionListResponse, error) { observers, errFetchObs := vsp.proc.GetObservers(core.MetachainShardId) if errFetchObs != nil { return nil, errFetchObs From 309deee106afc623f9d76fe5c9dbb0c8c00914bf Mon Sep 17 00:00:00 2001 From: Marius C Date: Tue, 21 Feb 2023 12:55:58 +0200 Subject: [PATCH 6/6] FIX: After review --- README.md | 2 +- process/errors.go | 4 ++-- process/validatorAuctionProcessor.go | 1 + process/validatorStatisticsProcessor.go | 5 ++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 234dec93..bef3670e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ For more details, go [here](https://docs.multiversx.com/sdk-and-tools/proxy/). ### validator - `/v1.0/validator/statistics` (GET) --> returns the validator statistics data from an observer from any shard. Has a cache to avoid many requests -- `/v1.0/validator/auction` (GET) --> returns the validator auction list data from an observer from metachain. Has a cache to avoid many requests +- `/v1.0/validator/auction` (GET) --> returns the validator auction list data from an observer from metachain. It doesn't have a cache mechanism, since there is already one in place at the node level ### block diff --git a/process/errors.go b/process/errors.go index b43f0f16..88591863 100644 --- a/process/errors.go +++ b/process/errors.go @@ -36,10 +36,10 @@ var ErrNilValidatorStatisticsCacher = errors.New("nil validator statistics cache var ErrNilEconomicMetricsCacher = errors.New("nil economic metrics cacher") // ErrValidatorStatisticsNotAvailable signals that the validator statistics data is not found -var ErrValidatorStatisticsNotAvailable = errors.New("validator statistics data not found at any observer") +var ErrValidatorStatisticsNotAvailable = errors.New("validator statistics data not found on any observer") // ErrAuctionListNotAvailable signals that the auction list data is not found -var ErrAuctionListNotAvailable = errors.New("auction list data not found at any observer") +var ErrAuctionListNotAvailable = errors.New("auction list data not found on any observer") // ErrInvalidCacheValidityDuration signals that the given validity duration for cache data is invalid var ErrInvalidCacheValidityDuration = errors.New("invalid cache validity duration") diff --git a/process/validatorAuctionProcessor.go b/process/validatorAuctionProcessor.go index ac77ba20..864aff80 100644 --- a/process/validatorAuctionProcessor.go +++ b/process/validatorAuctionProcessor.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-proxy-go/data" ) +// GetAuctionList returns the auction list from a metachain observer node func (vsp *ValidatorStatisticsProcessor) GetAuctionList() (*data.AuctionListResponse, error) { observers, errFetchObs := vsp.proc.GetObservers(core.MetachainShardId) if errFetchObs != nil { diff --git a/process/validatorStatisticsProcessor.go b/process/validatorStatisticsProcessor.go index e98a56b6..a9dfff9c 100644 --- a/process/validatorStatisticsProcessor.go +++ b/process/validatorStatisticsProcessor.go @@ -10,8 +10,7 @@ import ( ) const ( - // ValidatorStatisticsPath represents the path where an observer exposes his validator statistics data - ValidatorStatisticsPath = "/validator/statistics" + validatorStatisticsPath = "/validator/statistics" auctionListPath = "/validator/auction" ) @@ -68,7 +67,7 @@ func (vsp *ValidatorStatisticsProcessor) getValidatorStatisticsFromApi() (*data. var valStatsResponse data.ValidatorStatisticsApiResponse var err error for _, observer := range observers { - _, err = vsp.proc.CallGetRestEndPoint(observer.Address, ValidatorStatisticsPath, &valStatsResponse) + _, err = vsp.proc.CallGetRestEndPoint(observer.Address, validatorStatisticsPath, &valStatsResponse) if err == nil { log.Info("validator statistics fetched from API", "observer", observer.Address) return &valStatsResponse.Data, nil