forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 10
/
invariants.go
116 lines (98 loc) · 3.7 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
package keeper
import (
"fmt"
"math"
"sort"
"golang.org/x/exp/maps"
storetypes "github.com/shapeshift/cosmos-sdk/store/types"
sdk "github.com/shapeshift/cosmos-sdk/types"
"github.com/shapeshift/cosmos-sdk/x/group"
"github.com/shapeshift/cosmos-sdk/x/group/errors"
groupmath "github.com/shapeshift/cosmos-sdk/x/group/internal/math"
"github.com/shapeshift/cosmos-sdk/x/group/internal/orm"
)
const weightInvariant = "Group-TotalWeight"
// RegisterInvariants registers all group invariants.
func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) {
ir.RegisterRoute(group.ModuleName, weightInvariant, GroupTotalWeightInvariant(keeper))
}
// GroupTotalWeightInvariant checks that group's TotalWeight must be equal to the sum of its members.
func GroupTotalWeightInvariant(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
msg, broken := GroupTotalWeightInvariantHelper(ctx, keeper.key, keeper.groupTable, keeper.groupMemberByGroupIndex)
return sdk.FormatInvariant(group.ModuleName, weightInvariant, msg), broken
}
}
func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, groupTable orm.AutoUInt64Table, groupMemberByGroupIndex orm.Index) (string, bool) {
var msg string
var broken bool
groupIt, err := groupTable.PrefixScan(ctx.KVStore(key), 1, math.MaxUint64)
if err != nil {
msg += fmt.Sprintf("PrefixScan failure on group table\n%v\n", err)
return msg, broken
}
defer groupIt.Close()
groups := make(map[uint64]group.GroupInfo)
for {
var groupInfo group.GroupInfo
_, err = groupIt.LoadNext(&groupInfo)
if errors.ErrORMIteratorDone.Is(err) {
break
}
if err != nil {
msg += fmt.Sprintf("LoadNext failure on group table iterator\n%v\n", err)
return msg, broken
}
groups[groupInfo.Id] = groupInfo
}
groupByIDs := maps.Keys(groups)
sort.Slice(groupByIDs, func(i, j int) bool {
return groupByIDs[i] < groupByIDs[j]
})
for _, groupID := range groupByIDs {
groupInfo := groups[groupID]
membersWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for group member\n%v\n", err)
return msg, broken
}
memIt, err := groupMemberByGroupIndex.Get(ctx.KVStore(key), groupInfo.Id)
if err != nil {
msg += fmt.Sprintf("error while returning group member iterator for group with ID %d\n%v\n", groupInfo.Id, err)
return msg, broken
}
defer memIt.Close()
for {
var groupMember group.GroupMember
_, err = memIt.LoadNext(&groupMember)
if errors.ErrORMIteratorDone.Is(err) {
break
}
if err != nil {
msg += fmt.Sprintf("LoadNext failure on member table iterator\n%v\n", err)
return msg, broken
}
curMemWeight, err := groupmath.NewPositiveDecFromString(groupMember.GetMember().GetWeight())
if err != nil {
msg += fmt.Sprintf("error while parsing non-nengative decimal for group member %s\n%v\n", groupMember.Member.Address, err)
return msg, broken
}
membersWeight, err = groupmath.Add(membersWeight, curMemWeight)
if err != nil {
msg += fmt.Sprintf("decimal addition error while adding group member voting weight to total voting weight\n%v\n", err)
return msg, broken
}
}
groupWeight, err := groupmath.NewNonNegativeDecFromString(groupInfo.GetTotalWeight())
if err != nil {
msg += fmt.Sprintf("error while parsing non-nengative decimal for group with ID %d\n%v\n", groupInfo.Id, err)
return msg, broken
}
if groupWeight.Cmp(membersWeight) != 0 {
broken = true
msg += fmt.Sprintf("group's TotalWeight must be equal to the sum of its members' weights\ngroup weight: %s\nSum of group members weights: %s\n", groupWeight.String(), membersWeight.String())
break
}
}
return msg, broken
}