feat: Add invariants to group module (#10621)

## Description

Closes: #9898 

This PR adds invariants to group module

---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
likhita-809 2021-12-17 17:39:38 +05:30 committed by GitHub
parent 29fe4ecbbc
commit 59ae402537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 965 additions and 38 deletions

View File

@ -311,7 +311,6 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
@ -524,8 +523,6 @@ github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs=
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -728,7 +725,6 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4=
github.com/jhump/protoreflect v1.10.1 h1:iH+UZfsbRE6vpyZH7asAjTPWJf7RJbpZ9j/N3lDlKs0=
github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -953,7 +949,6 @@ github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nishanths/exhaustive v0.2.3/go.mod h1:bhIX678Nx8inLM9PbpvK1yv6oGtoP8BfaIeMzgBNKvc=
github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ=
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@ -1634,7 +1629,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk=
@ -1724,7 +1718,6 @@ golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -1733,7 +1726,6 @@ golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@ -1917,7 +1909,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=

View File

@ -0,0 +1,373 @@
package keeper
import (
"fmt"
"math"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/group"
"github.com/cosmos/cosmos-sdk/x/group/errors"
groupmath "github.com/cosmos/cosmos-sdk/x/group/internal/math"
"github.com/cosmos/cosmos-sdk/x/group/internal/orm"
)
const (
votesInvariant = "Tally-Votes"
weightInvariant = "Group-TotalWeight"
votesSumInvariant = "Tally-Votes-Sum"
)
// RegisterInvariants registers all group invariants
func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) {
ir.RegisterRoute(group.ModuleName, votesInvariant, TallyVotesInvariant(keeper))
ir.RegisterRoute(group.ModuleName, weightInvariant, GroupTotalWeightInvariant(keeper))
ir.RegisterRoute(group.ModuleName, votesSumInvariant, TallyVotesSumInvariant(keeper))
}
// TallyVotesInvariant checks that vote tally sums must never have less than the block before.
func TallyVotesInvariant(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
if ctx.BlockHeight()-1 < 0 {
return sdk.FormatInvariant(group.ModuleName, votesInvariant, "Not enough blocks to perform TallyVotesInvariant"), false
}
prevCtx, _ := ctx.CacheContext()
prevCtx = prevCtx.WithBlockHeight(ctx.BlockHeight() - 1)
msg, broken := TallyVotesInvariantHelper(ctx, prevCtx, keeper.key, keeper.proposalTable)
return sdk.FormatInvariant(group.ModuleName, votesInvariant, msg), broken
}
}
// 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
}
}
// TallyVotesSumInvariant checks that proposal VoteState must correspond to the vote choice.
func TallyVotesSumInvariant(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
msg, broken := TallyVotesSumInvariantHelper(ctx, keeper.key, keeper.groupTable, keeper.proposalTable, keeper.groupMemberTable, keeper.voteByProposalIndex, keeper.groupAccountTable)
return sdk.FormatInvariant(group.ModuleName, votesSumInvariant, msg), broken
}
}
func TallyVotesInvariantHelper(ctx sdk.Context, prevCtx sdk.Context, key storetypes.StoreKey, proposalTable orm.AutoUInt64Table) (string, bool) {
var msg string
var broken bool
prevIt, err := proposalTable.PrefixScan(prevCtx.KVStore(key), 1, math.MaxUint64)
if err != nil {
msg += fmt.Sprintf("PrefixScan failure on proposal table at block height %d\n%v\n", prevCtx.BlockHeight(), err)
return msg, broken
}
curIt, err := proposalTable.PrefixScan(ctx.KVStore(key), 1, math.MaxUint64)
if err != nil {
msg += fmt.Sprintf("PrefixScan failure on proposal table at block height %d\n%v\n", ctx.BlockHeight(), err)
return msg, broken
}
var curProposals []*group.Proposal
_, err = orm.ReadAll(curIt, &curProposals)
if err != nil {
msg += fmt.Sprintf("error while getting all the proposals at block height %d\n%v\n", ctx.BlockHeight(), err)
return msg, broken
}
var prevProposals []*group.Proposal
_, err = orm.ReadAll(prevIt, &prevProposals)
if err != nil {
msg += fmt.Sprintf("error while getting all the proposals at block height %d\n%v\n", prevCtx.BlockHeight(), err)
return msg, broken
}
for i := 0; i < len(prevProposals); i++ {
if prevProposals[i].ProposalId == curProposals[i].ProposalId {
prevYesCount, err := prevProposals[i].VoteState.GetYesCount()
if err != nil {
msg += fmt.Sprintf("error while getting yes votes weight of proposal at block height %d\n%v\n", prevCtx.BlockHeight(), err)
return msg, broken
}
curYesCount, err := curProposals[i].VoteState.GetYesCount()
if err != nil {
msg += fmt.Sprintf("error while getting yes votes weight of proposal at block height %d\n%v\n", ctx.BlockHeight(), err)
return msg, broken
}
prevNoCount, err := prevProposals[i].VoteState.GetNoCount()
if err != nil {
msg += fmt.Sprintf("error while getting no votes weight of proposal at block height %d\n%v\n", prevCtx.BlockHeight(), err)
return msg, broken
}
curNoCount, err := curProposals[i].VoteState.GetNoCount()
if err != nil {
msg += fmt.Sprintf("error while getting no votes weight of proposal at block height %d\n%v\n", ctx.BlockHeight(), err)
return msg, broken
}
prevAbstainCount, err := prevProposals[i].VoteState.GetAbstainCount()
if err != nil {
msg += fmt.Sprintf("error while getting abstain votes weight of proposal at block height %d\n%v\n", prevCtx.BlockHeight(), err)
return msg, broken
}
curAbstainCount, err := curProposals[i].VoteState.GetAbstainCount()
if err != nil {
msg += fmt.Sprintf("error while getting abstain votes weight of proposal at block height %d\n%v\n", ctx.BlockHeight(), err)
return msg, broken
}
prevVetoCount, err := prevProposals[i].VoteState.GetVetoCount()
if err != nil {
msg += fmt.Sprintf("error while getting veto votes weight of proposal at block height %d\n%v\n", prevCtx.BlockHeight(), err)
return msg, broken
}
curVetoCount, err := curProposals[i].VoteState.GetVetoCount()
if err != nil {
msg += fmt.Sprintf("error while getting veto votes weight of proposal at block height %d\n%v\n", ctx.BlockHeight(), err)
return msg, broken
}
if (curYesCount.Cmp(prevYesCount) == -1) || (curNoCount.Cmp(prevNoCount) == -1) || (curAbstainCount.Cmp(prevAbstainCount) == -1) || (curVetoCount.Cmp(prevVetoCount) == -1) {
broken = true
msg += "vote tally sums must never have less than the block before\n"
return msg, broken
}
}
}
return msg, broken
}
func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, groupTable orm.AutoUInt64Table, groupMemberByGroupIndex orm.Index) (string, bool) {
var msg string
var broken bool
var groupInfo group.GroupInfo
var groupMember group.GroupMember
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()
for {
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
}
_, err = groupIt.LoadNext(&groupInfo)
if errors.ErrORMIteratorDone.Is(err) {
break
}
memIt, err := groupMemberByGroupIndex.Get(ctx.KVStore(key), groupInfo.GroupId)
if err != nil {
msg += fmt.Sprintf("error while returning group member iterator for group with ID %d\n%v\n", groupInfo.GroupId, err)
return msg, broken
}
defer memIt.Close()
for {
_, err = memIt.LoadNext(&groupMember)
if errors.ErrORMIteratorDone.Is(err) {
break
}
curMemWeight, err := groupmath.NewNonNegativeDecFromString(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.GroupId, 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
}
func TallyVotesSumInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, groupTable orm.AutoUInt64Table, proposalTable orm.AutoUInt64Table, groupMemberTable orm.PrimaryKeyTable, voteByProposalIndex orm.Index, groupAccountTable orm.PrimaryKeyTable) (string, bool) {
var msg string
var broken bool
var groupInfo group.GroupInfo
var proposal group.Proposal
var groupAcc group.GroupAccountInfo
var groupMem group.GroupMember
var vote group.Vote
proposalIt, err := proposalTable.PrefixScan(ctx.KVStore(key), 1, math.MaxUint64)
if err != nil {
fmt.Println(err)
msg += fmt.Sprintf("PrefixScan failure on proposal table\n%v\n", err)
return msg, broken
}
defer proposalIt.Close()
for {
totalVotingWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for total voting weight\n%v\n", err)
return msg, broken
}
yesVoteWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for yes voting weight\n%v\n", err)
return msg, broken
}
noVoteWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for no voting weight\n%v\n", err)
return msg, broken
}
abstainVoteWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for abstain voting weight\n%v\n", err)
return msg, broken
}
vetoVoteWeight, err := groupmath.NewNonNegativeDecFromString("0")
if err != nil {
msg += fmt.Sprintf("error while parsing positive dec zero for veto voting weight\n%v\n", err)
return msg, broken
}
_, err = proposalIt.LoadNext(&proposal)
if errors.ErrORMIteratorDone.Is(err) {
break
}
err = groupAccountTable.GetOne(ctx.KVStore(key), orm.PrimaryKey(&group.GroupAccountInfo{Address: proposal.Address}), &groupAcc)
if err != nil {
msg += fmt.Sprintf("group account not found for address: %s\n%v\n", proposal.Address, err)
return msg, broken
}
if proposal.GroupAccountVersion != groupAcc.Version {
msg += fmt.Sprintf("group account with address %s was modified\n", groupAcc.Address)
return msg, broken
}
_, err = groupTable.GetOne(ctx.KVStore(key), groupAcc.GroupId, &groupInfo)
if err != nil {
msg += fmt.Sprintf("group info not found for group id %d\n%v\n", groupAcc.GroupId, err)
return msg, broken
}
if groupInfo.Version != proposal.GroupVersion {
msg += fmt.Sprintf("group with id %d was modified\n", groupInfo.GroupId)
return msg, broken
}
voteIt, err := voteByProposalIndex.Get(ctx.KVStore(key), proposal.ProposalId)
if err != nil {
msg += fmt.Sprintf("error while returning vote iterator for proposal with ID %d\n%v\n", proposal.ProposalId, err)
return msg, broken
}
defer voteIt.Close()
for {
_, err := voteIt.LoadNext(&vote)
if errors.ErrORMIteratorDone.Is(err) {
break
}
err = groupMemberTable.GetOne(ctx.KVStore(key), orm.PrimaryKey(&group.GroupMember{GroupId: groupAcc.GroupId, Member: &group.Member{Address: vote.Voter}}), &groupMem)
if err != nil {
msg += fmt.Sprintf("group member not found with group ID %d and group member %s\n%v\n", groupAcc.GroupId, vote.Voter, err)
return msg, broken
}
curMemVotingWeight, err := groupmath.NewNonNegativeDecFromString(groupMem.Member.Weight)
if err != nil {
msg += fmt.Sprintf("error while parsing non-negative decimal for group member %s\n%v\n", groupMem.Member.Address, err)
return msg, broken
}
totalVotingWeight, err = groupmath.Add(totalVotingWeight, curMemVotingWeight)
if err != nil {
msg += fmt.Sprintf("decimal addition error while adding current member voting weight to total voting weight\n%v\n", err)
return msg, broken
}
switch vote.Choice {
case group.Choice_CHOICE_YES:
yesVoteWeight, err = groupmath.Add(yesVoteWeight, curMemVotingWeight)
if err != nil {
msg += fmt.Sprintf("decimal addition error\n%v\n", err)
return msg, broken
}
case group.Choice_CHOICE_NO:
noVoteWeight, err = groupmath.Add(noVoteWeight, curMemVotingWeight)
if err != nil {
msg += fmt.Sprintf("decimal addition error\n%v\n", err)
return msg, broken
}
case group.Choice_CHOICE_ABSTAIN:
abstainVoteWeight, err = groupmath.Add(abstainVoteWeight, curMemVotingWeight)
if err != nil {
msg += fmt.Sprintf("decimal addition error\n%v\n", err)
return msg, broken
}
case group.Choice_CHOICE_VETO:
vetoVoteWeight, err = groupmath.Add(vetoVoteWeight, curMemVotingWeight)
if err != nil {
msg += fmt.Sprintf("decimal addition error\n%v\n", err)
return msg, broken
}
}
}
totalProposalVotes, err := proposal.VoteState.TotalCounts()
if err != nil {
msg += fmt.Sprintf("error while getting total weighted votes of proposal with ID %d\n%v\n", proposal.ProposalId, err)
return msg, broken
}
proposalYesCount, err := proposal.VoteState.GetYesCount()
if err != nil {
msg += fmt.Sprintf("error while getting the weighted sum of yes votes for proposal with ID %d\n%v\n", proposal.ProposalId, err)
return msg, broken
}
proposalNoCount, err := proposal.VoteState.GetNoCount()
if err != nil {
msg += fmt.Sprintf("error while getting the weighted sum of no votes for proposal with ID %d\n%v\n", proposal.ProposalId, err)
return msg, broken
}
proposalAbstainCount, err := proposal.VoteState.GetAbstainCount()
if err != nil {
msg += fmt.Sprintf("error while getting the weighted sum of abstain votes for proposal with ID %d\n%v\n", proposal.ProposalId, err)
return msg, broken
}
proposalVetoCount, err := proposal.VoteState.GetVetoCount()
if err != nil {
msg += fmt.Sprintf("error while getting the weighted sum of veto votes for proposal with ID %d\n%v\n", proposal.ProposalId, err)
return msg, broken
}
if totalProposalVotes.Cmp(totalVotingWeight) != 0 {
broken = true
msg += fmt.Sprintf("proposal VoteState must correspond to the sum of votes weights\nProposal with ID %d has total proposal votes %s, but got sum of votes weights %s\n", proposal.ProposalId, totalProposalVotes.String(), totalVotingWeight.String())
break
}
if (yesVoteWeight.Cmp(proposalYesCount) != 0) || (noVoteWeight.Cmp(proposalNoCount) != 0) || (abstainVoteWeight.Cmp(proposalAbstainCount) != 0) || (vetoVoteWeight.Cmp(proposalVetoCount) != 0) {
broken = true
msg += fmt.Sprintf("proposal VoteState must correspond to the vote choice\nProposal with ID %d and voter address %s must correspond to the vote choice\n", proposal.ProposalId, vote.Voter)
break
}
}
return msg, broken
}

