-
Notifications
You must be signed in to change notification settings - Fork 728
Commit
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package integration | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
abci "github.com/cometbft/cometbft/abci/types" | ||
cmtprototypes "github.com/cometbft/cometbft/proto/tendermint/types" | ||
|
||
"cosmossdk.io/core/appmodule" | ||
"cosmossdk.io/log" | ||
"cosmossdk.io/math" | ||
storetypes "cosmossdk.io/store/types" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address" | ||
"github.com/cosmos/cosmos-sdk/runtime" | ||
"github.com/cosmos/cosmos-sdk/testutil/integration" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" | ||
"github.com/cosmos/cosmos-sdk/x/auth" | ||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" | ||
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
"github.com/cosmos/cosmos-sdk/x/auth/vesting" | ||
"github.com/cosmos/cosmos-sdk/x/bank" | ||
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
"github.com/cosmos/cosmos-sdk/x/distribution" | ||
distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" | ||
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" | ||
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" | ||
"github.com/cosmos/cosmos-sdk/x/staking" | ||
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
|
||
"github.com/cosmos/gaia/v22/x/lsm" | ||
lsmkeeper "github.com/cosmos/gaia/v22/x/lsm/keeper" | ||
lsmtypes "github.com/cosmos/gaia/v22/x/lsm/types" | ||
) | ||
|
||
type fixture struct { | ||
app *integration.App | ||
|
||
sdkCtx sdk.Context | ||
cdc codec.Codec | ||
keys map[string]*storetypes.KVStoreKey | ||
|
||
accountKeeper authkeeper.AccountKeeper | ||
bankKeeper bankkeeper.Keeper | ||
distributionKeeper distributionkeeper.Keeper | ||
stakingKeeper *stakingkeeper.Keeper | ||
lsmKeeper *lsmkeeper.Keeper | ||
} | ||
|
||
func initFixture(tb testing.TB) *fixture { | ||
tb.Helper() | ||
keys := storetypes.NewKVStoreKeys( | ||
authtypes.StoreKey, banktypes.StoreKey, distributiontypes.StoreKey, stakingtypes.StoreKey, lsmtypes.StoreKey, | ||
) | ||
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, staking.AppModuleBasic{}, vesting.AppModuleBasic{}).Codec | ||
|
||
logger := log.NewTestLogger(tb) | ||
cms := integration.CreateMultiStore(keys, logger) | ||
|
||
newCtx := sdk.NewContext(cms, cmtprototypes.Header{}, true, logger) | ||
|
||
authority := authtypes.NewModuleAddress("gov") | ||
|
||
maccPerms := map[string][]string{ | ||
distributiontypes.ModuleName: {authtypes.Minter}, | ||
minttypes.ModuleName: {authtypes.Minter}, | ||
stakingtypes.ModuleName: {authtypes.Minter}, | ||
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, | ||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, | ||
} | ||
|
||
accountKeeper := authkeeper.NewAccountKeeper( | ||
cdc, | ||
runtime.NewKVStoreService(keys[authtypes.StoreKey]), | ||
authtypes.ProtoBaseAccount, | ||
maccPerms, | ||
addresscodec.NewBech32Codec(sdk.Bech32MainPrefix), | ||
Check warning Code scanning / CodeQL Directly using the bech32 constants Warning test
Directly using the bech32 constants instead of the configuration values
|
||
sdk.Bech32MainPrefix, | ||
Check warning Code scanning / CodeQL Directly using the bech32 constants Warning test
Directly using the bech32 constants instead of the configuration values
|
||
authority.String(), | ||
) | ||
|
||
blockedAddresses := map[string]bool{ | ||
accountKeeper.GetAuthority(): false, | ||
} | ||
bankKeeper := bankkeeper.NewBaseKeeper( | ||
cdc, | ||
runtime.NewKVStoreService(keys[banktypes.StoreKey]), | ||
accountKeeper, | ||
blockedAddresses, | ||
authority.String(), | ||
log.NewNopLogger(), | ||
) | ||
|
||
stakingKeeper := stakingkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), | ||
accountKeeper, bankKeeper, authority.String(), addresscodec.NewBech32Codec(sdk.Bech32PrefixValAddr), addresscodec.NewBech32Codec(sdk.Bech32PrefixConsAddr)) | ||
Check warning Code scanning / CodeQL Directly using the bech32 constants Warning test
Directly using the bech32 constants instead of the configuration values
Check warning Code scanning / CodeQL Directly using the bech32 constants Warning test
Directly using the bech32 constants instead of the configuration values
|
||
distributionKeeper := distributionkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[distributiontypes. | ||
StoreKey]), accountKeeper, bankKeeper, stakingKeeper, distributiontypes.ModuleName, authority.String()) | ||
lsmKeeper := lsmkeeper.NewKeeper(cdc, runtime.NewKVStoreService(keys[lsmtypes.StoreKey]), accountKeeper, | ||
bankKeeper, stakingKeeper, distributionKeeper, authority.String()) | ||
|
||
authModule := auth.NewAppModule(cdc, accountKeeper, authsims.RandomGenesisAccounts, nil) | ||
bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil) | ||
stakingModule := staking.NewAppModule(cdc, stakingKeeper, accountKeeper, bankKeeper, nil) | ||
distributionModule := distribution.NewAppModule(cdc, distributionKeeper, accountKeeper, bankKeeper, | ||
stakingKeeper, nil) | ||
lsmModule := lsm.NewAppModule(cdc, lsmKeeper, accountKeeper, bankKeeper, stakingKeeper) | ||
|
||
integrationApp := integration.NewIntegrationApp(newCtx, logger, keys, cdc, map[string]appmodule.AppModule{ | ||
authtypes.ModuleName: authModule, | ||
banktypes.ModuleName: bankModule, | ||
distributiontypes.ModuleName: distributionModule, | ||
stakingtypes.ModuleName: stakingModule, | ||
lsmtypes.ModuleName: lsmModule, | ||
}) | ||
|
||
sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) | ||
|
||
stakingKeeper.SetHooks(stakingtypes.NewMultiStakingHooks( | ||
lsmKeeper.Hooks(), | ||
)) | ||
|
||
// Register staking MsgServer and QueryServer | ||
stakingtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), stakingkeeper.NewMsgServerImpl(stakingKeeper)) | ||
stakingtypes.RegisterQueryServer(integrationApp.QueryHelper(), stakingkeeper.NewQuerier(stakingKeeper)) | ||
|
||
// set default staking params | ||
require.NoError(tb, stakingKeeper.SetParams(sdkCtx, stakingtypes.DefaultParams())) | ||
|
||
// Register lsm MsgServer and QueryServer | ||
lsmtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), lsmkeeper.NewMsgServerImpl(lsmKeeper)) | ||
lsmtypes.RegisterQueryServer(integrationApp.QueryHelper(), lsmkeeper.NewQuerier(lsmKeeper)) | ||
|
||
// set default lsm params | ||
require.NoError(tb, lsmKeeper.SetParams(sdkCtx, lsmtypes.DefaultParams())) | ||
|
||
f := fixture{ | ||
app: integrationApp, | ||
sdkCtx: sdkCtx, | ||
cdc: cdc, | ||
keys: keys, | ||
accountKeeper: accountKeeper, | ||
bankKeeper: bankKeeper, | ||
distributionKeeper: distributionKeeper, | ||
stakingKeeper: stakingKeeper, | ||
lsmKeeper: lsmKeeper, | ||
} | ||
|
||
return &f | ||
} | ||
|
||
func delegateCoinsFromAccount(ctx sdk.Context, sk stakingkeeper.Keeper, addr sdk.AccAddress, amount math.Int, | ||
val stakingtypes.ValidatorI, | ||
) error { | ||
_, err := sk.Delegate(ctx, addr, amount, stakingtypes.Unbonded, val.(stakingtypes.Validator), true) | ||
|
||
return err | ||
} | ||
|
||
func applyValidatorSetUpdates(t *testing.T, ctx sdk.Context, k *stakingkeeper.Keeper, | ||
expectedUpdatesLen int, | ||
) []abci.ValidatorUpdate { | ||
t.Helper() | ||
updates, err := k.ApplyAndReturnValidatorSetUpdates(ctx) | ||
require.NoError(t, err) | ||
if expectedUpdatesLen >= 0 { | ||
require.Equal(t, expectedUpdatesLen, len(updates), "%v", updates) | ||
} | ||
return updates | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package keeper | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
sdkmath "cosmossdk.io/math" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
|
||
"github.com/cosmos/gaia/v22/x/lsm/types" | ||
) | ||
|
||
// Wrapper struct | ||
type Hooks struct { | ||
k Keeper | ||
} | ||
|
||
var _ stakingtypes.StakingHooks = Hooks{} | ||
|
||
// Create new lsm hooks | ||
func (k Keeper) Hooks() Hooks { | ||
return Hooks{k} | ||
} | ||
|
||
// initialize liquid validator record | ||
func (h Hooks) AfterValidatorCreated(ctx context.Context, valAddr sdk.ValAddress) error { | ||
val, err := h.k.stakingKeeper.Validator(ctx, valAddr) | ||
if err != nil { | ||
return err | ||
} | ||
lVal := types.NewLiquidValidator(val.GetOperator()) | ||
del, err := h.k.stakingKeeper.GetDelegation(ctx, sdk.AccAddress(val.GetOperator()), valAddr) | ||
if err != nil && !errors.Is(err, stakingtypes.ErrNoDelegation) { | ||
return err | ||
} else if err == nil { | ||
lVal.ValidatorBondShares = del.Shares | ||
} | ||
return h.k.SetLiquidValidator(ctx, lVal) | ||
} | ||
|
||
func (h Hooks) AfterValidatorRemoved(ctx context.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error { | ||
return h.k.RemoveLiquidValidator(ctx, valAddr) | ||
} | ||
|
||
func (h Hooks) BeforeDelegationCreated(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { | ||
return nil | ||
} | ||
|
||
func (h Hooks) BeforeDelegationSharesModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { | ||
return nil | ||
} | ||
|
||
func (h Hooks) AfterDelegationModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { | ||
if delAddr.Equals(sdk.AccAddress(valAddr)) { | ||
del, err := h.k.stakingKeeper.GetDelegation(ctx, sdk.AccAddress(valAddr), valAddr) | ||
if err != nil { | ||
return err | ||
} | ||
lVal, err := h.k.GetLiquidValidator(ctx, valAddr) | ||
if err != nil { | ||
return err | ||
} | ||
lVal.ValidatorBondShares = del.Shares | ||
return h.k.SetLiquidValidator(ctx, lVal) | ||
} | ||
return nil | ||
} | ||
|
||
func (h Hooks) BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, fraction sdkmath.LegacyDec) error { | ||
validator, err := h.k.stakingKeeper.Validator(ctx, valAddr) | ||
if err != nil { | ||
return err | ||
} | ||
liquidVal, err := h.k.GetLiquidValidator(ctx, valAddr) | ||
if err != nil { | ||
return err | ||
} | ||
initialLiquidTokens := validator.TokensFromShares(liquidVal.LiquidShares).TruncateInt() | ||
slashedLiquidTokens := fraction.Mul(sdkmath.LegacyNewDecFromInt(initialLiquidTokens)) | ||
|
||
decrease := slashedLiquidTokens.TruncateInt() | ||
if err := h.k.DecreaseTotalLiquidStakedTokens(ctx, decrease); err != nil { | ||
// This only error's if the total liquid staked tokens underflows | ||
// which would indicate there's a corrupted state where the validator has | ||
// liquid tokens that are not accounted for in the global total | ||
panic(err) | ||
} | ||
return nil | ||
} | ||
|
||
func (h Hooks) BeforeValidatorModified(_ context.Context, _ sdk.ValAddress) error { | ||
return nil | ||
} | ||
|
||
func (h Hooks) AfterValidatorBonded(_ context.Context, _ sdk.ConsAddress, _ sdk.ValAddress) error { | ||
return nil | ||
} | ||
|
||
func (h Hooks) AfterValidatorBeginUnbonding(_ context.Context, _ sdk.ConsAddress, _ sdk.ValAddress) error { | ||
return nil | ||
} | ||
|
||
func (h Hooks) BeforeDelegationRemoved(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { | ||
if delAddr.Equals(sdk.AccAddress(valAddr)) { | ||
lVal, err := h.k.GetLiquidValidator(ctx, valAddr) | ||
if err != nil { | ||
return err | ||
} | ||
lVal.ValidatorBondShares = sdkmath.LegacyZeroDec() | ||
return h.k.SetLiquidValidator(ctx, lVal) | ||
} | ||
return nil | ||
} | ||
|
||
func (h Hooks) AfterUnbondingInitiated(_ context.Context, _ uint64) error { | ||
return nil | ||
} |