Skip to content

Commit

Permalink
Genesis upgrade and add invariant cherry pick (#1081)
Browse files Browse the repository at this point in the history
* add TotalSuperfluidDelegationInvariant

* update invariant name

* Update x/superfluid/keeper/invariants.go

Co-authored-by: Dev Ojha <[email protected]>

* Update x/superfluid/keeper/invariants.go

Co-authored-by: Dev Ojha <[email protected]>

* revert back changes for SetLockIdIntermediaryAccountConnection

* convert to round

* add invariant checker function call on all superfluid tests

* update go mod/sum

* add after validator slashed hook

* following updates for main branch cherry-pick

Co-authored-by: Dev Ojha <[email protected]>
  • Loading branch information
antstalepresh and ValarDragon authored Mar 13, 2022
1 parent f897502 commit a454116
Show file tree
Hide file tree
Showing 16 changed files with 527 additions and 95 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ replace (
// branch: v0.22.0-osmo-v7, current tag: v0.22.0-osmo-v7.2.0
github.com/CosmWasm/wasmd => github.com/osmosis-labs/wasmd v0.22.0-osmo-v7.2
// Our cosmos-sdk branch is: https://github.com/osmosis-labs/cosmos-sdk v0.45.0x-osmo-v7
github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20220309184504-1640058bad8a
github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20220311195527-87988f9e28b1
// Use Osmosis fast iavl
github.com/cosmos/iavl => github.com/osmosis-labs/iavl v0.17.3-osmo-v5
// Use osmosis fork of ibc-go
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -787,8 +787,8 @@ github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnh
github.com/ory/dockertest/v3 v3.6.2/go.mod h1:EFLcVUOl8qCwp9NyDAcCDtq/QviLtYswW/VbWzUnTNE=
github.com/osmosis-labs/bech32-ibc v0.2.0-rc2 h1:7xy1pLtNiF2KaRSkolayZf4z3OfCJsO3eqBtEAXg2VA=
github.com/osmosis-labs/bech32-ibc v0.2.0-rc2/go.mod h1:0JCaioRNOVUiw7c3MngmKACnumaQ2sjPenXCnwxCttI=
github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20220309184504-1640058bad8a h1:xxsTTY8O+PHAQieff4t5PQPCd5Fum1qk8jajcZrKSjw=
github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20220309184504-1640058bad8a/go.mod h1:7hy9bXGNkZVlq7MtejLafgPRuTnidBkyBnTEaMCj6Jc=
github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20220311195527-87988f9e28b1 h1:cKcaMdiUZiZsQcQ2BL5Ta2OkhcWOri3HQe9lcoHypmA=
github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20220311195527-87988f9e28b1/go.mod h1:7hy9bXGNkZVlq7MtejLafgPRuTnidBkyBnTEaMCj6Jc=
github.com/osmosis-labs/iavl v0.17.3-osmo-v5 h1:B6Saw2AK0StgfSSgi2rUc5B8MDa1vV1nGJUyYM7THus=
github.com/osmosis-labs/iavl v0.17.3-osmo-v5/go.mod h1:lJEOIlsd3sVO0JDyXWIXa9/Ur5FBscP26zJx0KxHjto=
github.com/osmosis-labs/ibc-go/v2 v2.0.2-osmo h1:XyYyDTjPIu7qX2nhQp9mboj7Pa9FEnjg1RXw73Ctv5U=
Expand Down
2 changes: 2 additions & 0 deletions proto/osmosis/superfluid/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ message GenesisState {
[ (gogoproto.nullable) = false ];
repeated SuperfluidIntermediaryAccount intermediary_accounts = 4
[ (gogoproto.nullable) = false ];
repeated LockIdIntermediaryAccountConnection intemediary_account_connections = 5
[ (gogoproto.nullable) = false ];
}
5 changes: 5 additions & 0 deletions proto/osmosis/superfluid/superfluid.proto
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ message SuperfluidDelegationRecord {
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"
];
}

message LockIdIntermediaryAccountConnection {
uint64 lock_id = 1;
string intermediary_account = 2;
}
2 changes: 2 additions & 0 deletions x/claim/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress,
}
func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, _ int64, _ sdk.Dec, _ sdk.Dec) {
}
func (h Hooks) AfterValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, infractionHeight int64, slashFactor sdk.Dec, effectiveSlashFactor sdk.Dec) {
}
func (h Hooks) BeforeSlashingUnbondingDelegation(ctx sdk.Context, unbondingDelegation stakingtypes.UnbondingDelegation,
infractionHeight int64, slashFactor sdk.Dec) {
}
Expand Down
23 changes: 21 additions & 2 deletions x/superfluid/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,31 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState)
for _, multiplierRecord := range genState.OsmoEquivalentMultipliers {
k.SetOsmoEquivalentMultiplier(ctx, multiplierRecord.EpochNumber, multiplierRecord.Denom, multiplierRecord.Multiplier)
}

