Skip to content

Commit

Permalink
fix: check if operator is allowed to join on msg execution (#16)
Browse files Browse the repository at this point in the history
## Description

This PR adds a missing check to make sure that an operator is allowed to
join a service while executing `MsgJoinService` messages.

<!-- Add a description of the changes that this PR introduces and the
files that
are the most critical to review. -->

---

### Author Checklist

*All items are required. Please add a note to the item if the item is
not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch (see [PR
Targeting](https://github.com/milkyway-labs/milkyway/blob/master/CONTRIBUTING.md#pr-targeting))
- [x] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building
modules](https://docs.cosmos.network/v0.44/building-modules/intro.html)
- [x] included the necessary unit and integration
[tests](https://github.com/milkyway-labs/milkyway/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go
code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [x] reviewed "Files changed" and left comments if necessary
- [x] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable
and please add
your handle next to the items reviewed if you only reviewed selected
items.*

I have...

- [ ] confirmed the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)

(cherry picked from commit f5815d3)
  • Loading branch information
RiccardoM committed Jan 15, 2025
1 parent 987da9f commit 2a74f58
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 12 deletions.
10 changes: 10 additions & 0 deletions x/restaking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ func (k msgServer) JoinService(ctx context.Context, msg *types.MsgJoinService) (
return nil, errors.Wrapf(servicestypes.ErrServiceNotActive, "service %d is not active", msg.ServiceID)
}

// Make sure the operator is allowed to join
operatorAllowed, err := k.CanOperatorValidateService(ctx, msg.ServiceID, msg.OperatorID)
if err != nil {
return nil, err
}

if !operatorAllowed {
return nil, types.ErrOperatorNotAllowed
}

err = k.AddServiceToOperatorJoinedServices(ctx, msg.OperatorID, msg.ServiceID)
if err != nil {
return nil, err
Expand Down
112 changes: 100 additions & 12 deletions x/restaking/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
name: "non-existent service id returns an error",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1, operatorstypes.OPERATOR_STATUS_ACTIVE,
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
Expand All @@ -57,7 +58,8 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
name: "only operator admin can perform JoinService",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1, operatorstypes.OPERATOR_STATUS_ACTIVE,
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
Expand All @@ -66,7 +68,8 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
suite.Require().NoError(err)

err = suite.sk.SaveService(ctx, servicestypes.NewService(
1, servicestypes.SERVICE_STATUS_ACTIVE,
1,
servicestypes.SERVICE_STATUS_ACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
Expand All @@ -87,7 +90,8 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
name: "service not active returns error",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1, operatorstypes.OPERATOR_STATUS_ACTIVE,
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
Expand All @@ -96,7 +100,8 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
suite.Require().NoError(err)

err = suite.sk.SaveService(ctx, servicestypes.NewService(
1, servicestypes.SERVICE_STATUS_INACTIVE,
1,
servicestypes.SERVICE_STATUS_INACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
Expand All @@ -117,15 +122,17 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
name: "can't join inactive service",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1, operatorstypes.OPERATOR_STATUS_ACTIVE,
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
"cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4",
))
suite.Require().NoError(err)
err = suite.sk.SaveService(ctx, servicestypes.NewService(
1, servicestypes.SERVICE_STATUS_INACTIVE,
1,
servicestypes.SERVICE_STATUS_INACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
Expand All @@ -146,15 +153,17 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
name: "can't join created service",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1, operatorstypes.OPERATOR_STATUS_ACTIVE,
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
"cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4",
))
suite.Require().NoError(err)
err = suite.sk.SaveService(ctx, servicestypes.NewService(
1, servicestypes.SERVICE_STATUS_INACTIVE,
1,
servicestypes.SERVICE_STATUS_INACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
Expand All @@ -172,10 +181,11 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
shouldErr: true,
},
{
name: "join is performed correctly",
name: "can't join service due to allow list",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1, operatorstypes.OPERATOR_STATUS_ACTIVE,
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
Expand All @@ -184,7 +194,8 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
suite.Require().NoError(err)

err = suite.sk.SaveService(ctx, servicestypes.NewService(
1, servicestypes.SERVICE_STATUS_ACTIVE,
1,
servicestypes.SERVICE_STATUS_ACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
Expand All @@ -193,6 +204,83 @@ func (suite *KeeperTestSuite) TestMsgServer_JoinService() {
false,
))
suite.Require().NoError(err)

err = suite.k.AddOperatorToServiceAllowList(ctx, 1, 2)
suite.Require().NoError(err)
},
msg: types.NewMsgJoinService(
1,
1,
"cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4",
),
shouldErr: true,
},
{
name: "join is performed correctly - no allow list",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
"cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4",
))
suite.Require().NoError(err)

err = suite.sk.SaveService(ctx, servicestypes.NewService(
1,
servicestypes.SERVICE_STATUS_ACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
"https://milkyway.com/logo.png",
"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd",
false,
))
suite.Require().NoError(err)
},
msg: types.NewMsgJoinService(
1,
1,
"cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4",
),
shouldErr: false,
expEvents: sdk.Events{
sdk.NewEvent(
types.EventTypeJoinService,
sdk.NewAttribute(operatorstypes.AttributeKeyOperatorID, "1"),
sdk.NewAttribute(servicestypes.AttributeKeyServiceID, "1"),
),
},
},
{
name: "join is performed correctly - allow list",
store: func(ctx sdk.Context) {
err := suite.ok.SaveOperator(ctx, operatorstypes.NewOperator(
1,
operatorstypes.OPERATOR_STATUS_ACTIVE,
"MilkyWay Operator",
"https://milkyway.com",
"https://milkyway.com/picture",
"cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4",
))
suite.Require().NoError(err)

err = suite.sk.SaveService(ctx, servicestypes.NewService(
1,
servicestypes.SERVICE_STATUS_ACTIVE,
"MilkyWay",
"MilkyWay is a restaking platform",
"https://milkyway.com",
"https://milkyway.com/logo.png",
"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd",
false,
))
suite.Require().NoError(err)

err = suite.k.AddOperatorToServiceAllowList(ctx, 1, 1)
suite.Require().NoError(err)
},
msg: types.NewMsgJoinService(
1,
Expand Down
11 changes: 11 additions & 0 deletions x/restaking/migrations/v2/expected_interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package v2

import (
"context"
)

type Keeper interface {
IterateAllOperatorsJoinedServices(ctx context.Context, action func(operatorID uint32, serviceID uint32) (stop bool, err error)) error
CanOperatorValidateService(ctx context.Context, serviceID uint32, operatorID uint32) (bool, error)
RemoveServiceFromOperatorJoinedServices(ctx context.Context, operatorID uint32, serviceID uint32) error
}
52 changes: 52 additions & 0 deletions x/restaking/migrations/v2/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package v2

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// MigrateStore performs in-place store migrations from v1 to v2. The migrations include:
// - Removing joined operators that are not allowed by the services they have joined
func MigrateStore(ctx sdk.Context, keeper Keeper) error {
return removeNotAllowedJoinedServices(ctx, keeper)
}

type operatorJoinedService struct {
operatorID uint32
serviceID uint32
}

func removeNotAllowedJoinedServices(ctx sdk.Context, keeper Keeper) error {
// Get the list of deletable operators (i.e. operators that have joined services that they should not have joined)
var operatorsToDelete []operatorJoinedService
err := keeper.IterateAllOperatorsJoinedServices(ctx, func(operatorID uint32, serviceID uint32) (stop bool, err error) {
canOperatorValidator, err := keeper.CanOperatorValidateService(ctx, serviceID, operatorID)
if err != nil {
return true, err
}

if canOperatorValidator {
// Skip if the operator is allowed to join the service
return false, nil
}

// Add the service to the list of deletable services if the operator should have not been allowed to join it
operatorsToDelete = append(operatorsToDelete, operatorJoinedService{
operatorID: operatorID,
serviceID: serviceID,
})

return false, nil
})
if err != nil {
return err
}

for _, service := range operatorsToDelete {
err = keeper.RemoveServiceFromOperatorJoinedServices(ctx, service.operatorID, service.serviceID)
if err != nil {
return err
}
}

return nil
}
Loading

0 comments on commit 2a74f58

Please sign in to comment.