Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add invariants to x/foundation #758

Merged
merged 7 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/foundation) [\#709](https://github.com/line/lbm-sdk/pull/709) add `gov mint` for x/foundation proposal
* (iavl) [\#738](https://github.com/line/lbm-sdk/pull/738) bump github.com/cosmos/iavl from v0.17.3 to v0.19.3
* (baseapp) [\#756](https://github.com/line/lbm-sdk/pull/756) Change to create chCheckTx with the value set in app config
* (x/foundation) [\#758](https://github.com/line/lbm-sdk/pull/758) add invariants to x/foundation

### Improvements

Expand Down
2 changes: 1 addition & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ func NewSimApp(
slashingtypes.ModuleName,
govtypes.ModuleName,
minttypes.ModuleName,
foundation.ModuleName,
crisistypes.ModuleName,
ibchost.ModuleName,
genutiltypes.ModuleName,
Expand All @@ -621,7 +622,6 @@ func NewSimApp(
paramstypes.ModuleName,
upgradetypes.ModuleName,
vestingtypes.ModuleName,
foundation.ModuleName,
token.ModuleName,
collection.ModuleName,
// wasm after ibc transfer
Expand Down
2 changes: 0 additions & 2 deletions x/foundation/client/testutil/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/foundation"
stakingtypes "github.com/line/lbm-sdk/x/staking/types"
)

func (s *IntegrationTestSuite) TestGRPCParams() {
Expand All @@ -31,7 +30,6 @@ func (s *IntegrationTestSuite) TestGRPCParams() {
Params: foundation.Params{
FoundationTax: sdk.MustNewDecFromStr("0.2"),
CensoredMsgTypeUrls: []string{
sdk.MsgTypeURL((*stakingtypes.MsgCreateValidator)(nil)),
0Tech marked this conversation as resolved.
Show resolved Hide resolved
sdk.MsgTypeURL((*foundation.MsgWithdrawFromTreasury)(nil)),
},
},
Expand Down
2 changes: 0 additions & 2 deletions x/foundation/client/testutil/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/foundation"
"github.com/line/lbm-sdk/x/foundation/client/cli"
stakingtypes "github.com/line/lbm-sdk/x/staking/types"
)

func (s *IntegrationTestSuite) TestNewQueryCmdParams() {
Expand All @@ -33,7 +32,6 @@ func (s *IntegrationTestSuite) TestNewQueryCmdParams() {
Params: foundation.Params{
FoundationTax: sdk.MustNewDecFromStr("0.2"),
CensoredMsgTypeUrls: []string{
sdk.MsgTypeURL((*stakingtypes.MsgCreateValidator)(nil)),
sdk.MsgTypeURL((*foundation.MsgWithdrawFromTreasury)(nil)),
},
},
Expand Down
11 changes: 4 additions & 7 deletions x/foundation/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
bankcli "github.com/line/lbm-sdk/x/bank/client/cli"
"github.com/line/lbm-sdk/x/foundation"
"github.com/line/lbm-sdk/x/foundation/client/cli"
stakingtypes "github.com/line/lbm-sdk/x/staking/types"
)

type IntegrationTestSuite struct {
Expand Down Expand Up @@ -61,7 +60,6 @@ func (s *IntegrationTestSuite) SetupSuite() {
params := foundation.Params{
FoundationTax: sdk.MustNewDecFromStr("0.2"),
CensoredMsgTypeUrls: []string{
sdk.MsgTypeURL((*stakingtypes.MsgCreateValidator)(nil)),
sdk.MsgTypeURL((*foundation.MsgWithdrawFromTreasury)(nil)),
},
}
Expand Down Expand Up @@ -97,14 +95,13 @@ func (s *IntegrationTestSuite) SetupSuite() {
})
foundationData.Foundation = info

grantees := []sdk.AccAddress{s.stranger, s.leavingMember}
foundationData.Authorizations = make([]foundation.GrantAuthorization, len(grantees))
for i, grantee := range grantees {
treasuryReceivers := []sdk.AccAddress{s.stranger, s.leavingMember}
for _, receiver := range treasuryReceivers {
ga := foundation.GrantAuthorization{
Grantee: grantee.String(),
Grantee: receiver.String(),
}.WithAuthorization(&foundation.ReceiveFromTreasuryAuthorization{})
s.Require().NotNil(ga)
foundationData.Authorizations[i] = *ga
foundationData.Authorizations = append(foundationData.Authorizations, *ga)
}

foundationDataBz, err := s.cfg.Codec.MarshalJSON(&foundationData)
Expand Down
77 changes: 77 additions & 0 deletions x/foundation/keeper/invariants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package keeper

import (
"fmt"

sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/foundation"
)

const (
moduleAccountInvariant = "module-accounts"
totalWeightInvariant = "total-weight"
proposalInvariant = "proposals"
)

func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(foundation.ModuleName, moduleAccountInvariant, ModuleAccountInvariant(k))
ir.RegisterRoute(foundation.ModuleName, totalWeightInvariant, ProposalInvariant(k))
ir.RegisterRoute(foundation.ModuleName, proposalInvariant, ProposalInvariant(k))
}

func ModuleAccountInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
// cache, we don't want to write changes
ctx, _ = ctx.CacheContext()

treasuryAcc := k.authKeeper.GetModuleAccount(ctx, foundation.TreasuryName)
balance := k.bankKeeper.GetAllBalances(ctx, treasuryAcc.GetAddress())

treasury := k.GetTreasury(ctx)
msg := fmt.Sprintf("coins in the treasury; expected %s, got %s\n", treasury, balance)
broken := !treasury.IsEqual(sdk.NewDecCoinsFromCoins(balance...))

return sdk.FormatInvariant(foundation.ModuleName, moduleAccountInvariant, msg), broken
}
}

func TotalWeightInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
// cache, we don't want to write changes
ctx, _ = ctx.CacheContext()

expected := k.GetFoundationInfo(ctx).TotalWeight
real := sdk.NewDec(int64(len(k.GetMembers(ctx))))

msg := fmt.Sprintf("total weight of foundation; expected %s, got %s\n", expected, real)
broken := !real.Equal(expected)

return sdk.FormatInvariant(foundation.ModuleName, totalWeightInvariant, msg), broken
}
}

func ProposalInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
// cache, we don't want to write changes
ctx, _ = ctx.CacheContext()

version := k.GetFoundationInfo(ctx).Version
msg := fmt.Sprintf("current foundation version; %d\n", version)
broken := false

k.iterateProposals(ctx, func(proposal foundation.Proposal) (stop bool) {
if proposal.FoundationVersion == version {
return true
}

if proposal.Status == foundation.PROPOSAL_STATUS_SUBMITTED {
msg += fmt.Sprintf("active old proposal %d found; version %d\n", proposal.Id, proposal.FoundationVersion)
broken = true
}

return false
})

return sdk.FormatInvariant(foundation.ModuleName, proposalInvariant, msg), broken
}
}
96 changes: 96 additions & 0 deletions x/foundation/keeper/invariants_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package keeper_test

import (
sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/foundation"
"github.com/line/lbm-sdk/x/foundation/keeper"
)

func (s *KeeperTestSuite) TestModuleAccountInvariant() {
testCases := map[string]struct {
malleate func(ctx sdk.Context)
valid bool
}{
"invariant not broken": {
valid: true,
},
"treasury differs from the balance": {
malleate: func(ctx sdk.Context) {
balance := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, s.balance.Add(sdk.OneInt())))
s.keeper.SetPool(ctx, foundation.Pool{
Treasury: sdk.NewDecCoinsFromCoins(balance...),
})
},
},
}

for name, tc := range testCases {
ctx, _ := s.ctx.CacheContext()
if tc.malleate != nil {
tc.malleate(ctx)
}

invariant := keeper.ModuleAccountInvariant(s.keeper)
_, broken := invariant(ctx)
s.Require().Equal(!tc.valid, broken, name)
}
}

