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