cosmos-sdk/x/distribution/testutil/staking_helper.go
Julián Toledano 65925410c8
refactor(x/distribution)!: remove Accounts.String() (#19868)
Co-authored-by: son trinh <trinhleson2000@gmail.com>
2024-03-27 00:55:13 +00:00

152 lines
4.6 KiB
Go

package testutil
import (
"fmt"
"cosmossdk.io/core/address"
"cosmossdk.io/math"
"cosmossdk.io/x/distribution/keeper"
stakingtypes "cosmossdk.io/x/staking/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func CreateValidator(pk cryptotypes.PubKey, operator string, stake math.Int) (stakingtypes.Validator, error) {
val, err := stakingtypes.NewValidator(operator, pk, stakingtypes.Description{Moniker: "TestValidator"})
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 math.LegacyDec,
validator *stakingtypes.Validator,
distrKeeper *keeper.Keeper,
sk *MockStakingKeeper,
) math.Int {
if slashFactor.IsNegative() {
panic(fmt.Errorf("attempted to slash with a negative slash factor: %v", slashFactor))
}
valBz, err := sk.ValidatorAddressCodec().StringToBytes(validator.GetOperator())
if err != nil {
panic(err)
}
// call the before-modification hook
err = distrKeeper.Hooks().BeforeValidatorModified(ctx, valBz)
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 := math.LegacyNewDecFromInt(validator.Tokens).Mul(math.LegacyNewDecWithPrec(5, 1))
slashAmount := slashAmountDec.TruncateInt()
// cannot decrease balance below zero
tokensToBurn := math.MinInt(slashAmount, validator.Tokens)
tokensToBurn = math.MaxInt(tokensToBurn, math.ZeroInt()) // defensive.
// we need to calculate the *effective* slash fraction for distribution
if validator.Tokens.IsPositive() {
effectiveFraction := math.LegacyNewDecFromInt(tokensToBurn).QuoRoundUp(math.LegacyNewDecFromInt(validator.Tokens))
// possible if power has changed
if effectiveFraction.GT(math.LegacyOneDec()) {
effectiveFraction = math.LegacyOneDec()
}
// call the before-slashed hook
err := distrKeeper.Hooks().BeforeValidatorSlashed(ctx, valBz, effectiveFraction)
if err != nil {
panic(err)
}
}
// 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,
sk *MockStakingKeeper,
addressCodec address.Codec,
) (
newShares math.LegacyDec,
updatedDel stakingtypes.Delegation,
err error,
) {
valBz, err := sk.ValidatorAddressCodec().StringToBytes(validator.GetOperator())
if err != nil {
return math.LegacyZeroDec(), stakingtypes.Delegation{}, err
}
if delegation != nil {
err = distrKeeper.Hooks().BeforeDelegationSharesModified(ctx, delegator, valBz)
} else {
err = distrKeeper.Hooks().BeforeDelegationCreated(ctx, delegator, valBz)
if err != nil {
return math.LegacyZeroDec(), stakingtypes.Delegation{}, err
}
delAddr, err := addressCodec.BytesToString(delegator)
if err != nil {
return math.LegacyZeroDec(), stakingtypes.Delegation{}, err
}
del := stakingtypes.NewDelegation(delAddr, 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
}