Skip to content

Commit

Permalink
Merge 32f7133 into 66f5613
Browse files Browse the repository at this point in the history
  • Loading branch information
sstanculeanu committed Jun 20, 2023
2 parents 66f5613 + 32f7133 commit 8fc476c
Show file tree
Hide file tree
Showing 39 changed files with 706 additions and 49 deletions.
6 changes: 6 additions & 0 deletions api/errors/errors.go
Expand Up @@ -165,3 +165,9 @@ var ErrInvalidRole = errors.New("invalid role")

// ErrIsDataTrieMigrated signals that an error occurred while trying to verify the migration status of the data trie
var ErrIsDataTrieMigrated = errors.New("could not verify the migration status of the data trie")

// ErrGetEligibleManagedKeys signals that an error occurred while getting the eligible managed keys
var ErrGetEligibleManagedKeys = errors.New("error getting the eligible managed keys")

// ErrGetWaitingManagedKeys signals that an error occurred while getting the waiting managed keys
var ErrGetWaitingManagedKeys = errors.New("error getting the waiting managed keys")
70 changes: 70 additions & 0 deletions api/groups/nodeGroup.go
Expand Up @@ -27,6 +27,9 @@ const (
epochStartDataForEpoch = "/epoch-start/:epoch"
bootstrapStatusPath = "/bootstrapstatus"
connectedPeersRatingsPath = "/connected-peers-ratings"
managedKeysCount = "/managed-keys/count"
eligibleManagedKeys = "/managed-keys/eligible"
waitingManagedKeys = "/managed-keys/waiting"
)

// nodeFacadeHandler defines the methods to be implemented by a facade for node requests
Expand All @@ -37,6 +40,9 @@ type nodeFacadeHandler interface {
GetEpochStartDataAPI(epoch uint32) (*common.EpochStartDataAPI, error)
GetPeerInfo(pid string) ([]core.QueryP2PPeerInfo, error)
GetConnectedPeersRatings() string
GetManagedKeysCount() int
GetEligibleManagedKeys() ([]string, error)
GetWaitingManagedKeys() ([]string, error)
IsInterfaceNil() bool
}

Expand Down Expand Up @@ -109,6 +115,21 @@ func NewNodeGroup(facade nodeFacadeHandler) (*nodeGroup, error) {
Method: http.MethodGet,
Handler: ng.connectedPeersRatings,
},
{
Path: managedKeysCount,
Method: http.MethodGet,
Handler: ng.managedKeysCount,
},
{
Path: eligibleManagedKeys,
Method: http.MethodGet,
Handler: ng.managedKeysEligible,
},
{
Path: waitingManagedKeys,
Method: http.MethodGet,
Handler: ng.managedKeysWaiting,
},
}
ng.endpoints = endpoints

Expand Down Expand Up @@ -338,6 +359,55 @@ func (ng *nodeGroup) connectedPeersRatings(c *gin.Context) {
)
}

// managedKeysCount returns the node's number of managed keys
func (ng *nodeGroup) managedKeysCount(c *gin.Context) {
count := ng.getFacade().GetManagedKeysCount()
c.JSON(
http.StatusOK,
shared.GenericAPIResponse{
Data: gin.H{"count": count},
Error: "",
Code: shared.ReturnCodeSuccess,
},
)
}

// managedKeysEligible returns the node's eligible managed keys
func (ng *nodeGroup) managedKeysEligible(c *gin.Context) {
keys, err := ng.getFacade().GetEligibleManagedKeys()
if err != nil {
shared.RespondWithInternalError(c, errors.ErrGetEligibleManagedKeys, err)
return
}

c.JSON(
http.StatusOK,
shared.GenericAPIResponse{
Data: gin.H{"eligibleKeys": keys},
Error: "",
Code: shared.ReturnCodeSuccess,
},
)
}

// managedKeysWaiting returns the node's waiting managed keys
func (ng *nodeGroup) managedKeysWaiting(c *gin.Context) {
keys, err := ng.getFacade().GetWaitingManagedKeys()
if err != nil {
shared.RespondWithInternalError(c, errors.ErrGetWaitingManagedKeys, err)
return
}

c.JSON(
http.StatusOK,
shared.GenericAPIResponse{
Data: gin.H{"waitingKeys": keys},
Error: "",
Code: shared.ReturnCodeSuccess,
},
)
}