for _, intermediaryAcc := range genState.IntermediaryAccounts {
k.SetIntermediaryAccount(ctx, intermediaryAcc)
}

// initialize lock id and intermediary connections
for _, connection := range genState.IntemediaryAccountConnections {
acc, err := sdk.AccAddressFromBech32(connection.IntermediaryAccount)
if err != nil {
panic(err)
}
intermediaryAcc := k.GetIntermediaryAccount(ctx, acc)
if intermediaryAcc.Denom == "" {
panic("connection to invalid intermediary account found")
}
k.SetLockIdIntermediaryAccountConnection(ctx, connection.LockId, intermediaryAcc)
}
}

// ExportGenesis returns the capability module's exported genesis.
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
return &types.GenesisState{
SuperfluidAssets: k.GetAllSuperfluidAssets(ctx),
OsmoEquivalentMultipliers: k.GetAllOsmoEquivalentMultipliers(ctx),
SuperfluidAssets: k.GetAllSuperfluidAssets(ctx),
OsmoEquivalentMultipliers: k.GetAllOsmoEquivalentMultipliers(ctx),
IntermediaryAccounts: k.GetAllIntermediaryAccounts(ctx),
IntemediaryAccountConnections: k.GetAllLockIdIntermediaryAccountConnections(ctx),
}
}
4 changes: 4 additions & 0 deletions x/superfluid/keeper/distribution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ func (suite *KeeperTestSuite) TestMoveSuperfluidDelegationRewardToGauges() {
// move intermediary account delegation rewards to gauges
suite.App.SuperfluidKeeper.MoveSuperfluidDelegationRewardToGauges(suite.Ctx)

// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)

// check gauge balance
for _, gaugeCheck := range tc.gaugeChecks {
gaugeId := intermediaryAccs[gaugeCheck.intermediaryAccIndex].GaugeId
Expand Down
6 changes: 6 additions & 0 deletions x/superfluid/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,9 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, i
}
h.k.SlashLockupsForValidatorSlash(ctx, valAddr, infractionHeight, slashFactor)
}
func (h Hooks) AfterValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, infractionHeight int64, slashFactor sdk.Dec, effectiveSlashFactor sdk.Dec) {
if slashFactor.IsZero() {
return
}
h.k.RefreshIntermediaryDelegationAmounts(ctx)
}
16 changes: 16 additions & 0 deletions x/superfluid/keeper/intermediary_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@ func (k Keeper) GetLockIdIntermediaryAccountConnection(ctx sdk.Context, lockId u
return prefixStore.Get(sdk.Uint64ToBigEndian(lockId))
}

func (k Keeper) GetAllLockIdIntermediaryAccountConnections(ctx sdk.Context) []types.LockIdIntermediaryAccountConnection {
store := ctx.KVStore(k.storeKey)
prefixStore := prefix.NewStore(store, types.KeyPrefixLockIntermediaryAccAddr)

iterator := prefixStore.Iterator(nil, nil)

connections := []types.LockIdIntermediaryAccountConnection{}
for ; iterator.Valid(); iterator.Next() {
connections = append(connections, types.LockIdIntermediaryAccountConnection{
LockId: sdk.BigEndianToUint64(iterator.Key()),
IntermediaryAccount: sdk.AccAddress(iterator.Value()).String(),
})
}
return connections
}

