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  }