github.com/cosmos/cosmos-sdk@v0.50.10/x/gov/abci_test.go (about)

     1  package gov_test
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	abci "github.com/cometbft/cometbft/abci/types"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"cosmossdk.io/collections"
    11  	"cosmossdk.io/math"
    12  
    13  	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
    14  	sdk "github.com/cosmos/cosmos-sdk/types"
    15  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    16  	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    17  	"github.com/cosmos/cosmos-sdk/x/gov"
    18  	"github.com/cosmos/cosmos-sdk/x/gov/keeper"
    19  	"github.com/cosmos/cosmos-sdk/x/gov/types"
    20  	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    21  	stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
    22  	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
    23  )
    24  
    25  func TestUnregisteredProposal_InactiveProposalFails(t *testing.T) {
    26  	suite := createTestSuite(t)
    27  	ctx := suite.App.BaseApp.NewContext(false)
    28  	addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens)
    29  
    30  	// manually set proposal in store
    31  	startTime, endTime := time.Now().Add(-4*time.Hour), ctx.BlockHeader().Time
    32  	proposal, err := v1.NewProposal([]sdk.Msg{
    33  		&v1.Proposal{}, // invalid proposal message
    34  	}, 1, startTime, startTime, "", "Unsupported proposal", "Unsupported proposal", addrs[0], false)
    35  	require.NoError(t, err)
    36  
    37  	err = suite.GovKeeper.SetProposal(ctx, proposal)
    38  	require.NoError(t, err)
    39  
    40  	// manually set proposal in inactive proposal queue
    41  	err = suite.GovKeeper.InactiveProposalsQueue.Set(ctx, collections.Join(endTime, proposal.Id), proposal.Id)
    42  	require.NoError(t, err)
    43  
    44  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
    45  
    46  	err = gov.EndBlocker(ctx, suite.GovKeeper)
    47  	require.NoError(t, err)
    48  
    49  	_, err = suite.GovKeeper.Proposals.Get(ctx, proposal.Id)
    50  	require.Error(t, err, collections.ErrNotFound)
    51  }
    52  
    53  func TestUnregisteredProposal_ActiveProposalFails(t *testing.T) {
    54  	suite := createTestSuite(t)
    55  	ctx := suite.App.BaseApp.NewContext(false)
    56  	addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens)
    57  
    58  	// manually set proposal in store
    59  	startTime, endTime := time.Now().Add(-4*time.Hour), ctx.BlockHeader().Time
    60  	proposal, err := v1.NewProposal([]sdk.Msg{
    61  		&v1.Proposal{}, // invalid proposal message
    62  	}, 1, startTime, startTime, "", "Unsupported proposal", "Unsupported proposal", addrs[0], false)
    63  	require.NoError(t, err)
    64  	proposal.Status = v1.StatusVotingPeriod
    65  	proposal.VotingEndTime = &endTime
    66  
    67  	err = suite.GovKeeper.SetProposal(ctx, proposal)
    68  	require.NoError(t, err)
    69  
    70  	// manually set proposal in active proposal queue
    71  	err = suite.GovKeeper.ActiveProposalsQueue.Set(ctx, collections.Join(endTime, proposal.Id), proposal.Id)
    72  	require.NoError(t, err)
    73  
    74  	checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
    75  
    76  	err = gov.EndBlocker(ctx, suite.GovKeeper)
    77  	require.NoError(t, err)
    78  
    79  	p, err := suite.GovKeeper.Proposals.Get(ctx, proposal.Id)
    80  	require.NoError(t, err)
    81  	require.Equal(t, v1.StatusFailed, p.Status)
    82  }
    83  
    84  func TestTickExpiredDepositPeriod(t *testing.T) {
    85  	suite := createTestSuite(t)
    86  	app := suite.App
    87  	ctx := app.BaseApp.NewContext(false)
    88  	addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens)
    89  
    90  	app.FinalizeBlock(&abci.RequestFinalizeBlock{
    91  		Height: app.LastBlockHeight() + 1,
    92  		Hash:   app.LastCommitID().Hash,
    93  	})
    94  
    95  	govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
    96  
    97  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
    98  
    99  	newProposalMsg, err := v1.NewMsgSubmitProposal(
   100  		[]sdk.Msg{mkTestLegacyContent(t)},
   101  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)},
   102  		addrs[0].String(),
   103  		"",
   104  		"Proposal",
   105  		"description of proposal",
   106  		false,
   107  	)
   108  	require.NoError(t, err)
   109  
   110  	res, err := govMsgSvr.SubmitProposal(ctx, newProposalMsg)
   111  	require.NoError(t, err)
   112  	require.NotNil(t, res)
   113  
   114  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   115  
   116  	newHeader := ctx.BlockHeader()
   117  	newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
   118  	ctx = ctx.WithBlockHeader(newHeader)
   119  
   120  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   121  
   122  	params, _ := suite.GovKeeper.Params.Get(ctx)
   123  	newHeader = ctx.BlockHeader()
   124  	newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod)
   125  	ctx = ctx.WithBlockHeader(newHeader)
   126  
   127  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   128  
   129  	err = gov.EndBlocker(ctx, suite.GovKeeper)
   130  	require.NoError(t, err)
   131  
   132  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   133  }
   134  
   135  func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
   136  	suite := createTestSuite(t)
   137  	app := suite.App
   138  	ctx := app.BaseApp.NewContext(false)
   139  	addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens)
   140  
   141  	app.FinalizeBlock(&abci.RequestFinalizeBlock{
   142  		Height: app.LastBlockHeight() + 1,
   143  		Hash:   app.LastCommitID().Hash,
   144  	})
   145  
   146  	govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
   147  
   148  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   149  
   150  	newProposalMsg, err := v1.NewMsgSubmitProposal(
   151  		[]sdk.Msg{mkTestLegacyContent(t)},
   152  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)},
   153  		addrs[0].String(),
   154  		"",
   155  		"Proposal",
   156  		"description of proposal",
   157  		false,
   158  	)
   159  	require.NoError(t, err)
   160  
   161  	res, err := govMsgSvr.SubmitProposal(ctx, newProposalMsg)
   162  	require.NoError(t, err)
   163  	require.NotNil(t, res)
   164  
   165  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   166  
   167  	newHeader := ctx.BlockHeader()
   168  	newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second)
   169  	ctx = ctx.WithBlockHeader(newHeader)
   170  
   171  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   172  
   173  	newProposalMsg2, err := v1.NewMsgSubmitProposal(
   174  		[]sdk.Msg{mkTestLegacyContent(t)},
   175  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)},
   176  		addrs[0].String(),
   177  		"",
   178  		"Proposal",
   179  		"description of proposal",
   180  		false,
   181  	)
   182  	require.NoError(t, err)
   183  
   184  	res, err = govMsgSvr.SubmitProposal(ctx, newProposalMsg2)
   185  	require.NoError(t, err)
   186  	require.NotNil(t, res)
   187  
   188  	newHeader = ctx.BlockHeader()
   189  	params, _ := suite.GovKeeper.Params.Get(ctx)
   190  	newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(time.Duration(-1) * time.Second)
   191  	ctx = ctx.WithBlockHeader(newHeader)
   192  
   193  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   194  	require.NoError(t, gov.EndBlocker(ctx, suite.GovKeeper))
   195  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   196  
   197  	newHeader = ctx.BlockHeader()
   198  	newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second)
   199  	ctx = ctx.WithBlockHeader(newHeader)
   200  
   201  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   202  	require.NoError(t, gov.EndBlocker(ctx, suite.GovKeeper))
   203  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   204  }
   205  
   206  func TestTickPassedDepositPeriod(t *testing.T) {
   207  	suite := createTestSuite(t)
   208  	app := suite.App
   209  	ctx := app.BaseApp.NewContext(false)
   210  	addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens)
   211  
   212  	app.FinalizeBlock(&abci.RequestFinalizeBlock{
   213  		Height: app.LastBlockHeight() + 1,
   214  		Hash:   app.LastCommitID().Hash,
   215  	})
   216  
   217  	govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
   218  
   219  	newProposalMsg, err := v1.NewMsgSubmitProposal(
   220  		[]sdk.Msg{mkTestLegacyContent(t)},
   221  		sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)},
   222  		addrs[0].String(),
   223  		"",
   224  		"Proposal",
   225  		"description of proposal",
   226  		false,
   227  	)
   228  	require.NoError(t, err)
   229  
   230  	res, err := govMsgSvr.SubmitProposal(ctx, newProposalMsg)
   231  	require.NoError(t, err)
   232  	require.NotNil(t, res)
   233  
   234  	proposalID := res.ProposalId
   235  
   236  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   237  
   238  	newHeader := ctx.BlockHeader()
   239  	newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
   240  	ctx = ctx.WithBlockHeader(newHeader)
   241  
   242  	checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   243  
   244  	newDepositMsg := v1.NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000)})
   245  
   246  	res1, err := govMsgSvr.Deposit(ctx, newDepositMsg)
   247  	require.NoError(t, err)
   248  	require.NotNil(t, res1)
   249  
   250  	checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   251  }
   252  
   253  func TestTickPassedVotingPeriod(t *testing.T) {
   254  	testcases := []struct {
   255  		name      string
   256  		expedited bool
   257  	}{
   258  		{
   259  			name: "regular - deleted",
   260  		},
   261  		{
   262  			name:      "expedited - converted to regular",
   263  			expedited: true,
   264  		},
   265  	}
   266  
   267  	for _, tc := range testcases {
   268  		t.Run(tc.name, func(t *testing.T) {
   269  			suite := createTestSuite(t)
   270  			app := suite.App
   271  			ctx := app.BaseApp.NewContext(false)
   272  			depositMultiplier := getDepositMultiplier(tc.expedited)
   273  			addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens.Mul(math.NewInt(depositMultiplier)))
   274  
   275  			SortAddresses(addrs)
   276  
   277  			app.FinalizeBlock(&abci.RequestFinalizeBlock{
   278  				Height: app.LastBlockHeight() + 1,
   279  				Hash:   app.LastCommitID().Hash,
   280  			})
   281  
   282  			govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
   283  
   284  			checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   285  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   286  
   287  			proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, suite.StakingKeeper.TokensFromConsensusPower(ctx, 5*depositMultiplier))}
   288  			newProposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{mkTestLegacyContent(t)}, proposalCoins, addrs[0].String(), "", "Proposal", "description of proposal", tc.expedited)
   289  			require.NoError(t, err)
   290  
   291  			res, err := govMsgSvr.SubmitProposal(ctx, newProposalMsg)
   292  			require.NoError(t, err)
   293  			require.NotNil(t, res)
   294  
   295  			proposalID := res.ProposalId
   296  
   297  			newHeader := ctx.BlockHeader()
   298  			newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
   299  			ctx = ctx.WithBlockHeader(newHeader)
   300  
   301  			newDepositMsg := v1.NewMsgDeposit(addrs[1], proposalID, proposalCoins)
   302  
   303  			res1, err := govMsgSvr.Deposit(ctx, newDepositMsg)
   304  			require.NoError(t, err)
   305  			require.NotNil(t, res1)
   306  
   307  			params, _ := suite.GovKeeper.Params.Get(ctx)
   308  			votingPeriod := params.VotingPeriod
   309  			if tc.expedited {
   310  				votingPeriod = params.ExpeditedVotingPeriod
   311  			}
   312  
   313  			newHeader = ctx.BlockHeader()
   314  			newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*votingPeriod)
   315  			ctx = ctx.WithBlockHeader(newHeader)
   316  
   317  			checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   318  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   319  
   320  			proposal, err := suite.GovKeeper.Proposals.Get(ctx, res.ProposalId)
   321  			require.NoError(t, err)
   322  			require.Equal(t, v1.StatusVotingPeriod, proposal.Status)
   323  
   324  			err = gov.EndBlocker(ctx, suite.GovKeeper)
   325  			require.NoError(t, err)
   326  
   327  			if !tc.expedited {
   328  				checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   329  				return
   330  			}
   331  
   332  			// If expedited, it should be converted to a regular proposal instead.
   333  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   334  
   335  			proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId)
   336  			require.Nil(t, err)
   337  			require.Equal(t, v1.StatusVotingPeriod, proposal.Status)
   338  			require.False(t, proposal.Expedited)
   339  			require.Equal(t, proposal.VotingStartTime.Add(*params.VotingPeriod), *proposal.VotingEndTime)
   340  		})
   341  	}
   342  }
   343  
   344  func TestProposalPassedEndblocker(t *testing.T) {
   345  	testcases := []struct {
   346  		name      string
   347  		expedited bool
   348  	}{
   349  		{
   350  			name: "regular",
   351  		},
   352  		{
   353  			name:      "expedited",
   354  			expedited: true,
   355  		},
   356  	}
   357  
   358  	for _, tc := range testcases {
   359  		t.Run(tc.name, func(t *testing.T) {
   360  			suite := createTestSuite(t)
   361  			app := suite.App
   362  			ctx := app.BaseApp.NewContext(false)
   363  			depositMultiplier := getDepositMultiplier(tc.expedited)
   364  			addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 10, valTokens.Mul(math.NewInt(depositMultiplier)))
   365  
   366  			SortAddresses(addrs)
   367  
   368  			govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
   369  			stakingMsgSvr := stakingkeeper.NewMsgServerImpl(suite.StakingKeeper)
   370  
   371  			app.FinalizeBlock(&abci.RequestFinalizeBlock{
   372  				Height: app.LastBlockHeight() + 1,
   373  				Hash:   app.LastCommitID().Hash,
   374  			})
   375  
   376  			valAddr := sdk.ValAddress(addrs[0])
   377  			proposer := addrs[0]
   378  
   379  			createValidators(t, stakingMsgSvr, ctx, []sdk.ValAddress{valAddr}, []int64{10})
   380  			suite.StakingKeeper.EndBlocker(ctx)
   381  
   382  			macc := suite.GovKeeper.GetGovernanceAccount(ctx)
   383  			require.NotNil(t, macc)
   384  			initialModuleAccCoins := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
   385  
   386  			proposal, err := suite.GovKeeper.SubmitProposal(ctx, []sdk.Msg{mkTestLegacyContent(t)}, "", "title", "summary", proposer, tc.expedited)
   387  			require.NoError(t, err)
   388  
   389  			proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, suite.StakingKeeper.TokensFromConsensusPower(ctx, 10*depositMultiplier))}
   390  			newDepositMsg := v1.NewMsgDeposit(addrs[0], proposal.Id, proposalCoins)
   391  
   392  			res, err := govMsgSvr.Deposit(ctx, newDepositMsg)
   393  			require.NoError(t, err)
   394  			require.NotNil(t, res)
   395  
   396  			macc = suite.GovKeeper.GetGovernanceAccount(ctx)
   397  			require.NotNil(t, macc)
   398  			moduleAccCoins := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
   399  
   400  			deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...)
   401  			require.True(t, moduleAccCoins.Equal(deposits))
   402  
   403  			err = suite.GovKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")
   404  			require.NoError(t, err)
   405  
   406  			newHeader := ctx.BlockHeader()
   407  			params, _ := suite.GovKeeper.Params.Get(ctx)
   408  			newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*params.VotingPeriod)
   409  			ctx = ctx.WithBlockHeader(newHeader)
   410  
   411  			gov.EndBlocker(ctx, suite.GovKeeper)
   412  
   413  			macc = suite.GovKeeper.GetGovernanceAccount(ctx)
   414  			require.NotNil(t, macc)
   415  			require.True(t, suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress()).Equal(initialModuleAccCoins))
   416  		})
   417  	}
   418  }
   419  
   420  func TestEndBlockerProposalHandlerFailed(t *testing.T) {
   421  	suite := createTestSuite(t)
   422  	app := suite.App
   423  	ctx := app.BaseApp.NewContext(false)
   424  	addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 1, valTokens)
   425  
   426  	SortAddresses(addrs)
   427  
   428  	stakingMsgSvr := stakingkeeper.NewMsgServerImpl(suite.StakingKeeper)
   429  
   430  	app.FinalizeBlock(&abci.RequestFinalizeBlock{
   431  		Height: app.LastBlockHeight() + 1,
   432  		Hash:   app.LastCommitID().Hash,
   433  	})
   434  
   435  	valAddr := sdk.ValAddress(addrs[0])
   436  	proposer := addrs[0]
   437  
   438  	createValidators(t, stakingMsgSvr, ctx, []sdk.ValAddress{valAddr}, []int64{10})
   439  	suite.StakingKeeper.EndBlocker(ctx)
   440  
   441  	msg := banktypes.NewMsgSend(authtypes.NewModuleAddress(types.ModuleName), addrs[0], sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000))))
   442  	proposal, err := suite.GovKeeper.SubmitProposal(ctx, []sdk.Msg{msg}, "", "title", "summary", proposer, false)
   443  	require.NoError(t, err)
   444  
   445  	proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, suite.StakingKeeper.TokensFromConsensusPower(ctx, 10)))
   446  	newDepositMsg := v1.NewMsgDeposit(addrs[0], proposal.Id, proposalCoins)
   447  
   448  	govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
   449  	res, err := govMsgSvr.Deposit(ctx, newDepositMsg)
   450  	require.NoError(t, err)
   451  	require.NotNil(t, res)
   452  
   453  	err = suite.GovKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")
   454  	require.NoError(t, err)
   455  
   456  	params, _ := suite.GovKeeper.Params.Get(ctx)
   457  	newHeader := ctx.BlockHeader()
   458  	newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*params.VotingPeriod)
   459  	ctx = ctx.WithBlockHeader(newHeader)
   460  
   461  	// validate that the proposal fails/has been rejected
   462  	gov.EndBlocker(ctx, suite.GovKeeper)
   463  
   464  	// check proposal events
   465  	events := ctx.EventManager().Events()
   466  	attr, eventOk := events.GetAttributes(types.AttributeKeyProposalLog)
   467  	require.True(t, eventOk)
   468  	require.Contains(t, attr[0].Value, "failed on execution")
   469  
   470  	proposal, err = suite.GovKeeper.Proposals.Get(ctx, proposal.Id)
   471  	require.Nil(t, err)
   472  	require.Equal(t, v1.StatusFailed, proposal.Status)
   473  }
   474  
   475  func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) {
   476  	testcases := []struct {
   477  		name string
   478  		// indicates whether the expedited proposal passes.
   479  		expeditedPasses bool
   480  		// indicates whether the converted regular proposal is expected to eventually pass
   481  		regularEventuallyPassing bool
   482  	}{
   483  		{
   484  			name:            "expedited passes and not converted to regular",
   485  			expeditedPasses: true,
   486  		},
   487  		{
   488  			name:                     "expedited fails, converted to regular - regular eventually passes",
   489  			expeditedPasses:          false,
   490  			regularEventuallyPassing: true,
   491  		},
   492  		{
   493  			name:                     "expedited fails, converted to regular - regular eventually fails",
   494  			expeditedPasses:          false,
   495  			regularEventuallyPassing: false,
   496  		},
   497  	}
   498  
   499  	for _, tc := range testcases {
   500  		t.Run(tc.name, func(t *testing.T) {
   501  			suite := createTestSuite(t)
   502  			app := suite.App
   503  			ctx := app.BaseApp.NewContext(false)
   504  			depositMultiplier := getDepositMultiplier(true)
   505  			addrs := simtestutil.AddTestAddrs(suite.BankKeeper, suite.StakingKeeper, ctx, 3, valTokens.Mul(math.NewInt(depositMultiplier)))
   506  			params, err := suite.GovKeeper.Params.Get(ctx)
   507  			require.NoError(t, err)
   508  
   509  			SortAddresses(addrs)
   510  
   511  			govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper)
   512  			stakingMsgSvr := stakingkeeper.NewMsgServerImpl(suite.StakingKeeper)
   513  
   514  			app.FinalizeBlock(&abci.RequestFinalizeBlock{
   515  				Height: app.LastBlockHeight() + 1,
   516  				Hash:   app.LastCommitID().Hash,
   517  			})
   518  
   519  			valAddr := sdk.ValAddress(addrs[0])
   520  			proposer := addrs[0]
   521  
   522  			// Create a validator so that able to vote on proposal.
   523  			createValidators(t, stakingMsgSvr, ctx, []sdk.ValAddress{valAddr}, []int64{10})
   524  			suite.StakingKeeper.EndBlocker(ctx)
   525  
   526  			checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   527  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   528  
   529  			macc := suite.GovKeeper.GetGovernanceAccount(ctx)
   530  			require.NotNil(t, macc)
   531  			initialModuleAccCoins := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
   532  
   533  			submitterInitialBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[0])
   534  			depositorInitialBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[1])
   535  
   536  			proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, suite.StakingKeeper.TokensFromConsensusPower(ctx, 5*depositMultiplier))}
   537  			newProposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{}, proposalCoins, proposer.String(), "metadata", "title", "summary", true)
   538  			require.NoError(t, err)
   539  
   540  			res, err := govMsgSvr.SubmitProposal(ctx, newProposalMsg)
   541  			require.NoError(t, err)
   542  			require.NotNil(t, res)
   543  
   544  			proposalID := res.ProposalId
   545  
   546  			newHeader := ctx.BlockHeader()
   547  			newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
   548  			ctx = ctx.WithBlockHeader(newHeader)
   549  
   550  			newDepositMsg := v1.NewMsgDeposit(addrs[1], proposalID, proposalCoins)
   551  
   552  			res1, err := govMsgSvr.Deposit(ctx, newDepositMsg)
   553  			require.NoError(t, err)
   554  			require.NotNil(t, res1)
   555  
   556  			newHeader = ctx.BlockHeader()
   557  			newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*params.ExpeditedVotingPeriod)
   558  			ctx = ctx.WithBlockHeader(newHeader)
   559  
   560  			checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   561  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   562  
   563  			proposal, err := suite.GovKeeper.Proposals.Get(ctx, res.ProposalId)
   564  			require.Nil(t, err)
   565  			require.Equal(t, v1.StatusVotingPeriod, proposal.Status)
   566  
   567  			if tc.expeditedPasses {
   568  				// Validator votes YES, letting the expedited proposal pass.
   569  				err = suite.GovKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "metadata")
   570  				require.NoError(t, err)
   571  			}
   572  
   573  			// Here the expedited proposal is converted to regular after expiry.
   574  			gov.EndBlocker(ctx, suite.GovKeeper)
   575  
   576  			if tc.expeditedPasses {
   577  				checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   578  
   579  				proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId)
   580  				require.Nil(t, err)
   581  
   582  				require.Equal(t, v1.StatusPassed, proposal.Status)
   583  
   584  				submitterEventualBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[0])
   585  				depositorEventualBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[1])
   586  
   587  				eventualModuleAccCoins := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
   588  
   589  				// Module account has refunded the deposit
   590  				require.Equal(t, initialModuleAccCoins, eventualModuleAccCoins)
   591  
   592  				require.Equal(t, submitterInitialBalance, submitterEventualBalance)
   593  				require.Equal(t, depositorInitialBalance, depositorEventualBalance)
   594  				return
   595  			}
   596  
   597  			// Expedited proposal should be converted to a regular proposal instead.
   598  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   599  			proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId)
   600  			require.Nil(t, err)
   601  			require.Equal(t, v1.StatusVotingPeriod, proposal.Status)
   602  			require.False(t, proposal.Expedited)
   603  			require.Equal(t, proposal.VotingStartTime.Add(*params.VotingPeriod), *proposal.VotingEndTime)
   604  
   605  			// We also want to make sure that the deposit is not refunded yet and is still present in the module account
   606  			macc = suite.GovKeeper.GetGovernanceAccount(ctx)
   607  			require.NotNil(t, macc)
   608  			intermediateModuleAccCoins := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
   609  			require.NotEqual(t, initialModuleAccCoins, intermediateModuleAccCoins)
   610  
   611  			// Submit proposal deposit + 1 extra top up deposit
   612  			expectedIntermediateMofuleAccCoings := initialModuleAccCoins.Add(proposalCoins...).Add(proposalCoins...)
   613  			require.Equal(t, expectedIntermediateMofuleAccCoings, intermediateModuleAccCoins)
   614  
   615  			// block header time at the voting period
   616  			newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*params.VotingPeriod)
   617  			ctx = ctx.WithBlockHeader(newHeader)
   618  
   619  			checkInactiveProposalsQueue(t, ctx, suite.GovKeeper)
   620  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   621  
   622  			if tc.regularEventuallyPassing {
   623  				// Validator votes YES, letting the converted regular proposal pass.
   624  				err = suite.GovKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "metadata")
   625  				require.NoError(t, err)
   626  			}
   627  
   628  			// Here we validate the converted regular proposal
   629  			gov.EndBlocker(ctx, suite.GovKeeper)
   630  
   631  			macc = suite.GovKeeper.GetGovernanceAccount(ctx)
   632  			require.NotNil(t, macc)
   633  			eventualModuleAccCoins := suite.BankKeeper.GetAllBalances(ctx, macc.GetAddress())
   634  
   635  			submitterEventualBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[0])
   636  			depositorEventualBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[1])
   637  
   638  			checkActiveProposalsQueue(t, ctx, suite.GovKeeper)
   639  
   640  			proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId)
   641  			require.Nil(t, err)
   642  
   643  			if tc.regularEventuallyPassing {
   644  				// Module account has refunded the deposit
   645  				require.Equal(t, initialModuleAccCoins, eventualModuleAccCoins)
   646  				require.Equal(t, submitterInitialBalance, submitterEventualBalance)
   647  				require.Equal(t, depositorInitialBalance, depositorEventualBalance)
   648  
   649  				require.Equal(t, v1.StatusPassed, proposal.Status)
   650  				return
   651  			}
   652  
   653  			// Not enough votes - module account has returned the deposit
   654  			require.Equal(t, initialModuleAccCoins, eventualModuleAccCoins)
   655  			require.Equal(t, submitterInitialBalance, submitterEventualBalance)
   656  			require.Equal(t, depositorInitialBalance, depositorEventualBalance)
   657  
   658  			require.Equal(t, v1.StatusRejected, proposal.Status)
   659  		})
   660  	}
   661  }
   662  
   663  func createValidators(t *testing.T, stakingMsgSvr stakingtypes.MsgServer, ctx sdk.Context, addrs []sdk.ValAddress, powerAmt []int64) {
   664  	require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.")
   665  
   666  	for i := 0; i < len(addrs); i++ {
   667  		valTokens := sdk.TokensFromConsensusPower(powerAmt[i], sdk.DefaultPowerReduction)
   668  		valCreateMsg, err := stakingtypes.NewMsgCreateValidator(
   669  			addrs[i].String(), pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens),
   670  			TestDescription, TestCommissionRates, math.OneInt(),
   671  		)
   672  		require.NoError(t, err)
   673  		res, err := stakingMsgSvr.CreateValidator(ctx, valCreateMsg)
   674  		require.NoError(t, err)
   675  		require.NotNil(t, res)
   676  	}
   677  }
   678  
   679  // With expedited proposal's minimum deposit set higher than the default deposit, we must
   680  // initialize and deposit an amount depositMultiplier times larger
   681  // than the regular min deposit amount.
   682  func getDepositMultiplier(expedited bool) int64 {
   683  	if expedited {
   684  		return v1.DefaultMinExpeditedDepositTokensRatio
   685  	}
   686  
   687  	return 1
   688  }
   689  
   690  func checkActiveProposalsQueue(t *testing.T, ctx sdk.Context, k *keeper.Keeper) {
   691  	err := k.ActiveProposalsQueue.Walk(ctx, collections.NewPrefixUntilPairRange[time.Time, uint64](ctx.BlockTime()), func(key collections.Pair[time.Time, uint64], value uint64) (stop bool, err error) {
   692  		return false, err
   693  	})
   694  
   695  	require.NoError(t, err)
   696  }
   697  
   698  func checkInactiveProposalsQueue(t *testing.T, ctx sdk.Context, k *keeper.Keeper) {
   699  	err := k.InactiveProposalsQueue.Walk(ctx, collections.NewPrefixUntilPairRange[time.Time, uint64](ctx.BlockTime()), func(key collections.Pair[time.Time, uint64], value uint64) (stop bool, err error) {
   700  		return false, err
   701  	})
   702  
   703  	require.NoError(t, err)
   704  }