-
Notifications
You must be signed in to change notification settings - Fork 351
/
invariants.go
140 lines (117 loc) · 3.63 KB
/
invariants.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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package keeper
import (
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/committee/types"
)
// RegisterInvariants registers all committee invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, "valid-committees",
ValidCommitteesInvariant(k))
ir.RegisterRoute(types.ModuleName, "valid-proposals",
ValidProposalsInvariant(k))
ir.RegisterRoute(types.ModuleName, "valid-votes",
ValidVotesInvariant(k))
}
// ValidCommitteesInvariant verifies that all committees in the store are independently valid
func ValidCommitteesInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var validationErr error
var invalidCommittee types.Committee
k.IterateCommittees(ctx, func(com types.Committee) bool {
if err := com.Validate(); err != nil {
validationErr = err
invalidCommittee = com
return true
}
return false
})
broken := validationErr != nil
invariantMessage := sdk.FormatInvariant(
types.ModuleName,
"valid committees",
fmt.Sprintf(
"\tfound invalid committee, reason: %s\n"+
"\tcommittee:\n\t%+v\n",
validationErr, invalidCommittee),
)
return invariantMessage, broken
}
}
// ValidProposalsInvariant verifies that all proposals in the store are valid
func ValidProposalsInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var validationErr error
var invalidProposal types.Proposal
k.IterateProposals(ctx, func(proposal types.Proposal) bool {
invalidProposal = proposal
if err := proposal.PubProposal.ValidateBasic(); err != nil {
validationErr = err
return true
}
currentTime := ctx.BlockTime()
if !currentTime.Equal(time.Time{}) { // this avoids a simulator bug where app.InitGenesis is called with blockTime=0 instead of the correct time
if proposal.Deadline.Before(currentTime) {
validationErr = fmt.Errorf("deadline after current block time %s", currentTime)
return true
}
}
_, found := k.GetCommittee(ctx, proposal.CommitteeID)
if !found {
validationErr = fmt.Errorf("proposal has no committee %d", proposal.CommitteeID)
return true
}
return false
})
broken := validationErr != nil
invariantMessage := sdk.FormatInvariant(
types.ModuleName,
"valid proposals",
fmt.Sprintf(
"\tfound invalid proposal, reason: %s\n"+
"\tproposal:\n\t%s\n",
validationErr, invalidProposal),
)
return invariantMessage, broken
}
}
// ValidVotesInvariant verifies that all votes in the store are valid
func ValidVotesInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var validationErr error
var invalidVote types.Vote
k.IterateVotes(ctx, func(vote types.Vote) bool {
invalidVote = vote
if err := vote.Validate(); err != nil {
validationErr = err
return true
}
proposal, found := k.GetProposal(ctx, vote.ProposalID)
if !found {
validationErr = fmt.Errorf("vote has no proposal %d", vote.ProposalID)
return true
}
com, found := k.GetCommittee(ctx, proposal.CommitteeID)
if !found {
validationErr = fmt.Errorf("vote's proposal has no committee %d", proposal.CommitteeID)
return true
}
if !com.HasMember(vote.Voter) {
validationErr = fmt.Errorf("voter is not a member of committee %+v", com)
return true
}
return false
})
broken := validationErr != nil
invariantMessage := sdk.FormatInvariant(
types.ModuleName,
"valid votes",
fmt.Sprintf(
"\tfound invalid vote, reason: %s\n"+
"\tvote:\n\t%+v\n",
validationErr, invalidVote),
)
return invariantMessage, broken
}
}