From 951067323ed6cade41d7644b5eca36f812eeeeff Mon Sep 17 00:00:00 2001 From: crypin Date: Fri, 17 Feb 2023 10:53:49 +0900 Subject: [PATCH 1/3] feat!: add initial deposit ratio requirement of 0.5 for proposal submission --- README.md | 2 +- x/gov/abci_test.go | 8 +-- x/gov/keeper/msg_server.go | 14 ++++- x/gov/keeper/msg_server_test.go | 89 +++++++++++++++++++++++++++++ x/gov/simulation/operations.go | 31 ++++++---- x/gov/simulation/operations_test.go | 2 +- x/gov/spec/06_params.md | 9 +++ x/gov/types/errors.go | 1 + x/gov/types/params.go | 3 +- 9 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 x/gov/keeper/msg_server_test.go diff --git a/README.md b/README.md index b4f73bd7bb94..fe713a993975 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ breaking changes. This forked Cosmos SDK has the following changes and it contains state breaking changes. - [`x/staking`](https://github.com/cosmosquad-labs/cosmos-sdk/pull/10) fix: allow delegate only spendable coins -- [`x/gov`](https://github.com/cosmosquad-labs/cosmos-sdk/pull/8) feat: add additional voting powers hook on tally +- [`x/gov`](https://github.com/cosmosquad-labs/cosmos-sdk/pull/8) feat: add additional voting powers hook on tally, add initial deposit ratio requirement of 0.5 for proposal submission - [`x/vesting`](https://github.com/cosmosquad-labs/cosmos-sdk/pull/11) feat: periodic vesting msg ## Quick Start diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 7681bae95cf6..e7e19946beef 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -32,7 +32,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) { newProposalMsg, err := types.NewMsgSubmitProposal( types.ContentFromProposalType("test", "test", types.ProposalTypeText), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5000000)}, addrs[0], ) require.NoError(t, err) @@ -84,7 +84,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { newProposalMsg, err := types.NewMsgSubmitProposal( types.ContentFromProposalType("test", "test", types.ProposalTypeText), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5000000)}, addrs[0], ) require.NoError(t, err) @@ -107,7 +107,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { newProposalMsg2, err := types.NewMsgSubmitProposal( types.ContentFromProposalType("test2", "test2", types.ProposalTypeText), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5000000)}, addrs[0], ) require.NoError(t, err) @@ -164,7 +164,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { newProposalMsg, err := types.NewMsgSubmitProposal( types.ContentFromProposalType("test2", "test2", types.ProposalTypeText), - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5000000)}, addrs[0], ) require.NoError(t, err) diff --git a/x/gov/keeper/msg_server.go b/x/gov/keeper/msg_server.go index 6afebe579dbf..7b88f2f0b3b6 100644 --- a/x/gov/keeper/msg_server.go +++ b/x/gov/keeper/msg_server.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -26,6 +27,17 @@ var _ types.MsgServer = msgServer{} func (k msgServer) SubmitProposal(goCtx context.Context, msg *types.MsgSubmitProposal) (*types.MsgSubmitProposalResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + + // checking minimum initial deposit requirement for submitting proposals, ref. https://github.com/cosmos/cosmos-sdk/pull/12771 + initialDeposit := msg.GetInitialDeposit() + initialDepositRequired := k.GetDepositParams(ctx).MinDeposit + for i := range initialDepositRequired { + initialDepositRequired[i].Amount = initialDepositRequired[i].Amount.ToDec().Mul(types.MinInitialDepositRatio).RoundInt() + } + if !initialDeposit.IsAllGTE(initialDepositRequired) { + return nil, sdkerrors.Wrapf(types.ErrMinDepositTooSmall, "was (%s), need (%s)", initialDeposit, initialDepositRequired) + } + proposal, err := k.Keeper.SubmitProposal(ctx, msg.GetContent()) if err != nil { return nil, err @@ -33,7 +45,7 @@ func (k msgServer) SubmitProposal(goCtx context.Context, msg *types.MsgSubmitPro defer telemetry.IncrCounter(1, types.ModuleName, "proposal") - votingStarted, err := k.Keeper.AddDeposit(ctx, proposal.ProposalId, msg.GetProposer(), msg.GetInitialDeposit()) + votingStarted, err := k.Keeper.AddDeposit(ctx, proposal.ProposalId, msg.GetProposer(), initialDeposit) if err != nil { return nil, err } diff --git a/x/gov/keeper/msg_server_test.go b/x/gov/keeper/msg_server_test.go new file mode 100644 index 000000000000..ae36bd86d5b1 --- /dev/null +++ b/x/gov/keeper/msg_server_test.go @@ -0,0 +1,89 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/keeper" + "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +func TestSubmitProposal_InitialDeposit(t *testing.T) { + var baseDepositTestAmount = int64(100) + var meetsDepositValue = types.MinInitialDepositRatio.MulInt64(baseDepositTestAmount).RoundInt64() + + testcases := map[string]struct { + minDeposit sdk.Coins + minInitialDepositRatio sdk.Dec + initialDeposit sdk.Coins + accountBalance sdk.Coins + + expectError bool + }{ + "meets initial deposit, enough balance - success": { + minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))), + minInitialDepositRatio: types.MinInitialDepositRatio, + initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue))), + accountBalance: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue))), + }, + "does not meet initial deposit, enough balance - error": { + minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))), + minInitialDepositRatio: types.MinInitialDepositRatio, + initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue-1))), + accountBalance: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue))), + + expectError: true, + }, + "meets initial deposit, not enough balance - error": { + minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))), + minInitialDepositRatio: types.MinInitialDepositRatio, + initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue))), + accountBalance: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue-1))), + + expectError: true, + }, + "does not meet initial deposit and not enough balance - error": { + minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))), + minInitialDepositRatio: types.MinInitialDepositRatio, + initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue-1))), + accountBalance: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue-1))), + + expectError: true, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + + // Setup + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + govKeeper := app.GovKeeper + msgServer := keeper.NewMsgServerImpl(govKeeper) + + params := types.DefaultDepositParams() + params.MinDeposit = tc.minDeposit + govKeeper.SetDepositParams(ctx, params) + + address := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(0))[0] + simapp.FundAccount(app.BankKeeper, ctx, address, tc.accountBalance) + + msg, err := types.NewMsgSubmitProposal(TestProposal, tc.initialDeposit, address) + require.NoError(t, err) + + // System under test + _, err = msgServer.SubmitProposal(sdk.WrapSDKContext(ctx), msg) + + // Assertions + if tc.expectError { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index d25c9d5f3c71..82b35d06c49f 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -128,7 +128,7 @@ func SimulateMsgSubmitProposal( } simAccount, _ := simtypes.RandomAcc(r, accs) - deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address, true) switch { case skip: return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSubmitProposal, "skip deposit"), nil, nil @@ -219,7 +219,7 @@ func SimulateMsgDeposit(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Ke return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDeposit, "unable to generate proposalID"), nil, nil } - deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address, false) switch { case skip: return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgDeposit, "skip deposit"), nil, nil @@ -371,7 +371,7 @@ func operationSimulateMsgVoteWeighted(ak types.AccountKeeper, bk types.BankKeepe // This is to simulate multiple users depositing to get the // proposal above the minimum deposit amount func randomDeposit(r *rand.Rand, ctx sdk.Context, - ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, addr sdk.AccAddress, + ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper, addr sdk.AccAddress, useMinAmount bool, ) (deposit sdk.Coins, skip bool, err error) { account := ak.GetAccount(ctx, addr) spendable := bk.SpendableCoins(ctx, account.GetAddress()) @@ -380,25 +380,36 @@ func randomDeposit(r *rand.Rand, ctx sdk.Context, return nil, true, nil // skip } - minDeposit := k.GetDepositParams(ctx).MinDeposit + depositParams := k.GetDepositParams(ctx) + + minDeposit := depositParams.MinDeposit + denomIndex := r.Intn(len(minDeposit)) denom := minDeposit[denomIndex].Denom - depositCoins := spendable.AmountOf(denom) - if depositCoins.IsZero() { + spendableBalance := spendable.AmountOf(denom) + if spendableBalance.IsZero() { return nil, true, nil } - maxAmt := depositCoins - if maxAmt.GT(minDeposit[denomIndex].Amount) { - maxAmt = minDeposit[denomIndex].Amount + minDepositAmount := minDeposit[denomIndex].Amount + + minAmount := sdk.ZeroInt() + if useMinAmount { + minAmount = minDepositAmount.ToDec().Mul(types.MinInitialDepositRatio).RoundInt() } - amount, err := simtypes.RandPositiveInt(r, maxAmt) + amount, err := simtypes.RandPositiveInt(r, minDepositAmount.Sub(minAmount)) if err != nil { return nil, false, err } + amount = amount.Add(minAmount) + + if amount.GT(spendableBalance) { + return nil, true, nil + } + return sdk.Coins{sdk.NewCoin(denom, amount)}, false, nil } diff --git a/x/gov/simulation/operations_test.go b/x/gov/simulation/operations_test.go index b15eed03c5ca..72dae989d126 100644 --- a/x/gov/simulation/operations_test.go +++ b/x/gov/simulation/operations_test.go @@ -115,7 +115,7 @@ func TestSimulateMsgSubmitProposal(t *testing.T) { require.True(t, operationMsg.OK) require.Equal(t, "cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Proposer) - require.Equal(t, "2686011stake", msg.InitialDeposit.String()) + require.Equal(t, "7755634stake", msg.InitialDeposit.String()) require.Equal(t, "title-3: ZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", msg.GetContent().GetTitle()) require.Equal(t, "description-3: NJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeH", msg.GetContent().GetDescription()) require.Equal(t, "gov", msg.Route()) diff --git a/x/gov/spec/06_params.md b/x/gov/spec/06_params.md index 2cc0176693eb..31af466886b9 100644 --- a/x/gov/spec/06_params.md +++ b/x/gov/spec/06_params.md @@ -26,3 +26,12 @@ The governance module contains the following parameters: __NOTE__: The governance module contains parameters that are objects unlike other modules. If only a subset of parameters are desired to be changed, only they need to be included and not the entire parameter object structure. + +## Constant Variables + +| Key | Type | Constant Value | +|------------------------|------------------|------------------------| +| MinInitialDepositRatio | string (sdk.Dec) | "0.500000000000000000" | + +### MinInitialDepositRatio +The ratio representing the proportion of the deposit value that must be paid at proposal submission. \ No newline at end of file diff --git a/x/gov/types/errors.go b/x/gov/types/errors.go index 96973f1751a2..c04ee3832fdf 100644 --- a/x/gov/types/errors.go +++ b/x/gov/types/errors.go @@ -14,4 +14,5 @@ var ( ErrInvalidVote = sdkerrors.Register(ModuleName, 7, "invalid vote option") ErrInvalidGenesis = sdkerrors.Register(ModuleName, 8, "invalid genesis state") ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 9, "no handler exists for proposal type") + ErrMinDepositTooSmall = sdkerrors.Register(ModuleName, 10, "minimum deposit is too small") ) diff --git a/x/gov/types/params.go b/x/gov/types/params.go index 95621e100f8e..7079332008dd 100644 --- a/x/gov/types/params.go +++ b/x/gov/types/params.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -21,6 +21,7 @@ var ( DefaultQuorum = sdk.NewDecWithPrec(334, 3) DefaultThreshold = sdk.NewDecWithPrec(5, 1) DefaultVetoThreshold = sdk.NewDecWithPrec(334, 3) + MinInitialDepositRatio = sdk.NewDecWithPrec(5, 1) ) // Parameter store key From 6466df295127172203fdd9d15a3617566d4eaeb0 Mon Sep 17 00:00:00 2001 From: crypin Date: Fri, 17 Feb 2023 10:53:58 +0900 Subject: [PATCH 2/3] chore: fix vesting acc test code on custom gov --- x/auth/legacy/v043/store_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/auth/legacy/v043/store_test.go b/x/auth/legacy/v043/store_test.go index 6fbece49e8ad..1a9fb88660ed 100644 --- a/x/auth/legacy/v043/store_test.go +++ b/x/auth/legacy/v043/store_test.go @@ -332,6 +332,8 @@ func TestMigrateVestingAccounts(t *testing.T) { delayedAccount := types.NewPeriodicVestingAccount(baseAccount, vestedCoins, startTime, periods) + ctx = ctx.WithBlockTime(time.Unix(1601042400, 0)) + app.AccountKeeper.SetAccount(ctx, delayedAccount) // delegation of the original vesting, failed because of no spendable balances From fa4d31e4220cc606ff49b0327c4c0324dea3bdf9 Mon Sep 17 00:00:00 2001 From: crypin Date: Fri, 17 Feb 2023 15:02:08 +0900 Subject: [PATCH 3/3] test: fix test codes related min initial deposit, lint --- x/auth/vesting/msg_server.go | 1 - x/auth/vesting/types/msgs.go | 1 - x/feegrant/client/testutil/suite.go | 27 +++++++++++++++ x/gov/client/rest/grpc_query_test.go | 5 +-- x/gov/client/testutil/deposits.go | 50 +++++++--------------------- x/gov/client/testutil/suite.go | 9 ++--- x/gov/keeper/msg_server_test.go | 8 +++++ x/gov/types/hooks.go | 1 + 8 files changed, 56 insertions(+), 46 deletions(-) diff --git a/x/auth/vesting/msg_server.go b/x/auth/vesting/msg_server.go index 5557b96ba4a3..30634fafa6ec 100644 --- a/x/auth/vesting/msg_server.go +++ b/x/auth/vesting/msg_server.go @@ -156,5 +156,4 @@ func (s msgServer) CreatePeriodicVestingAccount(goCtx context.Context, msg *type ), ) return &types.MsgCreatePeriodicVestingAccountResponse{}, nil - } diff --git a/x/auth/vesting/types/msgs.go b/x/auth/vesting/types/msgs.go index 31c0fe53e927..f413c97ead2b 100644 --- a/x/auth/vesting/types/msgs.go +++ b/x/auth/vesting/types/msgs.go @@ -85,7 +85,6 @@ func (msg MsgCreateVestingAccount) GetSigners() []sdk.AccAddress { } // NewMsgCreatePeriodicVestingAccount returns a reference to a new MsgCreatePeriodicVestingAccount. -//nolint:interfacer func NewMsgCreatePeriodicVestingAccount(fromAddr, toAddr sdk.AccAddress, startTime int64, periods []Period) *MsgCreatePeriodicVestingAccount { return &MsgCreatePeriodicVestingAccount{ FromAddress: fromAddr.String(), diff --git a/x/feegrant/client/testutil/suite.go b/x/feegrant/client/testutil/suite.go index 781bc017b043..66c4ccd98a9b 100644 --- a/x/feegrant/client/testutil/suite.go +++ b/x/feegrant/client/testutil/suite.go @@ -18,8 +18,10 @@ import ( clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" + banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" "github.com/cosmos/cosmos-sdk/x/feegrant" "github.com/cosmos/cosmos-sdk/x/feegrant/client/cli" + govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" govtestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -51,6 +53,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.T().Skip("skipping test in unit-tests mode.") } + s.cfg.StakingTokens = s.cfg.StakingTokens.Add(govtypes.DefaultMinDepositTokens) s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) @@ -745,10 +748,22 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() { _, err = s.network.WaitForHeight(1) s.Require().NoError(err) + // Send some funds to the new account for initial deposit + _, err = banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + grantee, + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens)), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + ) + s.Require().NoError(err) + // granted fee allowance for an account which is not in state and creating // any tx with it by using --fee-account shouldn't fail out, err := govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(), "Text Proposal", "No desc", govtypes.ProposalTypeText, + fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens).String()), fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter.String()), ) @@ -875,6 +890,17 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { spendLimit.String(), ) + // Send some funds to the new account for initial deposit + _, err = banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + grantee, + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens)), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + ) + s.Require().NoError(err) + // exec filtered fee allowance cases := []struct { name string @@ -887,6 +913,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() { func() (testutil.BufferWriter, error) { return govtestutil.MsgSubmitProposal(val.ClientCtx, grantee.String(), "Text Proposal", "No desc", govtypes.ProposalTypeText, + fmt.Sprintf("--%s=%s", govcli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, govtypes.DefaultMinDepositTokens).String()), fmt.Sprintf("--%s=%s", flags.FlagFeeAccount, granter.String()), ) }, diff --git a/x/gov/client/rest/grpc_query_test.go b/x/gov/client/rest/grpc_query_test.go index 64aaf15c10b5..5ec2caf87139 100644 --- a/x/gov/client/rest/grpc_query_test.go +++ b/x/gov/client/rest/grpc_query_test.go @@ -52,9 +52,10 @@ func (s *IntegrationTestSuite) SetupSuite() { _, err = govtestutil.MsgVote(val.ClientCtx, val.Address.String(), "1", "yes") s.Require().NoError(err) - // create a proposal without deposit + // create a proposal with min initial deposit _, err = govtestutil.MsgSubmitProposal(val.ClientCtx, val.Address.String(), - "Text Proposal 2", "Where is the title!?", types.ProposalTypeText) + "Text Proposal 2", "Where is the title!?", types.ProposalTypeText, + fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.ToDec().Mul(types.MinInitialDepositRatio).RoundInt()).String())) s.Require().NoError(err) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) diff --git a/x/gov/client/testutil/deposits.go b/x/gov/client/testutil/deposits.go index 7c53c768d45d..0fce3678d33e 100644 --- a/x/gov/client/testutil/deposits.go +++ b/x/gov/client/testutil/deposits.go @@ -4,13 +4,14 @@ import ( "fmt" "time" + "github.com/stretchr/testify/suite" + tmcli "github.com/tendermint/tendermint/libs/cli" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/stretchr/testify/suite" - tmcli "github.com/tendermint/tendermint/libs/cli" ) type DepositTestSuite struct { @@ -69,46 +70,19 @@ func (s *DepositTestSuite) TestQueryDepositsInitialDeposit() { s.Require().Equal(deposits[0].Amount.String(), initialDeposit) } -func (s *DepositTestSuite) TestQueryDepositsWithoutInitialDeposit() { - val := s.network.Validators[0] - clientCtx := val.ClientCtx - - // create a proposal without deposit - _, err := MsgSubmitProposal(val.ClientCtx, val.Address.String(), - "Text Proposal 2", "Where is the title!?", types.ProposalTypeText) - s.Require().NoError(err) - - // deposit amount - _, err = MsgDeposit(clientCtx, val.Address.String(), "2", sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.Add(sdk.NewInt(50))).String()) - s.Require().NoError(err) - - // waiting for voting period to end - time.Sleep(20 * time.Second) - - // query deposit - deposit := s.queryDeposit(val, "2", false) - s.Require().Equal(deposit.Amount.String(), sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.Add(sdk.NewInt(50))).String()) - - // query deposits - deposits := s.queryDeposits(val, "2", false) - s.Require().Equal(len(deposits), 1) - // verify initial deposit - s.Require().Equal(deposits[0].Amount.String(), sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.Add(sdk.NewInt(50))).String()) -} - func (s *DepositTestSuite) TestQueryProposalNotEnoughDeposits() { val := s.network.Validators[0] clientCtx := val.ClientCtx - initialDeposit := sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.Sub(sdk.NewInt(2000))).String() + initialDeposit := sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.Sub(sdk.NewInt(1))).String() // create a proposal with deposit _, err := MsgSubmitProposal(val.ClientCtx, val.Address.String(), - "Text Proposal 3", "Where is the title!?", types.ProposalTypeText, + "Text Proposal 2", "Where is the title!?", types.ProposalTypeText, fmt.Sprintf("--%s=%s", cli.FlagDeposit, initialDeposit)) s.Require().NoError(err) // query proposal - args := []string{"3", fmt.Sprintf("--%s=json", tmcli.OutputFlag)} + args := []string{"2", fmt.Sprintf("--%s=json", tmcli.OutputFlag)} cmd := cli.GetCmdQueryProposal() _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) s.Require().NoError(err) @@ -119,7 +93,7 @@ func (s *DepositTestSuite) TestQueryProposalNotEnoughDeposits() { // query proposal _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) s.Require().Error(err) - s.Require().Contains(err.Error(), "proposal 3 doesn't exist") + s.Require().Contains(err.Error(), "proposal 2 doesn't exist") } func (s *DepositTestSuite) TestRejectedProposalDeposits() { @@ -129,13 +103,13 @@ func (s *DepositTestSuite) TestRejectedProposalDeposits() { // create a proposal with deposit _, err := MsgSubmitProposal(clientCtx, val.Address.String(), - "Text Proposal 4", "Where is the title!?", types.ProposalTypeText, + "Text Proposal 3", "Where is the title!?", types.ProposalTypeText, fmt.Sprintf("--%s=%s", cli.FlagDeposit, initialDeposit)) s.Require().NoError(err) // query deposits var deposits types.QueryDepositsResponse - args := []string{"4", fmt.Sprintf("--%s=json", tmcli.OutputFlag)} + args := []string{"3", fmt.Sprintf("--%s=json", tmcli.OutputFlag)} cmd := cli.GetCmdQueryDeposits() out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) s.Require().NoError(err) @@ -145,18 +119,18 @@ func (s *DepositTestSuite) TestRejectedProposalDeposits() { s.Require().Equal(deposits.Deposits[0].Amount.String(), sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens).String()) // vote - _, err = MsgVote(clientCtx, val.Address.String(), "4", "no") + _, err = MsgVote(clientCtx, val.Address.String(), "3", "no") s.Require().NoError(err) time.Sleep(20 * time.Second) - args = []string{"4", fmt.Sprintf("--%s=json", tmcli.OutputFlag)} + args = []string{"3", fmt.Sprintf("--%s=json", tmcli.OutputFlag)} cmd = cli.GetCmdQueryProposal() _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) s.Require().NoError(err) // query deposits - depositsRes := s.queryDeposits(val, "4", false) + depositsRes := s.queryDeposits(val, "3", false) s.Require().Equal(len(depositsRes), 1) // verify initial deposit s.Require().Equal(depositsRes[0].Amount.String(), initialDeposit.String()) diff --git a/x/gov/client/testutil/suite.go b/x/gov/client/testutil/suite.go index ee2634e3d188..5a1859c21df5 100644 --- a/x/gov/client/testutil/suite.go +++ b/x/gov/client/testutil/suite.go @@ -52,9 +52,10 @@ func (s *IntegrationTestSuite) SetupSuite() { _, err = MsgVote(val.ClientCtx, val.Address.String(), "1", "yes") s.Require().NoError(err) - // create a proposal without deposit + // create a proposal with min initial deposit _, err = MsgSubmitProposal(val.ClientCtx, val.Address.String(), - "Text Proposal 2", "Where is the title!?", types.ProposalTypeText) + "Text Proposal 2", "Where is the title!?", types.ProposalTypeText, + fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, types.DefaultMinDepositTokens.ToDec().Mul(types.MinInitialDepositRatio).RoundInt()).String())) s.Require().NoError(err) _, err = s.network.WaitForHeight(1) s.Require().NoError(err) @@ -287,7 +288,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { "description": "Hello, World!", "type": "Text", "deposit": "%s" -}`, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431))) +}`, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5000000))) validPropFile := testutil.WriteToNewTempFile(s.T(), validProp) testCases := []struct { name string @@ -335,7 +336,7 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { fmt.Sprintf("--%s='Text Proposal'", cli.FlagTitle), fmt.Sprintf("--%s='Where is the title!?'", cli.FlagDescription), fmt.Sprintf("--%s=%s", cli.FlagProposalType, types.ProposalTypeText), - fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)).String()), + fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5000000)).String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), diff --git a/x/gov/keeper/msg_server_test.go b/x/gov/keeper/msg_server_test.go index ae36bd86d5b1..4961f9d85f1f 100644 --- a/x/gov/keeper/msg_server_test.go +++ b/x/gov/keeper/msg_server_test.go @@ -52,6 +52,14 @@ func TestSubmitProposal_InitialDeposit(t *testing.T) { initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue-1))), accountBalance: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue-1))), + expectError: true, + }, + "does not meet initial deposit with zero initial deposit - error": { + minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))), + minInitialDepositRatio: types.MinInitialDepositRatio, + initialDeposit: sdk.NewCoins(), + accountBalance: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(meetsDepositValue))), + expectError: true, }, } diff --git a/x/gov/types/hooks.go b/x/gov/types/hooks.go index be4b0d356db9..47f22cd3ca81 100644 --- a/x/gov/types/hooks.go +++ b/x/gov/types/hooks.go @@ -42,6 +42,7 @@ func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalI h[i].AfterProposalVotingPeriodEnded(ctx, proposalID) } } + func (h MultiGovHooks) SetAdditionalVotingPowers(ctx sdk.Context, votes Votes, votingPowers *AdditionalVotingPowers) { for i := range h { h[i].SetAdditionalVotingPowers(ctx, votes, votingPowers)