129 lines
4.1 KiB
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
|
|
}
|