cosmos-sdk/x/distribution/testutil/staking_helper.go

129 lines
4.1 KiB
Go

package testutil
import (
"fmt"
"cosmossdk.io/math"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
func CreateValidator(pk cryptotypes.PubKey, stake math.Int) (stakingtypes.Validator, error) {
valConsAddr := sdk.GetConsAddress(pk)
val, err := stakingtypes.NewValidator(sdk.ValAddress(valConsAddr), pk, stakingtypes.Description{})
val.Tokens = stake
val.DelegatorShares = math.LegacyNewDecFromInt(val.Tokens)
return val, err
}
func CallCreateValidatorHooks(ctx sdk.Context, k keeper.Keeper, addr sdk.AccAddress, valAddr sdk.ValAddress) error {
err := k.Hooks().AfterValidatorCreated(ctx, valAddr)
if err != nil {
return err
}
err = k.Hooks().BeforeDelegationCreated(ctx, addr, valAddr)
if err != nil {
return err
}
err = k.Hooks().AfterDelegationModified(ctx, addr, valAddr)
if err != nil {
return err
}
return nil
}
// SlashValidator copies what x/staking Slash does. It should be used for testing only.
// And it must be updated whenever the original function is updated.
// The passed validator will get its tokens updated.
func SlashValidator(
ctx sdk.Context,
consAddr sdk.ConsAddress,
infractionHeight int64,
power int64,
slashFactor sdk.Dec,
validator *stakingtypes.Validator,
distrKeeper *keeper.Keeper,
) math.Int {
if slashFactor.IsNegative() {
panic(fmt.Errorf("attempted to slash with a negative slash factor: %v", slashFactor))
}
// call the before-modification hook
err := distrKeeper.Hooks().BeforeValidatorModified(ctx, validator.GetOperator())
if err != nil {
panic(err)
}
// we simplify this part, as we won't be able to test redelegations or
// unbonding delegations
if infractionHeight != ctx.BlockHeight() {
// if a new test lands here we might need to update this function to handle redelegations and unbonding
// or just make it an integration test.
panic("we can't test any other case here")
}
slashAmountDec := sdk.NewDecFromInt(validator.Tokens).Mul(sdk.NewDecWithPrec(5, 1))
slashAmount := slashAmountDec.TruncateInt()
// cannot decrease balance below zero
tokensToBurn := sdk.MinInt(slashAmount, validator.Tokens)
tokensToBurn = sdk.MaxInt(tokensToBurn, math.ZeroInt()) // defensive.
// we need to calculate the *effective* slash fraction for distribution
if validator.Tokens.IsPositive() {
effectiveFraction := sdk.NewDecFromInt(tokensToBurn).QuoRoundUp(sdk.NewDecFromInt(validator.Tokens))
// possible if power has changed
if effectiveFraction.GT(math.LegacyOneDec()) {
effectiveFraction = math.LegacyOneDec()
}
// call the before-slashed hook
distrKeeper.Hooks().BeforeValidatorSlashed(ctx, validator.GetOperator(), effectiveFraction)
}
// Deduct from validator's bonded tokens and update the validator.
// Burn the slashed tokens from the pool account and decrease the total supply.
validator.Tokens = validator.Tokens.Sub(tokensToBurn)
return tokensToBurn
}
// Delegate imitate what x/staking Delegate does. It should be used for testing only.
// If a delegation is passed we are simulating an update to a previous delegation,
// if it's nil then we simulate a new delegation.
func Delegate(
ctx sdk.Context,
distrKeeper keeper.Keeper,
delegator sdk.AccAddress,
validator *stakingtypes.Validator,
amount math.Int,
delegation *stakingtypes.Delegation,
) (
newShares sdk.Dec,
updatedDel stakingtypes.Delegation,
err error,
) {
if delegation != nil {
err = distrKeeper.Hooks().BeforeDelegationSharesModified(ctx, delegator, validator.GetOperator())
} else {
err = distrKeeper.Hooks().BeforeDelegationCreated(ctx, delegator, validator.GetOperator())
del := stakingtypes.NewDelegation(delegator, validator.GetOperator(), math.LegacyZeroDec())
delegation = &del
}
if err != nil {
return math.LegacyZeroDec(), stakingtypes.Delegation{}, err
}
// Add tokens from delegation to validator
updateVal, newShares := validator.AddTokensFromDel(amount)
*validator = updateVal
delegation.Shares = delegation.Shares.Add(newShares)
return newShares, *delegation, nil
}