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

Genesis upgrade and add invariant cherry pick #1081

Merged
merged 10 commits into from
Mar 13, 2022
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)
}
Comment on lines +91 to +96
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't backport this PR due to this change. We do need to get the export genesis changes onto v7.x though. Eugen can you make a PR to v7.x with the import / export genesis changes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I'll just have the bot open that PR, and we just comment out these lines

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},
// },
Comment on lines +27 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to fix these tests in an upcoming PR

}

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