github.com/Finschia/finschia-sdk@v0.48.1/x/foundation/keeper/internal/vote.go (about) 1 package internal 2 3 import ( 4 sdk "github.com/Finschia/finschia-sdk/types" 5 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 6 "github.com/Finschia/finschia-sdk/x/foundation" 7 ) 8 9 func (k Keeper) Vote(ctx sdk.Context, vote foundation.Vote) error { 10 if err := validateMetadata(vote.Metadata, k.config); err != nil { 11 return err 12 } 13 14 // Make sure that a voter hasn't already voted. 15 voter := sdk.MustAccAddressFromBech32(vote.Voter) 16 if k.hasVote(ctx, vote.ProposalId, voter) { 17 return sdkerrors.ErrInvalidRequest.Wrapf("Already voted: %s", vote.Voter) 18 } 19 20 proposal, err := k.GetProposal(ctx, vote.ProposalId) 21 if err != nil { 22 return err 23 } 24 25 // Ensure that we can still accept votes for this proposal. 26 if proposal.Status != foundation.PROPOSAL_STATUS_SUBMITTED { 27 return sdkerrors.ErrInvalidRequest.Wrapf("not possible with proposal status: %s", proposal.Status) 28 } 29 if !ctx.BlockTime().Before(proposal.VotingPeriodEnd) { 30 return sdkerrors.ErrInvalidRequest.Wrap("voting period has ended already") 31 } 32 33 vote.SubmitTime = ctx.BlockTime() 34 k.setVote(ctx, vote) 35 36 if err := ctx.EventManager().EmitTypedEvent(&foundation.EventVote{ 37 Vote: vote, 38 }); err != nil { 39 panic(err) 40 } 41 42 return nil 43 } 44 45 func (k Keeper) hasVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress) bool { 46 store := ctx.KVStore(k.storeKey) 47 key := voteKey(proposalID, voter) 48 return store.Has(key) 49 } 50 51 func (k Keeper) GetVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress) (*foundation.Vote, error) { 52 store := ctx.KVStore(k.storeKey) 53 key := voteKey(proposalID, voter) 54 bz := store.Get(key) 55 if len(bz) == 0 { 56 return nil, sdkerrors.ErrNotFound.Wrapf("No vote for proposal %d: %s", proposalID, voter) 57 } 58 59 var vote foundation.Vote 60 k.cdc.MustUnmarshal(bz, &vote) 61 62 return &vote, nil 63 } 64 65 func (k Keeper) setVote(ctx sdk.Context, vote foundation.Vote) { 66 store := ctx.KVStore(k.storeKey) 67 voter := sdk.MustAccAddressFromBech32(vote.Voter) 68 key := voteKey(vote.ProposalId, voter) 69 bz := k.cdc.MustMarshal(&vote) 70 store.Set(key, bz) 71 } 72 73 func (k Keeper) iterateVotes(ctx sdk.Context, proposalID uint64, fn func(vote foundation.Vote) (stop bool)) { 74 store := ctx.KVStore(k.storeKey) 75 prefix := append(voteKeyPrefix, Uint64ToBytes(proposalID)...) 76 iterator := sdk.KVStorePrefixIterator(store, prefix) 77 defer iterator.Close() 78 79 for ; iterator.Valid(); iterator.Next() { 80 var vote foundation.Vote 81 k.cdc.MustUnmarshal(iterator.Value(), &vote) 82 if stop := fn(vote); stop { 83 break 84 } 85 } 86 } 87 88 func (k Keeper) GetVotes(ctx sdk.Context, proposalID uint64) []foundation.Vote { 89 var votes []foundation.Vote 90 k.iterateVotes(ctx, proposalID, func(vote foundation.Vote) (stop bool) { 91 votes = append(votes, vote) 92 return false 93 }) 94 95 return votes 96 } 97 98 // pruneVotes prunes all votes for a proposal from state. 99 func (k Keeper) pruneVotes(ctx sdk.Context, proposalID uint64) { 100 keys := [][]byte{} 101 k.iterateVotes(ctx, proposalID, func(vote foundation.Vote) (stop bool) { 102 voter := sdk.MustAccAddressFromBech32(vote.Voter) 103 keys = append(keys, voteKey(proposalID, voter)) 104 return false 105 }) 106 107 store := ctx.KVStore(k.storeKey) 108 for _, key := range keys { 109 store.Delete(key) 110 } 111 }