View File

@ -0,0 +1,585 @@
package keeper_test
import (
"testing"
"time"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/group"
"github.com/cosmos/cosmos-sdk/x/group/internal/orm"
"github.com/cosmos/cosmos-sdk/x/group/keeper"
)
type invariantTestSuite struct {
suite.Suite
ctx sdk.Context
cdc *codec.ProtoCodec
key *storetypes.KVStoreKey
blockTime time.Time
}
func TestInvariantTestSuite(t *testing.T) {
suite.Run(t, new(invariantTestSuite))
}
func (s *invariantTestSuite) SetupSuite() {
interfaceRegistry := types.NewInterfaceRegistry()
group.RegisterInterfaces(interfaceRegistry)
cdc := codec.NewProtoCodec(interfaceRegistry)
key := sdk.NewKVStoreKey(group.ModuleName)
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db)
cms.MountStoreWithDB(key, storetypes.StoreTypeIAVL, db)
_ = cms.LoadLatestVersion()
sdkCtx := sdk.NewContext(cms, tmproto.Header{}, false, log.NewNopLogger())
s.ctx = sdkCtx
s.cdc = cdc
s.key = key
}
func (s *invariantTestSuite) TestTallyVotesInvariant() {
sdkCtx, _ := s.ctx.CacheContext()
curCtx, cdc, key := sdkCtx, s.cdc, s.key
prevCtx, _ := curCtx.CacheContext()
prevCtx = prevCtx.WithBlockHeight(curCtx.BlockHeight() - 1)
// Proposal Table
proposalTable, err := orm.NewAutoUInt64Table([2]byte{keeper.ProposalTablePrefix}, keeper.ProposalTableSeqPrefix, &group.Proposal{}, cdc)
s.Require().NoError(err)
_, _, addr1 := testdata.KeyTestPubAddr()
_, _, addr2 := testdata.KeyTestPubAddr()
specs := map[string]struct {
prevProposal *group.Proposal
curProposal *group.Proposal
expBroken bool
}{
"invariant not broken": {
prevProposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: prevCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "1", NoCount: "0", AbstainCount: "0", VetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
curProposal: &group.Proposal{
ProposalId: 1,
Address: addr2.String(),
Proposers: []string{addr2.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "2", NoCount: "0", AbstainCount: "0", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
},
"current block yes vote count must be greater than previous block yes vote count": {
prevProposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: prevCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "2", NoCount: "0", AbstainCount: "0", VetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
curProposal: &group.Proposal{
ProposalId: 1,
Address: addr2.String(),
Proposers: []string{addr2.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "1", NoCount: "0", AbstainCount: "0", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
expBroken: true,
},
"current block no vote count must be greater than previous block no vote count": {
prevProposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: prevCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "0", NoCount: "2", AbstainCount: "0", VetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
curProposal: &group.Proposal{
ProposalId: 1,
Address: addr2.String(),
Proposers: []string{addr2.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "0", NoCount: "1", AbstainCount: "0", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
expBroken: true,
},
"current block abstain vote count must be greater than previous block abstain vote count": {
prevProposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: prevCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "0", NoCount: "0", AbstainCount: "2", VetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
curProposal: &group.Proposal{
ProposalId: 1,
Address: addr2.String(),
Proposers: []string{addr2.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "0", NoCount: "0", AbstainCount: "1", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
expBroken: true,
},
"current block veto vote count must be greater than previous block veto vote count": {
prevProposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: prevCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "0", NoCount: "0", AbstainCount: "0", VetoCount: "2"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
curProposal: &group.Proposal{
ProposalId: 1,
Address: addr2.String(),
Proposers: []string{addr2.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "0", NoCount: "0", AbstainCount: "0", VetoCount: "1"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
expBroken: true,
},
}
for _, spec := range specs {
prevProposal := spec.prevProposal
curProposal := spec.curProposal
cachePrevCtx, _ := prevCtx.CacheContext()
cacheCurCtx, _ := curCtx.CacheContext()
_, err = proposalTable.Create(cachePrevCtx.KVStore(key), prevProposal)
s.Require().NoError(err)
_, err = proposalTable.Create(cacheCurCtx.KVStore(key), curProposal)
s.Require().NoError(err)
_, broken := keeper.TallyVotesInvariantHelper(cacheCurCtx, cachePrevCtx, key, *proposalTable)
s.Require().Equal(spec.expBroken, broken)
}
}
func (s *invariantTestSuite) TestGroupTotalWeightInvariant() {
sdkCtx, _ := s.ctx.CacheContext()
curCtx, cdc, key := sdkCtx, s.cdc, s.key
// Group Table
groupTable, err := orm.NewAutoUInt64Table([2]byte{keeper.GroupTablePrefix}, keeper.GroupTableSeqPrefix, &group.GroupInfo{}, cdc)
s.Require().NoError(err)
// Group Member Table
groupMemberTable, err := orm.NewPrimaryKeyTable([2]byte{keeper.GroupMemberTablePrefix}, &group.GroupMember{}, cdc)
s.Require().NoError(err)
groupMemberByGroupIndex, err := orm.NewIndex(groupMemberTable, keeper.GroupMemberByGroupIndexPrefix, func(val interface{}) ([]interface{}, error) {
group := val.(*group.GroupMember).GroupId
return []interface{}{group}, nil
}, group.GroupMember{}.GroupId)
s.Require().NoError(err)
_, _, addr1 := testdata.KeyTestPubAddr()
_, _, addr2 := testdata.KeyTestPubAddr()
specs := map[string]struct {
groupsInfo *group.GroupInfo
groupMembers []*group.GroupMember
expBroken bool
}{
"invariant not broken": {
groupsInfo: &group.GroupInfo{
GroupId: 1,
Admin: addr1.String(),
Version: 1,
TotalWeight: "3",
},
groupMembers: []*group.GroupMember{
{
GroupId: 1,
Member: &group.Member{
Address: addr1.String(),
Weight: "1",
},
},
{
GroupId: 1,
Member: &group.Member{
Address: addr2.String(),
Weight: "2",
},
},
},
expBroken: false,
},
"group's TotalWeight must be equal to sum of its members weight ": {
groupsInfo: &group.GroupInfo{
GroupId: 1,
Admin: addr1.String(),
Version: 1,
TotalWeight: "3",
},
groupMembers: []*group.GroupMember{
{
GroupId: 1,
Member: &group.Member{
Address: addr1.String(),
Weight: "2",
},
},
{
GroupId: 1,
Member: &group.Member{
Address: addr2.String(),
Weight: "2",
},
},
},
expBroken: true,
},
}
for _, spec := range specs {
cacheCurCtx, _ := curCtx.CacheContext()
groupsInfo := spec.groupsInfo
groupMembers := spec.groupMembers
_, err := groupTable.Create(cacheCurCtx.KVStore(key), groupsInfo)
s.Require().NoError(err)
for i := 0; i < len(groupMembers); i++ {
err := groupMemberTable.Create(cacheCurCtx.KVStore(key), groupMembers[i])
s.Require().NoError(err)
}
_, broken := keeper.GroupTotalWeightInvariantHelper(cacheCurCtx, key, *groupTable, groupMemberByGroupIndex)
s.Require().Equal(spec.expBroken, broken)
}
}
func (s *invariantTestSuite) TestTallyVotesSumInvariant() {
sdkCtx, _ := s.ctx.CacheContext()
curCtx, cdc, key := sdkCtx, s.cdc, s.key
// Group Table
groupTable, err := orm.NewAutoUInt64Table([2]byte{keeper.GroupTablePrefix}, keeper.GroupTableSeqPrefix, &group.GroupInfo{}, cdc)
s.Require().NoError(err)
// Group Account Table
groupAccountTable, err := orm.NewPrimaryKeyTable([2]byte{keeper.GroupAccountTablePrefix}, &group.GroupAccountInfo{}, cdc)
s.Require().NoError(err)
// Group Member Table
groupMemberTable, err := orm.NewPrimaryKeyTable([2]byte{keeper.GroupMemberTablePrefix}, &group.GroupMember{}, cdc)
s.Require().NoError(err)
// Proposal Table
proposalTable, err := orm.NewAutoUInt64Table([2]byte{keeper.ProposalTablePrefix}, keeper.ProposalTableSeqPrefix, &group.Proposal{}, cdc)
s.Require().NoError(err)
// Vote Table
voteTable, err := orm.NewPrimaryKeyTable([2]byte{keeper.VoteTablePrefix}, &group.Vote{}, cdc)
s.Require().NoError(err)
voteByProposalIndex, err := orm.NewIndex(voteTable, keeper.VoteByProposalIndexPrefix, func(value interface{}) ([]interface{}, error) {
return []interface{}{value.(*group.Vote).ProposalId}, nil
}, group.Vote{}.ProposalId)
s.Require().NoError(err)
_, _, adminAddr := testdata.KeyTestPubAddr()
_, _, addr1 := testdata.KeyTestPubAddr()
_, _, addr2 := testdata.KeyTestPubAddr()
specs := map[string]struct {
groupsInfo *group.GroupInfo
groupAcc *group.GroupAccountInfo
groupMembers []*group.GroupMember
proposal *group.Proposal
votes []*group.Vote
expBroken bool
}{
"invariant not broken": {
groupsInfo: &group.GroupInfo{
GroupId: 1,
Admin: adminAddr.String(),
Version: 1,
TotalWeight: "7",
},
groupAcc: &group.GroupAccountInfo{
Address: addr1.String(),
GroupId: 1,
Admin: adminAddr.String(),
Version: 1,
},
groupMembers: []*group.GroupMember{
{
GroupId: 1,
Member: &group.Member{
Address: addr1.String(),
Weight: "4",
},
},
{
GroupId: 1,
Member: &group.Member{
Address: addr2.String(),
Weight: "3",
},
},
},
proposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "4", NoCount: "3", AbstainCount: "0", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
votes: []*group.Vote{
{
ProposalId: 1,
Voter: addr1.String(),
Choice: group.Choice_CHOICE_YES,
SubmittedAt: curCtx.BlockTime(),
},
{
ProposalId: 1,
Voter: addr2.String(),
Choice: group.Choice_CHOICE_NO,
SubmittedAt: curCtx.BlockTime(),
},
},
expBroken: false,
},
"proposal tally must correspond to the sum of vote weights": {
groupsInfo: &group.GroupInfo{
GroupId: 1,
Admin: adminAddr.String(),
Version: 1,
TotalWeight: "5",
},
groupAcc: &group.GroupAccountInfo{
Address: addr1.String(),
GroupId: 1,
Admin: adminAddr.String(),
Version: 1,
},
groupMembers: []*group.GroupMember{
{
GroupId: 1,
Member: &group.Member{
Address: addr1.String(),
Weight: "2",
},
},
{
GroupId: 1,
Member: &group.Member{
Address: addr2.String(),
Weight: "3",
},
},
},
proposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "6", NoCount: "0", AbstainCount: "0", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
votes: []*group.Vote{
{
ProposalId: 1,
Voter: addr1.String(),
Choice: group.Choice_CHOICE_YES,
SubmittedAt: curCtx.BlockTime(),
},
{
ProposalId: 1,
Voter: addr2.String(),
Choice: group.Choice_CHOICE_YES,
SubmittedAt: curCtx.BlockTime(),
},
},
expBroken: true,
},
"proposal VoteState must correspond to the vote choice": {
groupsInfo: &group.GroupInfo{
GroupId: 1,
Admin: adminAddr.String(),
Version: 1,
TotalWeight: "7",
},
groupAcc: &group.GroupAccountInfo{
Address: addr1.String(),
GroupId: 1,
Admin: adminAddr.String(),
Version: 1,
},
groupMembers: []*group.GroupMember{
{
GroupId: 1,
Member: &group.Member{
Address: addr1.String(),
Weight: "4",
},
},
{
GroupId: 1,
Member: &group.Member{
Address: addr2.String(),
Weight: "3",
},
},
},
proposal: &group.Proposal{
ProposalId: 1,
Address: addr1.String(),
Proposers: []string{addr1.String()},
SubmittedAt: curCtx.BlockTime(),
GroupVersion: 1,
GroupAccountVersion: 1,
Status: group.ProposalStatusSubmitted,
Result: group.ProposalResultUnfinalized,
VoteState: group.Tally{YesCount: "4", NoCount: "3", AbstainCount: "0", VetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.ProposalExecutorResultNotRun,
},
votes: []*group.Vote{
{
ProposalId: 1,
Voter: addr1.String(),
Choice: group.Choice_CHOICE_YES,
SubmittedAt: curCtx.BlockTime(),
},
{
ProposalId: 1,
Voter: addr2.String(),
Choice: group.Choice_CHOICE_ABSTAIN,
SubmittedAt: curCtx.BlockTime(),
},
},
expBroken: true,
},
}
for _, spec := range specs {
cacheCurCtx, _ := curCtx.CacheContext()
groupsInfo := spec.groupsInfo
proposal := spec.proposal
groupAcc := spec.groupAcc
groupMembers := spec.groupMembers
votes := spec.votes
_, err := groupTable.Create(cacheCurCtx.KVStore(key), groupsInfo)
s.Require().NoError(err)
err = groupAcc.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Second))
s.Require().NoError(err)
err = groupAccountTable.Create(cacheCurCtx.KVStore(key), groupAcc)
s.Require().NoError(err)
for i := 0; i < len(groupMembers); i++ {
err = groupMemberTable.Create(cacheCurCtx.KVStore(key), groupMembers[i])
s.Require().NoError(err)
}
_, err = proposalTable.Create(cacheCurCtx.KVStore(key), proposal)
s.Require().NoError(err)
for i := 0; i < len(votes); i++ {
err = voteTable.Create(cacheCurCtx.KVStore(key), votes[i])
s.Require().NoError(err)
}
_, broken := keeper.TallyVotesSumInvariantHelper(cacheCurCtx, key, *groupTable, *proposalTable, *groupMemberTable, voteByProposalIndex, *groupAccountTable)
s.Require().Equal(spec.expBroken, broken)
}
}

View File

@ -8,7 +8,6 @@ import (
"testing"
"time"
gogotypes "github.com/gogo/protobuf/types"
"github.com/stretchr/testify/suite"
tmtime "github.com/tendermint/tendermint/libs/time"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@ -1408,12 +1407,7 @@ func (s *TestSuite) TestVote() {
s.Assert().Equal(req.Address, proposals[0].Address)
s.Assert().Equal(req.Metadata, proposals[0].Metadata)
s.Assert().Equal(req.Proposers, proposals[0].Proposers)
psubmittedAt, err := gogotypes.TimestampProto(proposals[0].SubmittedAt)
s.Require().NoError(err)
submittedAt, err := gogotypes.TimestampFromProto(psubmittedAt)
s.Require().NoError(err)
s.Assert().Equal(s.blockTime, submittedAt)
s.Assert().Equal(s.blockTime, proposals[0].SubmittedAt)
s.Assert().Equal(uint64(1), proposals[0].GroupVersion)
s.Assert().Equal(uint64(1), proposals[0].GroupAccountVersion)
@ -1751,11 +1745,7 @@ func (s *TestSuite) TestVote() {
s.Assert().Equal(spec.req.Voter, loaded.Voter)
s.Assert().Equal(spec.req.Choice, loaded.Choice)
s.Assert().Equal(spec.req.Metadata, loaded.Metadata)
lsubmittedAt, err := gogotypes.TimestampProto(loaded.SubmittedAt)
s.Require().NoError(err)
submittedAt, err := gogotypes.TimestampFromProto(lsubmittedAt)
s.Require().NoError(err)
s.Assert().Equal(s.blockTime, submittedAt)
s.Assert().Equal(s.blockTime, loaded.SubmittedAt)
// query votes by proposal
votesByProposalRes, err := s.keeper.VotesByProposal(ctx, &group.QueryVotesByProposalRequest{
@ -1769,11 +1759,7 @@ func (s *TestSuite) TestVote() {
s.Assert().Equal(spec.req.Voter, vote.Voter)
s.Assert().Equal(spec.req.Choice, vote.Choice)
s.Assert().Equal(spec.req.Metadata, vote.Metadata)
vsubmittedAt, err := gogotypes.TimestampProto(vote.SubmittedAt)
s.Require().NoError(err)
submittedAt, err = gogotypes.TimestampFromProto(vsubmittedAt)
s.Require().NoError(err)
s.Assert().Equal(s.blockTime, submittedAt)
s.Assert().Equal(s.blockTime, vote.SubmittedAt)
// query votes by voter
voter := spec.req.Voter
@ -1787,11 +1773,7 @@ func (s *TestSuite) TestVote() {
s.Assert().Equal(voter, votesByVoter[0].Voter)
s.Assert().Equal(spec.req.Choice, votesByVoter[0].Choice)
s.Assert().Equal(spec.req.Metadata, votesByVoter[0].Metadata)
vsubmittedAt, err = gogotypes.TimestampProto(votesByVoter[0].SubmittedAt)
s.Require().NoError(err)
submittedAt, err = gogotypes.TimestampFromProto(vsubmittedAt)
s.Require().NoError(err)
s.Assert().Equal(s.blockTime, submittedAt)
s.Assert().Equal(s.blockTime, votesByVoter[0].SubmittedAt)
// and proposal is updated
proposalRes, err := s.keeper.Proposal(ctx, &group.QueryProposalRequest{

View File

@ -273,7 +273,6 @@ func (k Keeper) CreateGroupAccount(goCtx context.Context, req *group.MsgCreateGr
// handle a rare collision
continue
}
acc := k.accKeeper.NewAccount(ctx, &authtypes.ModuleAccount{
BaseAccount: &authtypes.BaseAccount{
Address: accountAddr.String(),
@ -405,11 +404,6 @@ func (k Keeper) CreateProposal(goCtx context.Context, req *group.MsgCreatePropos
return nil, err
}
// blockTime, err := gogotypes.TimestampProto(ctx.BlockTime())
if err != nil {
return nil, sdkerrors.Wrap(err, "block time conversion")
}
policy := account.GetDecisionPolicy()
if policy == nil {
return nil, sdkerrors.Wrap(errors.ErrEmpty, "nil policy")

View File

@ -103,7 +103,9 @@ func (AppModule) Name() string {
}
// RegisterInvariants does nothing, there are no invariants to enforce
func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
groupkeeper.RegisterInvariants(ir, am.keeper)
}
// Deprecated: Route returns the message routing key for the group module.
func (am AppModule) Route() sdk.Route {