func (ng *nodeGroup) getFacade() nodeFacadeHandler {
ng.mutFacade.RLock()
defer ng.mutFacade.RUnlock()
Expand Down
169 changes: 169 additions & 0 deletions api/groups/nodeGroup_test.go
Expand Up @@ -68,6 +68,27 @@ type epochStartResponse struct {
generalResponse
}

type managedKeysCountResponse struct {
Data struct {
Count int `json:"count"`
} `json:"data"`
generalResponse
}

type managedEligibleKeysResponse struct {
Data struct {
Keys []string `json:"eligibleKeys"`
} `json:"data"`
generalResponse
}

type managedWaitingKeysResponse struct {
Data struct {
Keys []string `json:"waitingKeys"`
} `json:"data"`
generalResponse
}

func init() {
gin.SetMode(gin.TestMode)
}
Expand Down Expand Up @@ -651,6 +672,151 @@ func TestPrometheusMetrics_ShouldWork(t *testing.T) {
assert.True(t, keyAndValueFoundInResponse)
}

func TestNodeGroup_ManagedKeysCount(t *testing.T) {
t.Parallel()

providedCount := 1000
facade := mock.FacadeStub{
GetManagedKeysCountCalled: func() int {
return providedCount
},
}

nodeGroup, err := groups.NewNodeGroup(&facade)
require.NoError(t, err)

ws := startWebServer(nodeGroup, "node", getNodeRoutesConfig())

req, _ := http.NewRequest("GET", "/node/managed-keys/count", nil)
resp := httptest.NewRecorder()
ws.ServeHTTP(resp, req)

response := &managedKeysCountResponse{}
loadResponse(resp.Body, response)

assert.Equal(t, http.StatusOK, resp.Code)
assert.Equal(t, "", response.Error)
assert.Equal(t, providedCount, response.Data.Count)
}

func TestNodeGroup_ManagedKeysEligible(t *testing.T) {
t.Parallel()

t.Run("facade error should error", func(t *testing.T) {
t.Parallel()

facade := mock.FacadeStub{
GetEligibleManagedKeysCalled: func() ([]string, error) {
return nil, expectedErr
},
}

nodeGroup, err := groups.NewNodeGroup(&facade)
require.NoError(t, err)

ws := startWebServer(nodeGroup, "node", getNodeRoutesConfig())

req, _ := http.NewRequest("GET", "/node/managed-keys/eligible", nil)
resp := httptest.NewRecorder()
ws.ServeHTTP(resp, req)

response := &shared.GenericAPIResponse{}
loadResponse(resp.Body, response)

assert.Equal(t, http.StatusInternalServerError, resp.Code)
assert.True(t, strings.Contains(response.Error, expectedErr.Error()))
})
t.Run("should work", func(t *testing.T) {
t.Parallel()

providedKeys := []string{
"key1",
"key2",
"key3",
}
facade := mock.FacadeStub{
GetEligibleManagedKeysCalled: func() ([]string, error) {
return providedKeys, nil
},
}

nodeGroup, err := groups.NewNodeGroup(&facade)
require.NoError(t, err)

ws := startWebServer(nodeGroup, "node", getNodeRoutesConfig())

req, _ := http.NewRequest("GET", "/node/managed-keys/eligible", nil)
resp := httptest.NewRecorder()
ws.ServeHTTP(resp, req)

response := &managedEligibleKeysResponse{}
loadResponse(resp.Body, response)

assert.Equal(t, http.StatusOK, resp.Code)
assert.Equal(t, "", response.Error)
assert.Equal(t, providedKeys, response.Data.Keys)
})
}

func TestNodeGroup_ManagedKeysWaiting(t *testing.T) {
t.Parallel()

t.Run("facade error should error", func(t *testing.T) {
t.Parallel()

facade := mock.FacadeStub{
GetWaitingManagedKeysCalled: func() ([]string, error) {
return nil, expectedErr
},
}

nodeGroup, err := groups.NewNodeGroup(&facade)
require.NoError(t, err)

ws := startWebServer(nodeGroup, "node", getNodeRoutesConfig())

req, _ := http.NewRequest("GET", "/node/managed-keys/waiting", nil)
resp := httptest.NewRecorder()
ws.ServeHTTP(resp, req)

response := &shared.GenericAPIResponse{}
loadResponse(resp.Body, response)

assert.Equal(t, http.StatusInternalServerError, resp.Code)
assert.True(t, strings.Contains(response.Error, expectedErr.Error()))
})
t.Run("should work", func(t *testing.T) {
t.Parallel()

providedKeys := []string{
"key1",
"key2",
"key3",
}
facade := mock.FacadeStub{
GetWaitingManagedKeysCalled: func() ([]string, error) {
return providedKeys, nil
},
}

nodeGroup, err := groups.NewNodeGroup(&facade)
require.NoError(t, err)

ws := startWebServer(nodeGroup, "node", getNodeRoutesConfig())

req, _ := http.NewRequest("GET", "/node/managed-keys/waiting", nil)
resp := httptest.NewRecorder()
ws.ServeHTTP(resp, req)

response := &managedWaitingKeysResponse{}
loadResponse(resp.Body, response)

assert.Equal(t, http.StatusOK, resp.Code)
assert.Equal(t, "", response.Error)
assert.Equal(t, providedKeys, response.Data.Keys)
})
}

func TestNodeGroup_UpdateFacade(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -758,6 +924,9 @@ func getNodeRoutesConfig() config.ApiRoutesConfig {
{Name: "/epoch-start/:epoch", Open: true},
{Name: "/bootstrapstatus", Open: true},
{Name: "/connected-peers-ratings", Open: true},
{Name: "/managed-keys/count", Open: true},
{Name: "/managed-keys/eligible", Open: true},
{Name: "/managed-keys/waiting", Open: true},
},
},
},
Expand Down
27 changes: 27 additions & 0 deletions api/mock/facadeStub.go
Expand Up @@ -88,6 +88,9 @@ type FacadeStub struct {
PprofEnabledCalled func() bool
DecodeAddressPubkeyCalled func(pk string) ([]byte, error)
IsDataTrieMigratedCalled func(address string, options api.AccountQueryOptions) (bool, error)
GetManagedKeysCountCalled func() int
GetEligibleManagedKeysCalled func() ([]string, error)
GetWaitingManagedKeysCalled func() ([]string, error)
}

