@@ -33,6 +33,8 @@ import (
3333 minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
3434)
3535
36+ const minExecutionPeriod = 5 * time .Second
37+
3638type TestSuite struct {
3739 suite.Suite
3840
@@ -98,7 +100,7 @@ func (s *TestSuite) SetupTest() {
98100 policy := group .NewThresholdDecisionPolicy (
99101 "2" ,
100102 time .Second ,
101- 0 ,
103+ minExecutionPeriod , // Must wait 5 seconds before executing proposal
102104 )
103105 policyReq := & group.MsgCreateGroupPolicy {
104106 Admin : s .addrs [0 ].String (),
@@ -1551,36 +1553,48 @@ func (s *TestSuite) TestGroupPoliciesByAdminOrGroup() {
15511553func (s * TestSuite ) TestSubmitProposal () {
15521554 addrs := s .addrs
15531555 addr1 := addrs [0 ]
1554- addr2 := addrs [1 ]
1556+ addr2 := addrs [1 ] // Has weight 2
15551557 addr4 := addrs [3 ]
1556- addr5 := addrs [4 ]
1558+ addr5 := addrs [4 ] // Has weight 1
15571559
15581560 myGroupID := s .groupID
15591561 accountAddr := s .groupPolicyAddr
15601562
1561- msgSend := & banktypes.MsgSend {
1562- FromAddress : s .groupPolicyAddr .String (),
1563- ToAddress : addr2 .String (),
1564- Amount : sdk.Coins {sdk .NewInt64Coin ("test" , 100 )},
1565- }
1566-
1563+ // Create a new group policy to test TRY_EXEC
15671564 policyReq := & group.MsgCreateGroupPolicy {
15681565 Admin : addr1 .String (),
15691566 GroupId : myGroupID ,
15701567 }
1571- policy := group .NewThresholdDecisionPolicy (
1572- "100 " ,
1568+ noMinExecPeriodPolicy := group .NewThresholdDecisionPolicy (
1569+ "2 " ,
15731570 time .Second ,
1574- 0 ,
1571+ 0 , // no MinExecutionPeriod to test TRY_EXEC
15751572 )
1576- err := policyReq .SetDecisionPolicy (policy )
1573+ err := policyReq .SetDecisionPolicy (noMinExecPeriodPolicy )
15771574 s .Require ().NoError (err )
1575+ s .setNextAccount ()
1576+ res , err := s .groupKeeper .CreateGroupPolicy (s .ctx , policyReq )
1577+ s .Require ().NoError (err )
1578+ noMinExecPeriodPolicyAddr := sdk .MustAccAddressFromBech32 (res .Address )
15781579
1580+ // Create a new group policy with super high threshold
1581+ bigThresholdPolicy := group .NewThresholdDecisionPolicy (
1582+ "100" ,
1583+ time .Second ,
1584+ minExecutionPeriod ,
1585+ )
15791586 s .setNextAccount ()
1587+ err = policyReq .SetDecisionPolicy (bigThresholdPolicy )
1588+ s .Require ().NoError (err )
15801589 bigThresholdRes , err := s .groupKeeper .CreateGroupPolicy (s .ctx , policyReq )
15811590 s .Require ().NoError (err )
15821591 bigThresholdAddr := bigThresholdRes .Address
15831592
1593+ msgSend := & banktypes.MsgSend {
1594+ FromAddress : noMinExecPeriodPolicyAddr .String (),
1595+ ToAddress : addr2 .String (),
1596+ Amount : sdk.Coins {sdk .NewInt64Coin ("test" , 100 )},
1597+ }
15841598 defaultProposal := group.Proposal {
15851599 GroupPolicyAddress : accountAddr .String (),
15861600 Status : group .PROPOSAL_STATUS_SUBMITTED ,
@@ -1699,13 +1713,13 @@ func (s *TestSuite) TestSubmitProposal() {
16991713 }
17001714 },
17011715 req : & group.MsgSubmitProposal {
1702- GroupPolicyAddress : accountAddr .String (),
1716+ GroupPolicyAddress : noMinExecPeriodPolicyAddr .String (),
17031717 Proposers : []string {addr2 .String ()},
17041718 Exec : group .Exec_EXEC_TRY ,
17051719 },
17061720 msgs : []sdk.Msg {msgSend },
17071721 expProposal : group.Proposal {
1708- GroupPolicyAddress : accountAddr .String (),
1722+ GroupPolicyAddress : noMinExecPeriodPolicyAddr .String (),
17091723 Status : group .PROPOSAL_STATUS_ACCEPTED ,
17101724 FinalTallyResult : group.TallyResult {
17111725 YesCount : "2" ,
@@ -1716,24 +1730,24 @@ func (s *TestSuite) TestSubmitProposal() {
17161730 ExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_SUCCESS ,
17171731 },
17181732 postRun : func (sdkCtx sdk.Context ) {
1719- s .bankKeeper .EXPECT ().GetAllBalances (sdkCtx , accountAddr ).Return (sdk .NewCoins (sdk .NewInt64Coin ("test" , 9900 )))
1733+ s .bankKeeper .EXPECT ().GetAllBalances (sdkCtx , noMinExecPeriodPolicyAddr ).Return (sdk .NewCoins (sdk .NewInt64Coin ("test" , 9900 )))
17201734 s .bankKeeper .EXPECT ().GetAllBalances (sdkCtx , addr2 ).Return (sdk .NewCoins (sdk .NewInt64Coin ("test" , 100 )))
17211735
1722- fromBalances := s .bankKeeper .GetAllBalances (sdkCtx , accountAddr )
1736+ fromBalances := s .bankKeeper .GetAllBalances (sdkCtx , noMinExecPeriodPolicyAddr )
17231737 s .Require ().Contains (fromBalances , sdk .NewInt64Coin ("test" , 9900 ))
17241738 toBalances := s .bankKeeper .GetAllBalances (sdkCtx , addr2 )
17251739 s .Require ().Contains (toBalances , sdk .NewInt64Coin ("test" , 100 ))
17261740 },
17271741 },
17281742 "with try exec, not enough yes votes for proposal to pass" : {
17291743 req : & group.MsgSubmitProposal {
1730- GroupPolicyAddress : accountAddr .String (),
1744+ GroupPolicyAddress : noMinExecPeriodPolicyAddr .String (),
17311745 Proposers : []string {addr5 .String ()},
17321746 Exec : group .Exec_EXEC_TRY ,
17331747 },
17341748 msgs : []sdk.Msg {msgSend },
17351749 expProposal : group.Proposal {
1736- GroupPolicyAddress : accountAddr .String (),
1750+ GroupPolicyAddress : noMinExecPeriodPolicyAddr .String (),
17371751 Status : group .PROPOSAL_STATUS_SUBMITTED ,
17381752 FinalTallyResult : group.TallyResult {
17391753 YesCount : "0" , // Since tally doesn't pass Allow(), we consider the proposal not final
@@ -2399,6 +2413,7 @@ func (s *TestSuite) TestExecProposal() {
23992413 msgs := []sdk.Msg {msgSend1 }
24002414 return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_YES )
24012415 },
2416+ srcBlockTime : s .blockTime .Add (minExecutionPeriod ), // After min execution period end
24022417 expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
24032418 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_SUCCESS ,
24042419 expBalance : true ,
@@ -2412,6 +2427,7 @@ func (s *TestSuite) TestExecProposal() {
24122427
24132428 return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_YES )
24142429 },
2430+ srcBlockTime : s .blockTime .Add (minExecutionPeriod ), // After min execution period end
24152431 expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
24162432 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_SUCCESS ,
24172433 expBalance : true ,
@@ -2423,6 +2439,7 @@ func (s *TestSuite) TestExecProposal() {
24232439 msgs := []sdk.Msg {msgSend1 }
24242440 return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_NO )
24252441 },
2442+ srcBlockTime : s .blockTime .Add (minExecutionPeriod ), // After min execution period end
24262443 expProposalStatus : group .PROPOSAL_STATUS_REJECTED ,
24272444 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_NOT_RUN ,
24282445 },
@@ -2439,34 +2456,59 @@ func (s *TestSuite) TestExecProposal() {
24392456 },
24402457 expErr : true ,
24412458 },
2442- "Decision policy also applied on timeout " : {
2459+ "Decision policy also applied on exactly voting period end " : {
24432460 setupProposal : func (ctx context.Context ) uint64 {
24442461 msgs := []sdk.Msg {msgSend1 }
24452462 return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_NO )
24462463 },
2447- srcBlockTime : s .blockTime .Add (time .Second ),
2464+ srcBlockTime : s .blockTime .Add (time .Second ), // Voting period is 1s
24482465 expProposalStatus : group .PROPOSAL_STATUS_REJECTED ,
24492466 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_NOT_RUN ,
24502467 },
2451- "Decision policy also applied after timeout " : {
2468+ "Decision policy also applied after voting period end " : {
24522469 setupProposal : func (ctx context.Context ) uint64 {
24532470 msgs := []sdk.Msg {msgSend1 }
24542471 return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_NO )
24552472 },
2456- srcBlockTime : s .blockTime .Add (time .Second ).Add (time .Millisecond ),
2473+ srcBlockTime : s .blockTime .Add (time .Second ).Add (time .Millisecond ), // Voting period is 1s
24572474 expProposalStatus : group .PROPOSAL_STATUS_REJECTED ,
24582475 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_NOT_RUN ,
24592476 },
2477+ "exec proposal before MinExecutionPeriod should fail" : {
2478+ setupProposal : func (ctx context.Context ) uint64 {
2479+ msgs := []sdk.Msg {msgSend1 }
2480+ return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_YES )
2481+ },
2482+ srcBlockTime : s .blockTime .Add (4 * time .Second ), // min execution date is 5s later after s.blockTime
2483+ expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
2484+ expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_FAILURE , // Because MinExecutionPeriod has not passed
2485+ },
2486+ "exec proposal at exactly MinExecutionPeriod should pass" : {
2487+ setupProposal : func (ctx context.Context ) uint64 {
2488+ msgs := []sdk.Msg {msgSend1 }
2489+ s .bankKeeper .EXPECT ().Send (gomock .Any (), msgSend1 ).Return (nil , nil )
2490+ return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_YES )
2491+ },
2492+ srcBlockTime : s .blockTime .Add (5 * time .Second ), // min execution date is 5s later after s.blockTime
2493+ expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
2494+ expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_SUCCESS ,
2495+ },
24602496 "prevent double execution when successful" : {
24612497 setupProposal : func (ctx context.Context ) uint64 {
24622498 myProposalID := submitProposalAndVote (ctx , s , []sdk.Msg {msgSend1 }, proposers , group .VOTE_OPTION_YES )
24632499 s .bankKeeper .EXPECT ().Send (gomock .Any (), msgSend1 ).Return (nil , nil )
24642500
2501+ // Wait after min execution period end before Exec
2502+ sdkCtx := sdk .UnwrapSDKContext (ctx )
2503+ sdkCtx = sdkCtx .WithBlockTime (sdkCtx .BlockTime ().Add (minExecutionPeriod )) // MinExecutionPeriod is 5s
2504+ ctx = sdk .WrapSDKContext (sdkCtx )
2505+
24652506 _ , err := s .groupKeeper .Exec (ctx , & group.MsgExec {Executor : addr1 .String (), ProposalId : myProposalID })
24662507 s .Require ().NoError (err )
24672508 return myProposalID
24682509 },
2469- expErr : true , // since proposal is pruned after a successful MsgExec
2510+ srcBlockTime : s .blockTime .Add (minExecutionPeriod ), // After min execution period end
2511+ expErr : true , // since proposal is pruned after a successful MsgExec
24702512 expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
24712513 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_SUCCESS ,
24722514 expBalance : true ,
@@ -2481,6 +2523,7 @@ func (s *TestSuite) TestExecProposal() {
24812523
24822524 return submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_YES )
24832525 },
2526+ srcBlockTime : s .blockTime .Add (minExecutionPeriod ), // After min execution period end
24842527 expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
24852528 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_FAILURE ,
24862529 },
@@ -2489,6 +2532,11 @@ func (s *TestSuite) TestExecProposal() {
24892532 msgs := []sdk.Msg {msgSend2 }
24902533 myProposalID := submitProposalAndVote (ctx , s , msgs , proposers , group .VOTE_OPTION_YES )
24912534
2535+ // Wait after min execution period end before Exec
2536+ sdkCtx := sdk .UnwrapSDKContext (ctx )
2537+ sdkCtx = sdkCtx .WithBlockTime (sdkCtx .BlockTime ().Add (minExecutionPeriod )) // MinExecutionPeriod is 5s
2538+ ctx = sdk .WrapSDKContext (sdkCtx )
2539+
24922540 s .bankKeeper .EXPECT ().Send (gomock .Any (), msgSend2 ).Return (nil , fmt .Errorf ("error" ))
24932541 _ , err := s .groupKeeper .Exec (ctx , & group.MsgExec {Executor : addr1 .String (), ProposalId : myProposalID })
24942542 s .bankKeeper .EXPECT ().Send (gomock .Any (), msgSend2 ).Return (nil , nil )
@@ -2498,6 +2546,7 @@ func (s *TestSuite) TestExecProposal() {
24982546
24992547 return myProposalID
25002548 },
2549+ srcBlockTime : s .blockTime .Add (minExecutionPeriod ), // After min execution period end
25012550 expProposalStatus : group .PROPOSAL_STATUS_ACCEPTED ,
25022551 expExecutorResult : group .PROPOSAL_EXECUTOR_RESULT_SUCCESS ,
25032552 },
@@ -2689,6 +2738,11 @@ func (s *TestSuite) TestExecPrunedProposalsAndVotes() {
26892738
26902739 s .bankKeeper .EXPECT ().Send (gomock .Any (), msgSend2 ).Return (nil , fmt .Errorf ("error" ))
26912740
2741+ // Wait for min execution period end
2742+ sdkCtx := sdk .UnwrapSDKContext (ctx )
2743+ sdkCtx = sdkCtx .WithBlockTime (sdkCtx .BlockTime ().Add (minExecutionPeriod ))
2744+ ctx = sdk .WrapSDKContext (sdkCtx )
2745+
26922746 _ , err := s .groupKeeper .Exec (ctx , & group.MsgExec {Executor : addr1 .String (), ProposalId : myProposalID })
26932747 s .bankKeeper .EXPECT ().Send (gomock .Any (), msgSend2 ).Return (nil , nil )
26942748
@@ -2710,6 +2764,8 @@ func (s *TestSuite) TestExecPrunedProposalsAndVotes() {
27102764 sdkCtx = sdkCtx .WithBlockTime (spec .srcBlockTime )
27112765 }
27122766
2767+ // Wait for min execution period end
2768+ sdkCtx = sdkCtx .WithBlockTime (sdkCtx .BlockTime ().Add (minExecutionPeriod ))
27132769 ctx = sdk .WrapSDKContext (sdkCtx )
27142770 _ , err := s .groupKeeper .Exec (ctx , & group.MsgExec {Executor : addr1 .String (), ProposalId : proposalID })
27152771 if spec .expErr {
@@ -3173,3 +3229,59 @@ func (s *TestSuite) createGroupAndGroupPolicy(
31733229
31743230 return policyAddr , groupID
31753231}
3232+
3233+ func (s * TestSuite ) TestTallyProposalsAtVPEnd () {
3234+ addrs := s .addrs
3235+ addr1 := addrs [0 ]
3236+ addr2 := addrs [1 ]
3237+ votingPeriod := time .Duration (4 * time .Minute )
3238+ minExecutionPeriod := votingPeriod + group .DefaultConfig ().MaxExecutionPeriod
3239+
3240+ groupMsg := & group.MsgCreateGroupWithPolicy {
3241+ Admin : addr1 .String (),
3242+ Members : []group.MemberRequest {
3243+ {Address : addr1 .String (), Weight : "1" },
3244+ {Address : addr2 .String (), Weight : "1" },
3245+ },
3246+ }
3247+ policy := group .NewThresholdDecisionPolicy (
3248+ "1" ,
3249+ votingPeriod ,
3250+ minExecutionPeriod ,
3251+ )
3252+ s .Require ().NoError (groupMsg .SetDecisionPolicy (policy ))
3253+
3254+ s .setNextAccount ()
3255+ groupRes , err := s .groupKeeper .CreateGroupWithPolicy (s .ctx , groupMsg )
3256+ s .Require ().NoError (err )
3257+ accountAddr := groupRes .GetGroupPolicyAddress ()
3258+ groupPolicy , err := sdk .AccAddressFromBech32 (accountAddr )
3259+ s .Require ().NoError (err )
3260+ s .Require ().NotNil (groupPolicy )
3261+
3262+ proposalRes , err := s .groupKeeper .SubmitProposal (s .ctx , & group.MsgSubmitProposal {
3263+ GroupPolicyAddress : accountAddr ,
3264+ Proposers : []string {addr1 .String ()},
3265+ Messages : nil ,
3266+ })
3267+ s .Require ().NoError (err )
3268+
3269+ _ , err = s .groupKeeper .Vote (s .ctx , & group.MsgVote {
3270+ ProposalId : proposalRes .ProposalId ,
3271+ Voter : addr1 .String (),
3272+ Option : group .VOTE_OPTION_YES ,
3273+ })
3274+ s .Require ().NoError (err )
3275+
3276+ // move forward in time
3277+ ctx := s .sdkCtx .WithBlockTime (s .sdkCtx .BlockTime ().Add (votingPeriod + 1 ))
3278+
3279+ result , err := s .groupKeeper .TallyResult (ctx , & group.QueryTallyResultRequest {
3280+ ProposalId : proposalRes .ProposalId ,
3281+ })
3282+ s .Require ().Equal ("1" , result .Tally .YesCount )
3283+ s .Require ().NoError (err )
3284+
3285+ s .Require ().NoError (s .groupKeeper .TallyProposalsAtVPEnd (ctx ))
3286+ s .NotPanics (func () { module .EndBlocker (ctx , s .groupKeeper ) })
3287+ }
0 commit comments