Skip to content

Commit

Permalink
feat: add invariants to x/foundation (#758)
Browse files Browse the repository at this point in the history
* Add module account invariant

* Fix InitGenesis order

* Add proposal invariant

* Add total weight invariant

* Remove reverse dependency on stakingplus

* Update CHANGELOG.md
  • Loading branch information
0Tech committed Oct 26, 2022
1 parent 73a741b commit 532154f
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 28 deletions.
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)),
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

0 comments on commit 532154f

Please sign in to comment.