/
invariants.go
284 lines (228 loc) · 8.3 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
package keeper
import (
"fmt"
"github.com/magewar/mage/x/subspaces/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// RegisterInvariants registers all subspaces invariants
func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) {
ir.RegisterRoute(types.ModuleName, "valid-subspaces",
ValidSubspacesInvariant(keeper))
ir.RegisterRoute(types.ModuleName, "valid-sections",
ValidSectionsInvariant(keeper))
ir.RegisterRoute(types.ModuleName, "valid-user-groups",
ValidUserGroupsInvariant(keeper))
ir.RegisterRoute(types.ModuleName, "valid-user-groups-members",
ValidUserGroupMembersInvariant(keeper))
ir.RegisterRoute(types.ModuleName, "valid-user-permissions",
ValidUserPermissionsInvariant(keeper))
}
// --------------------------------------------------------------------------------------------------------------------
// ValidSubspacesInvariant checks that all the subspaces are valid
func ValidSubspacesInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var invalidSubspaces []types.Subspace
k.IterateSubspaces(ctx, func(subspace types.Subspace) (stop bool) {
invalid := false
nextSubspaceID, err := k.GetSubspaceID(ctx)
if err != nil {
invalid = true
}
// Make sure the subspace id is never higher than the next one
if subspace.ID >= nextSubspaceID {
invalid = true
}
// Check next section id
if !k.HasNextSectionID(ctx, subspace.ID) {
invalid = true
}
// Check the next group id
if !k.HasNextGroupID(ctx, subspace.ID) {
invalid = true
}
// Validate the subspace
err = subspace.Validate()
if err != nil {
invalid = true
}
if invalid {
invalidSubspaces = append(invalidSubspaces, subspace)
}
return false
})
return sdk.FormatInvariant(types.ModuleName, "invalid subspaces",
fmt.Sprintf("the following subspaces are invalid:\n %s", FormatOutputSubspaces(invalidSubspaces)),
), invalidSubspaces != nil
}
}
// FormatOutputSubspaces concatenate the subspaces given into a unique string
func FormatOutputSubspaces(subspaces []types.Subspace) (outputSubspaces string) {
for _, subspace := range subspaces {
outputSubspaces += fmt.Sprintf("%d\n", subspace.ID)
}
return outputSubspaces
}
// --------------------------------------------------------------------------------------------------------------------
// ValidSectionsInvariant checks that all the sections are valid
func ValidSectionsInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var invalidSections []types.Section
k.IterateSections(ctx, func(section types.Section) (stop bool) {
invalid := false
// Check the subspace existence
if !k.HasSubspace(ctx, section.SubspaceID) {
invalid = true
}
nextSectionID, err := k.GetNextSectionID(ctx, section.SubspaceID)
if err != nil {
invalid = true
}
// Make sure the section id is never equal or higher than the next section id
if section.ID >= nextSectionID {
invalid = true
}
// Check the parent section
if !k.HasSection(ctx, section.SubspaceID, section.ParentID) {
invalid = true
}
// Validate the section
err = section.Validate()
if err != nil {
invalid = true
}
if invalid {
invalidSections = append(invalidSections, section)
}
return false
})
return sdk.FormatInvariant(types.ModuleName, "invalid sections",
fmt.Sprintf("the following sections are invalid:\n%s", formatOutputSections(invalidSections)),
), invalidSections != nil
}
}
// formatOutputSections concatenates the given sections info into a string
func formatOutputSections(sections []types.Section) (output string) {
for _, section := range sections {
output += fmt.Sprintf("SubspaceID: %d, SectionID: %d\n", section.SubspaceID, section.ID)
}
return output
}
// --------------------------------------------------------------------------------------------------------------------
// ValidUserGroupsInvariant checks that all the subspaces are valid
func ValidUserGroupsInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var invalidUserGroups []types.UserGroup
k.IterateUserGroups(ctx, func(group types.UserGroup) (stop bool) {
invalid := false
// Check subspace existence
if !k.HasSubspace(ctx, group.SubspaceID) {
invalid = true
}
// Check section existence
if !k.HasSection(ctx, group.SubspaceID, group.SectionID) {
invalid = true
}
nextGroupID, err := k.GetNextGroupID(ctx, group.SubspaceID)
if err != nil {
invalid = true
}
// Make sure the group id is always lower than the next one
if group.ID >= nextGroupID {
invalid = true
}
// Validate the group
err = group.Validate()
if err != nil {
invalid = true
}
if invalid {
invalidUserGroups = append(invalidUserGroups, group)
}
return false
})
return sdk.FormatInvariant(types.ModuleName, "invalid user groups",
fmt.Sprintf("the following user groups are invalid:\n %s", formatOutputUserGroups(invalidUserGroups)),
), invalidUserGroups != nil
}
}
// formatOutputUserGroups concatenates the given subspaces info given into a string
func formatOutputUserGroups(groups []types.UserGroup) (outputUserGroups string) {
for _, group := range groups {
outputUserGroups += fmt.Sprintf("SubspaceID: %d, GroupID: %d\n", group.SubspaceID, group.ID)
}
return outputUserGroups
}
// --------------------------------------------------------------------------------------------------------------------
// ValidUserGroupMembersInvariant checks that all the user group members are valid
func ValidUserGroupMembersInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var invalidMembers []types.UserGroupMemberEntry
k.IterateUserGroupsMembers(ctx, func(entry types.UserGroupMemberEntry) (stop bool) {
invalid := false
// Check subspace existence
if !k.HasSubspace(ctx, entry.SubspaceID) {
invalid = true
}
// Check the group existence
if !k.HasUserGroup(ctx, entry.SubspaceID, entry.GroupID) {
invalid = true
}
// Validate the entry only if the group id is not 0, as this will return an error
err := entry.Validate()
if err != nil {
invalid = true
}
if invalid {
invalidMembers = append(invalidMembers, entry)
}
return false
})
return sdk.FormatInvariant(types.ModuleName, "invalid user group members",
fmt.Sprintf("the following user group members entries are invalid:\n%s", formatOutputUserGroupsMembers(invalidMembers)),
), invalidMembers != nil
}
}
// formatOutputUserGroupsMembers concatenates the given user group members data into a string
func formatOutputUserGroupsMembers(members []types.UserGroupMemberEntry) (output string) {
for _, entry := range members {
output += fmt.Sprintf("SubspaceID: %d, GroupID: %d, Member: %s\n", entry.SubspaceID, entry.GroupID, entry.User)
}
return output
}
// --------------------------------------------------------------------------------------------------------------------
// ValidUserPermissionsInvariant checks that all the user permission entries are valid
func ValidUserPermissionsInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
var invalidPermissionsEntries []types.UserPermission
k.IterateUserPermissions(ctx, func(entry types.UserPermission) (stop bool) {
invalid := false
// Check subspace existence
if !k.HasSubspace(ctx, entry.SubspaceID) {
invalid = true
}
// Check section existence
if !k.HasSection(ctx, entry.SubspaceID, entry.SectionID) {
invalid = true
}
// Validate the entry
err := entry.Validate()
if err != nil {
invalid = true
}
if invalid {
invalidPermissionsEntries = append(invalidPermissionsEntries, entry)
}
return false
})
return sdk.FormatInvariant(types.ModuleName, "invalid user permissions",
fmt.Sprintf("the following user permissions are invalid:\n%s", formatOutputUserPermissions(invalidPermissionsEntries)),
), invalidPermissionsEntries != nil
}
}
// formatOutputUserPermissions concatenates the given permission entries into a string
func formatOutputUserPermissions(entries []types.UserPermission) (output string) {
for _, entry := range entries {
output += fmt.Sprintf("SubspaceID: %d, SectionID: %d, User: %s, Permissions: %s\n", entry.SubspaceID, entry.SectionID, entry.User, entry.Permissions)
}
return output
}