From e19b5874e444f3181a4c1a8653d9ab51e9b9b65f Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Fri, 31 Jan 2025 18:24:28 +0200 Subject: [PATCH 1/4] test(mstaking): implement StakeAuthorization tests Implements comprehensive test suite for StakeAuthorization in the mstaking module. The tests cover: - Creation of new StakeAuthorization objects - Basic validation of authorization parameters - Message acceptance logic with allow/deny lists - Token limit validation and state updates - Message type URL handling for different authorization types This improves the overall test coverage and helps ensure the reliability of the staking authorization functionality. --- x/mstaking/types/authz_test.go | 273 ++++++++++++++++++++++++++++++++- 1 file changed, 272 insertions(+), 1 deletion(-) diff --git a/x/mstaking/types/authz_test.go b/x/mstaking/types/authz_test.go index 418467b4..642041fe 100644 --- a/x/mstaking/types/authz_test.go +++ b/x/mstaking/types/authz_test.go @@ -1,3 +1,274 @@ package types_test -// TODO implement test +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + + "github.com/initia-labs/initia/x/mstaking/types" +) + +func TestNewStakeAuthorization(t *testing.T) { + tests := []struct { + name string + allowedValidators []string + deniedValidators []string + authzType types.AuthorizationType + amount sdk.Coins + expectError bool + }{ + { + name: "valid authorization with allow list", + allowedValidators: []string{"val1", "val2"}, + deniedValidators: nil, + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + expectError: false, + }, + { + name: "valid authorization with deny list", + allowedValidators: nil, + deniedValidators: []string{"val1", "val2"}, + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + expectError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + authorization, err := types.NewStakeAuthorization( + tc.allowedValidators, + tc.deniedValidators, + tc.authzType, + tc.amount, + ) + + if tc.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.NotNil(t, authorization) + + if tc.allowedValidators != nil { + require.NotNil(t, authorization.GetAllowList()) + require.Equal(t, tc.allowedValidators, authorization.GetAllowList().Address) + } + + if tc.deniedValidators != nil { + require.NotNil(t, authorization.GetDenyList()) + require.Equal(t, tc.deniedValidators, authorization.GetDenyList().Address) + } + + require.Equal(t, tc.authzType, authorization.AuthorizationType) + if tc.amount != nil { + require.Equal(t, tc.amount, authorization.MaxTokens) + } + }) + } +} + +func TestStakeAuthorization_ValidateBasic(t *testing.T) { + tests := []struct { + name string + auth types.StakeAuthorization + expectError bool + }{ + { + name: "valid authorization", + auth: types.StakeAuthorization{ + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + }, + expectError: false, + }, + { + name: "invalid - negative coins", + auth: types.StakeAuthorization{ + MaxTokens: sdk.Coins{sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-1000)}}, + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + }, + expectError: true, + }, + { + name: "invalid - unspecified authorization type", + auth: types.StakeAuthorization{ + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED, + }, + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.auth.ValidateBasic() + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestStakeAuthorization_Accept(t *testing.T) { + ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()) + + tests := []struct { + name string + auth types.StakeAuthorization + msg sdk.Msg + expectError bool + }{ + { + name: "valid delegate with allow list", + auth: types.StakeAuthorization{ + Validators: &types.StakeAuthorization_AllowList{ + AllowList: &types.StakeAuthorization_Validators{ + Address: []string{"val1"}, + }, + }, + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + }, + msg: &types.MsgDelegate{ + DelegatorAddress: "delegator", + ValidatorAddress: "val1", + Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + }, + expectError: false, + }, + { + name: "invalid - validator not in allow list", + auth: types.StakeAuthorization{ + Validators: &types.StakeAuthorization_AllowList{ + AllowList: &types.StakeAuthorization_Validators{ + Address: []string{"val1"}, + }, + }, + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + }, + msg: &types.MsgDelegate{ + DelegatorAddress: "delegator", + ValidatorAddress: "val2", + Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + }, + expectError: true, + }, + { + name: "invalid - validator in deny list", + auth: types.StakeAuthorization{ + Validators: &types.StakeAuthorization_DenyList{ + DenyList: &types.StakeAuthorization_Validators{ + Address: []string{"val1"}, + }, + }, + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + }, + msg: &types.MsgDelegate{ + DelegatorAddress: "delegator", + ValidatorAddress: "val1", + Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + }, + expectError: true, + }, + { + name: "invalid - exceeds max tokens", + auth: types.StakeAuthorization{ + Validators: &types.StakeAuthorization_AllowList{ + AllowList: &types.StakeAuthorization_Validators{ + Address: []string{"val1"}, + }, + }, + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(400))), + AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + }, + msg: &types.MsgDelegate{ + DelegatorAddress: "delegator", + ValidatorAddress: "val1", + Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + }, + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + resp, err := tc.auth.Accept(context.Background(), tc.msg) + if tc.expectError { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.True(t, resp.Accept) + + // Check if authorization should be deleted (when max tokens are used up) + if tc.auth.MaxTokens != nil { + msgCoins := sdk.NewCoins(tc.msg.(*types.MsgDelegate).Amount) + if tc.auth.MaxTokens.IsEqual(msgCoins) { + require.True(t, resp.Delete) + } + } + }) + } +} + +func TestStakeAuthorization_MsgTypeURL(t *testing.T) { + tests := []struct { + name string + authzType types.AuthorizationType + expectError bool + }{ + { + name: "delegate authorization", + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, + expectError: false, + }, + { + name: "undelegate authorization", + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, + expectError: false, + }, + { + name: "redelegate authorization", + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, + expectError: false, + }, + { + name: "cancel unbonding delegation authorization", + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_CANCEL_UNBONDING_DELEGATION, + expectError: false, + }, + { + name: "unspecified authorization type", + authzType: types.AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED, + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + auth := types.StakeAuthorization{ + AuthorizationType: tc.authzType, + } + + if tc.expectError { + require.Panics(t, func() { auth.MsgTypeURL() }) + return + } + + url := auth.MsgTypeURL() + require.NotEmpty(t, url) + }) + } +} From 12589ce234456ffe0a8f21c18a7a21db82dfec5e Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Mon, 3 Feb 2025 20:38:50 +0200 Subject: [PATCH 2/4] Update authz_test.go --- x/mstaking/types/authz_test.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/x/mstaking/types/authz_test.go b/x/mstaking/types/authz_test.go index 642041fe..bcb58dd8 100644 --- a/x/mstaking/types/authz_test.go +++ b/x/mstaking/types/authz_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/authz" @@ -26,7 +27,7 @@ func TestNewStakeAuthorization(t *testing.T) { allowedValidators: []string{"val1", "val2"}, deniedValidators: nil, authzType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, - amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), expectError: false, }, { @@ -34,7 +35,7 @@ func TestNewStakeAuthorization(t *testing.T) { allowedValidators: nil, deniedValidators: []string{"val1", "val2"}, authzType: types.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, - amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), expectError: false, }, } @@ -83,7 +84,7 @@ func TestStakeAuthorization_ValidateBasic(t *testing.T) { { name: "valid authorization", auth: types.StakeAuthorization{ - MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, }, expectError: false, @@ -91,7 +92,7 @@ func TestStakeAuthorization_ValidateBasic(t *testing.T) { { name: "invalid - negative coins", auth: types.StakeAuthorization{ - MaxTokens: sdk.Coins{sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-1000)}}, + MaxTokens: sdk.Coins{sdk.Coin{Denom: "stake", Amount: math.NewInt(-1000)}}, AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, }, expectError: true, @@ -99,7 +100,7 @@ func TestStakeAuthorization_ValidateBasic(t *testing.T) { { name: "invalid - unspecified authorization type", auth: types.StakeAuthorization{ - MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_UNSPECIFIED, }, expectError: true, @@ -135,13 +136,13 @@ func TestStakeAuthorization_Accept(t *testing.T) { Address: []string{"val1"}, }, }, - MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, }, msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val1", - Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + Amount: sdk.NewCoin("stake", math.NewInt(500)), }, expectError: false, }, @@ -153,13 +154,13 @@ func TestStakeAuthorization_Accept(t *testing.T) { Address: []string{"val1"}, }, }, - MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, }, msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val2", - Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + Amount: sdk.NewCoin("stake", math.NewInt(500)), }, expectError: true, }, @@ -171,13 +172,13 @@ func TestStakeAuthorization_Accept(t *testing.T) { Address: []string{"val1"}, }, }, - MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))), AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, }, msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val1", - Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + Amount: sdk.NewCoin("stake", math.NewInt(500)), }, expectError: true, }, @@ -189,13 +190,13 @@ func TestStakeAuthorization_Accept(t *testing.T) { Address: []string{"val1"}, }, }, - MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(400))), + MaxTokens: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(400))), AuthorizationType: types.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, }, msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val1", - Amount: sdk.NewCoin("stake", sdk.NewInt(500)), + Amount: sdk.NewCoin("stake", math.NewInt(500)), }, expectError: true, }, From 60d3333b6e089d00844a39a944bf4de9625b967f Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Tue, 4 Feb 2025 15:24:45 +0200 Subject: [PATCH 3/4] Update authz_test.go --- x/mstaking/types/authz_test.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/x/mstaking/types/authz_test.go b/x/mstaking/types/authz_test.go index bcb58dd8..73e928a0 100644 --- a/x/mstaking/types/authz_test.go +++ b/x/mstaking/types/authz_test.go @@ -120,8 +120,6 @@ func TestStakeAuthorization_ValidateBasic(t *testing.T) { } func TestStakeAuthorization_Accept(t *testing.T) { - ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()) - tests := []struct { name string auth types.StakeAuthorization @@ -142,7 +140,7 @@ func TestStakeAuthorization_Accept(t *testing.T) { msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val1", - Amount: sdk.NewCoin("stake", math.NewInt(500)), + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), }, expectError: false, }, @@ -160,7 +158,7 @@ func TestStakeAuthorization_Accept(t *testing.T) { msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val2", - Amount: sdk.NewCoin("stake", math.NewInt(500)), + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), }, expectError: true, }, @@ -178,7 +176,7 @@ func TestStakeAuthorization_Accept(t *testing.T) { msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val1", - Amount: sdk.NewCoin("stake", math.NewInt(500)), + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), }, expectError: true, }, @@ -196,7 +194,7 @@ func TestStakeAuthorization_Accept(t *testing.T) { msg: &types.MsgDelegate{ DelegatorAddress: "delegator", ValidatorAddress: "val1", - Amount: sdk.NewCoin("stake", math.NewInt(500)), + Amount: sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(500))), }, expectError: true, }, @@ -215,8 +213,8 @@ func TestStakeAuthorization_Accept(t *testing.T) { // Check if authorization should be deleted (when max tokens are used up) if tc.auth.MaxTokens != nil { - msgCoins := sdk.NewCoins(tc.msg.(*types.MsgDelegate).Amount) - if tc.auth.MaxTokens.IsEqual(msgCoins) { + msgCoins := tc.msg.(*types.MsgDelegate).Amount + if tc.auth.MaxTokens.Equal(msgCoins) { require.True(t, resp.Delete) } } From b89b482a9f19006114cee6902930ca42b7f0e37a Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Tue, 4 Feb 2025 15:25:09 +0200 Subject: [PATCH 4/4] Update authz_test.go