Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sequencer): validate rollappId & permissioned sequencers #61

Merged
merged 1 commit into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 165 additions & 1 deletion x/sequencer/keeper/keeper_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

dymensionapp "github.com/dymensionxyz/dymension/app"
sharedtypes "github.com/dymensionxyz/dymension/shared/types"
"github.com/dymensionxyz/dymension/testutil/sample"
"github.com/dymensionxyz/dymension/x/sequencer/keeper"
"github.com/dymensionxyz/dymension/x/sequencer/types"
sequencertypes "github.com/dymensionxyz/dymension/x/sequencer/types"
Expand Down Expand Up @@ -86,6 +87,9 @@ func (suite *IntegrationTestSuite) TestCreateSequencer() {
suite.SetupTest()
goCtx := sdk.WrapSDKContext(suite.ctx)

// max sequencers per rollapp
maxSequencers := 10

// sequencersExpect is the expected result of query all
sequencersExpect := []*types.Sequencer{}

Expand All @@ -104,7 +108,7 @@ func (suite *IntegrationTestSuite) TestCreateSequencer() {
CodeStamp: "",
GenesisPath: "",
MaxWithholdingBlocks: 1,
MaxSequencers: 1,
MaxSequencers: uint64(maxSequencers),
PermissionedAddresses: sharedtypes.Sequencers{Addresses: []string{}},
}
suite.app.RollappKeeper.SetRollapp(suite.ctx, rollapp)
Expand Down Expand Up @@ -212,6 +216,166 @@ func (suite *IntegrationTestSuite) TestCreateSequencerAlreadyExists() {
suite.EqualError(err, types.ErrSequencerExists.Error())
}

func (suite *IntegrationTestSuite) TestCreateSequencerUnknownRollappId() {
suite.SetupTest()
goCtx := sdk.WrapSDKContext(suite.ctx)

pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
pkAny, err := codectypes.NewAnyWithValue(pubkey)
suite.Require().Nil(err)
sequencer := types.MsgCreateSequencer{
Creator: alice,
SequencerAddress: addr.String(),
Pubkey: pkAny,
RollappId: "rollappId",
Description: sequencertypes.Description{},
}

_, err = suite.msgServer.CreateSequencer(goCtx, &sequencer)
suite.EqualError(err, types.ErrUnknownRollappId.Error())
}

func (suite *IntegrationTestSuite) TestCreatePermissionedSequencer() {
suite.SetupTest()
goCtx := sdk.WrapSDKContext(suite.ctx)

pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
sequencerAddress := addr.String()

rollapp := rollapptypes.Rollapp{
RollappId: "rollapp1",
Creator: alice,
Version: 0,
CodeStamp: "",
GenesisPath: "",
MaxWithholdingBlocks: 1,
MaxSequencers: 1,
PermissionedAddresses: sharedtypes.Sequencers{Addresses: []string{sequencerAddress}},
}
suite.app.RollappKeeper.SetRollapp(suite.ctx, rollapp)

rollappId := rollapp.GetRollappId()

pkAny, err := codectypes.NewAnyWithValue(pubkey)
suite.Require().Nil(err)
sequencer := types.MsgCreateSequencer{
Creator: alice,
SequencerAddress: sequencerAddress,
Pubkey: pkAny,
RollappId: rollappId,
Description: sequencertypes.Description{},
}

_, err = suite.msgServer.CreateSequencer(goCtx, &sequencer)
suite.Require().Nil(err)

// query the spesific sequencer
queryResponse, err := suite.queryClient.Sequencer(goCtx, &types.QueryGetSequencerRequest{
SequencerAddress: sequencer.GetSequencerAddress(),
})
suite.Require().Nil(err)

// sequencerExpect is the expected result of creating a sequencer
sequencerExpect := types.Sequencer{
SequencerAddress: sequencer.GetSequencerAddress(),
Creator: sequencer.GetCreator(),
Pubkey: sequencer.GetPubkey(),
RollappId: rollappId,
Description: sequencer.GetDescription(),
}
equalSequencer(suite, &sequencerExpect, &queryResponse.Sequencer)
}

func (suite *IntegrationTestSuite) TestCreateSequencerNotPermissioned() {
suite.SetupTest()
goCtx := sdk.WrapSDKContext(suite.ctx)

rollapp := rollapptypes.Rollapp{
RollappId: "rollapp1",
Creator: alice,
Version: 0,
CodeStamp: "",
GenesisPath: "",
MaxWithholdingBlocks: 1,
MaxSequencers: 1,
PermissionedAddresses: sharedtypes.Sequencers{Addresses: []string{sample.AccAddress()}},
}
suite.app.RollappKeeper.SetRollapp(suite.ctx, rollapp)

rollappId := rollapp.GetRollappId()

pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
pkAny, err := codectypes.NewAnyWithValue(pubkey)
suite.Require().Nil(err)
sequencer := types.MsgCreateSequencer{
Creator: alice,
SequencerAddress: addr.String(),
Pubkey: pkAny,
RollappId: rollappId,
Description: sequencertypes.Description{},
}

_, err = suite.msgServer.CreateSequencer(goCtx, &sequencer)
suite.EqualError(err, types.ErrSequencerNotPermissioned.Error())
}

func (suite *IntegrationTestSuite) TestMaxSequencersLimit() {
suite.SetupTest()
goCtx := sdk.WrapSDKContext(suite.ctx)
maxSequencers := 3

rollapp := rollapptypes.Rollapp{
RollappId: "rollapp1",
Creator: alice,
Version: 0,
CodeStamp: "",
GenesisPath: "",
MaxWithholdingBlocks: 1,
MaxSequencers: uint64(maxSequencers),
PermissionedAddresses: sharedtypes.Sequencers{Addresses: []string{}},
}
suite.app.RollappKeeper.SetRollapp(suite.ctx, rollapp)

rollappId := rollapp.GetRollappId()

// create MaxSequencers
for i := 0; i < maxSequencers; i++ {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
pkAny, err := codectypes.NewAnyWithValue(pubkey)
suite.Require().Nil(err)
sequencer := types.MsgCreateSequencer{
Creator: alice,
SequencerAddress: addr.String(),
Pubkey: pkAny,
RollappId: rollappId,
Description: sequencertypes.Description{},
}
_, err = suite.msgServer.CreateSequencer(goCtx, &sequencer)
suite.Require().Nil(err)
}

// add more to be failed
for i := 0; i < 2; i++ {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
pkAny, err := codectypes.NewAnyWithValue(pubkey)
suite.Require().Nil(err)
sequencer := types.MsgCreateSequencer{
Creator: alice,
SequencerAddress: addr.String(),
Pubkey: pkAny,
RollappId: rollappId,
Description: sequencertypes.Description{},
}
_, err = suite.msgServer.CreateSequencer(goCtx, &sequencer)
suite.EqualError(err, types.ErrMaxSequencersLimit.Error())
}
}

//-------------------------------------------------------------------------------------------------------------------------------

// vereifyAll receives a list of expected results and a map of sequencerAddress->sequencer
Expand Down
36 changes: 36 additions & 0 deletions x/sequencer/keeper/msg_server_create_sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,45 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe
return nil, types.ErrSequencerExists
}

