-
Notifications
You must be signed in to change notification settings - Fork 0
/
staking_helper.go
executable file
·143 lines (122 loc) · 4.46 KB
/
staking_helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package testutil
import (
"fmt"
"cosmossdk.io/math"
"github.com/axiome-pro/axm-node/x/distribution/keeper"
stakingtypes "github.com/axiome-pro/axm-node/x/staking/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func CreateValidator(pk cryptotypes.PubKey, stake math.Int) (stakingtypes.Validator, error) {
valConsAddr := sdk.GetConsAddress(pk)
val, err := stakingtypes.NewValidator(sdk.ValAddress(valConsAddr).String(), 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,
) (
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)
del := stakingtypes.NewDelegation(delegator.String(), 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
}