func (s *KeeperTestSuite) TestTotalWeightInvariant() {
testCases := map[string]struct {
malleate func(ctx sdk.Context)
valid bool
}{
"invariant not broken": {
valid: true,
},
"total weight differs from the number of foundation members": {
malleate: func(ctx sdk.Context) {
info := s.keeper.GetFoundationInfo(ctx)
numMembers := len(s.keeper.GetMembers(ctx))
info.TotalWeight = sdk.NewDec(int64(numMembers)).Add(sdk.OneDec())
s.keeper.SetFoundationInfo(ctx, info)
},
},
}

for name, tc := range testCases {
ctx, _ := s.ctx.CacheContext()
if tc.malleate != nil {
tc.malleate(ctx)
}

invariant := keeper.TotalWeightInvariant(s.keeper)
_, broken := invariant(ctx)
s.Require().Equal(!tc.valid, broken, name)
}
}

func (s *KeeperTestSuite) TestProposalInvariant() {
testCases := map[string]struct {
malleate func(ctx sdk.Context)
valid bool
}{
"invariant not broken": {
valid: true,
},
"active old proposal exists": {
malleate: func(ctx sdk.Context) {
info := s.keeper.GetFoundationInfo(ctx)
info.Version--
s.keeper.SetFoundationInfo(ctx, info)
},
},
}

for name, tc := range testCases {
ctx, _ := s.ctx.CacheContext()
if tc.malleate != nil {
tc.malleate(ctx)
}

invariant := keeper.ProposalInvariant(s.keeper)
_, broken := invariant(ctx)
s.Require().Equal(!tc.valid, broken, name)
}
}
12 changes: 3 additions & 9 deletions x/foundation/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/line/lbm-sdk/testutil/testdata"
sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/foundation"
"github.com/line/lbm-sdk/x/stakingplus"
)

