github.com/Finschia/finschia-sdk@v0.48.1/x/foundation/keeper/internal/tally.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 // doTallyAndUpdate performs a tally, and, if the tally result is final, then: 10 // - updates the proposal's `Status` and `FinalTallyResult` fields, 11 // - prune all the votes. 12 func (k Keeper) doTallyAndUpdate(ctx sdk.Context, p *foundation.Proposal) error { 13 tallyResult, err := k.tally(ctx, *p) 14 if err != nil { 15 return err 16 } 17 18 info := k.GetFoundationInfo(ctx) 19 policy := info.GetDecisionPolicy() 20 sinceSubmission := ctx.BlockTime().Sub(p.SubmitTime) // duration passed since proposal submission. 21 result, err := policy.Allow(tallyResult, info.TotalWeight, sinceSubmission) 22 if err != nil { 23 return err 24 } 25 26 // If the result was final (i.e. enough votes to pass) or if the voting 27 // period ended, then we consider the proposal as final. 28 if isFinal := result.Final || ctx.BlockTime().After(p.VotingPeriodEnd); isFinal { 29 k.pruneVotes(ctx, p.Id) 30 p.FinalTallyResult = tallyResult 31 if result.Allow { 32 p.Status = foundation.PROPOSAL_STATUS_ACCEPTED 33 } else { 34 p.Status = foundation.PROPOSAL_STATUS_REJECTED 35 } 36 } 37 38 return nil 39 } 40 41 // tally is a function that tallies a proposal by iterating through its votes, 42 // and returns the tally result without modifying the proposal or any state. 43 func (k Keeper) tally(ctx sdk.Context, p foundation.Proposal) (foundation.TallyResult, error) { 44 // If proposal has already been tallied and updated, then its status is 45 // accepted/rejected, in which case we just return the previously stored result. 46 // 47 // In all other cases (including withdrawn, aborted...) we do the tally 48 // again. 49 if p.Status == foundation.PROPOSAL_STATUS_ACCEPTED || p.Status == foundation.PROPOSAL_STATUS_REJECTED { 50 return p.FinalTallyResult, nil 51 } 52 53 tallyResult := foundation.DefaultTallyResult() 54 var errIter error 55 k.iterateVotes(ctx, p.Id, func(vote foundation.Vote) (stop bool) { 56 voter := sdk.MustAccAddressFromBech32(vote.Voter) 57 58 _, err := k.GetMember(ctx, voter) 59 switch { 60 case sdkerrors.ErrNotFound.Is(err): 61 // If the member left the foundation after voting, then we simply skip the 62 // vote. 63 return false 64 case err != nil: 65 // For any other errors, we stop and return the error. 66 errIter = err 67 return true 68 } 69 70 if err := tallyResult.Add(vote.Option); err != nil { 71 panic(err) 72 } 73 74 return false 75 }) 76 77 if errIter != nil { 78 return tallyResult, errIter 79 } 80 81 return tallyResult, nil 82 }