-
Notifications
You must be signed in to change notification settings - Fork 201
/
validator_selection.go
107 lines (94 loc) · 3.71 KB
/
validator_selection.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
package keeper
import (
"fmt"
"sort"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cast"
"github.com/Stride-Labs/stride/x/stakeibc/types"
)
func (k Keeper) GetValidatorDelegationAmtDifferences(ctx sdk.Context, hostZone types.HostZone) (map[string]int64, error) {
/*
This function returns a map from Validator Address to how many extra tokens
need to be given to that validator
positive implies extra tokens need to be given,
negative impleis tokens need to be taken away
*/
validators := hostZone.GetValidators()
delegationDelta := make(map[string]int64)
totalDelegatedAmt := k.GetTotalValidatorDelegations(hostZone)
targetDelegation, err := k.GetTargetValAmtsForHostZone(ctx, hostZone, totalDelegatedAmt)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error getting target weights for host zone %s", hostZone.ChainId))
return nil, err
}
for _, validator := range validators {
targetDelForVal, err := cast.ToInt64E(targetDelegation[validator.GetAddress()])
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error getting target weights for host zone %s", hostZone.ChainId))
return nil, err
}
delAmt, err := cast.ToInt64E(validator.DelegationAmt)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error getting target weights for host zone %s", hostZone.ChainId))
return nil, err
}
delegationDelta[validator.GetAddress()] = targetDelForVal - delAmt
}
return delegationDelta, nil
}
func (k Keeper) GetTargetValAmtsForHostZone(ctx sdk.Context, hostZone types.HostZone, finalDelegation uint64) (map[string]uint64, error) {
// This will get the target validator delegation for the given hostZone
// such that the total validator delegation is equal to the finalDelegation
// output key is ADDRESS not NAME
totalWeight := k.GetTotalValidatorWeight(hostZone)
if totalWeight == 0 {
k.Logger(ctx).Error(fmt.Sprintf("No non-zero validators found for host zone %s", hostZone.ChainId))
return nil, types.ErrNoValidatorWeights
}
if finalDelegation == 0 {
k.Logger(ctx).Error(fmt.Sprintf("Cannot calculate target delegation if final amount is 0 %s", hostZone.ChainId))
return nil, types.ErrNoValidatorWeights
}
targetAmount := make(map[string]uint64)
allocatedAmt := uint64(0)
// sort validators by weight ascending, this is inplace sorting!
validators := hostZone.GetValidators()
for i, j := 0, len(validators)-1; i < j; i, j = i+1, j-1 {
validators[i], validators[j] = validators[j], validators[i]
}
// Do not use `Slice` here, it is stochastic
sort.SliceStable(validators, func(i, j int) bool {
return validators[i].Weight < validators[j].Weight
})
for i, validator := range hostZone.Validators {
if i == len(hostZone.Validators)-1 {
// for the last element, we need to make sure that the allocatedAmt is equal to the finalDelegation
targetAmount[validator.GetAddress()] = finalDelegation - allocatedAmt
} else {
delegateAmt, err := cast.ToUint64E(float64(validator.Weight*finalDelegation) / float64(totalWeight))
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error getting target weights for host zone %s", hostZone.ChainId))
return nil, err
}
allocatedAmt += delegateAmt
targetAmount[validator.GetAddress()] = delegateAmt
}
}
return targetAmount, nil
}
func (k Keeper) GetTotalValidatorDelegations(hostZone types.HostZone) uint64 {
validators := hostZone.GetValidators()
total_delegation := uint64(0)
for _, validator := range validators {
total_delegation += validator.DelegationAmt
}
return total_delegation
}
func (k Keeper) GetTotalValidatorWeight(hostZone types.HostZone) uint64 {
validators := hostZone.GetValidators()
total_weight := uint64(0)
for _, validator := range validators {
total_weight += validator.Weight
}
return total_weight
}