func (s *KeeperTestSuite) TestMsgUpdateParams() {
Expand Down Expand Up @@ -611,20 +610,15 @@ func (s *KeeperTestSuite) TestMsgRevoke() {
msgTypeURL: foundation.ReceiveFromTreasuryAuthorization{}.MsgTypeURL(),
valid: true,
},
"no grant": {
authority: s.authority,
grantee: s.members[0],
msgTypeURL: foundation.ReceiveFromTreasuryAuthorization{}.MsgTypeURL(),
},
"not authorized": {
authority: s.stranger,
grantee: s.stranger,
msgTypeURL: foundation.ReceiveFromTreasuryAuthorization{}.MsgTypeURL(),
},
"wrong granter": {
"no grant": {
authority: s.authority,
grantee: s.stranger,
msgTypeURL: stakingplus.CreateValidatorAuthorization{}.MsgTypeURL(),
grantee: s.members[0],
msgTypeURL: foundation.ReceiveFromTreasuryAuthorization{}.MsgTypeURL(),
},
}

Expand Down
4 changes: 3 additions & 1 deletion x/foundation/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule {
}

// RegisterInvariants does nothing, there are no invariants to enforce
func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper)
}

// Route is empty, as we do not handle Messages (just proposals)
func (AppModule) Route() sdk.Route { return sdk.Route{} }
Expand Down
6 changes: 0 additions & 6 deletions x/foundation/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/auth/legacy/legacytx"
"github.com/line/lbm-sdk/x/foundation"
"github.com/line/lbm-sdk/x/stakingplus"
)

func TestMsgUpdateParams(t *testing.T) {
Expand Down Expand Up @@ -874,7 +873,6 @@ func TestMsgGrantAminoJson(t *testing.T) {
operator = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
grantee = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
proposer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
validatorAddr = sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address())
)

testCases := map[string]struct {
Expand All @@ -885,10 +883,6 @@ func TestMsgGrantAminoJson(t *testing.T) {
&foundation.ReceiveFromTreasuryAuthorization{},
fmt.Sprintf("{\"account_number\":\"1\",\"chain_id\":\"foo\",\"fee\":{\"amount\":[],\"gas\":\"0\"},\"memo\":\"memo\",\"msgs\":[{\"type\":\"lbm-sdk/MsgSubmitProposal\",\"value\":{\"exec\":1,\"messages\":[{\"type\":\"lbm-sdk/MsgGrant\",\"value\":{\"authority\":\"%s\",\"authorization\":{\"type\":\"lbm-sdk/ReceiveFromTreasuryAuthorization\",\"value\":{}},\"grantee\":\"%s\"}}],\"metadata\":\"ReceiveFromTreasuryAuthorization\",\"proposers\":[\"%s\"]}}],\"sequence\":\"1\",\"timeout_height\":\"1\"}", operator.String(), grantee.String(), proposer.String()),
},
"CreateValidatorAuthorization": {
&stakingplus.CreateValidatorAuthorization{ValidatorAddress: validatorAddr.String()},
fmt.Sprintf("{\"account_number\":\"1\",\"chain_id\":\"foo\",\"fee\":{\"amount\":[],\"gas\":\"0\"},\"memo\":\"memo\",\"msgs\":[{\"type\":\"lbm-sdk/MsgSubmitProposal\",\"value\":{\"exec\":1,\"messages\":[{\"type\":\"lbm-sdk/MsgGrant\",\"value\":{\"authority\":\"%s\",\"authorization\":{\"type\":\"lbm-sdk/CreateValidatorAuthorization\",\"value\":{\"validator_address\":\"%s\"}},\"grantee\":\"%s\"}}],\"metadata\":\"CreateValidatorAuthorization\",\"proposers\":[\"%s\"]}}],\"sequence\":\"1\",\"timeout_height\":\"1\"}", operator.String(), validatorAddr.String(), grantee.String(), proposer.String()),
},
}

for name, tc := range testCases {
Expand Down