Skip to content

Commit

Permalink
nits
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Bowman committed Jul 10, 2023
1 parent 39400bb commit 9a0d03c
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 29 deletions.
2 changes: 1 addition & 1 deletion x/interchainstaking/types/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (vi ValidatorIntents) Normalize() ValidatorIntents {
func DetermineAllocationsForDelegation(currentAllocations map[string]sdkmath.Int, currentSum sdkmath.Int, targetAllocations ValidatorIntents, amount sdk.Coins) map[string]sdkmath.Int {
input := amount[0].Amount
deltas := CalculateDeltas(currentAllocations, currentSum, targetAllocations)
minValue := MinDeltas(deltas)
minValue := MinDelta(deltas)
sum := sdk.ZeroInt()

// raise all deltas such that the minimum value is zero.
Expand Down
64 changes: 38 additions & 26 deletions x/interchainstaking/types/rebalance.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package types

import (
fmt "fmt"
"math"
"sort"

Expand Down Expand Up @@ -57,12 +58,18 @@ func CalculateDeltas(currentAllocations map[string]sdkmath.Int, currentSum sdkma
return deltas
}

// CalculateDeltas determines, for the current delegations, in delta between actual allocations and the target intent.
// Positive delta represents current allocation is below target, and vice versa.
func CalculateDeltasNew(currentAllocations map[string]sdkmath.Int, locked map[string]bool, currentSum sdkmath.Int, targetAllocations ValidatorIntents) (targets, sources Deltas) {
targets = make(Deltas, 0)
sources = make(Deltas, 0)
// CalculateAllocationDeltas determines, for the current delegations, in delta between actual allocations and the target intent.
// Returns a slice of deltas for each of target allocations (underallocated) and source allocations (overallocated).
func CalculateAllocationDeltas(
currentAllocations map[string]sdkmath.Int,
locked map[string]bool,
currentSum sdkmath.Int,
targetAllocations ValidatorIntents,
) (targets, sources AllocationDeltas) {
targets = make(AllocationDeltas, 0)
sources = make(AllocationDeltas, 0)

// reduce ValidatorIntents to slice of Valoper addresses.
targetValopers := func(in ValidatorIntents) []string {
out := make([]string, 0, len(in))
for _, i := range in {
Expand All @@ -71,9 +78,11 @@ func CalculateDeltasNew(currentAllocations map[string]sdkmath.Int, locked map[st
return out
}(targetAllocations)

// create a slide of unique valopers across current and target allocations.
keySet := utils.Unique(append(targetValopers, utils.Keys(currentAllocations)...))
sort.Strings(keySet)
// for target allocations, raise the intent weight by the total delegated value to get target amount

// for target allocations, raise the intent weight by the total delegated value to get target amount.
for _, valoper := range keySet {
current, ok := currentAllocations[valoper]
if !ok {
Expand All @@ -85,42 +94,44 @@ func CalculateDeltasNew(currentAllocations map[string]sdkmath.Int, locked map[st
target = &ValidatorIntent{ValoperAddress: valoper, Weight: sdk.ZeroDec()}
}
targetAmount := target.Weight.MulInt(currentSum).TruncateInt()

// diff between target and current allocations
// positive == below target, negative == above target
// positive == below target (target), negative == above target (source)
delta := targetAmount.Sub(current)

if delta.IsPositive() {
targets = append(targets, &Delta{Amount: delta, ValoperAddress: valoper})
targets = append(targets, &AllocationDelta{Amount: delta, ValoperAddress: valoper})
} else {
if _, found := locked[valoper]; !found {
// only append to sources if the delegation is not locked - i.e. it doesn't have an incoming redelegation.
sources = append(sources, &Delta{Amount: delta.Abs(), ValoperAddress: valoper})
sources = append(sources, &AllocationDelta{Amount: delta.Abs(), ValoperAddress: valoper})
}
}
}

// sort for determinism.
targets.Sort()
sources.Sort()

return targets, sources
}

type Delta struct {
type AllocationDelta struct {
ValoperAddress string
Amount sdkmath.Int
}

type Deltas []*Delta
type AllocationDeltas []*AllocationDelta

func (d Deltas) Sort() {
func (d AllocationDeltas) Sort() {
// filter zeros
newDeltas := make(Deltas, 0)
newAllocationDeltas := make(AllocationDeltas, 0)
for _, delta := range d {
if !delta.Amount.IsZero() {
newDeltas = append(newDeltas, delta)
newAllocationDeltas = append(newAllocationDeltas, delta)
}
}
d = newDeltas
d = newAllocationDeltas

// sort keys by relative value of delta
sort.SliceStable(d, func(i, j int) bool {
Expand All @@ -142,6 +153,7 @@ type RebalanceTarget struct {

type RebalanceTargets []*RebalanceTarget

// Sort RebalanceTargets deterministically.
func (t RebalanceTargets) Sort() {
// sort keys by relative value of delta
sort.SliceStable(t, func(i, j int) bool {
Expand Down Expand Up @@ -172,7 +184,7 @@ func DetermineAllocationsForRebalancing(
logger log.Logger,
) RebalanceTargets {
out := make(RebalanceTargets, 0)
targets, sources := CalculateDeltasNew(currentAllocations, currentLocked, currentSum, targetAllocations)
targets, sources := CalculateAllocationDeltas(currentAllocations, currentLocked, currentSum, targetAllocations)

// rebalanceBudget = (total_delegations - locked)/2 == 50% of (total_delegations - locked)
// TODO: make this 2 (max_redelegation_factor) a param.
Expand Down Expand Up @@ -231,15 +243,15 @@ TARGET:
return out
}

// func (d Deltas) Render() (out string) {
// for _, delta := range d {
// out = out + fmt.Sprintf("%s:\t%d\n", delta.ValoperAddress, delta.Amount.Int64())
// }
// return
// }
func (d AllocationDeltas) String() (out string) {
for _, delta := range d {
out = fmt.Sprintf("%s%s:\t%d\n", out, delta.ValoperAddress, delta.Amount.Int64())
}
return out
}

// MinDeltas returns the lowest value in a slice of Deltas.
func MinDeltas(deltas ValidatorIntents) sdkmath.Int {
// MinDelta returns the lowest value in a slice of Deltas.
func MinDelta(deltas ValidatorIntents) sdkmath.Int {
minValue := sdk.NewInt(math.MaxInt64)
for _, intent := range deltas {
if minValue.GT(intent.Weight.TruncateInt()) {
Expand All @@ -250,8 +262,8 @@ func MinDeltas(deltas ValidatorIntents) sdkmath.Int {
return minValue
}

// MaxDeltas returns the greatest value in a slice of Deltas.
func MaxDeltas(deltas ValidatorIntents) sdkmath.Int {
// MaxDelta returns the greatest value in a slice of Deltas.
func MaxDelta(deltas ValidatorIntents) sdkmath.Int {
maxValue := sdk.NewInt(math.MinInt64)
for _, intent := range deltas {
if maxValue.LT(intent.Weight.TruncateInt()) {
Expand Down
2 changes: 1 addition & 1 deletion x/interchainstaking/types/rebalance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func GenerateValidatorsDeterministic(n int) (out []string) {
}

func TestDetermineAllocationsForRebalancing(t *testing.T) {
vals := GenerateDeterministicValidators(5)
vals := GenerateValidatorsDeterministic(5)

type testcase struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion x/interchainstaking/types/redemptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func DetermineAllocationsForUndelegation(currentAllocations map[string]math.Int,
return outWeights
}

maxValue := MaxDeltas(deltas)
maxValue := MaxDelta(deltas)
sum = sdk.ZeroInt()

// drop all deltas such that the maximum value is zero, and invert.
Expand Down

0 comments on commit 9a0d03c

Please sign in to comment.