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 }