// load rollapp object for stateful validations
rollapp, found := k.rollappKeeper.GetRollapp(ctx, msg.RollappId)
// check to see if the rollapp has been registered before
if found {
// check if there are permissionedAddresses.
// if the list is not empty, it means that only premissioned sequencers can be added
permissionedAddresses := rollapp.GetPermissionedAddresses().Addresses
if len(permissionedAddresses) > 0 {
bPermissioned := false
// check to see if the sequencer is in the permissioned list
for i := range permissionedAddresses {
if permissionedAddresses[i] == seqAddrStr {
// Found!
bPermissioned = true
break
}
}
// Err: only permissioned sequencers allowed and this one is not in the list
if !bPermissioned {
return nil, types.ErrSequencerNotPermissioned
}
}
} else {
return nil, types.ErrUnknownRollappId
}

// update sequencers list
sequencersByRollapp, found := k.GetSequencersByRollapp(ctx, msg.RollappId)
if found {
// check to see if we reached maxsimum number of sequeners
maxSequencers := int(rollapp.GetMaxSequencers())
activeSequencers := sequencersByRollapp.GetSequencers()
currentNumOfSequencers := len(activeSequencers.GetAddresses())
if maxSequencers < currentNumOfSequencers {
return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "rollapp id: %s cannot have more than %d sequencers but got: %d", msg.RollappId, maxSequencers, currentNumOfSequencers)
}
if maxSequencers == currentNumOfSequencers {
return nil, types.ErrMaxSequencersLimit
}
// add sequencer to list
sequencersByRollapp.Sequencers.Addresses = append(sequencersByRollapp.Sequencers.Addresses, seqAddrStr)
} else {
Expand Down
7 changes: 5 additions & 2 deletions x/sequencer/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (

// x/sequencer module sentinel errors
var (
ErrSequencerExists = sdkerrors.Register(ModuleName, 1000, "sequencer already exist for this address; must use new sequencer address")
ErrInvalidSequencerAddress = sdkerrors.Register(ModuleName, 1001, "invalid sequencer address")
ErrSequencerExists = sdkerrors.Register(ModuleName, 1000, "sequencer already exist for this address; must use new sequencer address")
ErrInvalidSequencerAddress = sdkerrors.Register(ModuleName, 1001, "invalid sequencer address")
ErrUnknownRollappId = sdkerrors.Register(ModuleName, 1002, "rollapp does not exist")
ErrMaxSequencersLimit = sdkerrors.Register(ModuleName, 1003, "too many sequencers for rollapp")
ErrSequencerNotPermissioned = sdkerrors.Register(ModuleName, 1004, "sequencer is not permissioned for serving the rollapp")
)
2 changes: 2 additions & 0 deletions x/sequencer/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
rollapptypes "github.com/dymensionxyz/dymension/x/rollapp/types"
)

type RollappKeeper interface {
// Methods imported from rollapp should be defined here
GetRollapp(ctx sdk.Context, rollappId string) (val rollapptypes.Rollapp, found bool)
}

// AccountKeeper defines the expected account keeper used for simulations (noalias)
Expand Down