Skip to content

Commit

Permalink
Merge pull request #1939 from lavanet/fix-reputation-rank-query
Browse files Browse the repository at this point in the history
fix: reputation rank from query
  • Loading branch information
Yaroms authored Feb 5, 2025
2 parents 0c170e7 + 1125698 commit e1540ac
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 12 deletions.
2 changes: 1 addition & 1 deletion protocol/chaintracker/chain_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ func (ct *ChainTracker) updatePollingTimeBasedOnBlockGap(pollingTime time.Durati
if blockGapsLen > PollingUpdateLength { // check we have enough samples
// smaller times give more resolution to indentify changes, and also make block arrival predictions more optimistic
// so we take a 0.33 percentile because we want to be on the safe side by have a smaller time than expected
percentileTime := lavaslices.Percentile(ct.blockEventsGap, 0.33)
percentileTime := lavaslices.Percentile(ct.blockEventsGap, 0.33, false)
stability := lavaslices.Stability(ct.blockEventsGap, percentileTime)
utils.LavaFormatTrace("block gaps",
utils.LogAttr("block gaps", ct.blockEventsGap),
Expand Down
2 changes: 1 addition & 1 deletion protocol/provideroptimizer/selection_tier.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func (st *SelectionTierInst) ShiftTierChance(numTiers int, initialTierChances ma
}
medianScore := lavaslices.Median(scores)
medianScoreReversed := 1 / (medianScore + 0.0001)
percentile25Score := lavaslices.Percentile(scores, 0.25)
percentile25Score := lavaslices.Percentile(scores, 0.25, false)
percentile25ScoreReversed := 1 / (percentile25Score + 0.0001)

averageChance := 1 / float64(numTiers)
Expand Down
52 changes: 52 additions & 0 deletions scripts/automation_scripts/get_reputation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash

# Check if chain ID argument is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <chain_id>"
exit 1
fi

CHAIN_ID=$1

# Get all provider addresses and their monikers
providers_output=$(lavad q pairing providers $CHAIN_ID)
if ! echo "$providers_output" | grep -q "address:"; then
echo "$CHAIN_ID has no providers!"
exit 0
fi

# Initialize an array for providers with no reputation
declare -a no_reputation=()

echo "$CHAIN_ID reputation:"
echo "Active providers:"

# Process each provider
while IFS= read -r line; do
if [[ $line =~ address:\ *(lava@[a-z0-9]*) ]]; then
addr="${BASH_REMATCH[1]}"
# Get the moniker from the previous line
moniker=$(echo "$providers_output" | grep -B 1 "$addr" | grep "moniker:" | awk '{print $2}')

# Get reputation details
reputation=$(lavad q pairing provider-reputation-details $addr $CHAIN_ID "*")
score=$(echo "$reputation" | grep -A1 "reputation_pairing_score:" | tail -n 1 | awk '{print $2}' | tr -d '"')

# Get rank and performance
provider_info=$(lavad q pairing provider-reputation $addr $CHAIN_ID "*")
rank=$(echo "$provider_info" | grep "rank:" | awk '{print $2}' | tr -d '"')
performance=$(echo "$provider_info" | grep "overall_performance:" | cut -d ':' -f 2 | sed 's/^ *//')

if [ ! -z "$score" ]; then
printf "%s (%s): %s [Rank: %s, Performance: %s]\n" "$addr" "$moniker" "$score" "$rank" "$performance"
else
no_reputation+=("$addr ($moniker)")
fi
fi
done <<< "$providers_output"

# Print providers with no reputation if any exist
if [ ${#no_reputation[@]} -ne 0 ]; then
echo -e "\nNo reputation:"
printf '%s\n' "${no_reputation[@]}"
fi
11 changes: 9 additions & 2 deletions utils/lavaslices/slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,19 @@ func Median[T Number](slice []T) T {
}
}

func Percentile[T Number](slice []T, rank float64) T {
// Percentile returns the value at the given rank in the slice.
// If reverse is true, the slice is sorted in descending order.
// If reverse is false, the slice is sorted in ascending order.
func Percentile[T Number](slice []T, rank float64, reverse bool) T {
data_len := len(slice)
if data_len == 0 || rank < 0.0 || rank > 1.0 {
return 0
}
slices.Sort(slice)
if reverse {
slices.SortFunc(slice, func(i, j T) bool { return i > j })
} else {
slices.Sort(slice)
}

// Calculate the position based on the rank
position := int(float64(data_len-1) * rank)
Expand Down
4 changes: 2 additions & 2 deletions utils/lavaslices/slices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ func TestPercentile(t *testing.T) {
{"even length identical", []int{4, 4, 4, 4}, 4},
} {
t.Run(tt.name, func(t *testing.T) {
percentile := Percentile(tt.slice, 0.5)
percentile := Percentile(tt.slice, 0.5, false)
median := Median(tt.slice)
require.Equal(t, tt.median, median)
require.Equal(t, tt.median, percentile)
Expand All @@ -245,7 +245,7 @@ func TestPercentile(t *testing.T) {
{"rank even length identical", []time.Duration{4 * time.Millisecond, 4 * time.Millisecond, 4 * time.Millisecond, 4 * time.Millisecond}, 4 * time.Millisecond, 0.33},
} {
t.Run(tt2.name, func(t *testing.T) {
percentile := Percentile(tt2.slice, tt2.rank)
percentile := Percentile(tt2.slice, tt2.rank, false)
require.Equal(t, tt2.percentile, percentile)
})
}
Expand Down
17 changes: 11 additions & 6 deletions x/pairing/keeper/grpc_query_provider_reputation.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,16 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid
}
pairingScores = append(pairingScores, score.Score.MustFloat64())
}
// Sort in descending order (highest scores first)
sort.Slice(pairingScores, func(i, j int) bool {
return pairingScores[i] < pairingScores[j]
return pairingScores[i] > pairingScores[j]
})

// find the provider's rank
rank := len(pairingScores)
// find the provider's rank (1 is best)
rank := 1
for i, score := range pairingScores {
if data.score.MustFloat64() <= score {
rank -= i
if data.score.MustFloat64() >= score {
rank = i + 1
break
}
}
Expand All @@ -94,11 +95,15 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid
mean := lavaslices.Average(pairingScores)
variance := lavaslices.Variance(pairingScores, mean)

// Calculate the 80th percentile threshold
percentileThreshold := lavaslices.Percentile(pairingScores, percentileRank, true)

// create the reputation data and append
chainClusterRes.Rank = uint64(rank)
chainClusterRes.Providers = uint64(len(pairingScores))

if pairingScores[len(pairingScores)-rank] > lavaslices.Percentile(pairingScores, percentileRank) {
// Compare the provider's score against the threshold
if data.score.MustFloat64() >= percentileThreshold {
chainClusterRes.OverallPerformance = goodScore
if variance < varianceThreshold {
chainClusterRes.OverallPerformance += " (" + lowVariance + ")"
Expand Down

0 comments on commit e1540ac

Please sign in to comment.