github.com/Finschia/finschia-sdk@v0.48.1/x/gov/keeper/proposal.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 "github.com/Finschia/finschia-sdk/client" 7 sdk "github.com/Finschia/finschia-sdk/types" 8 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 9 "github.com/Finschia/finschia-sdk/x/gov/types" 10 ) 11 12 // SubmitProposal create new proposal given a content 13 func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, error) { 14 if !keeper.router.HasRoute(content.ProposalRoute()) { 15 return types.Proposal{}, sdkerrors.Wrap(types.ErrNoProposalHandlerExists, content.ProposalRoute()) 16 } 17 18 // Execute the proposal content in a new context branch (with branched store) 19 // to validate the actual parameter changes before the proposal proceeds 20 // through the governance process. State is not persisted. 21 cacheCtx, _ := ctx.CacheContext() 22 handler := keeper.router.GetRoute(content.ProposalRoute()) 23 if err := handler(cacheCtx, content); err != nil { 24 return types.Proposal{}, sdkerrors.Wrap(types.ErrInvalidProposalContent, err.Error()) 25 } 26 27 proposalID, err := keeper.GetProposalID(ctx) 28 if err != nil { 29 return types.Proposal{}, err 30 } 31 32 submitTime := ctx.BlockHeader().Time 33 depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod 34 35 proposal, err := types.NewProposal(content, proposalID, submitTime, submitTime.Add(depositPeriod)) 36 if err != nil { 37 return types.Proposal{}, err 38 } 39 40 keeper.SetProposal(ctx, proposal) 41 keeper.InsertInactiveProposalQueue(ctx, proposalID, proposal.DepositEndTime) 42 keeper.SetProposalID(ctx, proposalID+1) 43 44 // called right after a proposal is submitted 45 keeper.AfterProposalSubmission(ctx, proposalID) 46 47 ctx.EventManager().EmitEvent( 48 sdk.NewEvent( 49 types.EventTypeSubmitProposal, 50 sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposalID)), 51 ), 52 ) 53 54 return proposal, nil 55 } 56 57 // GetProposal get proposal from store by ProposalID 58 func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (types.Proposal, bool) { 59 store := ctx.KVStore(keeper.storeKey) 60 61 bz := store.Get(types.ProposalKey(proposalID)) 62 if bz == nil { 63 return types.Proposal{}, false 64 } 65 66 var proposal types.Proposal 67 keeper.MustUnmarshalProposal(bz, &proposal) 68 69 return proposal, true 70 } 71 72 // SetProposal set a proposal to store 73 func (keeper Keeper) SetProposal(ctx sdk.Context, proposal types.Proposal) { 74 store := ctx.KVStore(keeper.storeKey) 75 76 bz := keeper.MustMarshalProposal(proposal) 77 78 store.Set(types.ProposalKey(proposal.ProposalId), bz) 79 } 80 81 // DeleteProposal deletes a proposal from store 82 func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) { 83 store := ctx.KVStore(keeper.storeKey) 84 proposal, ok := keeper.GetProposal(ctx, proposalID) 85 if !ok { 86 panic(fmt.Sprintf("couldn't find proposal with id#%d", proposalID)) 87 } 88 keeper.RemoveFromInactiveProposalQueue(ctx, proposalID, proposal.DepositEndTime) 89 keeper.RemoveFromActiveProposalQueue(ctx, proposalID, proposal.VotingEndTime) 90 store.Delete(types.ProposalKey(proposalID)) 91 } 92 93 // IterateProposals iterates over the all the proposals and performs a callback function 94 func (keeper Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.Proposal) (stop bool)) { 95 store := ctx.KVStore(keeper.storeKey) 96 97 iterator := sdk.KVStorePrefixIterator(store, types.ProposalsKeyPrefix) 98 defer iterator.Close() 99 100 for ; iterator.Valid(); iterator.Next() { 101 var proposal types.Proposal 102 err := keeper.UnmarshalProposal(iterator.Value(), &proposal) 103 if err != nil { 104 panic(err) 105 } 106 107 if cb(proposal) { 108 break 109 } 110 } 111 } 112 113 // GetProposals returns all the proposals from store 114 func (keeper Keeper) GetProposals(ctx sdk.Context) (proposals types.Proposals) { 115 keeper.IterateProposals(ctx, func(proposal types.Proposal) bool { 116 proposals = append(proposals, proposal) 117 return false 118 }) 119 return 120 } 121 122 // GetProposalsFiltered retrieves proposals filtered by a given set of params which 123 // include pagination parameters along with voter and depositor addresses and a 124 // proposal status. The voter address will filter proposals by whether or not 125 // that address has voted on proposals. The depositor address will filter proposals 126 // by whether or not that address has deposited to them. Finally, status will filter 127 // proposals by status. 128 // 129 // NOTE: If no filters are provided, all proposals will be returned in paginated 130 // form. 131 func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, params types.QueryProposalsParams) types.Proposals { 132 proposals := keeper.GetProposals(ctx) 133 filteredProposals := make([]types.Proposal, 0, len(proposals)) 134 135 for _, p := range proposals { 136 matchVoter, matchDepositor, matchStatus := true, true, true 137 138 // match status (if supplied/valid) 139 if types.ValidProposalStatus(params.ProposalStatus) { 140 matchStatus = p.Status == params.ProposalStatus 141 } 142 143 // match voter address (if supplied) 144 if len(params.Voter) > 0 { 145 _, matchVoter = keeper.GetVote(ctx, p.ProposalId, params.Voter) 146 } 147 148 // match depositor (if supplied) 149 if len(params.Depositor) > 0 { 150 _, matchDepositor = keeper.GetDeposit(ctx, p.ProposalId, params.Depositor) 151 } 152 153 if matchVoter && matchDepositor && matchStatus { 154 filteredProposals = append(filteredProposals, p) 155 } 156 } 157 158 start, end := client.Paginate(len(filteredProposals), params.Page, params.Limit, 100) 159 if start < 0 || end < 0 { 160 filteredProposals = []types.Proposal{} 161 } else { 162 filteredProposals = filteredProposals[start:end] 163 } 164 165 return filteredProposals 166 } 167 168 // GetProposalID gets the highest proposal ID 169 func (keeper Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err error) { 170 store := ctx.KVStore(keeper.storeKey) 171 bz := store.Get(types.ProposalIDKey) 172 if bz == nil { 173 return 0, sdkerrors.Wrap(types.ErrInvalidGenesis, "initial proposal ID hasn't been set") 174 } 175 176 proposalID = types.GetProposalIDFromBytes(bz) 177 return proposalID, nil 178 } 179 180 // SetProposalID sets the new proposal ID to the store 181 func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) { 182 store := ctx.KVStore(keeper.storeKey) 183 store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID)) 184 } 185 186 func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) { 187 proposal.VotingStartTime = ctx.BlockHeader().Time 188 votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod 189 proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod) 190 proposal.Status = types.StatusVotingPeriod 191 keeper.SetProposal(ctx, proposal) 192 193 keeper.RemoveFromInactiveProposalQueue(ctx, proposal.ProposalId, proposal.DepositEndTime) 194 keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime) 195 } 196 197 func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) { 198 bz, err := keeper.cdc.Marshal(&proposal) 199 if err != nil { 200 return nil, err 201 } 202 return bz, nil 203 } 204 205 func (keeper Keeper) UnmarshalProposal(bz []byte, proposal *types.Proposal) error { 206 err := keeper.cdc.Unmarshal(bz, proposal) 207 if err != nil { 208 return err 209 } 210 return nil 211 } 212 213 func (keeper Keeper) MustMarshalProposal(proposal types.Proposal) []byte { 214 bz, err := keeper.MarshalProposal(proposal) 215 if err != nil { 216 panic(err) 217 } 218 return bz 219 } 220 221 func (keeper Keeper) MustUnmarshalProposal(bz []byte, proposal *types.Proposal) { 222 err := keeper.UnmarshalProposal(bz, proposal) 223 if err != nil { 224 panic(err) 225 } 226 }