github.com/cosmos/cosmos-sdk@v0.50.10/x/group/keeper/tally.go (about)

     1  package keeper
     2  
     3  import (
     4  	errorsmod "cosmossdk.io/errors"
     5  
     6  	sdk "github.com/cosmos/cosmos-sdk/types"
     7  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
     8  	"github.com/cosmos/cosmos-sdk/x/group"
     9  	"github.com/cosmos/cosmos-sdk/x/group/errors"
    10  	"github.com/cosmos/cosmos-sdk/x/group/internal/orm"
    11  )
    12  
    13  // Tally is a function that tallies a proposal by iterating through its votes,
    14  // and returns the tally result without modifying the proposal or any state.
    15  func (k Keeper) Tally(ctx sdk.Context, p group.Proposal, groupID uint64) (group.TallyResult, error) {
    16  	// If proposal has already been tallied and updated, then its status is
    17  	// accepted/rejected, in which case we just return the previously stored result.
    18  	//
    19  	// In all other cases (including withdrawn, aborted...) we do the tally
    20  	// again.
    21  	if p.Status == group.PROPOSAL_STATUS_ACCEPTED || p.Status == group.PROPOSAL_STATUS_REJECTED {
    22  		return p.FinalTallyResult, nil
    23  	}
    24  
    25  	it, err := k.voteByProposalIndex.Get(ctx.KVStore(k.key), p.Id)
    26  	if err != nil {
    27  		return group.TallyResult{}, err
    28  	}
    29  	defer it.Close()
    30  
    31  	tallyResult := group.DefaultTallyResult()
    32  
    33  	for {
    34  		var vote group.Vote
    35  		_, err = it.LoadNext(&vote)
    36  		if errors.ErrORMIteratorDone.Is(err) {
    37  			break
    38  		}
    39  		if err != nil {
    40  			return group.TallyResult{}, err
    41  		}
    42  
    43  		var member group.GroupMember
    44  		err := k.groupMemberTable.GetOne(ctx.KVStore(k.key), orm.PrimaryKey(&group.GroupMember{
    45  			GroupId: groupID,
    46  			Member:  &group.Member{Address: vote.Voter},
    47  		}), &member)
    48  
    49  		switch {
    50  		case sdkerrors.ErrNotFound.Is(err):
    51  			// If the member left the group after voting, then we simply skip the
    52  			// vote.
    53  			continue
    54  		case err != nil:
    55  			// For any other errors, we stop and return the error.
    56  			return group.TallyResult{}, err
    57  		}
    58  
    59  		if err := tallyResult.Add(vote, member.Member.Weight); err != nil {
    60  			return group.TallyResult{}, errorsmod.Wrap(err, "add new vote")
    61  		}
    62  	}
    63  
    64  	return tallyResult, nil
    65  }