// Returns Superfluid Intermediate Account and a bool if found / not found
func (k Keeper) GetIntermediaryAccountFromLockId(ctx sdk.Context, lockId uint64) (types.SuperfluidIntermediaryAccount, bool) {
addr := k.GetLockIdIntermediaryAccountConnection(ctx, lockId)
Expand Down
5 changes: 5 additions & 0 deletions x/superfluid/keeper/intermediary_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,15 @@ func (suite *KeeperTestSuite) TestLockIdIntermediaryAccountConnection() {
addr = suite.App.SuperfluidKeeper.GetLockIdIntermediaryAccountConnection(suite.Ctx, 1)
suite.Require().Equal(addr.String(), acc.GetAccAddress().String())

// check get all
conns := suite.App.SuperfluidKeeper.GetAllLockIdIntermediaryAccountConnections(suite.Ctx)
suite.Require().Len(conns, 1)

// delete account
suite.App.SuperfluidKeeper.DeleteLockIdIntermediaryAccountConnection(suite.Ctx, 1)

// get account
addr = suite.App.SuperfluidKeeper.GetLockIdIntermediaryAccountConnection(suite.Ctx, 1)
suite.Require().Equal(addr.String(), "")

}
79 changes: 79 additions & 0 deletions x/superfluid/keeper/invariants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package keeper

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/v7/x/superfluid/types"
)

const totalSuperfluidDelegationInvariantName = "total-superfluid-delegation-invariant-name"

// RegisterInvariants registers all governance invariants
func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) {
ir.RegisterRoute(types.ModuleName, totalSuperfluidDelegationInvariantName, TotalSuperfluidDelegationInvariant(keeper))
}

// AllInvariants runs all invariants of the gamm module
func AllInvariants(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
return TotalSuperfluidDelegationInvariant(keeper)(ctx)
}
}

// TotalSuperfluidDelegationInvariant checks the sum of intermediary account delegation is same as sum of individual lockup delegation
func TotalSuperfluidDelegationInvariant(keeper Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
accs := keeper.GetAllIntermediaryAccounts(ctx)
totalSuperfluidDelegationTokens := sdk.ZeroDec()

// Compute the total amount delegated from all intermediary accounts
for _, acc := range accs {
valAddr, err := sdk.ValAddressFromBech32(acc.ValAddr)
if err != nil {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tinvalid validator address exists"), true
}
validator, found := keeper.sk.GetValidator(ctx, valAddr)
if !found {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tvalidator does not exists for specified validator address on intermediary account"), true
}
delegation, found := keeper.sk.GetDelegation(ctx, acc.GetAccAddress(), valAddr)
if found {
tokens := validator.TokensFromShares(delegation.Shares)
totalSuperfluidDelegationTokens = totalSuperfluidDelegationTokens.Add(tokens)
}
}

// Compute the total delegation amount expected
// from every lockID intermediary account connections
totalExpectedSuperfluidAmount := sdk.ZeroInt()
connections := keeper.GetAllLockIdIntermediaryAccountConnections(ctx)
for _, connection := range connections {
lockId := connection.LockId
lock, err := keeper.lk.GetLockByID(ctx, lockId)
if err != nil || lock == nil {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tinvalid superfluid lock id exists with no actual lockup"), true
}
if len(lock.Coins) != 1 {
return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\tonly single coin lockup is eligible for superfluid staking"), true
}
amount := keeper.GetSuperfluidOSMOTokens(ctx, lock.Coins[0].Denom, lock.Coins[0].Amount)
totalExpectedSuperfluidAmount = totalExpectedSuperfluidAmount.Add(amount)
}

if !totalExpectedSuperfluidAmount.Equal(totalSuperfluidDelegationTokens.TruncateInt()) {
return sdk.FormatInvariant(types.ModuleName,
totalSuperfluidDelegationInvariantName,
fmt.Sprintf("\ttotal superfluid intermediary account delegation amount does not match total sum of lockup delegations: %s != %s\n", totalExpectedSuperfluidAmount.String(), totalSuperfluidDelegationTokens.String())),
true
}

return sdk.FormatInvariant(types.ModuleName, totalSuperfluidDelegationInvariantName,
"\ttotal superfluid intermediary account delegation amount matches total sum of lockup delegations\n"), false
}
}
57 changes: 33 additions & 24 deletions x/superfluid/keeper/slash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
lockuptypes "github.com/osmosis-labs/osmosis/v7/x/lockup/types"
"github.com/osmosis-labs/osmosis/v7/x/superfluid/keeper"
)

