Skip to content

Commit

Permalink
[AppGate] Add the MaxDelegatedGateways parameter (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
h5law authored Oct 31, 2023
1 parent 0f139ee commit aef9615
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 12 deletions.
2 changes: 2 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ genesis:
- amount: "10000"
denom: upokt
application:
params:
maxDelegatedGateways: 7
applicationList:
- address: pokt1mrqt5f7qh8uxs27cjm9t7v9e74a9vvdnq5jva4
stake:
Expand Down
19 changes: 19 additions & 0 deletions docs/static/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46735,6 +46735,13 @@ paths:
params:
description: params holds all the parameters of this module.
type: object
properties:
max_delegated_gateways:
type: integer
format: int64
title: >-
The maximum number of gateways an application can delegate
trust to
description: >-
QueryParamsResponse is response type for the Query/Params RPC
method.
Expand Down Expand Up @@ -77831,6 +77838,11 @@ definitions:
type: object
pocket.application.Params:
type: object
properties:
max_delegated_gateways:
type: integer
format: int64
title: The maximum number of gateways an application can delegate trust to
description: Params defines the parameters for the module.
pocket.application.QueryAllApplicationResponse:
type: object
Expand Down Expand Up @@ -78004,6 +78016,13 @@ definitions:
params:
description: params holds all the parameters of this module.
type: object
properties:
max_delegated_gateways:
type: integer
format: int64
title: >-
The maximum number of gateways an application can delegate trust
to
description: QueryParamsResponse is response type for the Query/Params RPC method.
pocket.shared.ApplicationServiceConfig:
type: object
Expand Down
3 changes: 2 additions & 1 deletion proto/pocket/application/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ option go_package = "pocket/x/application/types";
// Params defines the parameters for the module.
message Params {
option (gogoproto.goproto_stringer) = false;


int64 max_delegated_gateways = 1 [(gogoproto.jsontag) = "max_delegated_gateways"]; // The maximum number of gateways an application can delegate trust to
}
1 change: 1 addition & 0 deletions testutil/keeper/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
// StakedGatewayMap is used to mock whether a gateway is staked or not for use
// in the application's mocked gateway keeper. This enables the tester to
// control whether a gateway is "staked" or not and whether it can be delegated to
// WARNING: Using this map may cause issues if running multiple tests in parallel
var StakedGatewayMap = make(map[string]struct{})

func ApplicationKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
Expand Down
7 changes: 7 additions & 0 deletions x/application/keeper/msg_server_delegate_to_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ func (k msgServer) DelegateToGateway(goCtx context.Context, msg *types.MsgDelega
return nil, sdkerrors.Wrapf(types.ErrAppGatewayNotFound, "gateway not found with address: %s", msg.GatewayAddress)
}

// Ensure the application is not already delegated to the maximum number of gateways
maxDelegatedParam := k.GetParams(ctx).MaxDelegatedGateways
if int64(len(app.DelegateeGatewayAddresses)) >= maxDelegatedParam {
logger.Info("Application already delegated to maximum number of gateways: %d", maxDelegatedParam)
return nil, sdkerrors.Wrapf(types.ErrAppMaxDelegatedGateways, "application already delegated to %d gateways", maxDelegatedParam)
}

// Check if the application is already delegated to the gateway
for _, gatewayAddr := range app.DelegateeGatewayAddresses {
if gatewayAddr == msg.GatewayAddress {
Expand Down
72 changes: 70 additions & 2 deletions x/application/keeper/msg_server_delegate_to_gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func TestMsgServer_DelegateToGateway_FailDuplicate(t *testing.T) {

// Attempt to delegate the application to the gateway again
_, err = srv.DelegateToGateway(wctx, delegateMsg2)
require.Error(t, err)
require.ErrorIs(t, err, types.ErrAppAlreadyDelegated)
foundApp, isAppFound = k.GetApplication(ctx, appAddr)
require.True(t, isAppFound)
require.Equal(t, 1, len(foundApp.DelegateeGatewayAddresses))
Expand Down Expand Up @@ -177,8 +177,76 @@ func TestMsgServer_DelegateToGateway_FailGatewayNotStaked(t *testing.T) {

// Attempt to delegate the application to the unstaked gateway
_, err = srv.DelegateToGateway(wctx, delegateMsg)
require.Error(t, err)
require.ErrorIs(t, err, types.ErrAppGatewayNotFound)
foundApp, isAppFound := k.GetApplication(ctx, appAddr)
require.True(t, isAppFound)
require.Equal(t, 0, len(foundApp.DelegateeGatewayAddresses))
}

func TestMsgServer_DelegateToGateway_FailMaxReached(t *testing.T) {
k, ctx := keepertest.ApplicationKeeper(t)
srv := keeper.NewMsgServerImpl(*k)
wctx := sdk.WrapSDKContext(ctx)

// Generate an address for the application and gateway
appAddr := sample.AccAddress()
gatewayAddr := sample.AccAddress()
// Mock the gateway being staked via the staked gateway map
keepertest.StakedGatewayMap[gatewayAddr] = struct{}{}
t.Cleanup(func() {
delete(keepertest.StakedGatewayMap, gatewayAddr)
})

// Prepare the application
stakeMsg := &types.MsgStakeApplication{
Address: appAddr,
Stake: &sdk.Coin{Denom: "upokt", Amount: sdk.NewInt(100)},
Services: []*sharedtypes.ApplicationServiceConfig{
{
ServiceId: &sharedtypes.ServiceId{Id: "svc1"},
},
},
}

// Stake the application & verify that the application exists
_, err := srv.StakeApplication(wctx, stakeMsg)
require.NoError(t, err)
_, isAppFound := k.GetApplication(ctx, appAddr)
require.True(t, isAppFound)

// Prepare the delegation message
delegateMsg := &types.MsgDelegateToGateway{
AppAddress: appAddr,
GatewayAddress: gatewayAddr,
}

// Delegate the application to the max number of gateways
maxDelegatedParam := k.GetParams(ctx).MaxDelegatedGateways
for i := int64(0); i < k.GetParams(ctx).MaxDelegatedGateways; i++ {
// Prepare the delegation message
gatewayAddr := sample.AccAddress()
// Mock the gateway being staked via the staked gateway map
keepertest.StakedGatewayMap[gatewayAddr] = struct{}{}
t.Cleanup(func() {
delete(keepertest.StakedGatewayMap, gatewayAddr)
})
delegateMsg := &types.MsgDelegateToGateway{
AppAddress: appAddr,
GatewayAddress: gatewayAddr,
}
// Delegate the application to the gateway
_, err = srv.DelegateToGateway(wctx, delegateMsg)
require.NoError(t, err)
// Check number of gateways delegated to is correct
foundApp, isAppFound := k.GetApplication(ctx, appAddr)
require.True(t, isAppFound)
require.Equal(t, int(i+1), len(foundApp.DelegateeGatewayAddresses))
}

// Attempt to delegate the application when the max is already reached
_, err = srv.DelegateToGateway(wctx, delegateMsg)
require.ErrorIs(t, err, types.ErrAppMaxDelegatedGateways)
foundApp, isAppFound := k.GetApplication(ctx, appAddr)
require.True(t, isAppFound)
require.Equal(t, maxDelegatedParam, int64(len(foundApp.DelegateeGatewayAddresses)))
}
18 changes: 10 additions & 8 deletions x/application/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import (

// x/application module sentinel errors
var (
ErrAppInvalidStake = sdkerrors.Register(ModuleName, 1, "invalid application stake")
ErrAppInvalidAddress = sdkerrors.Register(ModuleName, 2, "invalid application address")
ErrAppUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized application signer")
ErrAppNotFound = sdkerrors.Register(ModuleName, 4, "application not found")
ErrAppInvalidServiceConfigs = sdkerrors.Register(ModuleName, 6, "invalid service configs")
ErrAppGatewayNotFound = sdkerrors.Register(ModuleName, 7, "gateway not found")
ErrAppInvalidGatewayAddress = sdkerrors.Register(ModuleName, 8, "invalid gateway address")
ErrAppAlreadyDelegated = sdkerrors.Register(ModuleName, 9, "application already delegated to gateway")
ErrAppInvalidStake = sdkerrors.Register(ModuleName, 1, "invalid application stake")
ErrAppInvalidAddress = sdkerrors.Register(ModuleName, 2, "invalid application address")
ErrAppUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized application signer")
ErrAppNotFound = sdkerrors.Register(ModuleName, 4, "application not found")
ErrAppInvalidServiceConfigs = sdkerrors.Register(ModuleName, 6, "invalid service configs")
ErrAppGatewayNotFound = sdkerrors.Register(ModuleName, 7, "gateway not found")
ErrAppInvalidGatewayAddress = sdkerrors.Register(ModuleName, 8, "invalid gateway address")
ErrAppAlreadyDelegated = sdkerrors.Register(ModuleName, 9, "application already delegated to gateway")
ErrAppMaxDelegatedGateways = sdkerrors.Register(ModuleName, 10, "maximum number of delegated gateways reached")
ErrAppInvalidMaxDelegatedGateways = sdkerrors.Register(ModuleName, 11, "invalid MaxDelegatedGateways parameter")
)
54 changes: 54 additions & 0 deletions x/application/types/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "valid genesis state",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -62,6 +65,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - zero app stake",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -82,6 +88,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - negative application stake",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -102,6 +111,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - wrong stake denom",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -122,6 +134,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - missing denom",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -142,6 +157,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - due to duplicated app address",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -162,6 +180,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - due to nil app stake",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -182,6 +203,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - due to missing app stake",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -202,6 +226,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - due to invalid delegatee pub key",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -222,6 +249,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - due to invalid delegatee pub keys",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -242,6 +272,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - service config not present",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -256,6 +289,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - empty service config",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -270,6 +306,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - service ID too long",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -286,6 +325,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - service name too long",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -305,6 +347,9 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid - service ID with invalid characters",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 7,
},
ApplicationList: []types.Application{
{
Address: addr1,
Expand All @@ -318,6 +363,15 @@ func TestGenesisState_Validate(t *testing.T) {
},
valid: false,
},
{
desc: "invalid - MaxDelegatedGateways less than 1",
genState: &types.GenesisState{
Params: types.Params{
MaxDelegatedGateways: 0,
},
},
valid: false,
},

// this line is used by starport scaffolding # types/genesis/testcase
}
Expand Down
9 changes: 8 additions & 1 deletion x/application/types/params.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package types

import (
sdkerrors "cosmossdk.io/errors"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"gopkg.in/yaml.v2"
)

// TODO: Revisit default param values
const DefaultMaxDelegatedGateways int64 = 7

var _ paramtypes.ParamSet = (*Params)(nil)

// ParamKeyTable the param key table for launch module
Expand All @@ -14,7 +18,7 @@ func ParamKeyTable() paramtypes.KeyTable {

// NewParams creates a new Params instance
func NewParams() Params {
return Params{}
return Params{MaxDelegatedGateways: DefaultMaxDelegatedGateways}
}

// DefaultParams returns a default set of parameters
Expand All @@ -29,6 +33,9 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {

// Validate validates the set of params
func (p Params) Validate() error {
if p.MaxDelegatedGateways < 1 {
return sdkerrors.Wrapf(ErrAppInvalidMaxDelegatedGateways, "MaxDelegatedGateways param < 1: got %d", p.MaxDelegatedGateways)
}
return nil
}

Expand Down

0 comments on commit aef9615

Please sign in to comment.