// GetTokenSupply -
Expand Down Expand Up @@ -573,6 +576,30 @@ func (f *FacadeStub) IsSelfTrigger() bool {
return false
}

// GetManagedKeysCount -
func (f *FacadeStub) GetManagedKeysCount() int {
if f.GetManagedKeysCountCalled != nil {
return f.GetManagedKeysCountCalled()
}
return 0
}

// GetEligibleManagedKeys -
func (f *FacadeStub) GetEligibleManagedKeys() ([]string, error) {
if f.GetEligibleManagedKeysCalled != nil {
return f.GetEligibleManagedKeysCalled()
}
return make([]string, 0), nil
}

// GetWaitingManagedKeys -
func (f *FacadeStub) GetWaitingManagedKeys() ([]string, error) {
if f.GetWaitingManagedKeysCalled != nil {
return f.GetWaitingManagedKeysCalled()
}
return make([]string, 0), nil
}

// Close -
func (f *FacadeStub) Close() error {
return nil
Expand Down
3 changes: 3 additions & 0 deletions api/shared/interface.go
Expand Up @@ -127,5 +127,8 @@ type FacadeHandler interface {
GetLastPoolNonceForSender(sender string) (uint64, error)
GetTransactionsPoolNonceGapsForSender(sender string) (*common.TransactionsPoolNonceGapsForSenderApiResponse, error)
IsDataTrieMigrated(address string, options api.AccountQueryOptions) (bool, error)
GetManagedKeysCount() int
GetEligibleManagedKeys() ([]string, error)
GetWaitingManagedKeys() ([]string, error)
IsInterfaceNil() bool
}
11 changes: 10 additions & 1 deletion cmd/node/config/api.toml
Expand Up @@ -38,7 +38,16 @@
{ Name = "/bootstrapstatus", Open = true },

# /node/connected-peers-ratings will return the peers ratings
{ Name = "/connected-peers-ratings", Open = true }
{ Name = "/connected-peers-ratings", Open = true },

# /node/managed-keys/count will return the number of keys managed by the node
{ Name = "/managed-keys/count", Open = true },

# /node/managed-keys/eligible will return the eligible keys managed by the node on the current epoch
{ Name = "/managed-keys/eligible", Open = true },

# /node/managed-keys/waiting will return the waiting keys managed by the node on the current epoch
{ Name = "/managed-keys/waiting", Open = true }
]

[APIPackages.address]
Expand Down
4 changes: 2 additions & 2 deletions common/interface.go
Expand Up @@ -430,7 +430,7 @@ type StateSyncNotifierSubscriber interface {
// ManagedPeersMonitor defines the operations of an entity that monitors the managed peers holder
type ManagedPeersMonitor interface {
GetManagedKeysCount() int
GetEligibleManagedKeys(epoch uint32) ([][]byte, error)
GetWaitingManagedKeys(epoch uint32) ([][]byte, error)
GetEligibleManagedKeys() ([][]byte, error)
GetWaitingManagedKeys() ([][]byte, error)
IsInterfaceNil() bool
}
4 changes: 2 additions & 2 deletions errors/errors.go
Expand Up @@ -532,8 +532,8 @@ var ErrNilGenesisNodesSetupHandler = errors.New("nil genesis nodes setup handler
// ErrNilManagedPeersHolder signals that a nil managed peers holder has been provided
var ErrNilManagedPeersHolder = errors.New("nil managed peers holder")

// ErrEmptyPeerID signals that an empty peer ID has been provided
var ErrEmptyPeerID = errors.New("empty peer ID")
// ErrNilManagedPeersMonitor signals that a nil managed peers monitor has been provided
var ErrNilManagedPeersMonitor = errors.New("nil managed peers monitor")

// ErrNilPeersRatingHandler signals that a nil peers rating handler implementation has been provided
var ErrNilPeersRatingHandler = errors.New("nil peers rating handler")
Expand Down

0 comments on commit 8fc476c

Please sign in to comment.