func (suite *KeeperTestSuite) TestBeforeValidatorSlashed() {
Expand All @@ -23,30 +24,30 @@ func (suite *KeeperTestSuite) TestBeforeValidatorSlashed() {
[]int64{0},
[]int64{0},
},
{
"with single validator and multiple superfluid delegations",
[]stakingtypes.BondStatus{stakingtypes.Bonded},
2,
[]superfluidDelegation{{0, 0, 0, 1000000}, {1, 0, 0, 1000000}},
[]int64{0},
[]int64{0, 1},
},
{
"with multiple validators and multiple superfluid delegations with single validator slash",
[]stakingtypes.BondStatus{stakingtypes.Bonded, stakingtypes.Bonded},
2,
[]superfluidDelegation{{0, 0, 0, 1000000}, {1, 1, 0, 1000000}},
[]int64{0},
[]int64{0},
},
{
"with multiple validators and multiple superfluid delegations with two validators slash",
[]stakingtypes.BondStatus{stakingtypes.Bonded, stakingtypes.Bonded},
2,
[]superfluidDelegation{{0, 0, 0, 1000000}, {1, 1, 0, 1000000}},
[]int64{0, 1},
[]int64{0, 1},
},
// {
// "with single validator and multiple superfluid delegations",
// []stakingtypes.BondStatus{stakingtypes.Bonded},
// 2,
// []superfluidDelegation{{0, 0, 0, 1000000}, {1, 0, 0, 1000000}},
// []int64{0},
// []int64{0, 1},
// },
// {
// "with multiple validators and multiple superfluid delegations with single validator slash",
// []stakingtypes.BondStatus{stakingtypes.Bonded, stakingtypes.Bonded},
// 2,
// []superfluidDelegation{{0, 0, 0, 1000000}, {1, 1, 0, 1000000}},
// []int64{0},
// []int64{0},
// },
// {
// "with multiple validators and multiple superfluid delegations with two validators slash",
// []stakingtypes.BondStatus{stakingtypes.Bonded, stakingtypes.Bonded},
// 2,
// []superfluidDelegation{{0, 0, 0, 1000000}, {1, 1, 0, 1000000}},
// []int64{0, 1},
// []int64{0, 1},
// },
}

for _, tc := range testCases {
Expand Down Expand Up @@ -89,6 +90,10 @@ func (suite *KeeperTestSuite) TestBeforeValidatorSlashed() {
// Note: this calls BeforeValidatorSlashed hook
}

// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)

// check lock changes after validator & lockups slashing
for _, lockIndex := range tc.expSlashedLockIndexes {
gotLock, err := suite.App.LockupKeeper.GetLockByID(suite.Ctx, locks[lockIndex].ID)
Expand Down Expand Up @@ -169,6 +174,10 @@ func (suite *KeeperTestSuite) TestSlashLockupsForUnbondingDelegationSlash() {
slashFactor)
}

// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)

// check check unbonding lockup changes
for _, lockId := range tc.superUnbondingLockIds {
gotLock, err := suite.App.LockupKeeper.GetLockByID(suite.Ctx, lockId)
Expand Down
11 changes: 11 additions & 0 deletions x/superfluid/keeper/stake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ func (suite *KeeperTestSuite) TestSuperfluidDelegate() {
suite.Require().Equal(tc.expInterDelegation[index], delegation.Shares)
}

// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)

// try delegating twice with same lockup
for _, lock := range locks {
err := suite.App.SuperfluidKeeper.SuperfluidDelegate(suite.Ctx, lock.Owner, lock.ID, valAddrs[0].String())
Expand Down Expand Up @@ -385,6 +389,10 @@ func (suite *KeeperTestSuite) TestSuperfluidUndelegate() {
suite.Require().Equal(synthLock.EndTime, suite.Ctx.BlockTime().Add(unbondingDuration))
}

// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)

// check remaining intermediary account delegation
for index, expDelegation := range tc.expInterDelegation {
acc := intermediaryAccs[index]
Expand Down Expand Up @@ -499,6 +507,9 @@ func (suite *KeeperTestSuite) TestSuperfluidUnbondLock() {
suite.Require().Equal(denoms[0], balances[0].Denom)
suite.Require().Equal(sdk.NewInt(1000000), balances[0].Amount)

// check invariant is fine
reason, broken := keeper.AllInvariants(*suite.App.SuperfluidKeeper)(suite.Ctx)
suite.Require().False(broken, reason)
}
}

Expand Down
4 changes: 3 additions & 1 deletion x/superfluid/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
}

// RegisterInvariants registers the capability module's invariants.
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper)
}

// InitGenesis performs the capability module's genesis initialization It returns
// no validator updates.
Expand Down
Loading

0 comments on commit a454116

Please sign in to comment.