From 54a01366608e7276c467834d2fb9d3e164cf6c75 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 5 Aug 2024 16:55:18 +0300 Subject: [PATCH 01/33] CNS-1004: implement qos excellence score aggregation from relay payments --- proto/lavanet/lava/pairing/relay.proto | 7 ++++ utils/convert.go | 10 ++++++ x/pairing/keeper/msg_server_relay_payment.go | 30 ++++++++++++++++ x/pairing/keeper/reputation.go | 26 ++++++++++++++ x/pairing/types/QualityOfServiceReport.go | 26 ++++++++++++++ x/pairing/types/qos_score.go | 38 ++++++++++++++++++++ x/pairing/types/reputation.go | 7 ++++ 7 files changed, 144 insertions(+) create mode 100644 utils/convert.go diff --git a/proto/lavanet/lava/pairing/relay.proto b/proto/lavanet/lava/pairing/relay.proto index 33cae38d02..3ab345ab04 100644 --- a/proto/lavanet/lava/pairing/relay.proto +++ b/proto/lavanet/lava/pairing/relay.proto @@ -94,16 +94,23 @@ message RelayReply { } message QualityOfServiceReport{ + // Latency of provider answers in milliseconds, range 0-inf, lower is better string latency = 1 [ (gogoproto.moretags) = "yaml:\"Latency\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; + + // Percentage of times the provider returned a non-error response, range 0-1, higher is better string availability = 2 [ (gogoproto.moretags) = "yaml:\"availability\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; + + // Amount of time the provider is not synced (have the latest block) in milliseconds, range 0-inf, lower is better. + // Example: in ETH we have 15sec block time. So sync = 15000 means that the provider is one block + // behind the actual latest block. string sync = 3 [ (gogoproto.moretags) = "yaml:\"sync\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", diff --git a/utils/convert.go b/utils/convert.go new file mode 100644 index 0000000000..6fdd89ead4 --- /dev/null +++ b/utils/convert.go @@ -0,0 +1,10 @@ +package utils + +import "math" + +func SafeUint64ToInt64Convert(val uint64) int64 { + if val > math.MaxInt64 { + val = math.MaxInt64 + } + return int64(val) +} diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 9933b18a46..559429c79d 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -172,6 +172,36 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen k.handleBadgeCu(ctx, badgeData, relay.Provider, relay.CuSum, newBadgeTimerExpiry) } + // update the reputation's epoch QoS score + // the excellece QoS report can be nil when the provider and consumer geolocations are not equal + if relay.QosExcellenceReport != nil { + sub, found := k.subscriptionKeeper.GetSubscription(ctx, project.Subscription) + if !found { + return nil, utils.LavaFormatError("RelayPayment: could not get cluster for reputation score update", fmt.Errorf("relay consumer's subscription not found"), + utils.LogAttr("consumer", clientAddr), + utils.LogAttr("project", project.Index), + utils.LogAttr("subscription", project.Subscription), + utils.LogAttr("chain", relay.SpecId), + utils.LogAttr("provider", relay.Provider), + ) + } + + syncFactor := k.ReputationLatencyOverSyncFactor(ctx) + score, err := relay.QosExcellenceReport.ComputeQosExcellenceForReputation(syncFactor) + if err != nil { + return nil, utils.LavaFormatWarning("RelayPayment: could not compute qos excellence score", err, + utils.LogAttr("consumer", clientAddr), + utils.LogAttr("chain", relay.SpecId), + utils.LogAttr("provider", relay.Provider), + utils.LogAttr("qos_excellence_report", relay.QosExcellenceReport.String()), + utils.LogAttr("sync_factor", syncFactor.String()), + ) + } + + // note the current weight used is by relay num. In the future, it might change + k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum)) + } + // TODO: add support for spec changes spec, found := k.specKeeper.GetSpec(ctx, relay.SpecId) if !found || !spec.Enabled { diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 5b46bc4fe8..c57c7dabf0 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -4,6 +4,7 @@ import ( "fmt" "cosmossdk.io/collections" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/v2/utils" "github.com/lavanet/lava/v2/x/pairing/types" @@ -107,6 +108,31 @@ func (k Keeper) GetAllReputation(ctx sdk.Context) []types.ReputationGenesis { return entries } +// UpdateReputationEpochQosScore updates the epoch QoS score of the provider's reputation using the score from the relay +// payment's QoS excellence report +func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, cluster string, provider string, score math.LegacyDec, weight int64) { + // get current reputation and get parameters for the epoch score update + r, found := k.GetReputation(ctx, chainID, cluster, provider) + truncate := false + if found { + stabilizationPeriod := k.ReputationVarianceStabilizationPeriod(ctx) + if r.ShouldTruncate(stabilizationPeriod, ctx.BlockTime().UTC().Unix()) { + truncate = true + } + } else { + // new reputation score is not truncated and its decay factor is equal to 1 + r = types.NewReputation(ctx) + } + + // calculate the updated QoS epoch score + updatedEpochScore := r.EpochScore.Update(score, truncate, weight) + + // update the reputation and set + r.EpochScore = updatedEpochScore + r.TimeLastUpdated = ctx.BlockTime().UTC().Unix() + k.SetReputation(ctx, chainID, cluster, provider, r) +} + // GetReputationScore returns the current reputation pairing score func (k Keeper) GetReputationScore(ctx sdk.Context, chainID string, cluster string, provider string) (val types.ReputationPairingScore, found bool) { block := uint64(ctx.BlockHeight()) diff --git a/x/pairing/types/QualityOfServiceReport.go b/x/pairing/types/QualityOfServiceReport.go index d5bb0b4836..e06b1d7550 100644 --- a/x/pairing/types/QualityOfServiceReport.go +++ b/x/pairing/types/QualityOfServiceReport.go @@ -3,7 +3,9 @@ package types import ( "fmt" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/v2/utils" ) func (qos *QualityOfServiceReport) ComputeQoS() (sdk.Dec, error) { @@ -24,3 +26,27 @@ func (qos *QualityOfServiceReport) ComputeQoSExcellence() (sdk.Dec, error) { } return qos.Availability.Quo(qos.Sync).Quo(qos.Latency).ApproxRoot(3) } + +// ComputeQosExcellenceForReputation computes the score from the QoS excellence report to update the provider's reputation +// report score = latency + sync*syncFactor + ((1/availability) - 1) * FailureCost (note: larger value is worse) +func (qos QualityOfServiceReport) ComputeQosExcellenceForReputation(syncFactor math.LegacyDec) (math.LegacyDec, error) { + if qos.Availability.LT(sdk.ZeroDec()) || + qos.Latency.LT(sdk.ZeroDec()) || + qos.Sync.LT(sdk.ZeroDec()) || syncFactor.LT(sdk.ZeroDec()) { + return sdk.ZeroDec(), utils.LavaFormatWarning("ComputeQosExcellenceForReputation: compute failed", fmt.Errorf("QoS excellence scores is below 0"), + utils.LogAttr("availability", qos.Availability.String()), + utils.LogAttr("sync", qos.Sync.String()), + utils.LogAttr("latency", qos.Latency.String()), + ) + } + + latency := qos.Latency + sync := qos.Sync.Mul(syncFactor) + availability := math.LegacyNewDec(FailureCost) + if !qos.Availability.IsZero() { + availability = availability.Mul((math.LegacyOneDec().Quo(qos.Availability)).Sub(math.LegacyOneDec())) + } else { + availability = math.LegacyMaxSortableDec.QuoInt64(2) // on qs.Availability = 0 we take the largest score possible + } + return latency.Add(sync).Add(availability), nil +} diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index a9b5fc9bc9..e6d2a83225 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -8,6 +8,9 @@ import ( ) var ( + FailureCost int64 = 3000 // failed relay cost for QoS excellence report computation in milliseconds + TruncateStdMargin int64 = 3 // number of standard deviations that determine the truncation limit + // default QoS score is: score = 1.25, var = 0 DefaultQosScore = QosScore{ Score: Frac{Num: math.LegacyNewDec(5), Denom: math.LegacyNewDec(4)}, @@ -41,3 +44,38 @@ func NewQosScore(score Frac, variance Frac) QosScore { func (qs QosScore) Equal(other QosScore) bool { return qs.Score.Equal(other.Score) && qs.Variance.Equal(other.Variance) } + +// Update updates a QosScore with a new score from the QoS excellence report. The new score is truncated by the +// current variance. Then, it's updated using the weight (which is currently the relay num) +func (qs QosScore) Update(score math.LegacyDec, truncate bool, weight int64) QosScore { + if truncate { + score = qs.truncate(score) + } + + // updated_score_num = qos_score_num + score * weight + // updated_score_denom = qos_score_denom + weight + qs.Score.Num = qs.Score.Num.Add(score.MulInt64(weight)) + qs.Score.Denom = qs.Score.Denom.Add(math.LegacyNewDec(weight)) + + // updated_variance_num = qos_variance_num + (qos_score_num - score)^2 * weight + // updated_score_denom = qos_score_denom + weight + qs.Variance.Num = qs.Variance.Num.Add((qs.Score.Num.Sub(score)).Power(2).MulInt64(weight)) + qs.Variance.Denom = qs.Variance.Denom.Add(math.LegacyNewDec(weight)) + + return qs +} + +// Truncate truncates the QoS excellece report score by the current QoS score variance +func (qs QosScore) truncate(score math.LegacyDec) math.LegacyDec { + std, err := qs.Variance.Num.ApproxSqrt() + if err != nil { + utils.LavaFormatError("QosScore truncate: truncate failed, could not calculate qos variance sqrt", err, + utils.LogAttr("qos_score_variance", qs.Variance.String()), + ) + return score + } + + // truncated score = max(min(score, qos_score_num + 3*std), qos_score_num - 3*std) + return math.LegacyMaxDec(math.LegacyMinDec(score, qs.Score.Num.Add(std.MulInt64(TruncateStdMargin))), + qs.Score.Num.Sub(std.MulInt64(TruncateStdMargin))) +} diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 9d34cd91cc..cd4baf299f 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -54,6 +54,13 @@ func (r Reputation) Equal(other Reputation) bool { r.TimeLastUpdated == other.TimeLastUpdated && r.CreationTime == other.CreationTime } +// ShouldTruncate checks if the ReputationVarianceStabilizationPeriod has passed since +// the reputation's creation. If so, QoS score reports should be truncated before they're added to the +// reputation's epoch QoS score. +func (r Reputation) ShouldTruncate(stabilizationPeriod int64, currentTime int64) bool { + return r.CreationTime+stabilizationPeriod < currentTime +} + // ReputationScoreKey returns a key for the reputations fixation store (reputationsFS) func ReputationScoreKey(chainID string, cluster string, provider string) string { return chainID + " " + cluster + " " + provider From e3f018300048f5e40077fff543f71397c3fd5488 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 5 Aug 2024 16:55:26 +0300 Subject: [PATCH 02/33] CNS-1004: unit tests --- testutil/common/tester.go | 9 + .../keeper/msg_server_relay_payment_test.go | 190 ++++++++++++++++++ .../types/QualityOfServiceReport_test.go | 86 ++++++-- x/pairing/types/reputation_test.go | 39 ++++ 4 files changed, 307 insertions(+), 17 deletions(-) create mode 100644 x/pairing/types/reputation_test.go diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 941958f62c..3e7bad4d67 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -1053,6 +1053,15 @@ func (ts *Tester) GetNextMonth(from time.Time) int64 { return utils.NextMonth(from).UTC().Unix() } +func (ts *Tester) BlockTimeDefault() time.Duration { + return ts.Keepers.Downtime.GetParams(ts.Ctx).DowntimeDuration +} + +func (ts *Tester) EpochTimeDefault() time.Duration { + epochBlocks := ts.Keepers.Epochstorage.GetParams(ts.Ctx).EpochBlocks + return ts.BlockTimeDefault() * time.Duration(epochBlocks) +} + func (ts *Tester) AdvanceToBlock(block uint64) { if block < ts.BlockHeight() { panic("AdvanceToBlock: block in the past: " + diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 15c1076728..3b23f1f193 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1067,3 +1067,193 @@ func TestPairingCaching(t *testing.T) { require.Equal(t, totalCU*3, sub.Sub.MonthCuTotal-sub.Sub.MonthCuLeft) } } + +// TestUpdateReputationEpochQosScore tests the update of the reputation's epoch qos score +// Scenarios: +// 1. provider1 sends relay -> its reputation is updated (epoch score and time last updated), +// also, provider2 reputation is not updated +func TestUpdateReputationEpochQosScore(t *testing.T) { + ts := newTester(t) + ts.setupForPayments(2, 1, 0) // 2 providers, 1 client, default providers-to-pair + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + _, provider1 := ts.GetAccount(common.PROVIDER, 0) + _, provider2 := ts.GetAccount(common.PROVIDER, 1) + qos := &types.QualityOfServiceReport{ + Latency: sdk.ZeroDec(), + Availability: sdk.OneDec(), + Sync: sdk.ZeroDec(), + } + + res, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := res.Sub.Cluster + + // set default reputations for both providers. Advance epoch to change the current block time + ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider1, types.NewReputation(ts.Ctx)) + ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider2, types.NewReputation(ts.Ctx)) + ts.AdvanceEpoch() + + // send relay payment msg from provider1 + relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), 1) + relaySession.QosExcellenceReport = qos + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: provider1, + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + + // get both providers reputation: provider1 should have its epoch score and time last updated changed, + // provider2 should have nothing change from the default + r1, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) + require.True(t, found) + r2, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider2) + require.True(t, found) + + require.Greater(t, r1.TimeLastUpdated, r2.TimeLastUpdated) + epochScore1, err := r1.EpochScore.Score.Resolve() + require.NoError(t, err) + epochScore2, err := r2.EpochScore.Score.Resolve() + require.NoError(t, err) + variance1, err := r1.EpochScore.Variance.Resolve() + require.NoError(t, err) + variance2, err := r2.EpochScore.Variance.Resolve() + require.NoError(t, err) + require.True(t, epochScore1.LT(epochScore2)) // score is lower because QoS is excellent + require.True(t, variance1.GT(variance2)) // variance is higher because the QoS is significantly differnet from DefaultQos +} + +// TestUpdateReputationEpochQosScoreTruncation tests the following scenarios: +// 1. stabilization period has not passed -> no truncation +// 2. stabilization period passed -> with truncation (score update is smaller than the first one) +// note, this test works since we use a bad QoS report (compared to default) so we know that the score should +// increase (which is considered worse) +func TestUpdateReputationEpochQosScoreTruncation(t *testing.T) { + // these will be used to compare the score change with/without truncation + scoreUpdates := []sdk.Dec{} + + // we set the stabilization period to 2 epochs time. Advancing one epoch means we won't truncate, + // advancing 3 means we will truncate. + epochsToAdvance := []uint64{1, 3} + + for i := range epochsToAdvance { + ts := newTester(t) + ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + _, provider1 := ts.GetAccount(common.PROVIDER, 0) + qos := &types.QualityOfServiceReport{ + Latency: sdk.NewDec(1000), + Availability: sdk.OneDec(), + Sync: sdk.NewDec(1000), + } + + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + // set stabilization period to be 2*epoch time + resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) + require.NoError(t, err) + resQParams.Params.ReputationVarianceStabilizationPeriod = int64(ts.EpochTimeDefault().Seconds()) + ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) + + // set default reputation + ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider1, types.NewReputation(ts.Ctx)) + + // advance epochs + ts.AdvanceEpochs(epochsToAdvance[i]) + + // send relay payment msg from provider1 + relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), 1) + relaySession.QosExcellenceReport = qos + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: provider1, + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + + // get update of epoch score + r, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) + require.True(t, found) + epochScoreNoTruncation, err := r.EpochScore.Score.Resolve() + require.NoError(t, err) + defaultEpochScore, err := types.DefaultQosScore.Score.Resolve() + require.NoError(t, err) + scoreUpdates = append(scoreUpdates, epochScoreNoTruncation.Sub(defaultEpochScore)) + } + + // require that the score update that was not truncated is larger than the one that was truncated + require.True(t, scoreUpdates[0].GT(scoreUpdates[1])) +} + +// TestUpdateReputationEpochQosScoreTruncation tests the following scenario: +// 1. relay num is the reputation update weight. More relays = bigger update +func TestUpdateReputationEpochQosScoreRelayNumWeight(t *testing.T) { + // these will be used to compare the score change with high/low relay numbers + scoreUpdates := []sdk.Dec{} + + // we set the stabilization period to 2 epochs time. Advancing one epoch means we won't truncate, + // advancing 3 means we will truncate. + relayNums := []uint64{100, 1} + + for i := range relayNums { + ts := newTester(t) + ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + _, provider1 := ts.GetAccount(common.PROVIDER, 0) + qos := &types.QualityOfServiceReport{ + Latency: sdk.NewDec(1000), + Availability: sdk.OneDec(), + Sync: sdk.NewDec(1000), + } + + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + // set stabilization period to be 2*epoch time to avoid truncation + resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) + require.NoError(t, err) + resQParams.Params.ReputationVarianceStabilizationPeriod = int64(ts.EpochTimeDefault().Seconds()) + ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) + + // set default reputation + ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider1, types.NewReputation(ts.Ctx)) + ts.AdvanceEpoch() + + // send relay payment msg from provider1 + relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), relayNums[i]) + relaySession.QosExcellenceReport = qos + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: provider1, + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + + // get update of epoch score + r, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) + require.True(t, found) + epochScoreNoTruncation, err := r.EpochScore.Score.Resolve() + require.NoError(t, err) + defaultEpochScore, err := types.DefaultQosScore.Score.Resolve() + require.NoError(t, err) + scoreUpdates = append(scoreUpdates, epochScoreNoTruncation.Sub(defaultEpochScore)) + } + + // require that the score update that was with 1000 relay num is larger than the one with one relay num + require.True(t, scoreUpdates[0].GT(scoreUpdates[1])) +} diff --git a/x/pairing/types/QualityOfServiceReport_test.go b/x/pairing/types/QualityOfServiceReport_test.go index 83a15ce6d6..9ed38e134d 100644 --- a/x/pairing/types/QualityOfServiceReport_test.go +++ b/x/pairing/types/QualityOfServiceReport_test.go @@ -3,11 +3,12 @@ package types import ( "testing" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) -func TestQosReport(t *testing.T) { +func createTestQosReportScores(forReputation bool) ([]math.LegacyDec, error) { qos1 := &QualityOfServiceReport{ Latency: sdk.MustNewDecFromStr("1.5"), Availability: sdk.MustNewDecFromStr("1"), @@ -29,20 +30,71 @@ func TestQosReport(t *testing.T) { Sync: sdk.MustNewDecFromStr("0.5"), } - qos1Res, errQos1 := qos1.ComputeQoSExcellence() - qos2Res, errQos2 := qos2.ComputeQoSExcellence() - qos3Res, errQos3 := qos3.ComputeQoSExcellence() - qos4Res, errQos4 := qos4.ComputeQoSExcellence() - require.NoError(t, errQos1) - require.NoError(t, errQos2) - require.NoError(t, errQos3) - require.NoError(t, errQos4) - require.True(t, qos1Res.LT(qos2Res)) - require.True(t, qos1Res.LT(qos3Res)) - require.True(t, qos1Res.LT(qos4Res)) - - require.True(t, qos2Res.GT(qos3Res)) - require.True(t, qos2Res.GT(qos4Res)) - - require.True(t, qos4Res.LT(qos3Res)) + res := []math.LegacyDec{} + if forReputation { + syncFactor := sdk.MustNewDecFromStr("0.5") + qos1Res, errQos1 := qos1.ComputeQosExcellenceForReputation(syncFactor) + if errQos1 != nil { + return nil, errQos1 + } + qos2Res, errQos2 := qos2.ComputeQosExcellenceForReputation(syncFactor) + if errQos2 != nil { + return nil, errQos2 + } + qos3Res, errQos3 := qos3.ComputeQosExcellenceForReputation(syncFactor) + if errQos3 != nil { + return nil, errQos3 + } + qos4Res, errQos4 := qos4.ComputeQosExcellenceForReputation(syncFactor) + if errQos4 != nil { + return nil, errQos4 + } + res = append(res, qos1Res, qos2Res, qos3Res, qos4Res) + } else { + qos1Res, errQos1 := qos1.ComputeQoSExcellence() + if errQos1 != nil { + return nil, errQos1 + } + qos2Res, errQos2 := qos2.ComputeQoSExcellence() + if errQos2 != nil { + return nil, errQos2 + } + qos3Res, errQos3 := qos3.ComputeQoSExcellence() + if errQos3 != nil { + return nil, errQos3 + } + qos4Res, errQos4 := qos4.ComputeQoSExcellence() + if errQos4 != nil { + return nil, errQos4 + } + res = append(res, qos1Res, qos2Res, qos3Res, qos4Res) + } + + return res, nil +} + +func TestQosReport(t *testing.T) { + res, err := createTestQosReportScores(false) + require.NoError(t, err) + require.True(t, res[0].LT(res[1])) + require.True(t, res[0].LT(res[2])) + require.True(t, res[0].LT(res[3])) + + require.True(t, res[1].GT(res[2])) + require.True(t, res[1].GT(res[3])) + + require.True(t, res[3].LT(res[2])) +} + +func TestQosReportForReputation(t *testing.T) { + res, err := createTestQosReportScores(true) + require.NoError(t, err) + require.True(t, res[0].GT(res[1])) + require.True(t, res[0].GT(res[2])) + require.True(t, res[0].LT(res[3])) + + require.True(t, res[1].LT(res[2])) + require.True(t, res[1].LT(res[3])) + + require.True(t, res[3].GT(res[2])) } diff --git a/x/pairing/types/reputation_test.go b/x/pairing/types/reputation_test.go new file mode 100644 index 0000000000..944b633874 --- /dev/null +++ b/x/pairing/types/reputation_test.go @@ -0,0 +1,39 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestShouldTruncate tests the should truncate method +func TestShouldTruncate(t *testing.T) { + tests := []struct { + name string + creationTime int64 + stabilizationPeriod int64 + currentTime int64 + truncate bool + }{ + { + name: "stabilization time not passed", + creationTime: 1, + stabilizationPeriod: 1, + currentTime: 3, + truncate: true, + }, + { + name: "stabilization time passed", + creationTime: 3, + stabilizationPeriod: 1, + currentTime: 3, + truncate: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reputation := Reputation{CreationTime: tt.creationTime} + require.Equal(t, tt.truncate, reputation.ShouldTruncate(tt.stabilizationPeriod, tt.currentTime)) + }) + } +} From 44f6f9bdbceaaf3d6fcbdd445d45b3778a5633cc Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 12:03:45 +0300 Subject: [PATCH 03/33] CNS-1005: implement decay factor --- x/pairing/types/reputation.go | 41 +++++++++++++++++++++++++++ x/pairing/types/reputation_test.go | 45 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index cd4baf299f..48cbcb846a 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -1,9 +1,14 @@ package types import ( + "fmt" + stdMath "math" + "cosmossdk.io/collections" "cosmossdk.io/collections/indexes" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/v2/utils" ) var ( @@ -61,6 +66,42 @@ func (r Reputation) ShouldTruncate(stabilizationPeriod int64, currentTime int64) return r.CreationTime+stabilizationPeriod < currentTime } +// DecayFactor calculates the appropriate decay factor for a reputation from the time it was last updated +// the decay factor is: exp(-timeSinceLastUpdate/halfLifeFactor) +func (r Reputation) DecayFactor(halfLifeFactor int64, currentTime int64) math.LegacyDec { + if halfLifeFactor <= 0 { + utils.LavaFormatWarning("DecayFactor: calculate reputation decay factor failed, invalid half life factor", + fmt.Errorf("half life factor is not positive"), + utils.LogAttr("half_life_factor", halfLifeFactor), + ) + return math.LegacyZeroDec() + } + + timeSinceLastUpdate := currentTime - r.TimeLastUpdated + if timeSinceLastUpdate < 0 { + utils.LavaFormatError("DecayFactor: calculate reputation decay factor failed, invalid reputation", + fmt.Errorf("reputation last update time is larger than current time"), + utils.LogAttr("current_time", currentTime), + utils.LogAttr("reputation_time_last_updated", r.TimeLastUpdated), + ) + return math.LegacyZeroDec() + } + + exponent := float64(timeSinceLastUpdate / halfLifeFactor) + decayFactorFloat := stdMath.Exp(exponent) + decayFactorString := fmt.Sprintf("%.18f", decayFactorFloat) + decayFactor, err := math.LegacyNewDecFromStr(decayFactorString) + if err != nil { + utils.LavaFormatError("DecayFactor: calculate reputation decay factor failed, invalid decay factor string", err, + utils.LogAttr("decay_factor_string", decayFactorString), + utils.LogAttr("time_since_last_update", timeSinceLastUpdate), + utils.LogAttr("half_life_factor", halfLifeFactor), + ) + return math.LegacyZeroDec() + } + return decayFactor +} + // ReputationScoreKey returns a key for the reputations fixation store (reputationsFS) func ReputationScoreKey(chainID string, cluster string, provider string) string { return chainID + " " + cluster + " " + provider diff --git a/x/pairing/types/reputation_test.go b/x/pairing/types/reputation_test.go index 944b633874..356969e4a8 100644 --- a/x/pairing/types/reputation_test.go +++ b/x/pairing/types/reputation_test.go @@ -3,6 +3,7 @@ package types import ( "testing" + "cosmossdk.io/math" "github.com/stretchr/testify/require" ) @@ -37,3 +38,47 @@ func TestShouldTruncate(t *testing.T) { }) } } + +// TestDecayFactor tests the decay factor method. Note that upon error, the returned decay factor is zero +func TestDecayFactor(t *testing.T) { + tests := []struct { + name string + timeLastUpdated int64 + halfLifeFactor int64 + currentTime int64 + valid bool + }{ + { + name: "happy flow", + timeLastUpdated: 1, + halfLifeFactor: 1, + currentTime: 2, + valid: true, + }, + { + name: "invalid half life factor", + timeLastUpdated: 1, + halfLifeFactor: -1, + currentTime: 2, + valid: false, + }, + { + name: "current time smaller than reputation last update", + timeLastUpdated: 2, + halfLifeFactor: 1, + currentTime: 1, + valid: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reputation := Reputation{TimeLastUpdated: tt.timeLastUpdated} + decay := reputation.DecayFactor(tt.halfLifeFactor, tt.currentTime) + if tt.valid { + require.False(t, decay.Equal(math.LegacyZeroDec())) + } else { + require.True(t, decay.Equal(math.LegacyZeroDec())) + } + }) + } +} From 883c25c0c4614333b4edf54dc19322862f57e04f Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 19:36:41 +0300 Subject: [PATCH 04/33] CNS-1005: update reputation on epoch start and set repuation pairing scores --- x/pairing/keeper/keeper.go | 1 + x/pairing/keeper/reputation.go | 207 +++++++++++++++++++++++++++- x/pairing/keeper/reputation_test.go | 13 +- x/pairing/types/qos_score.go | 6 + x/pairing/types/reputation.go | 18 ++- x/pairing/types/reputation_test.go | 2 +- 6 files changed, 230 insertions(+), 17 deletions(-) diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index ebfadaef7c..e45cf8c4d8 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -126,6 +126,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) BeginBlock(ctx sdk.Context) { if k.epochStorageKeeper.IsEpochStart(ctx) { + k.UpdateReputationQosScore(ctx) // remove old session payments k.RemoveOldEpochPayments(ctx) // unstake any unstaking providers diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 78389e39dd..4508faa11e 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -2,6 +2,8 @@ package keeper import ( "fmt" + "sort" + "strings" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -117,30 +119,223 @@ func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, c k.SetReputation(ctx, chainID, cluster, provider, r) } +type providerQosScore struct { + provider string + score types.QosScore + stake sdk.Coin +} + +type stakeProviderScores struct { + providerScores []providerQosScore + totalStake sdk.Coin +} + +// UpdateReputationQosScore updates all the reputations on epoch start with the epoch score aggregated over the epoch +func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { + // scores is a map of "chainID cluster" -> stakeProviderScores + // it will be used to compare providers QoS scores within the same chain ID and cluster and determine + // the providers' reputation pairing score. + // note, the map is already sorted by QoS score in descending order. + scores, err := k.updateReputationsScores(ctx) + if err != nil { + panic(utils.LavaFormatError("UpdateReputationQosScore: could not update providers QoS scores", err)) + } + + // iterate over providers QoS scores with the same chain ID and cluster + for chainCluster, stakeProvidersScore := range scores { + split := strings.Split(chainCluster, " ") + chainID, cluster := split[0], split[1] + + // get benchmark score value + benchmark, err := k.getBenchmarkReputationScore(stakeProvidersScore) + if err != nil { + panic(utils.LavaFormatError("UpdateReputationQosScore: could not get benchmark QoS score", err)) + } + + // set reputation pairing score by the benchmark + err = k.setReputationPairingScoreByBenchmark(ctx, chainID, cluster, benchmark, stakeProvidersScore.providerScores) + if err != nil { + panic(utils.LavaFormatError("UpdateReputationQosScore: could not set repuatation pairing scores", err)) + } + } +} + +// updateReputationsScores does the following for each reputation: +// 1. applies time decay +// 2. resets the reputation epoch score +// 3. updates it last update time +// 4. add it to the scores map +func (k Keeper) updateReputationsScores(ctx sdk.Context) (map[string]stakeProviderScores, error) { + halfLifeFactor := k.ReputationHalfLifeFactor(ctx) + currentTime := ctx.BlockTime().UTC().Unix() + + scores := map[string]stakeProviderScores{} + + // iterate over all reputations + iter, err := k.reputations.Iterate(ctx, nil) + if err != nil { + return nil, utils.LavaFormatError("updateReputationsScores: failed to create reputations iterator", err) + } + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + return nil, utils.LavaFormatError("updateReputationsScores: failed to get reputation key from iterator", err) + } + chainID := key.K1() + cluster := key.K2() + provider := key.K3() + + reputation, err := iter.Value() + if err != nil { + return nil, utils.LavaFormatError("updateReputationsScores: failed to get reputation from iterator", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", provider), + ) + } + + // apply time decay on current score and add the epoch score (which is reset right after) + reputation = reputation.ApplyTimeDecay(halfLifeFactor, currentTime) + + // reset epoch score, update last update time and set the reputation + reputation.EpochScore = types.ZeroQosScore + reputation.TimeLastUpdated = currentTime + k.SetReputation(ctx, chainID, cluster, provider, reputation) + + // add entry to the scores map + providerScores, ok := scores[chainID+" "+cluster] + if !ok { + providerScores.providerScores = []providerQosScore{{provider: provider, score: reputation.Score, stake: reputation.Stake}} + providerScores.totalStake = reputation.Stake + } else { + providerScores.providerScores = append(providerScores.providerScores, providerQosScore{provider: provider, score: reputation.Score, stake: reputation.Stake}) + providerScores.totalStake = providerScores.totalStake.Add(reputation.Stake) + } + scores[chainID+" "+cluster] = providerScores + } + + sortProviderScores(scores) + return scores, nil +} + +// sortProviderScores sorts the stakeProviderScores map score slices in descending order +func sortProviderScores(scores map[string]stakeProviderScores) { + for chainCluster, stakeProviderScores := range scores { + split := strings.Split(chainCluster, " ") + chainID, cluster := split[0], split[1] + + sort.Slice(stakeProviderScores.providerScores, func(i, j int) bool { + iScore, err := stakeProviderScores.providerScores[i].score.Score.Resolve() + if err != nil { + panic(utils.LavaFormatError("UpdateReputationQosScore: cannot sort provider scores", err, + utils.LogAttr("provider", stakeProviderScores.providerScores[i].provider), + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + )) + } + + jScore, err := stakeProviderScores.providerScores[j].score.Score.Resolve() + if err != nil { + panic(utils.LavaFormatError("UpdateReputationQosScore: cannot sort provider scores", err, + utils.LogAttr("provider", stakeProviderScores.providerScores[j].provider), + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + )) + } + + return iScore.GT(jScore) + }) + } +} + +// getBenchmarkReputationScore gets the score that will be used as the normalization factor when converting +// the provider's QoS score to the reputation pairing score. +// To do that, we go over all the QoS scores of providers that share chain ID and cluster from the highest +// score to the lowest (that input stakeProviderScores are sorted). We aggregate the providers stake until +// we pass totalStake * ReputationPairingScoreBenchmarkStakeThreshold (currently equal to 10% of total stake). +// Then, we return the last provider's score as the benchmark +func (k Keeper) getBenchmarkReputationScore(stakeProviderScores stakeProviderScores) (math.LegacyDec, error) { + threshold := types.ReputationPairingScoreBenchmarkStakeThreshold.MulInt(stakeProviderScores.totalStake.Amount) + aggregatedStake := sdk.ZeroDec() + scoreBenchmarkIndex := 0 + for i, providerScore := range stakeProviderScores.providerScores { + aggregatedStake = aggregatedStake.Add(providerScore.stake.Amount.ToLegacyDec()) + if aggregatedStake.GTE(threshold) { + scoreBenchmarkIndex = i + break + } + } + + benchmark, err := stakeProviderScores.providerScores[scoreBenchmarkIndex].score.Score.Resolve() + if err != nil { + return sdk.ZeroDec(), utils.LavaFormatError("getBenchmarkReputationScore: could not resolve benchmark score", err) + } + + return benchmark, nil +} + +// setReputationPairingScoreByBenchmark sets the reputation pairing score using a benchmark score for all providers with the same chain ID and cluster +// The reputation pairing scores are determined as follows: if the provider's QoS score is larger than the benchmark, it gets the max +// reputation pairing score. If not, it's normalized by the benchmark and scaled to fit the range [MinReputationPairingScore, MaxReputationPairingScore]. +// To scale, we use the following formula: +// scaled_score = min_score + (max_score - min_score) * (score / benchmark) +func (k Keeper) setReputationPairingScoreByBenchmark(ctx sdk.Context, chainID string, cluster string, benchmark math.LegacyDec, scores []providerQosScore) error { + scale := types.MaxReputationPairingScore.Sub(types.MinReputationPairingScore) + for _, providerScore := range scores { + score, err := providerScore.score.Score.Resolve() + if err != nil { + return utils.LavaFormatError("setReputationPairingScoreByBenchmark: cannot resolve provider score", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", providerScore.provider), + ) + } + + scaledScore := types.MaxReputationPairingScore + if score.LT(benchmark) { + scaledScore = types.MinReputationPairingScore.Add(score.Mul(scale)) + } + + err = k.SetReputationScore(ctx, chainID, cluster, providerScore.provider, scaledScore) + if err != nil { + return utils.LavaFormatError("setReputationPairingScoreByBenchmark: set reputation pairing score failed", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", providerScore.provider), + ) + } + } + + return nil +} + // GetReputationScore returns the current reputation pairing score -func (k Keeper) GetReputationScore(ctx sdk.Context, chainID string, cluster string, provider string) (val types.ReputationPairingScore, found bool) { +func (k Keeper) GetReputationScore(ctx sdk.Context, chainID string, cluster string, provider string) (val math.LegacyDec, found bool) { block := uint64(ctx.BlockHeight()) key := types.ReputationScoreKey(chainID, cluster, provider) var score types.ReputationPairingScore found = k.reputationsFS.FindEntry(ctx, key, block, &score) - return score, found + return score.Score, found } // GetReputationScore returns a reputation pairing score in a specific block -func (k Keeper) GetReputationScoreForBlock(ctx sdk.Context, chainID string, cluster string, provider string, block uint64) (val types.ReputationPairingScore, entryBlock uint64, found bool) { +func (k Keeper) GetReputationScoreForBlock(ctx sdk.Context, chainID string, cluster string, provider string, block uint64) (val math.LegacyDec, entryBlock uint64, found bool) { var score types.ReputationPairingScore key := types.ReputationScoreKey(chainID, cluster, provider) entryBlock, _, _, found = k.reputationsFS.FindEntryDetailed(ctx, key, block, &score) - return score, entryBlock, found + return score.Score, entryBlock, found } // SetReputationScore sets a reputation pairing score -func (k Keeper) SetReputationScore(ctx sdk.Context, chainID string, cluster string, provider string, score types.ReputationPairingScore) error { +func (k Keeper) SetReputationScore(ctx sdk.Context, chainID string, cluster string, provider string, score math.LegacyDec) error { key := types.ReputationScoreKey(chainID, cluster, provider) - err := k.reputationsFS.AppendEntry(ctx, key, uint64(ctx.BlockHeight()), &score) + reputationScore := types.ReputationPairingScore{Score: score} + err := k.reputationsFS.AppendEntry(ctx, key, uint64(ctx.BlockHeight()), &reputationScore) if err != nil { return utils.LavaFormatError("SetReputationScore: set reputation pairing score failed", err, utils.LogAttr("chain_id", chainID), diff --git a/x/pairing/keeper/reputation_test.go b/x/pairing/keeper/reputation_test.go index a11a64aaa7..9c32f0278f 100644 --- a/x/pairing/keeper/reputation_test.go +++ b/x/pairing/keeper/reputation_test.go @@ -72,20 +72,19 @@ func TestGetAllReputations(t *testing.T) { } } -func createNReputationsScores(keeper *keeper.Keeper, ctx sdk.Context, n int) ([]types.ReputationPairingScore, sdk.Context) { - items := make([]types.ReputationPairingScore, n) +func createNReputationsScores(keeper *keeper.Keeper, ctx sdk.Context, n int) ([]math.LegacyDec, sdk.Context) { + items := make([]math.LegacyDec, n) height := ctx.BlockHeight() for i := range items { decIndex := math.LegacyNewDec(int64(i + 1)) strIndex := strconv.Itoa(i) - rps := types.ReputationPairingScore{Score: decIndex} - err := keeper.SetReputationScore(ctx, strIndex, strIndex, strIndex, rps) + err := keeper.SetReputationScore(ctx, strIndex, strIndex, strIndex, decIndex) if err != nil { panic(err) } - items[i] = rps + items[i] = decIndex height++ ctx = ctx.WithBlockHeight(height) } @@ -99,7 +98,7 @@ func TestGetReputationScore(t *testing.T) { strIndex := strconv.Itoa(i) entry, found := keeper.GetReputationScore(ctx, strIndex, strIndex, strIndex) require.True(t, found) - require.True(t, item.Score.Equal(entry.Score)) + require.True(t, item.Equal(entry)) } _, found := keeper.GetReputationScore(ctx, "dummy", "dummy", "dummy") @@ -113,7 +112,7 @@ func TestGetReputationScoreForBlock(t *testing.T) { strIndex := strconv.Itoa(i) entry, entryBlock, found := keeper.GetReputationScoreForBlock(ctx, strIndex, strIndex, strIndex, uint64(ctx.BlockHeight())) require.True(t, found) - require.True(t, item.Score.Equal(entry.Score)) + require.True(t, item.Equal(entry)) require.Equal(t, uint64(i), entryBlock) } diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index e6d2a83225..fbc262bd81 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -16,6 +16,12 @@ var ( Score: Frac{Num: math.LegacyNewDec(5), Denom: math.LegacyNewDec(4)}, Variance: Frac{Num: math.LegacyZeroDec(), Denom: math.LegacySmallestDec()}, } + + // zero QoS score is: score = 0, var = 0 + ZeroQosScore = QosScore{ + Score: Frac{Num: math.LegacyZeroDec(), Denom: math.LegacySmallestDec()}, + Variance: Frac{Num: math.LegacyZeroDec(), Denom: math.LegacySmallestDec()}, + } ) func NewFrac(num math.LegacyDec, denom math.LegacyDec) (Frac, error) { diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 8aca965d3e..e146609e5c 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -12,7 +12,10 @@ import ( ) var ( - ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) + ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) + ReputationPairingScoreBenchmarkStakeThreshold = sdk.NewDecWithPrec(1, 1) // 0.1 = 10% + MaxReputationPairingScore = sdk.NewDec(2) + MinReputationPairingScore = sdk.NewDecWithPrec(5, 1) // 0.5 ) // ReputationKey returns a key to the reputations indexed map @@ -44,9 +47,9 @@ func (r Reputation) ShouldTruncate(stabilizationPeriod int64, currentTime int64) return r.CreationTime+stabilizationPeriod < currentTime } -// DecayFactor calculates the appropriate decay factor for a reputation from the time it was last updated +// calcDecayFactor calculates the appropriate decay factor for a reputation from the time it was last updated // the decay factor is: exp(-timeSinceLastUpdate/halfLifeFactor) -func (r Reputation) DecayFactor(halfLifeFactor int64, currentTime int64) math.LegacyDec { +func (r Reputation) calcDecayFactor(halfLifeFactor int64, currentTime int64) math.LegacyDec { if halfLifeFactor <= 0 { utils.LavaFormatWarning("DecayFactor: calculate reputation decay factor failed, invalid half life factor", fmt.Errorf("half life factor is not positive"), @@ -80,6 +83,15 @@ func (r Reputation) DecayFactor(halfLifeFactor int64, currentTime int64) math.Le return decayFactor } +func (r Reputation) ApplyTimeDecay(halfLifeFactor int64, currentTime int64) Reputation { + decayFactor := r.calcDecayFactor(halfLifeFactor, currentTime) + r.Score.Score.Num = (r.Score.Score.Num.Mul(decayFactor)).Add(r.EpochScore.Score.Num) + r.Score.Score.Denom = (r.Score.Score.Denom.Mul(decayFactor)).Add(r.EpochScore.Score.Denom) + r.Score.Variance.Num = (r.Score.Variance.Num.Mul(decayFactor)).Add(r.EpochScore.Variance.Num) + r.Score.Variance.Denom = (r.Score.Variance.Denom.Mul(decayFactor)).Add(r.EpochScore.Variance.Denom) + return r +} + // ReputationScoreKey returns a key for the reputations fixation store (reputationsFS) func ReputationScoreKey(chainID string, cluster string, provider string) string { return chainID + " " + cluster + " " + provider diff --git a/x/pairing/types/reputation_test.go b/x/pairing/types/reputation_test.go index 356969e4a8..8fe51186fd 100644 --- a/x/pairing/types/reputation_test.go +++ b/x/pairing/types/reputation_test.go @@ -73,7 +73,7 @@ func TestDecayFactor(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { reputation := Reputation{TimeLastUpdated: tt.timeLastUpdated} - decay := reputation.DecayFactor(tt.halfLifeFactor, tt.currentTime) + decay := reputation.calcDecayFactor(tt.halfLifeFactor, tt.currentTime) if tt.valid { require.False(t, decay.Equal(math.LegacyZeroDec())) } else { From 32a544c6880eae5e2f3449ad8bfc684aaf7081f9 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 19:46:30 +0300 Subject: [PATCH 05/33] CNS-1004: add stake to reputation --- x/pairing/keeper/msg_server_relay_payment.go | 12 +++++++++++- x/pairing/keeper/reputation.go | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 559429c79d..5a5e6fad5a 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -198,8 +198,18 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen ) } + stakeEntry, found := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, relay.SpecId, relay.Provider) + if !found { + return nil, utils.LavaFormatWarning("RelayPayment: could not get stake entry for reputation", fmt.Errorf("stake entry not found"), + utils.LogAttr("consumer", clientAddr), + utils.LogAttr("chain", relay.SpecId), + utils.LogAttr("provider", relay.Provider), + ) + } + effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.EffectiveStake()) + // note the current weight used is by relay num. In the future, it might change - k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum)) + k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum), effectiveStake) } // TODO: add support for spec changes diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 2facff6914..b982ea91c1 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -94,7 +94,7 @@ func (k Keeper) GetAllReputation(ctx sdk.Context) []types.ReputationGenesis { // UpdateReputationEpochQosScore updates the epoch QoS score of the provider's reputation using the score from the relay // payment's QoS excellence report -func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, cluster string, provider string, score math.LegacyDec, weight int64) { +func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, cluster string, provider string, score math.LegacyDec, weight int64, stake sdk.Coin) { // get current reputation and get parameters for the epoch score update r, found := k.GetReputation(ctx, chainID, cluster, provider) truncate := false @@ -114,6 +114,7 @@ func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, c // update the reputation and set r.EpochScore = updatedEpochScore r.TimeLastUpdated = ctx.BlockTime().UTC().Unix() + r.Stake = stake k.SetReputation(ctx, chainID, cluster, provider, r) } From 820f179a3c94bee5ec1999d7b98f93753f94c9c3 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 19:47:41 +0300 Subject: [PATCH 06/33] CNS-1005: fix error comments --- x/pairing/types/reputation.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index e146609e5c..655217a66e 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -51,7 +51,7 @@ func (r Reputation) ShouldTruncate(stabilizationPeriod int64, currentTime int64) // the decay factor is: exp(-timeSinceLastUpdate/halfLifeFactor) func (r Reputation) calcDecayFactor(halfLifeFactor int64, currentTime int64) math.LegacyDec { if halfLifeFactor <= 0 { - utils.LavaFormatWarning("DecayFactor: calculate reputation decay factor failed, invalid half life factor", + utils.LavaFormatWarning("calcDecayFactor: calculate reputation decay factor failed, invalid half life factor", fmt.Errorf("half life factor is not positive"), utils.LogAttr("half_life_factor", halfLifeFactor), ) @@ -60,7 +60,7 @@ func (r Reputation) calcDecayFactor(halfLifeFactor int64, currentTime int64) mat timeSinceLastUpdate := currentTime - r.TimeLastUpdated if timeSinceLastUpdate < 0 { - utils.LavaFormatError("DecayFactor: calculate reputation decay factor failed, invalid reputation", + utils.LavaFormatError("calcDecayFactor: calculate reputation decay factor failed, invalid reputation", fmt.Errorf("reputation last update time is larger than current time"), utils.LogAttr("current_time", currentTime), utils.LogAttr("reputation_time_last_updated", r.TimeLastUpdated), @@ -73,7 +73,7 @@ func (r Reputation) calcDecayFactor(halfLifeFactor int64, currentTime int64) mat decayFactorString := fmt.Sprintf("%.18f", decayFactorFloat) decayFactor, err := math.LegacyNewDecFromStr(decayFactorString) if err != nil { - utils.LavaFormatError("DecayFactor: calculate reputation decay factor failed, invalid decay factor string", err, + utils.LavaFormatError("calcDecayFactor: calculate reputation decay factor failed, invalid decay factor string", err, utils.LogAttr("decay_factor_string", decayFactorString), utils.LogAttr("time_since_last_update", timeSinceLastUpdate), utils.LogAttr("half_life_factor", halfLifeFactor), From 1a599a017ebc67d4d9f673ff4329daa4ec3f7110 Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 7 Aug 2024 11:35:54 +0300 Subject: [PATCH 07/33] CNS-1004: add stake check in unit test --- x/pairing/keeper/msg_server_relay_payment_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 3b23f1f193..9de1ca65b6 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1125,6 +1125,10 @@ func TestUpdateReputationEpochQosScore(t *testing.T) { require.NoError(t, err) require.True(t, epochScore1.LT(epochScore2)) // score is lower because QoS is excellent require.True(t, variance1.GT(variance2)) // variance is higher because the QoS is significantly differnet from DefaultQos + + entry, found := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, provider1) + require.True(t, found) + require.True(t, entry.Stake.IsEqual(r1.Stake)) } // TestUpdateReputationEpochQosScoreTruncation tests the following scenarios: From 82faf7f695904d7469d55247f0cc6026ff4819f6 Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 7 Aug 2024 12:25:08 +0300 Subject: [PATCH 08/33] CNS-1005: add support for reputation pairing req (currently disabled) --- x/pairing/keeper/filters/filter.go | 15 +++---- x/pairing/keeper/pairing_test.go | 8 +--- x/pairing/keeper/qos_excellence_test.go | 32 --------------- x/pairing/keeper/scores/geo_req_test.go | 4 +- x/pairing/keeper/scores/pairing_score.go | 25 ++++++------ x/pairing/keeper/scores/qos_req.go | 49 ----------------------- x/pairing/keeper/scores/reputation_req.go | 46 +++++++++++++++++++++ x/pairing/keeper/scores/score.go | 2 +- 8 files changed, 68 insertions(+), 113 deletions(-) delete mode 100644 x/pairing/keeper/qos_excellence_test.go delete mode 100644 x/pairing/keeper/scores/qos_req.go create mode 100644 x/pairing/keeper/scores/reputation_req.go diff --git a/x/pairing/keeper/filters/filter.go b/x/pairing/keeper/filters/filter.go index 8a1481f11f..cdd54c0f2c 100644 --- a/x/pairing/keeper/filters/filter.go +++ b/x/pairing/keeper/filters/filter.go @@ -60,7 +60,7 @@ func initFilters(filters []Filter, strictestPolicy planstypes.Policy) (activeFil return activeFilters } -func SetupScores(ctx sdk.Context, filters []Filter, providers []epochstoragetypes.StakeEntry, strictestPolicy *planstypes.Policy, currentEpoch uint64, slotCount int, cluster string, qg pairingscores.QosGetter) ([]*pairingscores.PairingScore, error) { +func SetupScores(ctx sdk.Context, filters []Filter, providers []epochstoragetypes.StakeEntry, strictestPolicy *planstypes.Policy, currentEpoch uint64, slotCount int, cluster string, rg pairingscores.ReputationGetter) ([]*pairingscores.PairingScore, error) { filters = initFilters(filters, *strictestPolicy) var filtersResult [][]bool @@ -105,14 +105,11 @@ func SetupScores(ctx sdk.Context, filters []Filter, providers []epochstoragetype } if result { - // TODO: uncomment this code once the providerQosFS's update is implemented (it's currently always empty) - // qos, err := qg.GetQos(ctx, providers[j].Chain, cluster, providers[j].Address) - // if err != nil { - // // only printing error and skipping provider so pairing won't fail - // utils.LavaFormatError("could not construct provider qos", err) - // continue - // } - providerScore := pairingscores.NewPairingScore(&providers[j], types.QualityOfServiceReport{}) + reputationScore, _, found := rg.GetReputationScoreForBlock(ctx, providers[j].Chain, cluster, providers[j].Address, currentEpoch) + if !found { + reputationScore = types.MinReputationPairingScore + } + providerScore := pairingscores.NewPairingScore(&providers[j], reputationScore) providerScore.SlotFiltering = slotFiltering providerScores = append(providerScores, providerScore) } diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index bbec8a799b..26823a051c 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -1131,14 +1131,8 @@ func TestGeolocationPairingScores(t *testing.T) { stakeEntries := providersRes.StakeEntry providerScores := []*pairingscores.PairingScore{} - subRes, err := ts.QuerySubscriptionCurrent(tt.dev.Addr.String()) - require.NoError(t, err) - cluster := subRes.Sub.Cluster - for i := range stakeEntries { - // TODO: require err to be nil once the providerQosFS's update is implemented - qos, _ := ts.Keepers.Pairing.GetQos(ts.Ctx, ts.spec.Index, cluster, stakeEntries[i].Address) - providerScore := pairingscores.NewPairingScore(&stakeEntries[i], qos) + providerScore := pairingscores.NewPairingScore(&stakeEntries[i], sdk.OneDec()) providerScores = append(providerScores, providerScore) } diff --git a/x/pairing/keeper/qos_excellence_test.go b/x/pairing/keeper/qos_excellence_test.go deleted file mode 100644 index dcf145278f..0000000000 --- a/x/pairing/keeper/qos_excellence_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package keeper_test - -import ( - "testing" -) - -// TODO: All tests are not implemented since providerQosFS update and Qos score are not implemented yet - -// TestProviderQosMap checks that getting a providers' Qos map for specific chainID and cluster works properly -func TestProviderQosMap(t *testing.T) { -} - -// TestGetQos checks that using GetQos() returns the right Qos -func TestGetQos(t *testing.T) { -} - -// TestQosReqForSlots checks that if Qos req is active, all slots are assigned with Qos req -func TestQosReqForSlots(t *testing.T) { -} - -// TestQosScoreCluster that consumer pairing uses the correct cluster for QoS score calculations. -func TestQosScoreCluster(t *testing.T) { -} - -// TestQosScore checks that the qos score component is as expected (score == ComputeQos(), new users (sub usage less -// than a month) are not infuenced by Qos score, invalid Qos score == 1) -func TestQosScore(t *testing.T) { -} - -// TestUpdateClusteringCriteria checks that updating the clustering criteria doesn't make different version clusters to be mixed -func TestUpdateClusteringCriteria(t *testing.T) { -} diff --git a/x/pairing/keeper/scores/geo_req_test.go b/x/pairing/keeper/scores/geo_req_test.go index 3e1f22eae7..eb81ad4592 100644 --- a/x/pairing/keeper/scores/geo_req_test.go +++ b/x/pairing/keeper/scores/geo_req_test.go @@ -3,8 +3,8 @@ package scores import ( "testing" + "cosmossdk.io/math" epochstoragetypes "github.com/lavanet/lava/v2/x/epochstorage/types" - "github.com/lavanet/lava/v2/x/pairing/types" planstypes "github.com/lavanet/lava/v2/x/plans/types" "github.com/stretchr/testify/require" ) @@ -97,7 +97,7 @@ func TestGeoReqScore(t *testing.T) { t.Run(tt.name, func(t *testing.T) { geoReq.Geo = tt.reqGeo stakeEntry.Geolocation = tt.providerGeo - pairingScore := NewPairingScore(&stakeEntry, types.QualityOfServiceReport{}) + pairingScore := NewPairingScore(&stakeEntry, math.LegacyZeroDec()) score := geoReq.Score(*pairingScore) require.True(t, score.Equal(calculateCostFromLatency(tt.expectedLatency))) }) diff --git a/x/pairing/keeper/scores/pairing_score.go b/x/pairing/keeper/scores/pairing_score.go index 5e35d16c25..a5a3ff19df 100644 --- a/x/pairing/keeper/scores/pairing_score.go +++ b/x/pairing/keeper/scores/pairing_score.go @@ -3,7 +3,6 @@ package scores import ( "cosmossdk.io/math" epochstoragetypes "github.com/lavanet/lava/v2/x/epochstorage/types" - pairingtypes "github.com/lavanet/lava/v2/x/pairing/types" ) const ( @@ -13,12 +12,12 @@ const ( // PairingScore holds a provider's score with respect to a set of requirements (ScoreReq), indexed by their unique name. type PairingScore struct { - Provider *epochstoragetypes.StakeEntry - Score math.LegacyDec - ScoreComponents map[string]math.LegacyDec - SkipForSelection bool - SlotFiltering map[int]struct{} // slot indexes here are skipped - QosExcellenceReport pairingtypes.QualityOfServiceReport + Provider *epochstoragetypes.StakeEntry + Score math.LegacyDec + ScoreComponents map[string]math.LegacyDec + SkipForSelection bool + SlotFiltering map[int]struct{} // slot indexes here are skipped + reputationScore math.LegacyDec } func (ps *PairingScore) IsValidForSelection(slotIndex int) bool { @@ -40,13 +39,13 @@ func (ps *PairingScore) InvalidIndexes(possibleIndexes []int) []int { return invalidIndexes } -func NewPairingScore(stakeEntry *epochstoragetypes.StakeEntry, qos pairingtypes.QualityOfServiceReport) *PairingScore { +func NewPairingScore(stakeEntry *epochstoragetypes.StakeEntry, reputationScore math.LegacyDec) *PairingScore { score := PairingScore{ - Provider: stakeEntry, - Score: math.LegacyOneDec(), - ScoreComponents: map[string]math.LegacyDec{}, - SkipForSelection: false, - QosExcellenceReport: qos, + Provider: stakeEntry, + Score: math.LegacyOneDec(), + ScoreComponents: map[string]math.LegacyDec{}, + SkipForSelection: false, + reputationScore: reputationScore, } return &score } diff --git a/x/pairing/keeper/scores/qos_req.go b/x/pairing/keeper/scores/qos_req.go deleted file mode 100644 index 724d145fa2..0000000000 --- a/x/pairing/keeper/scores/qos_req.go +++ /dev/null @@ -1,49 +0,0 @@ -package scores - -import ( - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - pairingtypes "github.com/lavanet/lava/v2/x/pairing/types" - planstypes "github.com/lavanet/lava/v2/x/plans/types" -) - -const qosReqName = "qos-req" - -type QosGetter interface { - GetQos(ctx sdk.Context, chainID string, cluster string, provider string) (pairingtypes.QualityOfServiceReport, error) -} - -// QosReq implements the ScoreReq interface for provider staking requirement(s) -type QosReq struct{} - -func (qr QosReq) Init(policy planstypes.Policy) bool { - return true -} - -// Score calculates the the provider's qos score -func (qr QosReq) Score(score PairingScore) math.LegacyDec { - // TODO: update Qos in providerQosFS properly and uncomment this code below - // Also, the qos score should range between 0.5-2 - - // qosScore, err := score.QosExcellenceReport.ComputeQoS() - // if err != nil { - // return math.NewUint(1) - // } - - // return math.Uint(qosScore) - return math.LegacyOneDec() -} - -func (qr QosReq) GetName() string { - return qosReqName -} - -// Equal used to compare slots to determine slot groups. -// Equal always returns true (there are no different "types" of qos) -func (qr QosReq) Equal(other ScoreReq) bool { - return true -} - -func (qr QosReq) GetReqForSlot(policy planstypes.Policy, slotIdx int) ScoreReq { - return qr -} diff --git a/x/pairing/keeper/scores/reputation_req.go b/x/pairing/keeper/scores/reputation_req.go new file mode 100644 index 0000000000..06fde02a81 --- /dev/null +++ b/x/pairing/keeper/scores/reputation_req.go @@ -0,0 +1,46 @@ +package scores + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/v2/x/pairing/types" + planstypes "github.com/lavanet/lava/v2/x/plans/types" +) + +const reputationReqName = "reputation-req" + +type ReputationGetter interface { + GetReputationScoreForBlock(ctx sdk.Context, chainID string, cluster string, provider string, block uint64) (val math.LegacyDec, entryBlock uint64, found bool) +} + +// ReputationReq implements the ScoreReq interface for provider staking requirement(s) +type ReputationReq struct{} + +func (rr ReputationReq) Init(policy planstypes.Policy) bool { + return true +} + +// Score gets the provider's reputation pairing score using the reputationFS fixation store +func (rr ReputationReq) Score(score PairingScore) math.LegacyDec { + if score.reputationScore.GT(types.MaxReputationPairingScore) { + return types.MaxReputationPairingScore + } else if score.reputationScore.LT(types.MinReputationPairingScore) { + return types.MinReputationPairingScore + } + + return score.reputationScore +} + +func (rr ReputationReq) GetName() string { + return reputationReqName +} + +// Equal used to compare slots to determine slot groups. +// Equal always returns true (there are no different "types" of reputation) +func (rr ReputationReq) Equal(other ScoreReq) bool { + return true +} + +func (rr ReputationReq) GetReqForSlot(policy planstypes.Policy, slotIdx int) ScoreReq { + return rr +} diff --git a/x/pairing/keeper/scores/score.go b/x/pairing/keeper/scores/score.go index 972d604e11..de3d1a1a7b 100644 --- a/x/pairing/keeper/scores/score.go +++ b/x/pairing/keeper/scores/score.go @@ -65,7 +65,7 @@ func GetAllReqs() []ScoreReq { return []ScoreReq{ &StakeReq{}, &GeoReq{}, - &QosReq{}, + // &ReputationReq{}, TODO: uncomment when you want to enable reputation influence on pairing } } From f4eb857ae6972f70f8a2b0b5e7fef4588667cdfe Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 7 Aug 2024 14:08:18 +0300 Subject: [PATCH 09/33] CNS-1005: remove redundant func --- x/pairing/keeper/reputation.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 068e290264..17b3824ce7 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -24,11 +24,6 @@ past blocks. */ -// TODO: remove and reimplement in future work -func (k Keeper) GetQos(ctx sdk.Context, chainID string, cluster string, provider string) (qos types.QualityOfServiceReport, err error) { - return qos, nil -} - // GetReputation gets a Reputation from the store func (k Keeper) GetReputation(ctx sdk.Context, chainID string, cluster string, provider string) (types.Reputation, bool) { key := types.ReputationKey(chainID, cluster, provider) From 36c47b3f0008b6e0be99b9a1fce0d6e37778eff1 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 11 Aug 2024 15:13:48 +0300 Subject: [PATCH 10/33] CNS-1005: small fixes --- x/pairing/keeper/filters/filter.go | 2 +- x/pairing/keeper/msg_server_relay_payment.go | 2 +- x/pairing/types/qos_score.go | 9 ++++++++ x/pairing/types/reputation.go | 24 +++++++++++++++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/x/pairing/keeper/filters/filter.go b/x/pairing/keeper/filters/filter.go index 41b3bd570b..aed203859c 100644 --- a/x/pairing/keeper/filters/filter.go +++ b/x/pairing/keeper/filters/filter.go @@ -110,7 +110,7 @@ func SetupScores(ctx sdk.Context, filters []Filter, providers []epochstoragetype if result { reputationScore, _, found := rg.GetReputationScoreForBlock(ctx, providers[j].Chain, cluster, providers[j].Address, currentEpoch) if !found { - reputationScore = types.MinReputationPairingScore + reputationScore = types.DefaultReputationPairingScore } providerScore := pairingscores.NewPairingScore(&providers[j], reputationScore) providerScore.SlotFiltering = slotFiltering diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 44d6daa29e..c36f6741cf 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -198,7 +198,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen ) } - stakeEntry, found := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, relay.SpecId, relay.Provider) + stakeEntry, found := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, relay.SpecId, relay.Provider) if !found { return nil, utils.LavaFormatWarning("RelayPayment: could not get stake entry for reputation", fmt.Errorf("stake entry not found"), utils.LogAttr("consumer", clientAddr), diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index 68a77bd379..746ee1ecfb 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -45,6 +45,15 @@ func (qs QosScore) Equal(other QosScore) bool { return qs.Score.Equal(other.Score) && qs.Variance.Equal(other.Variance) } +// Validate validates that both nums are non-negative and both denoms are strictly positive (non-zero) +func (qs QosScore) Validate() bool { + if qs.Score.Num.IsNegative() || !qs.Score.Denom.IsPositive() || qs.Variance.Num.IsNegative() || + !qs.Variance.Denom.IsPositive() { + return false + } + return true +} + // Update updates a QosScore with a new score from the QoS excellence report. The new score is truncated by the // current variance. Then, it's updated using the weight (which is currently the relay num) func (qs QosScore) Update(score math.LegacyDec, truncate bool, weight int64) QosScore { diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 02f8b68b81..bebeb1531b 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -15,7 +15,8 @@ var ( ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) ReputationPairingScoreBenchmarkStakeThreshold = sdk.NewDecWithPrec(1, 1) // 0.1 = 10% MaxReputationPairingScore = sdk.NewDec(2) - MinReputationPairingScore = sdk.NewDecWithPrec(5, 1) // 0.5 + MinReputationPairingScore = sdk.NewDecWithPrec(5, 1) // 0.5 + DefaultReputationPairingScore = sdk.NewDecWithPrec(125, 2) // 1.25 ) // ReputationKey returns a key to the reputations indexed map @@ -83,13 +84,30 @@ func (r Reputation) calcDecayFactor(halfLifeFactor int64, currentTime int64) mat return decayFactor } -func (r Reputation) ApplyTimeDecay(halfLifeFactor int64, currentTime int64) Reputation { +func (r Reputation) ApplyTimeDecayAndUpdateScore(halfLifeFactor int64, currentTime int64) (Reputation, error) { decayFactor := r.calcDecayFactor(halfLifeFactor, currentTime) r.Score.Score.Num = (r.Score.Score.Num.Mul(decayFactor)).Add(r.EpochScore.Score.Num) r.Score.Score.Denom = (r.Score.Score.Denom.Mul(decayFactor)).Add(r.EpochScore.Score.Denom) r.Score.Variance.Num = (r.Score.Variance.Num.Mul(decayFactor)).Add(r.EpochScore.Variance.Num) r.Score.Variance.Denom = (r.Score.Variance.Denom.Mul(decayFactor)).Add(r.EpochScore.Variance.Denom) - return r + if !r.Validate() { + return Reputation{}, utils.LavaFormatError("ApplyTimeDecayAndUpdateScore: cannot update reputation", + fmt.Errorf("reputation result is invalid"), + utils.LogAttr("reputation_result", r.String()), + utils.LogAttr("decay_factor", decayFactor.String()), + utils.LogAttr("half_life_factor", halfLifeFactor), + ) + } + return r, nil +} + +func (r Reputation) Validate() bool { + if r.CreationTime <= 0 || r.TimeLastUpdated <= 0 || r.TimeLastUpdated < r.CreationTime || + r.Stake.Denom != commontypes.TokenDenom || !r.Score.Validate() || !r.EpochScore.Validate() { + return false + } + + return true } // ReputationScoreKey returns a key for the reputations fixation store (reputationsFS) From ce24252f974269b55be6e7c3e2b6ae59f4184cb3 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 12 Aug 2024 11:26:18 +0300 Subject: [PATCH 11/33] CNS-1005: make higher pairing score for lower QoS score and make functions public --- x/pairing/keeper/reputation.go | 141 +++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 49 deletions(-) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 17b3824ce7..a0d0146eb9 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -115,15 +115,15 @@ func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, c k.SetReputation(ctx, chainID, cluster, provider, r) } -type providerQosScore struct { - provider string - score types.QosScore - stake sdk.Coin +type ProviderQosScore struct { + Provider string + Score types.QosScore + Stake sdk.Coin } -type stakeProviderScores struct { - providerScores []providerQosScore - totalStake sdk.Coin +type StakeProviderScores struct { + ProviderScores []ProviderQosScore + TotalStake sdk.Coin } // UpdateReputationQosScore updates all the reputations on epoch start with the epoch score aggregated over the epoch @@ -131,41 +131,49 @@ func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { // scores is a map of "chainID cluster" -> stakeProviderScores // it will be used to compare providers QoS scores within the same chain ID and cluster and determine // the providers' reputation pairing score. - // note, the map is already sorted by QoS score in descending order. - scores, err := k.updateReputationsScores(ctx) + // note, the map is already sorted by QoS score in ascending order. + scores, err := k.UpdateReputationsForEpochStart(ctx) if err != nil { panic(utils.LavaFormatError("UpdateReputationQosScore: could not update providers QoS scores", err)) } + // sort keys + keys := []string{} + for key := range scores { + keys = append(keys, key) + } + sort.Strings(keys) + // iterate over providers QoS scores with the same chain ID and cluster - for chainCluster, stakeProvidersScore := range scores { + for _, chainCluster := range keys { + stakeProvidersScore := scores[chainCluster] split := strings.Split(chainCluster, " ") chainID, cluster := split[0], split[1] // get benchmark score value - benchmark, err := k.getBenchmarkReputationScore(stakeProvidersScore) + benchmark, err := k.GetBenchmarkReputationScore(stakeProvidersScore) if err != nil { panic(utils.LavaFormatError("UpdateReputationQosScore: could not get benchmark QoS score", err)) } // set reputation pairing score by the benchmark - err = k.setReputationPairingScoreByBenchmark(ctx, chainID, cluster, benchmark, stakeProvidersScore.providerScores) + err = k.setReputationPairingScoreByBenchmark(ctx, chainID, cluster, benchmark, stakeProvidersScore.ProviderScores) if err != nil { panic(utils.LavaFormatError("UpdateReputationQosScore: could not set repuatation pairing scores", err)) } } } -// updateReputationsScores does the following for each reputation: +// UpdateReputationsForEpochStart does the following for each reputation: // 1. applies time decay // 2. resets the reputation epoch score // 3. updates it last update time // 4. add it to the scores map -func (k Keeper) updateReputationsScores(ctx sdk.Context) (map[string]stakeProviderScores, error) { +func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]StakeProviderScores, error) { halfLifeFactor := k.ReputationHalfLifeFactor(ctx) currentTime := ctx.BlockTime().UTC().Unix() - scores := map[string]stakeProviderScores{} + scores := map[string]StakeProviderScores{} // iterate over all reputations iter, err := k.reputations.Iterate(ctx, nil) @@ -193,7 +201,14 @@ func (k Keeper) updateReputationsScores(ctx sdk.Context) (map[string]stakeProvid } // apply time decay on current score and add the epoch score (which is reset right after) - reputation = reputation.ApplyTimeDecay(halfLifeFactor, currentTime) + reputation, err = reputation.ApplyTimeDecayAndUpdateScore(halfLifeFactor, currentTime) + if err != nil { + return nil, utils.LavaFormatError("updateReputationsScores: apply time decay and update reputation", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", provider), + ) + } // reset epoch score, update last update time and set the reputation reputation.EpochScore = types.ZeroQosScore @@ -203,11 +218,11 @@ func (k Keeper) updateReputationsScores(ctx sdk.Context) (map[string]stakeProvid // add entry to the scores map providerScores, ok := scores[chainID+" "+cluster] if !ok { - providerScores.providerScores = []providerQosScore{{provider: provider, score: reputation.Score, stake: reputation.Stake}} - providerScores.totalStake = reputation.Stake + providerScores.ProviderScores = []ProviderQosScore{{Provider: provider, Score: reputation.Score, Stake: reputation.Stake}} + providerScores.TotalStake = reputation.Stake } else { - providerScores.providerScores = append(providerScores.providerScores, providerQosScore{provider: provider, score: reputation.Score, stake: reputation.Stake}) - providerScores.totalStake = providerScores.totalStake.Add(reputation.Stake) + providerScores.ProviderScores = append(providerScores.ProviderScores, ProviderQosScore{Provider: provider, Score: reputation.Score, Stake: reputation.Stake}) + providerScores.TotalStake = providerScores.TotalStake.Add(reputation.Stake) } scores[chainID+" "+cluster] = providerScores } @@ -216,55 +231,62 @@ func (k Keeper) updateReputationsScores(ctx sdk.Context) (map[string]stakeProvid return scores, nil } -// sortProviderScores sorts the stakeProviderScores map score slices in descending order -func sortProviderScores(scores map[string]stakeProviderScores) { +// sortProviderScores sorts the stakeProviderScores map score slices in ascending order +func sortProviderScores(scores map[string]StakeProviderScores) { for chainCluster, stakeProviderScores := range scores { split := strings.Split(chainCluster, " ") chainID, cluster := split[0], split[1] - sort.Slice(stakeProviderScores.providerScores, func(i, j int) bool { - iScore, err := stakeProviderScores.providerScores[i].score.Score.Resolve() + sort.Slice(stakeProviderScores.ProviderScores, func(i, j int) bool { + iScore, err := stakeProviderScores.ProviderScores[i].Score.Score.Resolve() if err != nil { panic(utils.LavaFormatError("UpdateReputationQosScore: cannot sort provider scores", err, - utils.LogAttr("provider", stakeProviderScores.providerScores[i].provider), + utils.LogAttr("provider", stakeProviderScores.ProviderScores[i].Provider), utils.LogAttr("chain_id", chainID), utils.LogAttr("cluster", cluster), )) } - jScore, err := stakeProviderScores.providerScores[j].score.Score.Resolve() + jScore, err := stakeProviderScores.ProviderScores[j].Score.Score.Resolve() if err != nil { panic(utils.LavaFormatError("UpdateReputationQosScore: cannot sort provider scores", err, - utils.LogAttr("provider", stakeProviderScores.providerScores[j].provider), + utils.LogAttr("provider", stakeProviderScores.ProviderScores[j].Provider), utils.LogAttr("chain_id", chainID), utils.LogAttr("cluster", cluster), )) } - return iScore.GT(jScore) + // if scores are equal, determine order by address + if iScore.Equal(jScore) { + iProvider := stakeProviderScores.ProviderScores[i].Provider + jProvider := stakeProviderScores.ProviderScores[j].Provider + return iProvider < jProvider + } + + return iScore.LT(jScore) }) } } -// getBenchmarkReputationScore gets the score that will be used as the normalization factor when converting +// GetBenchmarkReputationScore gets the score that will be used as the normalization factor when converting // the provider's QoS score to the reputation pairing score. -// To do that, we go over all the QoS scores of providers that share chain ID and cluster from the highest -// score to the lowest (that input stakeProviderScores are sorted). We aggregate the providers stake until +// To do that, we go over all the QoS scores of providers that share chain ID and cluster from the lowest +// score to the heighest (that input stakeProviderScores are sorted). We aggregate the providers stake until // we pass totalStake * ReputationPairingScoreBenchmarkStakeThreshold (currently equal to 10% of total stake). // Then, we return the last provider's score as the benchmark -func (k Keeper) getBenchmarkReputationScore(stakeProviderScores stakeProviderScores) (math.LegacyDec, error) { - threshold := types.ReputationPairingScoreBenchmarkStakeThreshold.MulInt(stakeProviderScores.totalStake.Amount) +func (k Keeper) GetBenchmarkReputationScore(stakeProviderScores StakeProviderScores) (math.LegacyDec, error) { + threshold := types.ReputationPairingScoreBenchmarkStakeThreshold.MulInt(stakeProviderScores.TotalStake.Amount) aggregatedStake := sdk.ZeroDec() scoreBenchmarkIndex := 0 - for i, providerScore := range stakeProviderScores.providerScores { - aggregatedStake = aggregatedStake.Add(providerScore.stake.Amount.ToLegacyDec()) + for i, providerScore := range stakeProviderScores.ProviderScores { + aggregatedStake = aggregatedStake.Add(providerScore.Stake.Amount.ToLegacyDec()) if aggregatedStake.GTE(threshold) { scoreBenchmarkIndex = i break } } - benchmark, err := stakeProviderScores.providerScores[scoreBenchmarkIndex].score.Score.Resolve() + benchmark, err := stakeProviderScores.ProviderScores[scoreBenchmarkIndex].Score.Score.Resolve() if err != nil { return sdk.ZeroDec(), utils.LavaFormatError("getBenchmarkReputationScore: could not resolve benchmark score", err) } @@ -272,34 +294,55 @@ func (k Keeper) getBenchmarkReputationScore(stakeProviderScores stakeProviderSco return benchmark, nil } -// setReputationPairingScoreByBenchmark sets the reputation pairing score using a benchmark score for all providers with the same chain ID and cluster -// The reputation pairing scores are determined as follows: if the provider's QoS score is larger than the benchmark, it gets the max -// reputation pairing score. If not, it's normalized by the benchmark and scaled to fit the range [MinReputationPairingScore, MaxReputationPairingScore]. -// To scale, we use the following formula: -// scaled_score = min_score + (max_score - min_score) * (score / benchmark) -func (k Keeper) setReputationPairingScoreByBenchmark(ctx sdk.Context, chainID string, cluster string, benchmark math.LegacyDec, scores []providerQosScore) error { +// setReputationPairingScoreByBenchmark sets the reputation pairing score using a benchmark score for all providers +// with the same chain ID and cluster. +// The reputation pairing scores are determined as follows: if the provider's QoS score is smaller than the benchmark, +// it gets the max reputation pairing score. If not, it's normalized by the benchmark and scaled to fit the range +// [MinReputationPairingScore, MaxReputationPairingScore]. Note, smaller scores are better. +// To scale, we use the following formula: scaled_score = min_score + (max_score - min_score) * (benchmark / score) +// We divide (benchmark / score) and not the other way around since we expect that benchmark < score. +func (k Keeper) setReputationPairingScoreByBenchmark(ctx sdk.Context, chainID string, cluster string, benchmark math.LegacyDec, scores []ProviderQosScore) error { + if benchmark.IsNegative() { + return utils.LavaFormatError("setReputationPairingScoreByBenchmark: cannot set reputation pairing score with benchmark", fmt.Errorf("benchmark is negative"), + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("benchmark", benchmark.String()), + ) + } + scale := types.MaxReputationPairingScore.Sub(types.MinReputationPairingScore) for _, providerScore := range scores { - score, err := providerScore.score.Score.Resolve() + score, err := providerScore.Score.Score.Resolve() if err != nil { return utils.LavaFormatError("setReputationPairingScoreByBenchmark: cannot resolve provider score", err, utils.LogAttr("chain_id", chainID), utils.LogAttr("cluster", cluster), - utils.LogAttr("provider", providerScore.provider), + utils.LogAttr("provider", providerScore.Provider), + ) + } + + if score.IsNegative() { + utils.LavaFormatError("setReputationPairingScoreByBenchmark: invalid provider score", fmt.Errorf("score is negative"), + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", providerScore.Provider), + utils.LogAttr("score", score.String()), ) } - scaledScore := types.MaxReputationPairingScore - if score.LT(benchmark) { - scaledScore = types.MinReputationPairingScore.Add(score.Mul(scale)) + scaledScore := types.MinReputationPairingScore + if score.IsZero() { + scaledScore = types.MaxReputationPairingScore + } else if score.GT(benchmark) { + scaledScore = types.MinReputationPairingScore.Add((benchmark.Quo(score)).Mul(scale)) } - err = k.SetReputationScore(ctx, chainID, cluster, providerScore.provider, scaledScore) + err = k.SetReputationScore(ctx, chainID, cluster, providerScore.Provider, scaledScore) if err != nil { return utils.LavaFormatError("setReputationPairingScoreByBenchmark: set reputation pairing score failed", err, utils.LogAttr("chain_id", chainID), utils.LogAttr("cluster", cluster), - utils.LogAttr("provider", providerScore.provider), + utils.LogAttr("provider", providerScore.Provider), ) } } From 7bf01baf9911959c293296b6fb23b72a28fa35fb Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 12 Aug 2024 13:33:21 +0300 Subject: [PATCH 12/33] CNS-1005: partial unit tests --- x/pairing/keeper/helpers_test.go | 32 ++ .../keeper/msg_server_relay_payment_test.go | 327 +++++++++++++++++- 2 files changed, 358 insertions(+), 1 deletion(-) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index f8456cffe1..0782fb01ae 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -7,7 +7,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/v2/testutil/common" testutil "github.com/lavanet/lava/v2/testutil/keeper" + dualstakingtypes "github.com/lavanet/lava/v2/x/dualstaking/types" epochstoragetypes "github.com/lavanet/lava/v2/x/epochstorage/types" + "github.com/lavanet/lava/v2/x/pairing/types" pairingtypes "github.com/lavanet/lava/v2/x/pairing/types" planstypes "github.com/lavanet/lava/v2/x/plans/types" rewardstypes "github.com/lavanet/lava/v2/x/rewards/types" @@ -144,6 +146,36 @@ func (ts *tester) setupForPayments(providersCount, clientsCount, providersToPair return ts } +const ( + GreatQos = iota + GoodQos + BadQos +) + +func (ts *tester) setupForReputation(modifyHalfLifeFactor bool) (*tester, []pairingtypes.QualityOfServiceReport) { + ts.setupForPayments(0, 1, 5) // 0 providers, 1 client, default providers-to-pair + + greatQos := types.QualityOfServiceReport{Latency: sdk.ZeroDec(), Availability: sdk.OneDec(), Sync: sdk.ZeroDec()} + goodQos := types.QualityOfServiceReport{Latency: sdk.NewDec(5), Availability: sdk.OneDec(), Sync: sdk.NewDec(5)} + badQos := types.QualityOfServiceReport{Latency: sdk.NewDec(1000), Availability: sdk.OneDec(), Sync: sdk.NewDec(1000)} + + if modifyHalfLifeFactor { + // set half life factor to be epoch time + resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) + require.NoError(ts.T, err) + resQParams.Params.ReputationHalfLifeFactor = int64(ts.EpochTimeDefault().Seconds()) + ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) + } + + // set min self delegation to zero + resQParams2, err := ts.Keepers.Dualstaking.Params(ts.GoCtx, &dualstakingtypes.QueryParamsRequest{}) + require.NoError(ts.T, err) + resQParams2.Params.MinSelfDelegation = sdk.NewCoin(ts.TokenDenom(), sdk.ZeroInt()) + ts.Keepers.Dualstaking.SetParams(ts.Ctx, resQParams2.Params) + + return ts, []pairingtypes.QualityOfServiceReport{greatQos, goodQos, badQos} +} + // payAndVerifyBalance performs payment and then verifies the balances // (provider balance should increase and consumer should decrease) // The providerRewardPerc arg is the part of the provider reward after dedcuting diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 3d52f85bf1..11a1717f58 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -3,11 +3,13 @@ package keeper_test import ( "testing" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/v2/testutil/common" commonconsts "github.com/lavanet/lava/v2/testutil/common/consts" "github.com/lavanet/lava/v2/utils/lavaslices" "github.com/lavanet/lava/v2/utils/sigs" + "github.com/lavanet/lava/v2/x/pairing/keeper" "github.com/lavanet/lava/v2/x/pairing/types" planstypes "github.com/lavanet/lava/v2/x/plans/types" projectstypes "github.com/lavanet/lava/v2/x/projects/types" @@ -1122,7 +1124,7 @@ func TestUpdateReputationEpochQosScore(t *testing.T) { require.True(t, epochScore1.LT(epochScore2)) // score is lower because QoS is excellent require.True(t, variance1.GT(variance2)) // variance is higher because the QoS is significantly differnet from DefaultQos - entry, found := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, provider1) + entry, found := ts.Keepers.Epochstorage.GetStakeEntryCurrent(ts.Ctx, ts.spec.Index, provider1) require.True(t, found) require.True(t, entry.Stake.IsEqual(r1.Stake)) } @@ -1257,3 +1259,326 @@ func TestUpdateReputationEpochQosScoreRelayNumWeight(t *testing.T) { // require that the score update that was with 1000 relay num is larger than the one with one relay num require.True(t, scoreUpdates[0].GT(scoreUpdates[1])) } + +// TestUpdateReputationScores tests that on epoch start: score is modified, epoch score is zeroed time last +// updated is modified, and reputation stake changed to current stake. We do this with the following scenario: +// 1. we set half life factor to be one epoch time +// 2. we set a provider with default QoS score, let him send a relay and advance epoch +// 3. we check expected result +func TestReputationUpdateOnEpochStart(t *testing.T) { + ts := newTester(t) + ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + _, provider1 := ts.GetAccount(common.PROVIDER, 0) + qos := &types.QualityOfServiceReport{ + Latency: sdk.NewDec(1000), + Availability: sdk.OneDec(), + Sync: sdk.NewDec(1000), + } + + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + // set half life factor to be epoch time + resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) + require.NoError(t, err) + resQParams.Params.ReputationHalfLifeFactor = int64(ts.EpochTimeDefault().Seconds()) + ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) + + // set default reputation and keep some properties for future comparison + ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider1, types.NewReputation(ts.Ctx)) + creationTime := ts.BlockTime().UTC().Unix() + entry, found := ts.Keepers.Epochstorage.GetStakeEntryCurrent(ts.Ctx, ts.spec.Index, provider1) + require.True(t, found) + stake := sdk.NewCoin(entry.Stake.Denom, entry.EffectiveStake().AddRaw(1)) + + // stake some more coins and advance epoch + err = ts.StakeProvider(entry.Vault, entry.Address, ts.spec, entry.EffectiveStake().Int64()) + require.NoError(t, err) + ts.AdvanceEpoch() + + // send relay payment msg from provider1 + relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), 10) + relaySession.QosExcellenceReport = qos + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: provider1, + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + + // advance epoch and check reputation for expected results + ts.AdvanceEpoch() + reputation, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) + require.True(t, found) + require.False(t, reputation.Score.Equal(types.ZeroQosScore)) + require.True(t, reputation.EpochScore.Equal(types.ZeroQosScore)) + require.Equal(t, ts.BlockTime().UTC().Unix(), reputation.TimeLastUpdated) + require.Equal(t, creationTime, reputation.CreationTime) + require.NotEqual(t, reputation.CreationTime, reputation.TimeLastUpdated) + + entry, found = ts.Keepers.Epochstorage.GetStakeEntryCurrent(ts.Ctx, ts.spec.Index, provider1) + require.True(t, found) + stakeAfterUpdate := sdk.NewCoin(entry.Stake.Denom, entry.EffectiveStake()) + + require.False(t, stakeAfterUpdate.IsEqual(stake)) + require.True(t, reputation.Stake.IsEqual(stakeAfterUpdate)) +} + +// TestUpdateReputationScoresMap checks that after calling UpdateReputationsForEpochStart() we get a sorted (by QoS score) +// map[chain+cluster]stakeProviderScores in ascending order. We do this with the following scenario: +// 1. have 4 providers: 2 on chain "mockspec", 3 on chain "mockspec1" (one provider is staked on both) +// 2. let the providers have different reputation scores and different stakes and call updateReputationsScores() +// 3. expect to see two map keys (for the two chains) and a list of providers in ascending order by QoS score +func TestUpdateReputationScoresSortedMap(t *testing.T) { + ts := newTester(t) + + // create provider addresses + _, p1 := ts.AddAccount(common.PROVIDER, 0, testStake) + _, p2 := ts.AddAccount(common.PROVIDER, 1, testStake) + _, p3 := ts.AddAccount(common.PROVIDER, 2, testStake) + _, p4 := ts.AddAccount(common.PROVIDER, 3, testStake) + + // set reputations like described above + providers := []string{p1, p2, p1, p3, p4} // p1 will be "staked" on two chains + specs := []string{"mockspec", "mockspec", "mockspec1", "mockspec1", "mockspec1"} + stakes := []math.Int{sdk.NewInt(1), sdk.NewInt(2), sdk.NewInt(3), sdk.NewInt(4), sdk.NewInt(5)} + zeroFrac := types.Frac{Num: sdk.ZeroDec(), Denom: sdk.MaxSortableDec} + epochScores := []types.QosScore{ + {Score: types.Frac{Num: sdk.NewDec(6), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, // score = 2 + {Score: types.Frac{Num: sdk.NewDec(9), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, // score = 3 + {Score: types.Frac{Num: sdk.NewDec(3), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, // score = 1 + {Score: types.Frac{Num: sdk.NewDec(12), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, // score = 4 + {Score: types.Frac{Num: sdk.NewDec(9), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, // score = 3 + } + for i := range providers { + reputation := types.NewReputation(ts.Ctx) + reputation.EpochScore = epochScores[i] + reputation.Score = types.ZeroQosScore + reputation.Stake = sdk.NewCoin(ts.TokenDenom(), stakes[i]) + ts.Keepers.Pairing.SetReputation(ts.Ctx, specs[i], "cluster", providers[i], reputation) + } + + // create expected map (supposed to be sorted by score) + expected := map[string]keeper.StakeProviderScores{ + "mockspec cluster": { + TotalStake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(3)), // 1+2 + ProviderScores: []keeper.ProviderQosScore{ + { + Provider: p1, + Score: types.QosScore{Score: types.Frac{Num: sdk.NewDec(6), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, + Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1)), + }, + { + Provider: p2, + Score: types.QosScore{Score: types.Frac{Num: sdk.NewDec(9), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, + Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(2)), + }, + }, + }, + + "mockspec1 cluster": { + TotalStake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(12)), // 3+4+5 + ProviderScores: []keeper.ProviderQosScore{ + { + Provider: p1, + Score: types.QosScore{Score: types.Frac{Num: sdk.NewDec(3), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, + Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(3)), + }, + { + Provider: p4, + Score: types.QosScore{Score: types.Frac{Num: sdk.NewDec(9), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, + Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(5)), + }, + { + Provider: p3, + Score: types.QosScore{Score: types.Frac{Num: sdk.NewDec(12), Denom: sdk.NewDec(3)}, Variance: zeroFrac}, + Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(4)), + }, + }, + }, + } + + // call UpdateReputationsForEpochStart() and check the scores map + scores, err := ts.Keepers.Pairing.UpdateReputationsForEpochStart(ts.Ctx) + require.NoError(t, err) + + for chainCluster, stakeProviderScores := range scores { + expectedScores := expected[chainCluster] + require.True(t, expectedScores.TotalStake.IsEqual(stakeProviderScores.TotalStake)) + for i := range stakeProviderScores.ProviderScores { + require.Equal(t, expectedScores.ProviderScores[i].Provider, stakeProviderScores.ProviderScores[i].Provider) + require.True(t, expectedScores.ProviderScores[i].Stake.IsEqual(stakeProviderScores.ProviderScores[i].Stake)) + + expectedScore, err := expectedScores.ProviderScores[i].Score.Score.Resolve() + require.NoError(t, err) + score, err := stakeProviderScores.ProviderScores[i].Score.Score.Resolve() + require.NoError(t, err) + require.True(t, expectedScore.RoundInt().Equal(score.RoundInt())) + } + } +} + +// TestReputationPairingScoreBenchmark tests that the benchmark value after calling getBenchmarkReputationScore() +// is the score of the last provider we iterate on when aggregating stake to pass ReputationPairingScoreBenchmarkStakeThreshold. +// +// We do this with the following scenario: +// 1. have 5 providers with varying stakes -> providers with 10% of stake should have max scores, the others should have +// pairing scores that differ by their QoS scores difference +func TestReputationPairingScoreBenchmark(t *testing.T) { + ts := newTester(t) + totalStake := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1000)) // threshold for benchmark will be 100ulava + + // create provider addresses + _, p1 := ts.AddAccount(common.PROVIDER, 0, testStake) + _, p2 := ts.AddAccount(common.PROVIDER, 1, testStake) + _, p3 := ts.AddAccount(common.PROVIDER, 2, testStake) + _, p4 := ts.AddAccount(common.PROVIDER, 3, testStake) + _, p5 := ts.AddAccount(common.PROVIDER, 4, testStake) + + qosScores := createQosScoresForBenchmarkTest() + + // create a StakeProviderScores object with ProviderScores list which is descending by score + sps := keeper.StakeProviderScores{ + TotalStake: totalStake, + ProviderScores: []keeper.ProviderQosScore{ + {Provider: p1, Score: qosScores[0], Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1))}, + {Provider: p2, Score: qosScores[1], Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(19))}, + {Provider: p3, Score: qosScores[2], Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(40))}, + {Provider: p4, Score: qosScores[3], Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(60))}, + {Provider: p5, Score: qosScores[4], Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1000))}, + }, + } + + // the benchmark should be equal to qosScores[3] since p4 is the last provider on which the + // stake aggregation should complete (1+19+40+60=100) + benchmark, err := ts.Keepers.Pairing.GetBenchmarkReputationScore(sps) + require.NoError(t, err) + expectedBenchmark, err := qosScores[3].Score.Resolve() + require.NoError(t, err) + require.True(t, benchmark.Equal(expectedBenchmark)) +} + +// createQosScoresForBenchmarkTest is a helper function to create an array of QoS scores +func createQosScoresForBenchmarkTest() []types.QosScore { + nums := []math.LegacyDec{sdk.NewDec(1000), sdk.NewDec(100), sdk.NewDec(90), sdk.NewDec(40), sdk.NewDec(10)} + zeroFrac := types.Frac{Num: sdk.ZeroDec(), Denom: sdk.MaxSortableDec} + qosScores := []types.QosScore{} + for _, num := range nums { + scoreFrac, err := types.NewFrac(num, sdk.OneDec()) + if err != nil { + panic(err) + } + qs := types.NewQosScore(scoreFrac, zeroFrac) + qosScores = append(qosScores, qs) + } + return qosScores +} + +// TestReputationPairingScore tests that on epoch start: +// 1. The reputation pairing score is set. +// 2. Providers that didn't send relays get the default reputation pairing score. +// 2. If a provider has a bad QoS report, it yields a bad reputation pairing score. +// We test it by having 4 providers: +// +// p1: high stake and great QoS (will be used as benchmark), +// p2: low stake and good QoS score +// p3: same low stake and bad QoS score +// p4: high stake that doesn't send relays. +// +// We check that all 4 have reputation pairing score: p1 with max score, p2 with better score than p3, p4 +// has no reputation pairing score. +func TestReputationPairingScore(t *testing.T) { + ts := newTester(t) + ts, reports := ts.setupForReputation(false) + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + minStake := ts.spec.MinStakeProvider.Amount.Int64() + stakes := []int64{minStake * 5, minStake + 10, minStake + 10, minStake * 2} + providers := []string{} + for i := 0; i < 4; i++ { + _, provider := ts.AddAccount(common.PROVIDER, i, testBalance) + providers = append(providers, provider) + } + for i := 0; i < 4; i++ { + // create providers + err = ts.StakeProvider(providers[i], providers[i], ts.spec, stakes[i]) + require.NoError(t, err) + ts.AdvanceEpoch() + + // send relays (except for last one) + if i < 3 { + relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) + relaySession.QosExcellenceReport = &reports[i] + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: providers[i], + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + } + } + + // advance epoch to update pairing scores + ts.AdvanceEpoch() + + // check results + pairingScores := []math.LegacyDec{} + for i := range providers { + score, found := ts.Keepers.Pairing.GetReputationScore(ts.Ctx, ts.spec.Index, cluster, providers[i]) + if i < 3 { + require.True(t, found) + pairingScores = append(pairingScores, score) + } else { + require.False(t, found) + } + } + require.True(t, pairingScores[0].Equal(types.MaxReputationPairingScore)) + require.True(t, pairingScores[1].GT(pairingScores[2])) +} + +// TestReputationPairingScoreWithinRange tests that the reputation pairing score is always between +// MinReputationPairingScore and MaxReputationPairingScore. +// We test it by setting two providers with extreme QoS reports: one very good, and one very bad. +// We expect that both pairing scores will be in the expected range. +func TestReputationPairingScoreWithinRange(t *testing.T) { + +} + +// TestReputationPairingScoreZeroQosScores tests that if all providers have a QoS score of zero, +// they all get the max reputation pairing score. +// We test it by having two providers with zero QoS score. We expect that both will have max reputation +// pairing score. +func TestReputationPairingScoreZeroQosScores(t *testing.T) { + +} + +// TestReputationPairingScoreFixation tests that the reputation pairing score is saved in a fixation store +// and can be fetched using a block argument. +// We test this by making two providers, one with high stake and great QoS score and one with low stake and +// bad QoS score. We get the bad provider pairing score and send another relay with a slightly improved QoS +// score. We expect that fetching the pairing score from the past will be lower than the current one +func TestReputationPairingScoreFixation(t *testing.T) { + +} + +// TestReputationPairingScoreStakeAggregation tests that the benchmark is determined by stake. We test the following +// scenarios: +// 1. Have 2 providers with equal stake -> pairing scores should differ by their QoS scores difference +// 2. Have 2 providers one with high score and low stake, the other with low score and high stake -> both should get max +// pairing score +func TestReputationPairingScoreStakeAggregation(t *testing.T) { + +} From 1215c13576d4427393bd0fc4d34f54dcce704063 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 12 Aug 2024 18:02:57 +0300 Subject: [PATCH 13/33] CNS-1005: unit tests --- x/pairing/keeper/helpers_test.go | 4 +- .../keeper/msg_server_relay_payment_test.go | 279 +++++++++++++++++- x/pairing/keeper/reputation.go | 2 +- 3 files changed, 269 insertions(+), 16 deletions(-) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 0782fb01ae..f42c97d257 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -155,8 +155,8 @@ const ( func (ts *tester) setupForReputation(modifyHalfLifeFactor bool) (*tester, []pairingtypes.QualityOfServiceReport) { ts.setupForPayments(0, 1, 5) // 0 providers, 1 client, default providers-to-pair - greatQos := types.QualityOfServiceReport{Latency: sdk.ZeroDec(), Availability: sdk.OneDec(), Sync: sdk.ZeroDec()} - goodQos := types.QualityOfServiceReport{Latency: sdk.NewDec(5), Availability: sdk.OneDec(), Sync: sdk.NewDec(5)} + greatQos := types.QualityOfServiceReport{Latency: sdk.OneDec(), Availability: sdk.OneDec(), Sync: sdk.OneDec()} + goodQos := types.QualityOfServiceReport{Latency: sdk.NewDec(3), Availability: sdk.OneDec(), Sync: sdk.NewDec(3)} badQos := types.QualityOfServiceReport{Latency: sdk.NewDec(1000), Availability: sdk.OneDec(), Sync: sdk.NewDec(1000)} if modifyHalfLifeFactor { diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 11a1717f58..716254ff0c 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1513,22 +1513,23 @@ func TestReputationPairingScore(t *testing.T) { // create providers err = ts.StakeProvider(providers[i], providers[i], ts.spec, stakes[i]) require.NoError(t, err) - ts.AdvanceEpoch() + } + // advance epoch to apply pairing + ts.AdvanceEpoch() - // send relays (except for last one) - if i < 3 { - relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) - relaySession.QosExcellenceReport = &reports[i] - sig, err := sigs.Sign(consumerAcc.SK, *relaySession) - require.NoError(t, err) - relaySession.Sig = sig + // send relays (except for last one) + for i := 0; i < 3; i++ { + relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) + relaySession.QosExcellenceReport = &reports[i] + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig - payment := types.MsgRelayPayment{ - Creator: providers[i], - Relays: []*types.RelaySession{relaySession}, - } - ts.relayPaymentWithoutPay(payment, true) + payment := types.MsgRelayPayment{ + Creator: providers[i], + Relays: []*types.RelaySession{relaySession}, } + ts.relayPaymentWithoutPay(payment, true) } // advance epoch to update pairing scores @@ -1554,7 +1555,62 @@ func TestReputationPairingScore(t *testing.T) { // We test it by setting two providers with extreme QoS reports: one very good, and one very bad. // We expect that both pairing scores will be in the expected range. func TestReputationPairingScoreWithinRange(t *testing.T) { + ts := newTester(t) + ts, reports := ts.setupForReputation(false) + + greatQos := reports[GreatQos] + badQos := reports[BadQos] + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + providers := []string{} + for i := 0; i < 2; i++ { + _, provider := ts.AddAccount(common.PROVIDER, i, testBalance) + providers = append(providers, provider) + } + + minStake := ts.spec.MinStakeProvider.Amount.Int64() + for i := 0; i < 2; i++ { + // create providers + err = ts.StakeProvider(providers[i], providers[i], ts.spec, minStake) + require.NoError(t, err) + } + // advance epoch to apply pairing + ts.AdvanceEpoch() + + // send relays + for i := 0; i < 2; i++ { + relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) + report := greatQos + if i == 0 { + report = badQos + } + relaySession.QosExcellenceReport = &report + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: providers[i], + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + } + + // advance epoch to update pairing scores + ts.AdvanceEpoch() + // check results are withing the expected range + for i := range providers { + score, found := ts.Keepers.Pairing.GetReputationScore(ts.Ctx, ts.spec.Index, cluster, providers[i]) + require.True(t, found) + if score.LT(types.MinReputationPairingScore) || score.GT(types.MaxReputationPairingScore) { + require.FailNow(t, "score is not within expected pairing score range") + } + } } // TestReputationPairingScoreZeroQosScores tests that if all providers have a QoS score of zero, @@ -1562,7 +1618,58 @@ func TestReputationPairingScoreWithinRange(t *testing.T) { // We test it by having two providers with zero QoS score. We expect that both will have max reputation // pairing score. func TestReputationPairingScoreZeroQosScores(t *testing.T) { + ts := newTester(t) + ts, _ = ts.setupForReputation(false) + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + providers := []string{} + for i := 0; i < 2; i++ { + _, provider := ts.AddAccount(common.PROVIDER, i, testBalance) + providers = append(providers, provider) + } + minStake := ts.spec.MinStakeProvider.Amount.Int64() + for i := 0; i < 2; i++ { + // create providers + err = ts.StakeProvider(providers[i], providers[i], ts.spec, minStake) + require.NoError(t, err) + } + // advance epoch to apply pairing + ts.AdvanceEpoch() + + // send relays + for i := 0; i < 2; i++ { + relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) + perfectQosReport := types.QualityOfServiceReport{ + Latency: sdk.ZeroDec(), + Availability: sdk.OneDec(), + Sync: sdk.ZeroDec(), + } + relaySession.QosExcellenceReport = &perfectQosReport + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: providers[i], + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + } + + // advance epoch to update pairing scores + ts.AdvanceEpoch() + + // check results are max pairing score + for i := range providers { + score, found := ts.Keepers.Pairing.GetReputationScore(ts.Ctx, ts.spec.Index, cluster, providers[i]) + require.True(t, found) + require.True(t, score.Equal(types.MaxReputationPairingScore)) + } } // TestReputationPairingScoreFixation tests that the reputation pairing score is saved in a fixation store @@ -1571,7 +1678,82 @@ func TestReputationPairingScoreZeroQosScores(t *testing.T) { // bad QoS score. We get the bad provider pairing score and send another relay with a slightly improved QoS // score. We expect that fetching the pairing score from the past will be lower than the current one func TestReputationPairingScoreFixation(t *testing.T) { + ts := newTester(t) + ts, reports := ts.setupForReputation(false) + + greatQos := reports[GreatQos] + goodQos := reports[GoodQos] + badQos := reports[BadQos] + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + providers := []string{} + for i := 0; i < 2; i++ { + _, provider := ts.AddAccount(common.PROVIDER, i, testBalance) + providers = append(providers, provider) + } + + minStake := ts.spec.MinStakeProvider.Amount.Int64() + for i := 0; i < 2; i++ { + // create providers + err = ts.StakeProvider(providers[i], providers[i], ts.spec, minStake) + require.NoError(t, err) + } + // advance epoch to apply pairing + ts.AdvanceEpoch() + // send relays + for i := 0; i < 2; i++ { + relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) + + if i == 0 { + relaySession.QosExcellenceReport = &greatQos + } else { + relaySession.QosExcellenceReport = &badQos + } + + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: providers[i], + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + } + + // advance epoch to update pairing scores + ts.AdvanceEpoch() + badQosBlock := ts.BlockHeight() + + // send another relay with provider1 with a better QoS report + relaySession := ts.newRelaySession(providers[1], 0, 100, ts.BlockHeight(), 10) + relaySession.QosExcellenceReport = &goodQos + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + + payment := types.MsgRelayPayment{ + Creator: providers[1], + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + + // advance epoch to update pairing scores + ts.AdvanceEpoch() + goodQosBlock := ts.BlockHeight() + + // fetch pairing score for both badQosBlock and goodQosBlock + // verify that the pairing score changes for the better + badQosPairingScore, _, found := ts.Keepers.Pairing.GetReputationScoreForBlock(ts.Ctx, ts.spec.Index, cluster, providers[1], badQosBlock) + require.True(t, found) + goodQosPairingScore, _, found := ts.Keepers.Pairing.GetReputationScoreForBlock(ts.Ctx, ts.spec.Index, cluster, providers[1], goodQosBlock) + require.True(t, found) + require.True(t, goodQosPairingScore.GT(badQosPairingScore)) } // TestReputationPairingScoreStakeAggregation tests that the benchmark is determined by stake. We test the following @@ -1580,5 +1762,76 @@ func TestReputationPairingScoreFixation(t *testing.T) { // 2. Have 2 providers one with high score and low stake, the other with low score and high stake -> both should get max // pairing score func TestReputationPairingScoreStakeAggregation(t *testing.T) { + ts := newTester(t) + ts, reports := ts.setupForReputation(false) + + greatQos := reports[GreatQos] + goodQos := reports[GoodQos] + badQos := reports[BadQos] + + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster := resQCurrent.Sub.Cluster + + providers := []string{} + for i := 0; i < 2; i++ { + _, provider := ts.AddAccount(common.PROVIDER, i, testBalance) + providers = append(providers, provider) + } + minStake := ts.spec.MinStakeProvider.Amount.Int64() + + tests := []struct { + name string + stakes []int64 + reports []types.QualityOfServiceReport + differentScores bool + }{ + {"equal stake, different QoS", []int64{minStake, minStake}, []types.QualityOfServiceReport{goodQos, badQos}, true}, + {"high score + low stake, low score + high stake", []int64{minStake, minStake * 20}, []types.QualityOfServiceReport{greatQos, badQos}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i := 0; i < 2; i++ { + // create providers + err = ts.StakeProvider(providers[i], providers[i], ts.spec, tt.stakes[i]) + require.NoError(t, err) + } + // advance epoch to apply pairing + ts.AdvanceEpoch() + + // send relays + for i := 0; i < 2; i++ { + relaySession := ts.newRelaySession(providers[i], 0, 100, ts.BlockHeight(), 10) + relaySession.QosExcellenceReport = &tt.reports[i] + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + payment := types.MsgRelayPayment{ + Creator: providers[i], + Relays: []*types.RelaySession{relaySession}, + } + ts.relayPaymentWithoutPay(payment, true) + } + + // advance epoch to update pairing scores + ts.AdvanceEpoch() + + // get pairing scores and check results + pairingScores := []math.LegacyDec{} + for i := range providers { + score, found := ts.Keepers.Pairing.GetReputationScore(ts.Ctx, ts.spec.Index, cluster, providers[i]) + require.True(t, found) + pairingScores = append(pairingScores, score) + } + + if tt.differentScores { + require.True(t, pairingScores[0].GT(pairingScores[1])) + } else { + require.True(t, pairingScores[0].Equal(pairingScores[1])) + require.True(t, pairingScores[0].Equal(types.MaxReputationPairingScore)) + } + }) + } } diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index a0d0146eb9..ac79aff5f9 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -331,7 +331,7 @@ func (k Keeper) setReputationPairingScoreByBenchmark(ctx sdk.Context, chainID st } scaledScore := types.MinReputationPairingScore - if score.IsZero() { + if score.IsZero() || score.LTE(benchmark) { scaledScore = types.MaxReputationPairingScore } else if score.GT(benchmark) { scaledScore = types.MinReputationPairingScore.Add((benchmark.Quo(score)).Mul(scale)) From 994e762331f8196bf3e3f3d8cfdbbd817f8e72c5 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 13 Aug 2024 11:18:26 +0300 Subject: [PATCH 14/33] CNS-1004: minor adds --- x/pairing/keeper/msg_server_relay_payment.go | 2 +- x/pairing/types/qos_score.go | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 44d6daa29e..c36f6741cf 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -198,7 +198,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen ) } - stakeEntry, found := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, relay.SpecId, relay.Provider) + stakeEntry, found := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, relay.SpecId, relay.Provider) if !found { return nil, utils.LavaFormatWarning("RelayPayment: could not get stake entry for reputation", fmt.Errorf("stake entry not found"), utils.LogAttr("consumer", clientAddr), diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index 68a77bd379..746ee1ecfb 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -45,6 +45,15 @@ func (qs QosScore) Equal(other QosScore) bool { return qs.Score.Equal(other.Score) && qs.Variance.Equal(other.Variance) } +// Validate validates that both nums are non-negative and both denoms are strictly positive (non-zero) +func (qs QosScore) Validate() bool { + if qs.Score.Num.IsNegative() || !qs.Score.Denom.IsPositive() || qs.Variance.Num.IsNegative() || + !qs.Variance.Denom.IsPositive() { + return false + } + return true +} + // Update updates a QosScore with a new score from the QoS excellence report. The new score is truncated by the // current variance. Then, it's updated using the weight (which is currently the relay num) func (qs QosScore) Update(score math.LegacyDec, truncate bool, weight int64) QosScore { From a160860a3a1f49cff8ff3067ce18385fcce1e220 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 15 Aug 2024 14:31:53 +0300 Subject: [PATCH 15/33] CNS-1006: impelemnted queries and partial unit test --- proto/lavanet/lava/pairing/query.proto | 52 +- scripts/test/cli_test.sh | 2 + testutil/common/tester.go | 20 + x/pairing/client/cli/query.go | 2 + .../client/cli/query_provider_reputation.go | 65 + .../cli/query_provider_reputation_details.go | 65 + .../keeper/grpc_query_provider_reputation.go | 109 + .../grpc_query_provider_reputation_details.go | 46 + .../grpc_query_provider_reputation_test.go | 65 + x/pairing/types/query.pb.go | 2208 +++++++++++++++-- x/pairing/types/query.pb.gw.go | 290 +++ x/pairing/types/relay.pb.go | 9 +- 12 files changed, 2659 insertions(+), 274 deletions(-) create mode 100644 x/pairing/client/cli/query_provider_reputation.go create mode 100644 x/pairing/client/cli/query_provider_reputation_details.go create mode 100644 x/pairing/keeper/grpc_query_provider_reputation.go create mode 100644 x/pairing/keeper/grpc_query_provider_reputation_details.go create mode 100644 x/pairing/keeper/grpc_query_provider_reputation_test.go diff --git a/proto/lavanet/lava/pairing/query.proto b/proto/lavanet/lava/pairing/query.proto index 5e74149ae5..d172262ddb 100644 --- a/proto/lavanet/lava/pairing/query.proto +++ b/proto/lavanet/lava/pairing/query.proto @@ -5,6 +5,7 @@ import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; import "lavanet/lava/pairing/params.proto"; +import "lavanet/lava/pairing/reputation.proto"; import "lavanet/lava/spec/spec.proto"; @@ -80,9 +81,19 @@ service Query { } // Queries a for the aggregated CU of all ProviderEpochCu objects all the providers. -rpc ProvidersEpochCu(QueryProvidersEpochCuRequest) returns (QueryProvidersEpochCuResponse) { - option (google.api.http).get = "/lavanet/lava/pairing/providers_epoch_cu"; -} + rpc ProvidersEpochCu(QueryProvidersEpochCuRequest) returns (QueryProvidersEpochCuResponse) { + option (google.api.http).get = "/lavanet/lava/pairing/providers_epoch_cu"; + } + +// Queries a for a provider reputation. + rpc ProviderReputation(QueryProviderReputationRequest) returns (QueryProviderReputationResponse) { + option (google.api.http).get = "/lavanet/lava/pairing/provider_reputation/{address}/{chainID}/{cluster}"; + } + +// Queries a for a provider reputation's details (mainly for developers). + rpc ProviderReputationDetails(QueryProviderReputationDetailsRequest) returns (QueryProviderReputationDetailsResponse) { + option (google.api.http).get = "/lavanet/lava/pairing/provider_reputation_details/{address}/{chainID}/{cluster}"; + } // this line is used by starport scaffolding # 2 @@ -238,4 +249,39 @@ message QueryProvidersEpochCuResponse { message ProviderCuInfo { string provider = 1; uint64 cu = 2; +} + +message QueryProviderReputationRequest { + string address = 1; + string chainID = 2; + string cluster = 3; +} + +message ReputationData { + uint64 rank = 1; // rank compared to other providers + uint64 providers = 2; // amount of providers with the same chainID+cluster + string overall_performance = 3; // overall performance metric which can be "good", "bad", or "not enough data" + string chainID = 4; + string cluster = 5; +} + +message QueryProviderReputationResponse { + repeated ReputationData data = 1 [(gogoproto.nullable) = false]; +} + +message QueryProviderReputationDetailsRequest { + string address = 1; + string chainID = 2; + string cluster = 3; +} + +message ReputationDevData { + Reputation reputation = 1 [(gogoproto.nullable) = false]; + ReputationPairingScore reputation_pairing_score = 2 [(gogoproto.nullable) = false]; + string chainID = 4; + string cluster = 5; +} + +message QueryProviderReputationDetailsResponse { + repeated ReputationDevData data = 1 [(gogoproto.nullable) = false]; } \ No newline at end of file diff --git a/scripts/test/cli_test.sh b/scripts/test/cli_test.sh index 90d59fbb18..5fc6c7ce00 100755 --- a/scripts/test/cli_test.sh +++ b/scripts/test/cli_test.sh @@ -156,6 +156,8 @@ trace lavad q pairing static-providers-list LAV1 >/dev/null trace lavad q pairing user-entry $(lavad keys show alice -a) ETH1 20 >/dev/null trace lavad q pairing verify-pairing STRK $(lavad keys show alice -a) $(lavad keys show alice -a) 60 >/dev/null trace lavad q pairing provider-pairing-chance $(lavad keys show servicer1 -a) STRK 1 "" >/dev/null +trace lavad q pairing provider-reputation $(lavad keys show servicer1 -a) ETH1 free >/dev/null +trace lavad q pairing provider-reputation-details $(lavad keys show servicer1 -a) ETH1 free >/dev/null echo "Testing dualstaking tx commands" wait_count_blocks 1 >/dev/null diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 3e7bad4d67..bb1ba1ea69 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -877,6 +877,26 @@ func (ts *Tester) QueryPairingProviderEpochCu(provider string, project string, c return ts.Keepers.Pairing.ProvidersEpochCu(ts.GoCtx, msg) } +// QueryPairingProviderReputation implements 'q pairing provider-reputation' +func (ts *Tester) QueryPairingProviderReputation(provider string, chainID string, cluster string) (*pairingtypes.QueryProviderReputationResponse, error) { + msg := &pairingtypes.QueryProviderReputationRequest{ + Address: provider, + ChainID: chainID, + Cluster: cluster, + } + return ts.Keepers.Pairing.ProviderReputation(ts.GoCtx, msg) +} + +// QueryPairingProviderReputationDetails implements 'q pairing provider-reputation-details' +func (ts *Tester) QueryPairingProviderReputationDetails(provider string, chainID string, cluster string) (*pairingtypes.QueryProviderReputationDetailsResponse, error) { + msg := &pairingtypes.QueryProviderReputationDetailsRequest{ + Address: provider, + ChainID: chainID, + Cluster: cluster, + } + return ts.Keepers.Pairing.ProviderReputationDetails(ts.GoCtx, msg) +} + // QueryPairingSubscriptionMonthlyPayout implements 'q pairing subscription-monthly-payout' func (ts *Tester) QueryPairingSubscriptionMonthlyPayout(consumer string) (*pairingtypes.QuerySubscriptionMonthlyPayoutResponse, error) { msg := &pairingtypes.QuerySubscriptionMonthlyPayoutRequest{ diff --git a/x/pairing/client/cli/query.go b/x/pairing/client/cli/query.go index b8ec234478..5926604104 100644 --- a/x/pairing/client/cli/query.go +++ b/x/pairing/client/cli/query.go @@ -41,6 +41,8 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdSubscriptionMonthlyPayout()) cmd.AddCommand(CmdProvidersEpochCu()) + cmd.AddCommand(CmdProviderReputation()) + cmd.AddCommand(CmdProviderReputationDetails()) cmd.AddCommand(CmdDebugQuery()) diff --git a/x/pairing/client/cli/query_provider_reputation.go b/x/pairing/client/cli/query_provider_reputation.go new file mode 100644 index 0000000000..020e112780 --- /dev/null +++ b/x/pairing/client/cli/query_provider_reputation.go @@ -0,0 +1,65 @@ +package cli + +import ( + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/lavanet/lava/v2/utils" + "github.com/lavanet/lava/v2/x/pairing/types" + "github.com/spf13/cobra" +) + +var _ = strconv.Itoa(0) + +func CmdProviderReputation() *cobra.Command { + cmd := &cobra.Command{ + Use: "provider-reputation [address] [chain-id] [cluster]", + Short: "Query for a provider's reputation. Use \"*\" for specify all for chain/cluster.", + Args: cobra.ExactArgs(3), + Example: ` + Reputation of alice for chain ETH1 and the cluster "free": + lavad q pairing provider-reputation alice ETH1 free + + Reputation of alice for all chains and the cluster "free": + lavad q pairing provider-reputation alice * free + + Reputation of alice for ETH1 and for all clusters: + lavad q pairing provider-reputation alice ETH1 * + + Reputation of alice for all chains and for all clusters: + lavad q pairing provider-reputation alice * *`, + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + address, err := utils.ParseCLIAddress(clientCtx, args[0]) + if err != nil { + return err + } + chainID := args[1] + cluster := args[2] + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryProviderReputationRequest{ + Address: address, + ChainID: chainID, + Cluster: cluster, + } + + res, err := queryClient.ProviderReputation(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/pairing/client/cli/query_provider_reputation_details.go b/x/pairing/client/cli/query_provider_reputation_details.go new file mode 100644 index 0000000000..2f2a2240a8 --- /dev/null +++ b/x/pairing/client/cli/query_provider_reputation_details.go @@ -0,0 +1,65 @@ +package cli + +import ( + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/lavanet/lava/v2/utils" + "github.com/lavanet/lava/v2/x/pairing/types" + "github.com/spf13/cobra" +) + +var _ = strconv.Itoa(0) + +func CmdProviderReputationDetails() *cobra.Command { + cmd := &cobra.Command{ + Use: "provider-reputation [address] [chain-id] [cluster]", + Short: "Query for a provider's reputation details. Mainly used by developers. Use \"*\" for specify all for chain/cluster.", + Args: cobra.ExactArgs(3), + Example: ` + Reputation details of alice for chain ETH1 and the cluster "free": + lavad q pairing provider-reputation-details alice ETH1 free + + Reputation details of alice for all chains and the cluster "free": + lavad q pairing provider-reputation-details alice * free + + Reputation details of alice for ETH1 and for all clusters: + lavad q pairing provider-reputation-details alice ETH1 * + + Reputation details of alice for all chains and for all clusters: + lavad q pairing provider-reputation-details alice * *`, + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + address, err := utils.ParseCLIAddress(clientCtx, args[0]) + if err != nil { + return err + } + chainID := args[1] + cluster := args[2] + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryProviderReputationDetailsRequest{ + Address: address, + ChainID: chainID, + Cluster: cluster, + } + + res, err := queryClient.ProviderReputationDetails(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/pairing/keeper/grpc_query_provider_reputation.go b/x/pairing/keeper/grpc_query_provider_reputation.go new file mode 100644 index 0000000000..e11b07ce26 --- /dev/null +++ b/x/pairing/keeper/grpc_query_provider_reputation.go @@ -0,0 +1,109 @@ +package keeper + +import ( + "context" + "fmt" + "sort" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/v2/utils" + "github.com/lavanet/lava/v2/utils/lavaslices" + "github.com/lavanet/lava/v2/x/pairing/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + varianceThreshold = float64(1) + goodScore = "good" + badScore = "bad" + lowVariance = "low variance" +) + +func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProviderReputationRequest) (*types.QueryProviderReputationResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + chains := []string{req.ChainID} + if req.ChainID == "*" { + chains = k.specKeeper.GetAllChainIDs(ctx) + } + + clusters := []string{req.Cluster} + if req.Cluster == "*" { + clusters = k.subscriptionKeeper.GetAllClusters(ctx) + } + + // get all the reputation scores of the requested provider and gather valid chainID+cluster pairs + type chainClusterScore struct { + chainID string + cluster string + score math.LegacyDec + } + requestedProviderData := []chainClusterScore{} + for _, chainID := range chains { + for _, cluster := range clusters { + score, found := k.GetReputationScore(ctx, chainID, cluster, req.Address) + if !found { + continue + } + requestedProviderData = append(requestedProviderData, chainClusterScore{chainID: chainID, cluster: cluster, score: score}) + } + } + + // get scores from other providers for the relevant chains and clusters + res := []types.ReputationData{} + for _, data := range requestedProviderData { + chainClusterRes := types.ReputationData{ChainID: data.chainID, Cluster: data.cluster} + + // get all reputation pairing score indices for a chainID+cluster pair + inds := k.reputationsFS.GetAllEntryIndicesWithPrefix(ctx, types.ReputationScoreKey(data.chainID, data.cluster, "")) + + // collect all pairing scores with indices and sort + pairingScores := []float64{} + for _, ind := range inds { + var score types.ReputationPairingScore + found := k.reputationsFS.FindEntry(ctx, ind, uint64(ctx.BlockHeight()), &score) + if !found { + return nil, utils.LavaFormatError("invalid reputationFS state", fmt.Errorf("reputation pairing score not found"), + utils.LogAttr("index", ind), + utils.LogAttr("block", ctx.BlockHeight()), + ) + } + pairingScores = append(pairingScores, score.Score.MustFloat64()) + } + sort.Slice(pairingScores, func(i, j int) bool { + return pairingScores[i] < pairingScores[j] + }) + + // find the provider's rank + rank := sort.SearchFloat64s(pairingScores, data.score.MustFloat64()) + if rank < len(pairingScores) && pairingScores[rank] == data.score.MustFloat64() { + rank += 1 + } + + // calculate the pairing scores variance + mean := lavaslices.Average(pairingScores) + variance := lavaslices.Variance(pairingScores, mean) + + // create the reputation data and append + chainClusterRes.Rank = uint64(rank) + chainClusterRes.Providers = uint64(len(pairingScores)) + if variance < varianceThreshold { + chainClusterRes.OverallPerformance = lowVariance + } else { + if float64(rank) > float64(len(pairingScores))*0.8 { + chainClusterRes.OverallPerformance = goodScore + } else { + chainClusterRes.OverallPerformance = badScore + } + } + res = append(res, chainClusterRes) + } + + return &types.QueryProviderReputationResponse{Data: res}, nil +} diff --git a/x/pairing/keeper/grpc_query_provider_reputation_details.go b/x/pairing/keeper/grpc_query_provider_reputation_details.go new file mode 100644 index 0000000000..78eeabd1b9 --- /dev/null +++ b/x/pairing/keeper/grpc_query_provider_reputation_details.go @@ -0,0 +1,46 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/v2/x/pairing/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) ProviderReputationDetails(goCtx context.Context, req *types.QueryProviderReputationDetailsRequest) (*types.QueryProviderReputationDetailsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + chains := []string{req.ChainID} + if req.ChainID == "*" { + chains = k.specKeeper.GetAllChainIDs(ctx) + } + + clusters := []string{req.Cluster} + if req.Cluster == "*" { + clusters = k.subscriptionKeeper.GetAllClusters(ctx) + } + + // get all the reputations and reputation scores of the requested provider + res := []types.ReputationDevData{} + for _, chainID := range chains { + for _, cluster := range clusters { + chainClusterRes := types.ReputationDevData{ChainID: chainID, Cluster: cluster} + score, foundPairingScore := k.GetReputationScore(ctx, chainID, cluster, req.Address) + reputation, foundReputation := k.GetReputation(ctx, chainID, cluster, req.Address) + if !foundPairingScore || !foundReputation { + continue + } + chainClusterRes.Reputation = reputation + chainClusterRes.ReputationPairingScore = types.ReputationPairingScore{Score: score} + res = append(res, chainClusterRes) + } + } + + return &types.QueryProviderReputationDetailsResponse{Data: res}, nil +} diff --git a/x/pairing/keeper/grpc_query_provider_reputation_test.go b/x/pairing/keeper/grpc_query_provider_reputation_test.go new file mode 100644 index 0000000000..f7b3094011 --- /dev/null +++ b/x/pairing/keeper/grpc_query_provider_reputation_test.go @@ -0,0 +1,65 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/v2/testutil/common" + "github.com/lavanet/lava/v2/x/pairing/types" + "github.com/stretchr/testify/require" +) + +func TestProviderReputation(t *testing.T) { + +} + +func TestProviderReputationDetails(t *testing.T) { + ts := newTester(t) + ts.setupForPayments(2, 0, 0) // 2 providers + + _, p1 := ts.GetAccount(common.PROVIDER, 0) + _, p2 := ts.GetAccount(common.PROVIDER, 1) + + specs := []string{"spec1", "spec2", "spec1", "spec1"} + clusters := []string{"cluster1", "cluster1", "cluster2", "cluster1"} + providers := []string{p1, p1, p1, p2} + + for i := range providers { + ts.Keepers.Pairing.SetReputation(ts.Ctx, specs[i], clusters[i], providers[i], types.Reputation{ + Stake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(int64(i+1))), + }) + err := ts.Keepers.Pairing.SetReputationScore(ts.Ctx, specs[i], clusters[i], providers[i], sdk.NewDec(int64(i+1))) + require.NoError(t, err) + } + + tests := []struct { + name string + provider string + chain string + cluster string + expected []math.LegacyDec + }{ + {"provider+chain+cluster", p1, "spec1", "cluster1", []math.LegacyDec{math.LegacyNewDec(1)}}, + {"provider+chain+all_clusters", p1, "spec1", "*", []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(3)}}, + {"provider+all_chain+cluster", p1, "*", "cluster1", []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(2)}}, + {"provider+all_chains+all_clusters", p1, "*", "*", []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(2), math.LegacyNewDec(3)}}, + {"second provider+chain+cluster", p2, "spec1", "cluster1", []math.LegacyDec{math.LegacyNewDec(4)}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := ts.QueryPairingProviderReputationDetails(tt.provider, tt.chain, tt.cluster) + require.NoError(t, err) + for i := range res.Data { + expectedStake := sdk.NewCoin(ts.TokenDenom(), tt.expected[i].TruncateInt()) + expectedScore := tt.expected[i] + + require.Equal(t, tt.chain, res.Data[i].ChainID) + require.Equal(t, tt.cluster, res.Data[i].Cluster) + require.True(t, expectedStake.IsEqual(res.Data[i].Reputation.Stake)) + require.True(t, expectedScore.Equal(res.Data[i].ReputationPairingScore.Score)) + } + }) + } +} diff --git a/x/pairing/types/query.pb.go b/x/pairing/types/query.pb.go index f03473e840..c80ef15f45 100644 --- a/x/pairing/types/query.pb.go +++ b/x/pairing/types/query.pb.go @@ -1543,6 +1543,360 @@ func (m *ProviderCuInfo) GetCu() uint64 { return 0 } +type QueryProviderReputationRequest struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + ChainID string `protobuf:"bytes,2,opt,name=chainID,proto3" json:"chainID,omitempty"` + Cluster string `protobuf:"bytes,3,opt,name=cluster,proto3" json:"cluster,omitempty"` +} + +func (m *QueryProviderReputationRequest) Reset() { *m = QueryProviderReputationRequest{} } +func (m *QueryProviderReputationRequest) String() string { return proto.CompactTextString(m) } +func (*QueryProviderReputationRequest) ProtoMessage() {} +func (*QueryProviderReputationRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9e149ce9d21da0d8, []int{29} +} +func (m *QueryProviderReputationRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryProviderReputationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryProviderReputationRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryProviderReputationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryProviderReputationRequest.Merge(m, src) +} +func (m *QueryProviderReputationRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryProviderReputationRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryProviderReputationRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryProviderReputationRequest proto.InternalMessageInfo + +func (m *QueryProviderReputationRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *QueryProviderReputationRequest) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *QueryProviderReputationRequest) GetCluster() string { + if m != nil { + return m.Cluster + } + return "" +} + +type ReputationData struct { + Rank uint64 `protobuf:"varint,1,opt,name=rank,proto3" json:"rank,omitempty"` + Providers uint64 `protobuf:"varint,2,opt,name=providers,proto3" json:"providers,omitempty"` + OverallPerformance string `protobuf:"bytes,3,opt,name=overall_performance,json=overallPerformance,proto3" json:"overall_performance,omitempty"` + ChainID string `protobuf:"bytes,4,opt,name=chainID,proto3" json:"chainID,omitempty"` + Cluster string `protobuf:"bytes,5,opt,name=cluster,proto3" json:"cluster,omitempty"` +} + +func (m *ReputationData) Reset() { *m = ReputationData{} } +func (m *ReputationData) String() string { return proto.CompactTextString(m) } +func (*ReputationData) ProtoMessage() {} +func (*ReputationData) Descriptor() ([]byte, []int) { + return fileDescriptor_9e149ce9d21da0d8, []int{30} +} +func (m *ReputationData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReputationData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReputationData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReputationData) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReputationData.Merge(m, src) +} +func (m *ReputationData) XXX_Size() int { + return m.Size() +} +func (m *ReputationData) XXX_DiscardUnknown() { + xxx_messageInfo_ReputationData.DiscardUnknown(m) +} + +var xxx_messageInfo_ReputationData proto.InternalMessageInfo + +func (m *ReputationData) GetRank() uint64 { + if m != nil { + return m.Rank + } + return 0 +} + +func (m *ReputationData) GetProviders() uint64 { + if m != nil { + return m.Providers + } + return 0 +} + +func (m *ReputationData) GetOverallPerformance() string { + if m != nil { + return m.OverallPerformance + } + return "" +} + +func (m *ReputationData) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *ReputationData) GetCluster() string { + if m != nil { + return m.Cluster + } + return "" +} + +type QueryProviderReputationResponse struct { + Data []ReputationData `protobuf:"bytes,1,rep,name=data,proto3" json:"data"` +} + +func (m *QueryProviderReputationResponse) Reset() { *m = QueryProviderReputationResponse{} } +func (m *QueryProviderReputationResponse) String() string { return proto.CompactTextString(m) } +func (*QueryProviderReputationResponse) ProtoMessage() {} +func (*QueryProviderReputationResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9e149ce9d21da0d8, []int{31} +} +func (m *QueryProviderReputationResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryProviderReputationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryProviderReputationResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryProviderReputationResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryProviderReputationResponse.Merge(m, src) +} +func (m *QueryProviderReputationResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryProviderReputationResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryProviderReputationResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryProviderReputationResponse proto.InternalMessageInfo + +func (m *QueryProviderReputationResponse) GetData() []ReputationData { + if m != nil { + return m.Data + } + return nil +} + +type QueryProviderReputationDetailsRequest struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + ChainID string `protobuf:"bytes,2,opt,name=chainID,proto3" json:"chainID,omitempty"` + Cluster string `protobuf:"bytes,3,opt,name=cluster,proto3" json:"cluster,omitempty"` +} + +func (m *QueryProviderReputationDetailsRequest) Reset() { *m = QueryProviderReputationDetailsRequest{} } +func (m *QueryProviderReputationDetailsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryProviderReputationDetailsRequest) ProtoMessage() {} +func (*QueryProviderReputationDetailsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9e149ce9d21da0d8, []int{32} +} +func (m *QueryProviderReputationDetailsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryProviderReputationDetailsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryProviderReputationDetailsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryProviderReputationDetailsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryProviderReputationDetailsRequest.Merge(m, src) +} +func (m *QueryProviderReputationDetailsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryProviderReputationDetailsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryProviderReputationDetailsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryProviderReputationDetailsRequest proto.InternalMessageInfo + +func (m *QueryProviderReputationDetailsRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *QueryProviderReputationDetailsRequest) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *QueryProviderReputationDetailsRequest) GetCluster() string { + if m != nil { + return m.Cluster + } + return "" +} + +type ReputationDevData struct { + Reputation Reputation `protobuf:"bytes,1,opt,name=reputation,proto3" json:"reputation"` + ReputationPairingScore ReputationPairingScore `protobuf:"bytes,2,opt,name=reputation_pairing_score,json=reputationPairingScore,proto3" json:"reputation_pairing_score"` + ChainID string `protobuf:"bytes,4,opt,name=chainID,proto3" json:"chainID,omitempty"` + Cluster string `protobuf:"bytes,5,opt,name=cluster,proto3" json:"cluster,omitempty"` +} + +func (m *ReputationDevData) Reset() { *m = ReputationDevData{} } +func (m *ReputationDevData) String() string { return proto.CompactTextString(m) } +func (*ReputationDevData) ProtoMessage() {} +func (*ReputationDevData) Descriptor() ([]byte, []int) { + return fileDescriptor_9e149ce9d21da0d8, []int{33} +} +func (m *ReputationDevData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReputationDevData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReputationDevData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReputationDevData) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReputationDevData.Merge(m, src) +} +func (m *ReputationDevData) XXX_Size() int { + return m.Size() +} +func (m *ReputationDevData) XXX_DiscardUnknown() { + xxx_messageInfo_ReputationDevData.DiscardUnknown(m) +} + +var xxx_messageInfo_ReputationDevData proto.InternalMessageInfo + +func (m *ReputationDevData) GetReputation() Reputation { + if m != nil { + return m.Reputation + } + return Reputation{} +} + +func (m *ReputationDevData) GetReputationPairingScore() ReputationPairingScore { + if m != nil { + return m.ReputationPairingScore + } + return ReputationPairingScore{} +} + +func (m *ReputationDevData) GetChainID() string { + if m != nil { + return m.ChainID + } + return "" +} + +func (m *ReputationDevData) GetCluster() string { + if m != nil { + return m.Cluster + } + return "" +} + +type QueryProviderReputationDetailsResponse struct { + Data []ReputationDevData `protobuf:"bytes,1,rep,name=data,proto3" json:"data"` +} + +func (m *QueryProviderReputationDetailsResponse) Reset() { + *m = QueryProviderReputationDetailsResponse{} +} +func (m *QueryProviderReputationDetailsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryProviderReputationDetailsResponse) ProtoMessage() {} +func (*QueryProviderReputationDetailsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9e149ce9d21da0d8, []int{34} +} +func (m *QueryProviderReputationDetailsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryProviderReputationDetailsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryProviderReputationDetailsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryProviderReputationDetailsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryProviderReputationDetailsResponse.Merge(m, src) +} +func (m *QueryProviderReputationDetailsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryProviderReputationDetailsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryProviderReputationDetailsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryProviderReputationDetailsResponse proto.InternalMessageInfo + +func (m *QueryProviderReputationDetailsResponse) GetData() []ReputationDevData { + if m != nil { + return m.Data + } + return nil +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "lavanet.lava.pairing.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "lavanet.lava.pairing.QueryParamsResponse") @@ -1573,125 +1927,148 @@ func init() { proto.RegisterType((*QueryProvidersEpochCuRequest)(nil), "lavanet.lava.pairing.QueryProvidersEpochCuRequest") proto.RegisterType((*QueryProvidersEpochCuResponse)(nil), "lavanet.lava.pairing.QueryProvidersEpochCuResponse") proto.RegisterType((*ProviderCuInfo)(nil), "lavanet.lava.pairing.ProviderCuInfo") + proto.RegisterType((*QueryProviderReputationRequest)(nil), "lavanet.lava.pairing.QueryProviderReputationRequest") + proto.RegisterType((*ReputationData)(nil), "lavanet.lava.pairing.ReputationData") + proto.RegisterType((*QueryProviderReputationResponse)(nil), "lavanet.lava.pairing.QueryProviderReputationResponse") + proto.RegisterType((*QueryProviderReputationDetailsRequest)(nil), "lavanet.lava.pairing.QueryProviderReputationDetailsRequest") + proto.RegisterType((*ReputationDevData)(nil), "lavanet.lava.pairing.ReputationDevData") + proto.RegisterType((*QueryProviderReputationDetailsResponse)(nil), "lavanet.lava.pairing.QueryProviderReputationDetailsResponse") } func init() { proto.RegisterFile("lavanet/lava/pairing/query.proto", fileDescriptor_9e149ce9d21da0d8) } var fileDescriptor_9e149ce9d21da0d8 = []byte{ - // 1806 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4f, 0x6f, 0xdc, 0xc6, - 0x15, 0x17, 0x57, 0xab, 0xb5, 0xf4, 0xf4, 0xc7, 0xc6, 0x44, 0xb2, 0xa5, 0xad, 0xb2, 0x5a, 0x53, - 0x49, 0xaa, 0x3f, 0xce, 0x32, 0xda, 0xc4, 0x89, 0xa1, 0x28, 0x6e, 0x2b, 0xc9, 0x31, 0xa4, 0xaa, - 0x8d, 0x44, 0xd5, 0x3d, 0x04, 0x05, 0x08, 0x8a, 0x9c, 0x5d, 0x31, 0xe2, 0x72, 0x18, 0x72, 0xb8, - 0x96, 0x2a, 0x6c, 0x0b, 0xb4, 0x5f, 0xa0, 0x40, 0xdb, 0x43, 0x4f, 0xbd, 0x04, 0xe8, 0x29, 0xdf, - 0xa0, 0xb7, 0x02, 0x45, 0x0e, 0x3d, 0x18, 0xe8, 0xa5, 0x28, 0x8a, 0xa0, 0xb0, 0x7b, 0x2e, 0xd0, - 0x6f, 0x50, 0x70, 0x66, 0xc8, 0x25, 0x57, 0x5c, 0xee, 0xca, 0xf6, 0x45, 0xda, 0x19, 0xbe, 0xdf, - 0xcc, 0xef, 0xbd, 0x79, 0xef, 0xcd, 0x8f, 0x84, 0xaa, 0xad, 0xb7, 0x75, 0x07, 0x53, 0x25, 0xfc, - 0xaf, 0xb8, 0xba, 0xe5, 0x59, 0x4e, 0x53, 0xf9, 0x32, 0xc0, 0xde, 0x45, 0xcd, 0xf5, 0x08, 0x25, - 0x68, 0x56, 0x58, 0xd4, 0xc2, 0xff, 0x35, 0x61, 0x51, 0x9e, 0x6d, 0x92, 0x26, 0x61, 0x06, 0x4a, - 0xf8, 0x8b, 0xdb, 0x96, 0x17, 0x9b, 0x84, 0x34, 0x6d, 0xac, 0xe8, 0xae, 0xa5, 0xe8, 0x8e, 0x43, - 0xa8, 0x4e, 0x2d, 0xe2, 0xf8, 0xe2, 0xe9, 0x9a, 0x41, 0xfc, 0x16, 0xf1, 0x95, 0x13, 0xdd, 0xc7, - 0x7c, 0x0b, 0xa5, 0xbd, 0x71, 0x82, 0xa9, 0xbe, 0xa1, 0xb8, 0x7a, 0xd3, 0x72, 0x98, 0xb1, 0xb0, - 0xbd, 0x9b, 0xc9, 0xcb, 0xd5, 0x3d, 0xbd, 0x15, 0x2d, 0xb7, 0x98, 0x32, 0xf1, 0x5d, 0x6c, 0xb0, - 0x3f, 0xe2, 0xe9, 0x52, 0x7a, 0x01, 0x5b, 0x77, 0x7c, 0xc5, 0x25, 0xb6, 0x65, 0x08, 0xbf, 0xca, - 0xeb, 0x29, 0x03, 0xec, 0x12, 0xe3, 0xd4, 0xa7, 0xc4, 0xd3, 0x9b, 0x58, 0xf1, 0xa9, 0x7e, 0x86, - 0x35, 0xec, 0xd0, 0x28, 0x08, 0xe5, 0x7b, 0xe9, 0xbd, 0x82, 0x13, 0xdf, 0xf0, 0x2c, 0x37, 0xe4, - 0x9b, 0x1a, 0x08, 0xeb, 0xe5, 0xf4, 0xde, 0x1e, 0xf9, 0x02, 0x1b, 0xd4, 0x8f, 0x7e, 0x08, 0xa3, - 0xef, 0xa6, 0x8c, 0x4c, 0xf2, 0xd4, 0xa1, 0x56, 0x0b, 0x2b, 0xed, 0x8d, 0xf8, 0x37, 0x37, 0x94, - 0x67, 0x01, 0x1d, 0x85, 0xc1, 0x3a, 0x64, 0xce, 0xab, 0xf8, 0xcb, 0x00, 0xfb, 0x54, 0x3e, 0x82, - 0x37, 0x52, 0xb3, 0xbe, 0x4b, 0x1c, 0x1f, 0xa3, 0x4d, 0x28, 0xf1, 0x20, 0xcd, 0x4b, 0x55, 0x69, - 0x65, 0xb2, 0xbe, 0x58, 0xcb, 0x3a, 0xbe, 0x1a, 0x47, 0x6d, 0x17, 0xbf, 0xf9, 0x76, 0x69, 0x44, - 0x15, 0x08, 0xf9, 0x08, 0xe6, 0xf8, 0x92, 0x1e, 0x69, 0x5b, 0x26, 0xf6, 0xa2, 0xbd, 0xd0, 0x3c, - 0xdc, 0x30, 0x4e, 0x75, 0xcb, 0xd9, 0xdb, 0x65, 0xab, 0x4e, 0xa8, 0xd1, 0x10, 0x55, 0x00, 0xfc, - 0x53, 0xf2, 0xf4, 0x53, 0x8f, 0xfc, 0x1c, 0x3b, 0xf3, 0x85, 0xaa, 0xb4, 0x32, 0xae, 0x26, 0x66, - 0xe4, 0x33, 0xb8, 0xdd, 0xbb, 0xa4, 0x20, 0xfa, 0x43, 0x00, 0x16, 0xe6, 0x47, 0x61, 0x94, 0xe7, - 0xa5, 0xea, 0xe8, 0xca, 0x64, 0xfd, 0xed, 0x34, 0xd9, 0xe4, 0x99, 0xd4, 0x8e, 0x63, 0x63, 0xc1, - 0x3a, 0x01, 0xdf, 0x2f, 0x8e, 0x17, 0x6e, 0x8d, 0xca, 0xfb, 0x30, 0x9b, 0xda, 0x2c, 0x41, 0x5f, - 0x37, 0x4d, 0x0f, 0xfb, 0x7e, 0x44, 0x5f, 0x0c, 0x93, 0x8e, 0x15, 0x52, 0x8e, 0xc9, 0xa7, 0x3d, - 0xb1, 0x88, 0x79, 0x7f, 0x06, 0x53, 0xf1, 0xc6, 0x16, 0xf6, 0x5f, 0x86, 0x79, 0x6a, 0x01, 0x79, - 0x5f, 0x84, 0xe8, 0x31, 0xa6, 0x87, 0xfc, 0x74, 0x06, 0x87, 0xfd, 0x36, 0x94, 0x0c, 0xdb, 0xc2, - 0x0e, 0x15, 0xb4, 0xc5, 0x48, 0xfe, 0xba, 0x00, 0x77, 0xae, 0x2c, 0x26, 0x88, 0xef, 0xc1, 0x84, - 0x1b, 0x9d, 0xc2, 0xcb, 0xb0, 0xee, 0xa2, 0xd1, 0x32, 0x4c, 0x1b, 0x81, 0xe7, 0x61, 0x87, 0x6a, - 0x0c, 0xc3, 0x58, 0x14, 0xd5, 0x29, 0x31, 0xf9, 0x28, 0x9c, 0x43, 0x0f, 0x60, 0x21, 0x4c, 0x62, - 0xcd, 0xc6, 0x0d, 0xaa, 0x51, 0xa2, 0x39, 0xf8, 0x9c, 0x6a, 0x22, 0xff, 0xe6, 0x47, 0x19, 0x60, - 0x2e, 0x34, 0x38, 0xc0, 0x0d, 0xfa, 0x13, 0xf2, 0x63, 0x7c, 0x1e, 0x31, 0x46, 0xf7, 0xe1, 0x4e, - 0x58, 0xc8, 0x9a, 0xad, 0xfb, 0x54, 0x0b, 0x5c, 0x53, 0xa7, 0xd8, 0xd4, 0x4e, 0x6c, 0x62, 0x9c, - 0xcd, 0x17, 0x19, 0x6e, 0x36, 0x7c, 0x7c, 0xa0, 0xfb, 0xf4, 0x09, 0x7f, 0xb8, 0x1d, 0x3e, 0x43, - 0x1b, 0x30, 0xc7, 0x8c, 0x34, 0xd2, 0x48, 0x6f, 0x36, 0xc6, 0x40, 0x88, 0x3d, 0xfc, 0xac, 0x91, - 0xd8, 0x49, 0xfe, 0x25, 0x2c, 0xb0, 0x70, 0xfd, 0x14, 0x7b, 0x56, 0xe3, 0xe2, 0x55, 0xc3, 0x8f, - 0xca, 0x30, 0x1e, 0x05, 0x89, 0x79, 0x38, 0xa1, 0xc6, 0x63, 0x34, 0x0b, 0x63, 0x49, 0x17, 0xf8, - 0x40, 0xfe, 0x4a, 0x82, 0x72, 0x16, 0x03, 0x71, 0x66, 0xb3, 0x30, 0xd6, 0xd6, 0x6d, 0xcb, 0x64, - 0x04, 0xc6, 0x55, 0x3e, 0x40, 0xab, 0x70, 0x2b, 0x74, 0x0d, 0x9b, 0x5a, 0xf7, 0x40, 0x79, 0x40, - 0x6f, 0xf2, 0xf9, 0xb8, 0xda, 0x50, 0x15, 0xa6, 0x8c, 0x40, 0x73, 0xb1, 0x27, 0x0e, 0x8a, 0x6f, - 0x0e, 0x46, 0x70, 0x88, 0x3d, 0x7e, 0x4c, 0x6f, 0x02, 0x88, 0xbe, 0xa4, 0x59, 0x26, 0x0b, 0xd5, - 0x04, 0x3b, 0xea, 0x70, 0x66, 0xcf, 0x14, 0x95, 0xf5, 0x7b, 0x09, 0xee, 0xa6, 0xca, 0x41, 0x10, - 0xdd, 0x39, 0xd5, 0x1d, 0x03, 0x47, 0x01, 0x4b, 0xba, 0x2f, 0xf5, 0xb8, 0xdf, 0xb7, 0xd2, 0x50, - 0x15, 0x26, 0x9b, 0x98, 0xd8, 0xc4, 0x60, 0xed, 0x9f, 0x39, 0x32, 0xa6, 0x26, 0xa7, 0x18, 0xd6, - 0x0e, 0x7c, 0x8a, 0x3d, 0xc6, 0x3f, 0xc4, 0xf2, 0xa1, 0x6c, 0x83, 0x9c, 0x47, 0x4b, 0x44, 0xf1, - 0x53, 0x28, 0x19, 0x6c, 0x86, 0xb3, 0xda, 0xae, 0x85, 0xf9, 0xfc, 0xcf, 0x6f, 0x97, 0xde, 0x69, - 0x5a, 0xf4, 0x34, 0x38, 0xa9, 0x19, 0xa4, 0xa5, 0x88, 0xab, 0x89, 0xff, 0x7b, 0xd7, 0x37, 0xcf, - 0x14, 0x7a, 0xe1, 0x62, 0xbf, 0xb6, 0x8b, 0x0d, 0x55, 0xa0, 0x65, 0x5d, 0xf4, 0x84, 0x27, 0x3e, - 0xf6, 0x58, 0x65, 0xbc, 0x42, 0x83, 0xe9, 0xe6, 0xc3, 0x68, 0x32, 0x1f, 0x9e, 0x8a, 0x66, 0x90, - 0xd8, 0x42, 0x38, 0xf1, 0x18, 0xc6, 0x0d, 0xe2, 0xf8, 0x41, 0x4b, 0x04, 0xf7, 0x9a, 0xd5, 0x1b, - 0x83, 0xc3, 0x8d, 0x5b, 0xfa, 0xf9, 0xce, 0x13, 0x51, 0xb4, 0x7c, 0x20, 0x7f, 0x0c, 0x4b, 0x6c, - 0xe3, 0xe3, 0xf0, 0xca, 0x36, 0xe2, 0x04, 0x3a, 0xb0, 0x7c, 0x3a, 0xb0, 0x1e, 0xe4, 0x16, 0x54, - 0xfb, 0x83, 0x5f, 0x7b, 0xfb, 0x91, 0x8f, 0xe0, 0x3b, 0x6c, 0xbb, 0x47, 0x8d, 0x06, 0x36, 0xa8, - 0xd5, 0xc6, 0x87, 0xec, 0x5e, 0x4f, 0xa4, 0x61, 0x2a, 0x52, 0x13, 0x09, 0xe7, 0x6f, 0x43, 0x29, - 0xec, 0x1d, 0xf1, 0x71, 0x88, 0x51, 0x98, 0xe0, 0x8b, 0xd9, 0x6b, 0x0a, 0xfa, 0x75, 0x28, 0x71, - 0xf5, 0x20, 0x82, 0x5f, 0xee, 0xb9, 0x57, 0x43, 0x7d, 0x51, 0x13, 0x18, 0x61, 0x89, 0x7e, 0x00, - 0x33, 0x2e, 0x76, 0x4c, 0xcb, 0x69, 0x6a, 0x02, 0x5b, 0x18, 0x88, 0x9d, 0x16, 0x08, 0x3e, 0x94, - 0xff, 0x27, 0x89, 0x86, 0x7e, 0x6c, 0x9e, 0xf5, 0x36, 0x87, 0xc7, 0x70, 0x23, 0xea, 0x70, 0x9c, - 0xd3, 0xbb, 0xd9, 0x77, 0x7d, 0x9f, 0x0b, 0x41, 0x8d, 0xd0, 0x68, 0x0e, 0x4a, 0x2d, 0xfd, 0x5c, - 0x33, 0x82, 0x64, 0x4a, 0x04, 0x68, 0x1d, 0x8a, 0x61, 0x74, 0x58, 0x82, 0x4e, 0xd6, 0xef, 0xa4, - 0x17, 0x67, 0x4a, 0xeb, 0xd8, 0xc5, 0x86, 0xca, 0x8c, 0xd0, 0x1e, 0xdc, 0x8c, 0x64, 0x8b, 0x26, - 0x04, 0x48, 0x91, 0xe1, 0xaa, 0x69, 0x5c, 0xac, 0x6d, 0xda, 0x1b, 0x42, 0x84, 0xa8, 0x33, 0xd1, - 0x1c, 0x1f, 0xcb, 0xdf, 0xeb, 0xe9, 0x35, 0x3f, 0x22, 0x0e, 0x3d, 0xb5, 0x2f, 0x0e, 0xf5, 0x0b, - 0x12, 0xd0, 0x21, 0x7a, 0x8d, 0x7c, 0x06, 0xe8, 0x38, 0x21, 0xca, 0x38, 0x10, 0xc9, 0x30, 0x95, - 0x94, 0x6a, 0x02, 0x95, 0x9a, 0x43, 0x0b, 0x30, 0xce, 0x72, 0x3a, 0x6c, 0x85, 0xa9, 0x7a, 0x35, - 0xc3, 0xcc, 0xd1, 0x5b, 0x24, 0x70, 0xa8, 0x28, 0x58, 0x31, 0x92, 0x7f, 0xd1, 0xd3, 0x82, 0x7a, - 0xd8, 0x76, 0x1b, 0x39, 0x25, 0x54, 0xb7, 0xd9, 0xae, 0x45, 0x95, 0x0f, 0xd0, 0x36, 0xdc, 0x30, - 0x31, 0xd5, 0x2d, 0xdb, 0x9f, 0x2f, 0xb0, 0x8a, 0x58, 0xc9, 0x3e, 0xc1, 0xab, 0xde, 0xa8, 0x11, - 0x50, 0xde, 0x85, 0x99, 0x6e, 0xf7, 0x63, 0x8e, 0xe6, 0xb5, 0xe1, 0xae, 0x17, 0x85, 0x94, 0x17, - 0x5f, 0xc0, 0xf4, 0x0e, 0x2f, 0x66, 0xb1, 0x48, 0x32, 0x12, 0x52, 0x3a, 0x12, 0x0f, 0xc3, 0xbc, - 0x0b, 0x8d, 0x22, 0xd6, 0x6f, 0xf5, 0xd1, 0x98, 0x29, 0x5a, 0x6a, 0x04, 0x92, 0x77, 0xe0, 0x6d, - 0x9e, 0xd2, 0x09, 0xaf, 0xfa, 0x9d, 0x71, 0xbf, 0x42, 0x96, 0x3b, 0xf0, 0xce, 0xa0, 0x45, 0x72, - 0x43, 0xff, 0x49, 0x6f, 0xe8, 0x97, 0xb3, 0x9d, 0x48, 0x45, 0xa5, 0x1b, 0xf5, 0x8a, 0x68, 0x17, - 0x71, 0xaf, 0x63, 0x97, 0xe9, 0x4e, 0x10, 0xa9, 0x73, 0x0d, 0xde, 0xec, 0xf3, 0x5c, 0xb0, 0x7a, - 0x08, 0x45, 0xcb, 0x69, 0x10, 0xd1, 0x09, 0x07, 0x44, 0x70, 0x27, 0xd8, 0x73, 0x1a, 0x44, 0x34, - 0x42, 0x86, 0x93, 0xb7, 0xba, 0xc7, 0xce, 0x9f, 0xe6, 0x1e, 0xfb, 0x0c, 0x14, 0xe2, 0xea, 0x2e, - 0x18, 0x41, 0xfd, 0x19, 0x82, 0x31, 0xc6, 0x0f, 0xfd, 0x5a, 0x82, 0x12, 0xaf, 0x3b, 0xb4, 0x92, - 0xd3, 0x3e, 0x52, 0xef, 0x1e, 0xe5, 0xd5, 0x21, 0x2c, 0xb9, 0x9f, 0xf2, 0x5b, 0xbf, 0xfa, 0xfb, - 0x7f, 0x7e, 0x5b, 0xa8, 0xa0, 0x45, 0x25, 0xe7, 0x85, 0x0e, 0xfd, 0x41, 0x82, 0x89, 0xae, 0x68, - 0x59, 0xcf, 0x5b, 0xbe, 0xe7, 0xdd, 0xa4, 0x7c, 0x6f, 0x38, 0x63, 0x41, 0x67, 0x83, 0xd1, 0x59, - 0x47, 0xab, 0x7d, 0xe8, 0x44, 0x00, 0xe5, 0x52, 0xdc, 0x6d, 0x1d, 0xf4, 0x47, 0x09, 0xc6, 0xa3, - 0x85, 0xd0, 0xda, 0x10, 0xbb, 0x45, 0xcc, 0xd6, 0x87, 0xb2, 0x15, 0xc4, 0x36, 0x19, 0xb1, 0x0f, - 0x50, 0x3d, 0x9f, 0x98, 0x72, 0x29, 0x94, 0x45, 0x27, 0xc1, 0xf0, 0x4f, 0x12, 0x40, 0xb7, 0xbf, - 0xa3, 0x7b, 0x43, 0x5e, 0x03, 0x9c, 0xe5, 0xf5, 0x2e, 0x0d, 0x79, 0x8b, 0xf1, 0xfc, 0x10, 0x7d, - 0x90, 0xcd, 0xb3, 0x89, 0x63, 0xd9, 0xdd, 0x25, 0xa8, 0x5c, 0x72, 0x7d, 0xdc, 0x41, 0x7f, 0x95, - 0x60, 0x3a, 0xa5, 0x74, 0x91, 0x92, 0xb3, 0x7d, 0x96, 0x2a, 0x2f, 0xbf, 0x37, 0x3c, 0x40, 0x50, - 0x56, 0x19, 0xe5, 0x03, 0xb4, 0x9f, 0x4d, 0xb9, 0xcd, 0x40, 0x39, 0xac, 0x95, 0xcb, 0x28, 0xfa, - 0x1d, 0xe5, 0x92, 0xc9, 0xb4, 0x0e, 0xfa, 0xaf, 0x04, 0x73, 0x99, 0xa2, 0x13, 0x7d, 0x34, 0xc4, - 0xa9, 0x67, 0xa9, 0xe7, 0xf2, 0x83, 0xeb, 0x03, 0x85, 0x83, 0x27, 0xcc, 0xc1, 0x9f, 0xa1, 0xcf, - 0xf3, 0x73, 0x27, 0x72, 0x51, 0xe3, 0x72, 0x36, 0xe5, 0x56, 0xd7, 0xe9, 0x84, 0xf0, 0x66, 0x21, - 0x60, 0x42, 0xbb, 0x83, 0xbe, 0x92, 0x60, 0x22, 0x16, 0xa5, 0xb9, 0x15, 0xda, 0xab, 0x8e, 0x73, - 0x2b, 0xf4, 0x8a, 0xce, 0x1d, 0x94, 0x60, 0x81, 0x1f, 0xbe, 0xcb, 0x84, 0x88, 0xcc, 0x52, 0xf8, - 0x8b, 0x04, 0x6f, 0x64, 0xa8, 0x50, 0x74, 0x3f, 0x87, 0x43, 0x7f, 0xc9, 0x5b, 0xfe, 0xf0, 0xba, - 0x30, 0xe1, 0xc4, 0x27, 0xcc, 0x89, 0x8f, 0xd0, 0xfd, 0x6c, 0x27, 0x7c, 0x06, 0xed, 0xbe, 0xbd, - 0x69, 0xb6, 0xe5, 0xd3, 0x84, 0x17, 0x7f, 0x96, 0xe0, 0x66, 0x8f, 0x10, 0x45, 0x1b, 0x39, 0x54, - 0xb2, 0x85, 0x70, 0xb9, 0x7e, 0x1d, 0x88, 0x60, 0xbe, 0xcd, 0x98, 0x6f, 0xa1, 0xcd, 0x6c, 0xe6, - 0x38, 0x82, 0x09, 0x45, 0xab, 0x5c, 0x46, 0x37, 0x72, 0x47, 0xb9, 0xe4, 0x5a, 0xba, 0x83, 0xfe, - 0x96, 0x28, 0x8e, 0xd4, 0x9d, 0x3c, 0x54, 0x71, 0x64, 0x49, 0x81, 0xa1, 0x8a, 0x23, 0xf3, 0xfa, - 0x97, 0xbf, 0xcf, 0x1c, 0xda, 0x44, 0x0f, 0x06, 0x14, 0x47, 0x8b, 0xa3, 0x35, 0xae, 0x52, 0x12, - 0xc5, 0x81, 0xfe, 0x25, 0xc1, 0x42, 0x5f, 0x99, 0x81, 0x3e, 0xce, 0x4b, 0x91, 0x01, 0x0a, 0xa7, - 0xbc, 0xf5, 0x72, 0x60, 0xe1, 0xda, 0x2e, 0x73, 0xed, 0x21, 0xda, 0xea, 0x93, 0x65, 0x89, 0x05, - 0xae, 0xb8, 0x17, 0x1f, 0x1b, 0xfa, 0x9d, 0x04, 0xd0, 0x7d, 0xbb, 0x78, 0x8d, 0xb7, 0xc7, 0xd5, - 0x57, 0x16, 0x79, 0x95, 0x31, 0x5e, 0x46, 0x77, 0xfb, 0x30, 0x36, 0xcf, 0xa2, 0x26, 0x85, 0xbe, - 0x96, 0xe0, 0x56, 0xaf, 0x7a, 0x42, 0xf5, 0x61, 0x2e, 0xfb, 0xb4, 0x14, 0x2b, 0xbf, 0x7f, 0x2d, - 0x8c, 0x20, 0xfa, 0x1e, 0x23, 0xba, 0x86, 0x56, 0x06, 0xe8, 0x04, 0xfe, 0x59, 0x45, 0x33, 0x82, - 0xed, 0xdd, 0x6f, 0x9e, 0x57, 0xa4, 0x67, 0xcf, 0x2b, 0xd2, 0xbf, 0x9f, 0x57, 0xa4, 0xdf, 0xbc, - 0xa8, 0x8c, 0x3c, 0x7b, 0x51, 0x19, 0xf9, 0xc7, 0x8b, 0xca, 0xc8, 0xe7, 0x6b, 0x89, 0xcf, 0x0c, - 0xa9, 0xd5, 0xda, 0x75, 0xe5, 0x3c, 0x5e, 0x92, 0x7d, 0x6e, 0x38, 0x29, 0xb1, 0x4f, 0xbe, 0xef, - 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x1a, 0x9c, 0x9b, 0xe8, 0x97, 0x17, 0x00, 0x00, + // 2068 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x5f, 0x6f, 0x1c, 0x57, + 0x15, 0xcf, 0xac, 0xd7, 0x8e, 0x7d, 0x92, 0x38, 0xe1, 0xc6, 0x76, 0xec, 0xc5, 0xdd, 0x38, 0x93, + 0xa6, 0x75, 0xe2, 0x74, 0xa7, 0x76, 0x93, 0x36, 0x4a, 0xdd, 0x40, 0x6d, 0x27, 0x91, 0x43, 0x20, + 0xf6, 0x9a, 0x80, 0x54, 0x21, 0x8d, 0xae, 0x67, 0xef, 0xae, 0xa7, 0x9e, 0x9d, 0xbb, 0x9d, 0xb9, + 0xb3, 0xb1, 0xb1, 0x16, 0x24, 0xf8, 0x02, 0x48, 0x80, 0x10, 0x4f, 0xbc, 0x54, 0xea, 0x53, 0xbf, + 0x01, 0x6f, 0x48, 0xa8, 0x0f, 0x3c, 0x54, 0xf0, 0x82, 0x10, 0xaa, 0x50, 0xc2, 0x33, 0x88, 0x0f, + 0x80, 0x84, 0xe6, 0xde, 0x33, 0x3b, 0x33, 0xeb, 0xd9, 0xd9, 0x75, 0x52, 0x5e, 0xe2, 0xbd, 0xf7, + 0x9e, 0x73, 0xcf, 0xef, 0xfc, 0xbd, 0xe7, 0x4c, 0x60, 0xc1, 0xa1, 0x6d, 0xea, 0x32, 0x61, 0x84, + 0x7f, 0x8d, 0x16, 0xb5, 0x3d, 0xdb, 0x6d, 0x18, 0x9f, 0x04, 0xcc, 0x3b, 0xac, 0xb4, 0x3c, 0x2e, + 0x38, 0x99, 0x42, 0x8a, 0x4a, 0xf8, 0xb7, 0x82, 0x14, 0xa5, 0xa9, 0x06, 0x6f, 0x70, 0x49, 0x60, + 0x84, 0xbf, 0x14, 0x6d, 0x69, 0xbe, 0xc1, 0x79, 0xc3, 0x61, 0x06, 0x6d, 0xd9, 0x06, 0x75, 0x5d, + 0x2e, 0xa8, 0xb0, 0xb9, 0xeb, 0xe3, 0xe9, 0x0d, 0x8b, 0xfb, 0x4d, 0xee, 0x1b, 0xbb, 0xd4, 0x67, + 0x4a, 0x84, 0xd1, 0x5e, 0xde, 0x65, 0x82, 0x2e, 0x1b, 0x2d, 0xda, 0xb0, 0x5d, 0x49, 0x8c, 0xb4, + 0x57, 0x32, 0x71, 0xb5, 0xa8, 0x47, 0x9b, 0xd1, 0x75, 0xd7, 0x32, 0x49, 0x3c, 0xd6, 0x0a, 0x44, + 0xf2, 0xa6, 0xf9, 0x14, 0x99, 0xdf, 0x62, 0x96, 0xfc, 0x07, 0x4f, 0x2f, 0xa7, 0x2f, 0x71, 0xa8, + 0xeb, 0x1b, 0x2d, 0xee, 0xd8, 0x16, 0xaa, 0x5f, 0x5a, 0x4a, 0x11, 0xb0, 0x16, 0xb7, 0xf6, 0x7c, + 0xc1, 0x3d, 0xda, 0x60, 0x86, 0x2f, 0xe8, 0x3e, 0x33, 0x99, 0x2b, 0x22, 0x5b, 0x95, 0x6e, 0xa6, + 0x65, 0x05, 0xbb, 0xbe, 0xe5, 0xd9, 0xad, 0x10, 0x4c, 0x6a, 0x81, 0xd4, 0x57, 0xd3, 0xb2, 0x3d, + 0xfe, 0x31, 0xb3, 0x84, 0x1f, 0xfd, 0x40, 0xa2, 0x37, 0x53, 0x44, 0x35, 0xfe, 0xcc, 0x15, 0x76, + 0x93, 0x19, 0xed, 0xe5, 0xee, 0x6f, 0x45, 0xa8, 0x4f, 0x01, 0xd9, 0x0e, 0x6d, 0xba, 0x25, 0x6d, + 0x54, 0x65, 0x9f, 0x04, 0xcc, 0x17, 0xfa, 0x36, 0x5c, 0x4c, 0xed, 0xfa, 0x2d, 0xee, 0xfa, 0x8c, + 0xdc, 0x85, 0x31, 0x65, 0xcb, 0x59, 0x6d, 0x41, 0x5b, 0x3c, 0xb3, 0x32, 0x5f, 0xc9, 0xf2, 0x72, + 0x45, 0x71, 0xad, 0x15, 0xbf, 0xf8, 0xea, 0xf2, 0xa9, 0x2a, 0x72, 0xe8, 0xdb, 0x30, 0xad, 0xae, + 0xf4, 0x78, 0xdb, 0xae, 0x31, 0x2f, 0x92, 0x45, 0x66, 0xe1, 0xb4, 0xb5, 0x47, 0x6d, 0x77, 0x73, + 0x43, 0xde, 0x3a, 0x51, 0x8d, 0x96, 0xa4, 0x0c, 0xe0, 0xef, 0xf1, 0x67, 0x0f, 0x3c, 0xfe, 0x63, + 0xe6, 0xce, 0x16, 0x16, 0xb4, 0xc5, 0xf1, 0x6a, 0x62, 0x47, 0xdf, 0x87, 0x99, 0xde, 0x2b, 0x11, + 0xe8, 0x77, 0x00, 0xa4, 0x99, 0xef, 0x87, 0x56, 0x9e, 0xd5, 0x16, 0x46, 0x16, 0xcf, 0xac, 0x5c, + 0x4b, 0x83, 0x4d, 0xfa, 0xa4, 0xb2, 0xd3, 0x25, 0x46, 0xd4, 0x09, 0xf6, 0x47, 0xc5, 0xf1, 0xc2, + 0x85, 0x11, 0xfd, 0x11, 0x4c, 0xa5, 0x84, 0x25, 0xe0, 0xd3, 0x5a, 0xcd, 0x63, 0xbe, 0x1f, 0xc1, + 0xc7, 0x65, 0x52, 0xb1, 0x42, 0x4a, 0x31, 0x7d, 0xaf, 0xc7, 0x16, 0x5d, 0xdc, 0x4f, 0xe0, 0x6c, + 0x57, 0xb0, 0xcd, 0xfc, 0x97, 0x41, 0x9e, 0xba, 0x40, 0x7f, 0x84, 0x26, 0x7a, 0xc8, 0xc4, 0x96, + 0xf2, 0xce, 0x60, 0xb3, 0xcf, 0xc0, 0x98, 0xe5, 0xd8, 0xcc, 0x15, 0x08, 0x1b, 0x57, 0xfa, 0xe7, + 0x05, 0xb8, 0x74, 0xec, 0x32, 0x04, 0xbe, 0x09, 0x13, 0xad, 0xc8, 0x0b, 0x2f, 0x83, 0x3a, 0xe6, + 0x26, 0x57, 0xe1, 0x9c, 0x15, 0x78, 0x1e, 0x73, 0x85, 0x29, 0x79, 0x24, 0x8a, 0x62, 0xf5, 0x2c, + 0x6e, 0xde, 0x0f, 0xf7, 0xc8, 0x1d, 0x98, 0x0b, 0x83, 0xd8, 0x74, 0x58, 0x5d, 0x98, 0x82, 0x9b, + 0x2e, 0x3b, 0x10, 0x26, 0xc6, 0xdf, 0xec, 0x88, 0x64, 0x98, 0x0e, 0x09, 0x1e, 0xb3, 0xba, 0xf8, + 0x3e, 0xff, 0x1e, 0x3b, 0x88, 0x10, 0x93, 0xdb, 0x70, 0x29, 0x4c, 0x64, 0xd3, 0xa1, 0xbe, 0x30, + 0x83, 0x56, 0x8d, 0x0a, 0x56, 0x33, 0x77, 0x1d, 0x6e, 0xed, 0xcf, 0x16, 0x25, 0xdf, 0x54, 0x78, + 0xfc, 0x98, 0xfa, 0xe2, 0xa9, 0x3a, 0x5c, 0x0b, 0xcf, 0xc8, 0x32, 0x4c, 0x4b, 0x22, 0x93, 0xd7, + 0xd3, 0xc2, 0x46, 0x25, 0x13, 0x91, 0x87, 0x4f, 0xea, 0x09, 0x49, 0xfa, 0x4f, 0x61, 0x4e, 0x9a, + 0xeb, 0x07, 0xcc, 0xb3, 0xeb, 0x87, 0xaf, 0x6a, 0x7e, 0x52, 0x82, 0xf1, 0xc8, 0x48, 0x52, 0xc3, + 0x89, 0x6a, 0x77, 0x4d, 0xa6, 0x60, 0x34, 0xa9, 0x82, 0x5a, 0xe8, 0x9f, 0x6a, 0x50, 0xca, 0x42, + 0x80, 0x3e, 0x9b, 0x82, 0xd1, 0x36, 0x75, 0xec, 0x9a, 0x04, 0x30, 0x5e, 0x55, 0x0b, 0x72, 0x1d, + 0x2e, 0x84, 0xaa, 0xb1, 0x9a, 0x19, 0x3b, 0x54, 0x19, 0xf4, 0xbc, 0xda, 0xef, 0x66, 0x1b, 0x59, + 0x80, 0xb3, 0x56, 0x60, 0xb6, 0x98, 0x87, 0x8e, 0x52, 0xc2, 0xc1, 0x0a, 0xb6, 0x98, 0xa7, 0xdc, + 0xf4, 0x1a, 0x00, 0xd6, 0x25, 0xd3, 0xae, 0x49, 0x53, 0x4d, 0x48, 0x57, 0x87, 0x3b, 0x9b, 0x35, + 0xcc, 0xac, 0x5f, 0x6b, 0x70, 0x25, 0x95, 0x0e, 0x08, 0x74, 0x7d, 0x8f, 0xba, 0x16, 0x8b, 0x0c, + 0x96, 0x54, 0x5f, 0xeb, 0x51, 0xbf, 0x6f, 0xa6, 0x91, 0x05, 0x38, 0xd3, 0x60, 0xdc, 0xe1, 0x96, + 0xac, 0xed, 0x52, 0x91, 0xd1, 0x6a, 0x72, 0x4b, 0xf2, 0x3a, 0x81, 0x2f, 0x98, 0x27, 0xf1, 0x87, + 0xbc, 0x6a, 0xa9, 0x3b, 0xa0, 0xe7, 0xc1, 0x42, 0x2b, 0x3e, 0x80, 0x31, 0x4b, 0xee, 0x28, 0x54, + 0x6b, 0x95, 0x30, 0x9e, 0xff, 0xf6, 0xd5, 0xe5, 0x37, 0x1a, 0xb6, 0xd8, 0x0b, 0x76, 0x2b, 0x16, + 0x6f, 0x1a, 0xf8, 0x82, 0xa9, 0x3f, 0x6f, 0xf9, 0xb5, 0x7d, 0x43, 0x1c, 0xb6, 0x98, 0x5f, 0xd9, + 0x60, 0x56, 0x15, 0xb9, 0x75, 0x8a, 0x35, 0xe1, 0xa9, 0xcf, 0x3c, 0x99, 0x19, 0xaf, 0x50, 0x60, + 0xe2, 0x78, 0x18, 0x49, 0xc6, 0xc3, 0x33, 0x2c, 0x06, 0x09, 0x11, 0xa8, 0xc4, 0x43, 0x18, 0xb7, + 0xb8, 0xeb, 0x07, 0x4d, 0x34, 0xee, 0x09, 0xb3, 0xb7, 0xcb, 0x1c, 0x0a, 0x6e, 0xd2, 0x83, 0xf5, + 0xa7, 0x98, 0xb4, 0x6a, 0xa1, 0xbf, 0x0f, 0x97, 0xa5, 0xe0, 0x9d, 0xf0, 0x89, 0xb5, 0xba, 0x01, + 0xf4, 0xd8, 0xf6, 0xc5, 0xc0, 0x7c, 0xd0, 0x9b, 0xb0, 0xd0, 0x9f, 0xf9, 0x6b, 0x2f, 0x3f, 0xfa, + 0x36, 0x7c, 0x53, 0x8a, 0xbb, 0x5f, 0xaf, 0x33, 0x4b, 0xd8, 0x6d, 0xb6, 0x25, 0xdf, 0xf5, 0x44, + 0x18, 0xa6, 0x2c, 0x35, 0x91, 0x50, 0x7e, 0x06, 0xc6, 0xc2, 0xda, 0xd1, 0x75, 0x07, 0xae, 0xc2, + 0x00, 0x9f, 0xcf, 0xbe, 0x13, 0xe1, 0xaf, 0xc0, 0x98, 0xea, 0x1e, 0xd0, 0xf8, 0xa5, 0x9e, 0x77, + 0x35, 0xec, 0x2f, 0x2a, 0xc8, 0x83, 0x94, 0xe4, 0x43, 0x98, 0x6c, 0x31, 0xb7, 0x66, 0xbb, 0x0d, + 0x13, 0x79, 0x0b, 0x03, 0x79, 0xcf, 0x21, 0x87, 0x5a, 0xea, 0xff, 0xd1, 0xb0, 0xa0, 0xef, 0xd4, + 0xf6, 0x7b, 0x8b, 0xc3, 0x43, 0x38, 0x1d, 0x55, 0x38, 0x85, 0xe9, 0xad, 0xec, 0xb7, 0xbe, 0xcf, + 0x83, 0x50, 0x8d, 0xb8, 0xc9, 0x34, 0x8c, 0x35, 0xe9, 0x81, 0x69, 0x05, 0xc9, 0x90, 0x08, 0xc8, + 0x12, 0x14, 0x43, 0xeb, 0xc8, 0x00, 0x3d, 0xb3, 0x72, 0x29, 0x7d, 0xb9, 0xec, 0xb4, 0x76, 0x5a, + 0xcc, 0xaa, 0x4a, 0x22, 0xb2, 0x09, 0xe7, 0xa3, 0xb6, 0xc5, 0xc4, 0x06, 0xa4, 0x28, 0xf9, 0x16, + 0xd2, 0x7c, 0xdd, 0xde, 0xa6, 0xbd, 0x8c, 0x4d, 0x48, 0x75, 0x32, 0xda, 0x53, 0x6b, 0xfd, 0x5b, + 0x3d, 0xb5, 0xe6, 0xbb, 0xdc, 0x15, 0x7b, 0xce, 0xe1, 0x16, 0x3d, 0xe4, 0x81, 0x18, 0xa2, 0xd6, + 0xe8, 0xfb, 0x40, 0x76, 0x12, 0x4d, 0x99, 0x62, 0x24, 0x3a, 0x9c, 0x4d, 0xb6, 0x6a, 0xc8, 0x95, + 0xda, 0x23, 0x73, 0x30, 0x2e, 0x63, 0x3a, 0x2c, 0x85, 0xa9, 0x7c, 0xad, 0x85, 0x91, 0x43, 0x9b, + 0x3c, 0x70, 0x05, 0x26, 0x2c, 0xae, 0xf4, 0x9f, 0xf4, 0x94, 0xa0, 0x1e, 0xb4, 0x71, 0x21, 0x17, + 0x5c, 0x50, 0x47, 0x4a, 0x2d, 0x56, 0xd5, 0x82, 0xac, 0xc1, 0xe9, 0x1a, 0x13, 0xd4, 0x76, 0xfc, + 0xd9, 0x82, 0xcc, 0x88, 0xc5, 0x6c, 0x0f, 0x1e, 0xd7, 0xa6, 0x1a, 0x31, 0xea, 0x1b, 0x30, 0x19, + 0x57, 0x3f, 0xa9, 0x68, 0x5e, 0x19, 0x8e, 0xb5, 0x28, 0xa4, 0xb4, 0xf8, 0x18, 0xce, 0xad, 0xab, + 0x64, 0xc6, 0x4b, 0x92, 0x96, 0xd0, 0xd2, 0x96, 0xb8, 0x17, 0xc6, 0x5d, 0x48, 0x14, 0xa1, 0x7e, + 0xbd, 0x4f, 0x8f, 0x99, 0x82, 0x55, 0x8d, 0x98, 0xf4, 0x75, 0xb8, 0xa6, 0x42, 0x3a, 0xa1, 0x55, + 0x3f, 0x1f, 0xf7, 0x4b, 0x64, 0xbd, 0x03, 0x6f, 0x0c, 0xba, 0x24, 0xd7, 0xf4, 0x1f, 0xf4, 0x9a, + 0xfe, 0x6a, 0xb6, 0x12, 0x29, 0xab, 0xc4, 0x56, 0x2f, 0x63, 0xb9, 0xe8, 0xd6, 0x3a, 0xf9, 0x98, + 0xae, 0x07, 0x51, 0x77, 0x6e, 0xc2, 0x6b, 0x7d, 0xce, 0x11, 0xd5, 0x3d, 0x28, 0xda, 0x6e, 0x9d, + 0x63, 0x25, 0x1c, 0x60, 0xc1, 0xf5, 0x60, 0xd3, 0xad, 0x73, 0x2c, 0x84, 0x92, 0x4f, 0x5f, 0x8d, + 0xdd, 0xae, 0x4e, 0x73, 0xdd, 0x3e, 0x09, 0x85, 0x6e, 0x76, 0x17, 0xac, 0x40, 0x77, 0xa1, 0xdc, + 0xd3, 0xdd, 0x46, 0xb3, 0xd5, 0xab, 0x3c, 0x69, 0x89, 0x77, 0x7a, 0x24, 0xfd, 0x4e, 0x7f, 0xa6, + 0xc1, 0x64, 0x2c, 0x63, 0x83, 0x0a, 0x4a, 0x08, 0x14, 0x3d, 0xea, 0xee, 0xa3, 0x57, 0xe4, 0x6f, + 0x32, 0x9f, 0x7c, 0x23, 0x14, 0xda, 0x44, 0xd7, 0x69, 0xc0, 0x45, 0xde, 0x66, 0x1e, 0x75, 0x9c, + 0xb0, 0xa1, 0xa9, 0x73, 0xaf, 0x29, 0xdf, 0x74, 0x25, 0x8a, 0xe0, 0xd1, 0x56, 0x7c, 0x92, 0x44, + 0x5a, 0xec, 0x8b, 0x74, 0x34, 0x8d, 0x94, 0xe2, 0x3b, 0x98, 0x65, 0x99, 0xd8, 0x75, 0x35, 0x2a, + 0x68, 0xbe, 0xeb, 0xd2, 0xda, 0x46, 0xae, 0x0b, 0xf9, 0xf4, 0x00, 0xe3, 0xff, 0xb8, 0x88, 0x0d, + 0x15, 0x5d, 0xff, 0x1f, 0x1f, 0xfc, 0x57, 0x83, 0x6f, 0x24, 0x45, 0xb5, 0xa5, 0x1b, 0x1e, 0x00, + 0xc4, 0x83, 0x35, 0xbe, 0x23, 0x0b, 0x83, 0x54, 0x8a, 0x26, 0xb0, 0x98, 0x93, 0x38, 0x30, 0x1b, + 0xaf, 0xa2, 0xce, 0xdb, 0xf4, 0x2d, 0xee, 0x31, 0x7c, 0xf5, 0x6e, 0x0e, 0xba, 0x15, 0xdf, 0xa7, + 0x9d, 0x90, 0x07, 0x25, 0xcc, 0x78, 0x99, 0xa7, 0x2f, 0xe5, 0xd9, 0x7d, 0xac, 0x18, 0x39, 0x66, + 0x47, 0x07, 0x7f, 0x98, 0x72, 0xf0, 0x9b, 0x03, 0x1d, 0xac, 0x4c, 0x99, 0xf4, 0xf1, 0xca, 0x6f, + 0x66, 0x60, 0x54, 0x4a, 0x23, 0x3f, 0xd7, 0x60, 0x4c, 0x3d, 0x6c, 0x64, 0x31, 0xe7, 0x7d, 0x4e, + 0x0d, 0xf7, 0xa5, 0xeb, 0x43, 0x50, 0x2a, 0xb0, 0xfa, 0xeb, 0x3f, 0xfb, 0xcb, 0x3f, 0x7f, 0x59, + 0x28, 0x93, 0x79, 0x23, 0xe7, 0xc3, 0x0a, 0xf9, 0xad, 0x06, 0x13, 0xf1, 0x54, 0xb0, 0x94, 0x77, + 0x7d, 0xcf, 0xf0, 0x5f, 0xba, 0x39, 0x1c, 0x31, 0xc2, 0x59, 0x96, 0x70, 0x96, 0xc8, 0xf5, 0x3e, + 0x70, 0x22, 0x06, 0xe3, 0x08, 0x3d, 0xd6, 0x21, 0xbf, 0xd3, 0x60, 0x3c, 0xba, 0x88, 0xdc, 0x18, + 0x42, 0x5a, 0x84, 0x6c, 0x69, 0x28, 0x5a, 0x04, 0x76, 0x57, 0x02, 0xbb, 0x45, 0x56, 0xf2, 0x81, + 0x19, 0x47, 0x98, 0x63, 0x9d, 0x04, 0xc2, 0xcf, 0x34, 0x80, 0xb8, 0x81, 0x22, 0x37, 0x87, 0xec, + 0xb3, 0x14, 0xca, 0x93, 0x75, 0x65, 0xfa, 0xaa, 0xc4, 0xf9, 0x2e, 0xb9, 0x95, 0x8d, 0xb3, 0xc1, + 0xba, 0x73, 0x6d, 0x0c, 0xd0, 0x38, 0x52, 0x03, 0x68, 0x87, 0xfc, 0x51, 0x83, 0x73, 0xa9, 0x51, + 0x92, 0x18, 0x39, 0xe2, 0xb3, 0xc6, 0xde, 0xd2, 0xdb, 0xc3, 0x33, 0x20, 0xe4, 0xaa, 0x84, 0xfc, + 0x98, 0x3c, 0xca, 0x86, 0xdc, 0x96, 0x4c, 0x39, 0xa8, 0x8d, 0xa3, 0xc8, 0xfa, 0x1d, 0xe3, 0x48, + 0xce, 0x41, 0x1d, 0xf2, 0x2f, 0x0d, 0xa6, 0x33, 0xa7, 0x3a, 0xf2, 0xde, 0x10, 0x5e, 0xcf, 0x1a, + 0x4f, 0x4b, 0x77, 0x4e, 0xce, 0x88, 0x0a, 0xee, 0x4a, 0x05, 0x7f, 0x44, 0x3e, 0xca, 0x8f, 0x9d, + 0x6e, 0xd9, 0x53, 0xf3, 0x62, 0x4a, 0xad, 0x58, 0xe9, 0xc4, 0x64, 0x2b, 0x4d, 0x20, 0xab, 0x53, + 0x87, 0x7c, 0xaa, 0xc1, 0x44, 0x77, 0xea, 0xcb, 0xcd, 0xd0, 0xde, 0xf1, 0x33, 0x37, 0x43, 0x8f, + 0x0d, 0x92, 0x83, 0x02, 0x2c, 0xf0, 0x99, 0xa7, 0x3e, 0x7d, 0x66, 0xa6, 0xc2, 0x1f, 0x34, 0xb8, + 0x98, 0x31, 0xe6, 0x91, 0xdb, 0x39, 0x18, 0xfa, 0xcf, 0x94, 0xa5, 0x77, 0x4f, 0xca, 0x86, 0x4a, + 0x7c, 0x20, 0x95, 0x78, 0x8f, 0xdc, 0xce, 0x56, 0xc2, 0x97, 0xac, 0xf1, 0xe7, 0x11, 0xd3, 0xb1, + 0x7d, 0x91, 0xd0, 0xe2, 0xf7, 0x1a, 0x9c, 0xef, 0x99, 0xf4, 0xc8, 0x72, 0x0e, 0x94, 0xec, 0x49, + 0xb3, 0xb4, 0x72, 0x12, 0x16, 0x44, 0xbe, 0x26, 0x91, 0xaf, 0x92, 0xbb, 0xd9, 0xc8, 0x59, 0xc4, + 0x86, 0x23, 0xa3, 0x71, 0x14, 0xb5, 0xbc, 0x1d, 0xe3, 0x48, 0x0d, 0xab, 0x1d, 0xf2, 0xa7, 0x44, + 0x72, 0xa4, 0x9a, 0xde, 0xa1, 0x92, 0x23, 0xab, 0xd7, 0x1e, 0x2a, 0x39, 0x32, 0xfb, 0x6b, 0xfd, + 0xdb, 0x52, 0xa1, 0xbb, 0xe4, 0xce, 0x80, 0xe4, 0x68, 0x2a, 0x6e, 0x53, 0x8d, 0x01, 0x89, 0xe4, + 0x20, 0x7f, 0xd7, 0x60, 0xae, 0x6f, 0x1f, 0x4f, 0xde, 0xcf, 0x0b, 0x91, 0x01, 0x23, 0x44, 0x69, + 0xf5, 0xe5, 0x98, 0x51, 0xb5, 0x0d, 0xa9, 0xda, 0x3d, 0xb2, 0xda, 0x27, 0xca, 0x12, 0x17, 0x1c, + 0x53, 0xaf, 0xeb, 0x36, 0xf2, 0x2b, 0x0d, 0x20, 0x1e, 0xdf, 0xbf, 0xc6, 0xd7, 0xe3, 0xf8, 0x37, + 0x01, 0xfd, 0xba, 0x44, 0x7c, 0x95, 0x5c, 0xe9, 0x83, 0xb8, 0xb6, 0x1f, 0x15, 0x29, 0xf2, 0xb9, + 0x06, 0x17, 0x7a, 0xc7, 0x13, 0xb2, 0x32, 0xcc, 0x63, 0x9f, 0x9e, 0x75, 0x4a, 0xef, 0x9c, 0x88, + 0x07, 0x81, 0xbe, 0x2d, 0x81, 0xde, 0x20, 0x8b, 0x03, 0xfa, 0x04, 0xf5, 0xdd, 0xd2, 0xb4, 0x02, + 0xf2, 0x67, 0x0d, 0xc8, 0xf1, 0xde, 0x8d, 0xdc, 0x1a, 0xaa, 0x09, 0xe8, 0x19, 0x6f, 0x4a, 0xb7, + 0x4f, 0xc8, 0x85, 0xa8, 0x9f, 0x48, 0xd4, 0x9b, 0xe4, 0xe1, 0x80, 0x58, 0x8f, 0xdb, 0xd6, 0xac, + 0x22, 0x9a, 0xa8, 0xfa, 0xff, 0xd6, 0x60, 0xae, 0x6f, 0x43, 0x9a, 0x1b, 0xfa, 0x83, 0xa6, 0x87, + 0xdc, 0xd0, 0x1f, 0xd8, 0x03, 0xeb, 0x3f, 0x94, 0x9a, 0x6e, 0x93, 0x27, 0x43, 0x6b, 0x6a, 0xe2, + 0x6c, 0x9c, 0xaf, 0xf1, 0xda, 0xc6, 0x17, 0xcf, 0xcb, 0xda, 0x97, 0xcf, 0xcb, 0xda, 0x3f, 0x9e, + 0x97, 0xb5, 0x5f, 0xbc, 0x28, 0x9f, 0xfa, 0xf2, 0x45, 0xf9, 0xd4, 0x5f, 0x5f, 0x94, 0x4f, 0x7d, + 0x74, 0x23, 0xf1, 0x39, 0x36, 0x25, 0xb4, 0xbd, 0x62, 0x1c, 0x74, 0x25, 0xcb, 0xcf, 0xb2, 0xbb, + 0x63, 0xf2, 0xbf, 0xc6, 0xde, 0xf9, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf2, 0xdf, 0x5e, 0x89, + 0xe6, 0x1c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1732,6 +2109,10 @@ type QueryClient interface { SdkPairing(ctx context.Context, in *QueryGetPairingRequest, opts ...grpc.CallOption) (*QuerySdkPairingResponse, error) // Queries a for the aggregated CU of all ProviderEpochCu objects all the providers. ProvidersEpochCu(ctx context.Context, in *QueryProvidersEpochCuRequest, opts ...grpc.CallOption) (*QueryProvidersEpochCuResponse, error) + // Queries a for a provider reputation. + ProviderReputation(ctx context.Context, in *QueryProviderReputationRequest, opts ...grpc.CallOption) (*QueryProviderReputationResponse, error) + // Queries a for a provider reputation's details (mainly for developers). + ProviderReputationDetails(ctx context.Context, in *QueryProviderReputationDetailsRequest, opts ...grpc.CallOption) (*QueryProviderReputationDetailsResponse, error) } type queryClient struct { @@ -1859,6 +2240,24 @@ func (c *queryClient) ProvidersEpochCu(ctx context.Context, in *QueryProvidersEp return out, nil } +func (c *queryClient) ProviderReputation(ctx context.Context, in *QueryProviderReputationRequest, opts ...grpc.CallOption) (*QueryProviderReputationResponse, error) { + out := new(QueryProviderReputationResponse) + err := c.cc.Invoke(ctx, "/lavanet.lava.pairing.Query/ProviderReputation", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ProviderReputationDetails(ctx context.Context, in *QueryProviderReputationDetailsRequest, opts ...grpc.CallOption) (*QueryProviderReputationDetailsResponse, error) { + out := new(QueryProviderReputationDetailsResponse) + err := c.cc.Invoke(ctx, "/lavanet.lava.pairing.Query/ProviderReputationDetails", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Parameters queries the parameters of the module. @@ -1887,6 +2286,10 @@ type QueryServer interface { SdkPairing(context.Context, *QueryGetPairingRequest) (*QuerySdkPairingResponse, error) // Queries a for the aggregated CU of all ProviderEpochCu objects all the providers. ProvidersEpochCu(context.Context, *QueryProvidersEpochCuRequest) (*QueryProvidersEpochCuResponse, error) + // Queries a for a provider reputation. + ProviderReputation(context.Context, *QueryProviderReputationRequest) (*QueryProviderReputationResponse, error) + // Queries a for a provider reputation's details (mainly for developers). + ProviderReputationDetails(context.Context, *QueryProviderReputationDetailsRequest) (*QueryProviderReputationDetailsResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1932,6 +2335,12 @@ func (*UnimplementedQueryServer) SdkPairing(ctx context.Context, req *QueryGetPa func (*UnimplementedQueryServer) ProvidersEpochCu(ctx context.Context, req *QueryProvidersEpochCuRequest) (*QueryProvidersEpochCuResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ProvidersEpochCu not implemented") } +func (*UnimplementedQueryServer) ProviderReputation(ctx context.Context, req *QueryProviderReputationRequest) (*QueryProviderReputationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProviderReputation not implemented") +} +func (*UnimplementedQueryServer) ProviderReputationDetails(ctx context.Context, req *QueryProviderReputationDetailsRequest) (*QueryProviderReputationDetailsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProviderReputationDetails not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -2171,23 +2580,59 @@ func _Query_ProvidersEpochCu_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } -var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "lavanet.lava.pairing.Query", - HandlerType: (*QueryServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Params", - Handler: _Query_Params_Handler, - }, - { - MethodName: "Providers", - Handler: _Query_Providers_Handler, - }, - { - MethodName: "Provider", - Handler: _Query_Provider_Handler, - }, - { +func _Query_ProviderReputation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryProviderReputationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ProviderReputation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lavanet.lava.pairing.Query/ProviderReputation", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ProviderReputation(ctx, req.(*QueryProviderReputationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ProviderReputationDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryProviderReputationDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ProviderReputationDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/lavanet.lava.pairing.Query/ProviderReputationDetails", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ProviderReputationDetails(ctx, req.(*QueryProviderReputationDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "lavanet.lava.pairing.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "Providers", + Handler: _Query_Providers_Handler, + }, + { + MethodName: "Provider", + Handler: _Query_Provider_Handler, + }, + { MethodName: "GetPairing", Handler: _Query_GetPairing_Handler, }, @@ -2227,6 +2672,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "ProvidersEpochCu", Handler: _Query_ProvidersEpochCu_Handler, }, + { + MethodName: "ProviderReputation", + Handler: _Query_ProviderReputation_Handler, + }, + { + MethodName: "ProviderReputationDetails", + Handler: _Query_ProviderReputationDetails_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "lavanet/lava/pairing/query.proto", @@ -3369,123 +3822,396 @@ func (m *ProviderCuInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { - offset -= sovQuery(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *QueryParamsRequest) Size() (n int) { - if m == nil { - return 0 +func (m *QueryProviderReputationRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l - return n + return dAtA[:n], nil } -func (m *QueryParamsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovQuery(uint64(l)) - return n +func (m *QueryProviderReputationRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryProvidersRequest) Size() (n int) { - if m == nil { - return 0 - } +func (m *QueryProviderReputationRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.ChainID) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if len(m.Cluster) > 0 { + i -= len(m.Cluster) + copy(dAtA[i:], m.Cluster) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Cluster))) + i-- + dAtA[i] = 0x1a } - if m.ShowFrozen { - n += 2 + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainID))) + i-- + dAtA[i] = 0x12 } - return n + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *QueryProvidersResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.StakeEntry) > 0 { - for _, e := range m.StakeEntry { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } +func (m *ReputationData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - return n + return dAtA[:n], nil } -func (m *QueryProviderRequest) Size() (n int) { - if m == nil { - return 0 - } +func (m *ReputationData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReputationData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.Address) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if len(m.Cluster) > 0 { + i -= len(m.Cluster) + copy(dAtA[i:], m.Cluster) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Cluster))) + i-- + dAtA[i] = 0x2a } - l = len(m.ChainID) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainID))) + i-- + dAtA[i] = 0x22 } - return n + if len(m.OverallPerformance) > 0 { + i -= len(m.OverallPerformance) + copy(dAtA[i:], m.OverallPerformance) + i = encodeVarintQuery(dAtA, i, uint64(len(m.OverallPerformance))) + i-- + dAtA[i] = 0x1a + } + if m.Providers != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Providers)) + i-- + dAtA[i] = 0x10 + } + if m.Rank != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Rank)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil } -func (m *QueryProviderResponse) Size() (n int) { - if m == nil { - return 0 +func (m *QueryProviderReputationResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *QueryProviderReputationResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryProviderReputationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if len(m.StakeEntries) > 0 { - for _, e := range m.StakeEntries { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) + if len(m.Data) > 0 { + for iNdEx := len(m.Data) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Data[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa } } - return n + return len(dAtA) - i, nil } -func (m *QueryGetPairingRequest) Size() (n int) { - if m == nil { - return 0 +func (m *QueryProviderReputationDetailsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *QueryProviderReputationDetailsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryProviderReputationDetailsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.ChainID) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if len(m.Cluster) > 0 { + i -= len(m.Cluster) + copy(dAtA[i:], m.Cluster) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Cluster))) + i-- + dAtA[i] = 0x1a } - l = len(m.Client) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainID))) + i-- + dAtA[i] = 0x12 } - return n + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *QueryGetPairingResponse) Size() (n int) { - if m == nil { - return 0 +func (m *ReputationDevData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l + return dAtA[:n], nil +} + +func (m *ReputationDevData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReputationDevData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Cluster) > 0 { + i -= len(m.Cluster) + copy(dAtA[i:], m.Cluster) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Cluster))) + i-- + dAtA[i] = 0x2a + } + if len(m.ChainID) > 0 { + i -= len(m.ChainID) + copy(dAtA[i:], m.ChainID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainID))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.ReputationPairingScore.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Reputation.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryProviderReputationDetailsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryProviderReputationDetailsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryProviderReputationDetailsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + for iNdEx := len(m.Data) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Data[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryProvidersRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.ShowFrozen { + n += 2 + } + return n +} + +func (m *QueryProvidersResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.StakeEntry) > 0 { + for _, e := range m.StakeEntry { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryProviderRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryProviderResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.StakeEntries) > 0 { + for _, e := range m.StakeEntries { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryGetPairingRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Client) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryGetPairingResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l if len(m.Providers) > 0 { for _, e := range m.Providers { l = e.Size() @@ -3865,64 +4591,184 @@ func (m *ProviderCuInfo) Size() (n int) { return n } -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } +func (m *QueryProviderReputationRequest) Size() (n int) { + if m == nil { + return 0 } - - if iNdEx > l { - return io.ErrUnexpectedEOF + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) } - return nil -} -func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Cluster) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *ReputationData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Rank != 0 { + n += 1 + sovQuery(uint64(m.Rank)) + } + if m.Providers != 0 { + n += 1 + sovQuery(uint64(m.Providers)) + } + l = len(m.OverallPerformance) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Cluster) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryProviderReputationResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Data) > 0 { + for _, e := range m.Data { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryProviderReputationDetailsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Cluster) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *ReputationDevData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Reputation.Size() + n += 1 + l + sovQuery(uint64(l)) + l = m.ReputationPairingScore.Size() + n += 1 + l + sovQuery(uint64(l)) + l = len(m.ChainID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Cluster) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryProviderReputationDetailsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Data) > 0 { + for _, e := range m.Data { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -6985,6 +7831,830 @@ func (m *ProviderCuInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryProviderReputationRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryProviderReputationRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryProviderReputationRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cluster = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ReputationData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReputationData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReputationData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Rank", wireType) + } + m.Rank = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Rank |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Providers", wireType) + } + m.Providers = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Providers |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OverallPerformance", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OverallPerformance = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cluster = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryProviderReputationResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryProviderReputationResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryProviderReputationResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data, ReputationData{}) + if err := m.Data[len(m.Data)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryProviderReputationDetailsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryProviderReputationDetailsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryProviderReputationDetailsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cluster = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ReputationDevData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReputationDevData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReputationDevData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reputation", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Reputation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReputationPairingScore", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ReputationPairingScore.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cluster = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryProviderReputationDetailsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryProviderReputationDetailsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryProviderReputationDetailsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data, ReputationDevData{}) + if err := m.Data[len(m.Data)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/pairing/types/query.pb.gw.go b/x/pairing/types/query.pb.gw.go index 8eab096ed7..9f73baeea1 100644 --- a/x/pairing/types/query.pb.gw.go +++ b/x/pairing/types/query.pb.gw.go @@ -901,6 +901,202 @@ func local_request_Query_ProvidersEpochCu_0(ctx context.Context, marshaler runti } +func request_Query_ProviderReputation_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryProviderReputationRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["chainID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chainID") + } + + protoReq.ChainID, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chainID", err) + } + + val, ok = pathParams["cluster"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster") + } + + protoReq.Cluster, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster", err) + } + + msg, err := client.ProviderReputation(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ProviderReputation_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryProviderReputationRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["chainID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chainID") + } + + protoReq.ChainID, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chainID", err) + } + + val, ok = pathParams["cluster"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster") + } + + protoReq.Cluster, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster", err) + } + + msg, err := server.ProviderReputation(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_ProviderReputationDetails_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryProviderReputationDetailsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["chainID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chainID") + } + + protoReq.ChainID, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chainID", err) + } + + val, ok = pathParams["cluster"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster") + } + + protoReq.Cluster, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster", err) + } + + msg, err := client.ProviderReputationDetails(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ProviderReputationDetails_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryProviderReputationDetailsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["chainID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chainID") + } + + protoReq.ChainID, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chainID", err) + } + + val, ok = pathParams["cluster"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster") + } + + protoReq.Cluster, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster", err) + } + + msg, err := server.ProviderReputationDetails(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -1206,6 +1402,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_ProviderReputation_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ProviderReputation_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ProviderReputation_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ProviderReputationDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ProviderReputationDetails_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ProviderReputationDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1507,6 +1749,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_ProviderReputation_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ProviderReputation_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ProviderReputation_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ProviderReputationDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ProviderReputationDetails_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ProviderReputationDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1536,6 +1818,10 @@ var ( pattern_Query_SdkPairing_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lavanet", "lava", "pairing", "sdk_pairing"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ProvidersEpochCu_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lavanet", "lava", "pairing", "providers_epoch_cu"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ProviderReputation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lavanet", "lava", "pairing", "provider_reputation", "address", "chainID", "cluster"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ProviderReputationDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lavanet", "lava", "pairing", "provider_reputation_details", "address", "chainID", "cluster"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -1564,4 +1850,8 @@ var ( forward_Query_SdkPairing_0 = runtime.ForwardResponseMessage forward_Query_ProvidersEpochCu_0 = runtime.ForwardResponseMessage + + forward_Query_ProviderReputation_0 = runtime.ForwardResponseMessage + + forward_Query_ProviderReputationDetails_0 = runtime.ForwardResponseMessage ) diff --git a/x/pairing/types/relay.pb.go b/x/pairing/types/relay.pb.go index a5b9c357bc..e6d3c82efa 100644 --- a/x/pairing/types/relay.pb.go +++ b/x/pairing/types/relay.pb.go @@ -764,9 +764,14 @@ func (m *RelayReply) GetMetadata() []Metadata { } type QualityOfServiceReport struct { - Latency github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=latency,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"latency" yaml:"Latency"` + // Latency of provider answers in milliseconds, range 0-inf, lower is better + Latency github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=latency,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"latency" yaml:"Latency"` + // Percentage of times the provider returned a non-error response, range 0-1, higher is better Availability github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=availability,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"availability" yaml:"availability"` - Sync github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=sync,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"sync" yaml:"sync"` + // Amount of time the provider is not synced (have the latest block) in milliseconds, range 0-inf, lower is better. + // Example: in ETH we have 15sec block time. So sync = 15000 means that the provider is one block + // behind the actual latest block. + Sync github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=sync,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"sync" yaml:"sync"` } func (m *QualityOfServiceReport) Reset() { *m = QualityOfServiceReport{} } From 37cd180f9ce59bbd5344831c12ec8cd42102a9c0 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 15 Aug 2024 17:04:39 +0300 Subject: [PATCH 16/33] CNS-1006: small adjustments and README update --- proto/lavanet/lava/pairing/query.proto | 2 +- x/pairing/README.md | 5 +++++ .../client/cli/query_provider_reputation_details.go | 2 +- x/pairing/client/cli/query_providers_epoch_cu.go | 4 ++-- x/pairing/keeper/grpc_query_provider_reputation.go | 11 ++++++----- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/proto/lavanet/lava/pairing/query.proto b/proto/lavanet/lava/pairing/query.proto index d172262ddb..8f6b650bb4 100644 --- a/proto/lavanet/lava/pairing/query.proto +++ b/proto/lavanet/lava/pairing/query.proto @@ -260,7 +260,7 @@ message QueryProviderReputationRequest { message ReputationData { uint64 rank = 1; // rank compared to other providers uint64 providers = 2; // amount of providers with the same chainID+cluster - string overall_performance = 3; // overall performance metric which can be "good", "bad", or "not enough data" + string overall_performance = 3; // overall performance metric which can be "good", "bad", or "low variance" string chainID = 4; string cluster = 5; } diff --git a/x/pairing/README.md b/x/pairing/README.md index 13875e5281..b1737ef4af 100644 --- a/x/pairing/README.md +++ b/x/pairing/README.md @@ -342,8 +342,13 @@ The pairing module supports the following queries: | `list-epoch-payments` | none | show all epochPayment objects | | `list-provider-payment-storage` | none | show all providerPaymentStorage objects | | `list-unique-payment-storage-client-provider` | none | show all uniquePaymentStorageClientProvider objects | +| `provider` | chain-id (string) | show a provider staked on a specific chain | | `provider-monthly-payout` | provider (string) | show the current monthly payout for a specific provider | +| `provider-pairing-chance` | provider (string), chain-id (string) | show the chance of a provider has to be part of the pairing list for a specific chain | +| `provider-reputation` | provider (string), chain-id (string), cluster (string) | show the provider's rank compared to other provider with the same chain-id and cluster by their reputation score | +| `provider-reputation-details` | provider (string), chain-id (string), cluster (string) | developer query to show the provider's reputation score raw data | | `providers` | chain-id (string) | show all the providers staked on a specific chain | +| `providers-epoch-cu` | | developer query to list the amount of CU serviced by all the providers every epoch | | `sdk-pairing` | none | query used by Lava-SDK to get all the required pairing info | | `show-epoch-payments` | index (string) | show an epochPayment object by index | | `show-provider-payment-storage` | index (string) | show a providerPaymentStorage object by index | diff --git a/x/pairing/client/cli/query_provider_reputation_details.go b/x/pairing/client/cli/query_provider_reputation_details.go index 2f2a2240a8..09feed0b21 100644 --- a/x/pairing/client/cli/query_provider_reputation_details.go +++ b/x/pairing/client/cli/query_provider_reputation_details.go @@ -14,7 +14,7 @@ var _ = strconv.Itoa(0) func CmdProviderReputationDetails() *cobra.Command { cmd := &cobra.Command{ - Use: "provider-reputation [address] [chain-id] [cluster]", + Use: "provider-reputation-details [address] [chain-id] [cluster]", Short: "Query for a provider's reputation details. Mainly used by developers. Use \"*\" for specify all for chain/cluster.", Args: cobra.ExactArgs(3), Example: ` diff --git a/x/pairing/client/cli/query_providers_epoch_cu.go b/x/pairing/client/cli/query_providers_epoch_cu.go index d4e27f5e81..9b82552c72 100644 --- a/x/pairing/client/cli/query_providers_epoch_cu.go +++ b/x/pairing/client/cli/query_providers_epoch_cu.go @@ -10,10 +10,10 @@ import ( func CmdProvidersEpochCu() *cobra.Command { cmd := &cobra.Command{ Use: "providers-epoch-cu", - Short: "Query to show the amount of CU serviced by all provider in a specific epoch", + Short: "Query to list the amount of CU serviced by all the providers every epoch", Example: ` lavad q pairing providers-epoch-cu`, - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { diff --git a/x/pairing/keeper/grpc_query_provider_reputation.go b/x/pairing/keeper/grpc_query_provider_reputation.go index e11b07ce26..53cfe8d9f9 100644 --- a/x/pairing/keeper/grpc_query_provider_reputation.go +++ b/x/pairing/keeper/grpc_query_provider_reputation.go @@ -15,10 +15,11 @@ import ( ) const ( - varianceThreshold = float64(1) + varianceThreshold = float64(1) // decides if the overall_performance field can be calculated + percentileRank = float64(0.8) // rank for percentile to decide whether the overall_performance is "good" or "bad" goodScore = "good" badScore = "bad" - lowVariance = "low variance" + lowVariance = "low_variance" ) func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProviderReputationRequest) (*types.QueryProviderReputationResponse, error) { @@ -63,7 +64,7 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid // get all reputation pairing score indices for a chainID+cluster pair inds := k.reputationsFS.GetAllEntryIndicesWithPrefix(ctx, types.ReputationScoreKey(data.chainID, data.cluster, "")) - // collect all pairing scores with indices and sort + // collect all pairing scores with indices and sort in descending order pairingScores := []float64{} for _, ind := range inds { var score types.ReputationPairingScore @@ -77,7 +78,7 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid pairingScores = append(pairingScores, score.Score.MustFloat64()) } sort.Slice(pairingScores, func(i, j int) bool { - return pairingScores[i] < pairingScores[j] + return pairingScores[i] > pairingScores[j] }) // find the provider's rank @@ -96,7 +97,7 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid if variance < varianceThreshold { chainClusterRes.OverallPerformance = lowVariance } else { - if float64(rank) > float64(len(pairingScores))*0.8 { + if pairingScores[rank] > lavaslices.Percentile(pairingScores, percentileRank) { chainClusterRes.OverallPerformance = goodScore } else { chainClusterRes.OverallPerformance = badScore From d452affbb8356475360347445897743700f9518d Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 15 Aug 2024 17:41:10 +0300 Subject: [PATCH 17/33] CNS-1006: small fix and added unit test --- .../keeper/grpc_query_provider_reputation.go | 15 ++-- .../grpc_query_provider_reputation_test.go | 79 +++++++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/x/pairing/keeper/grpc_query_provider_reputation.go b/x/pairing/keeper/grpc_query_provider_reputation.go index 53cfe8d9f9..624862b162 100644 --- a/x/pairing/keeper/grpc_query_provider_reputation.go +++ b/x/pairing/keeper/grpc_query_provider_reputation.go @@ -64,7 +64,7 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid // get all reputation pairing score indices for a chainID+cluster pair inds := k.reputationsFS.GetAllEntryIndicesWithPrefix(ctx, types.ReputationScoreKey(data.chainID, data.cluster, "")) - // collect all pairing scores with indices and sort in descending order + // collect all pairing scores with indices and sort in ascending order pairingScores := []float64{} for _, ind := range inds { var score types.ReputationPairingScore @@ -78,13 +78,16 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid pairingScores = append(pairingScores, score.Score.MustFloat64()) } sort.Slice(pairingScores, func(i, j int) bool { - return pairingScores[i] > pairingScores[j] + return pairingScores[i] < pairingScores[j] }) // find the provider's rank - rank := sort.SearchFloat64s(pairingScores, data.score.MustFloat64()) - if rank < len(pairingScores) && pairingScores[rank] == data.score.MustFloat64() { - rank += 1 + rank := len(pairingScores) + for i, score := range pairingScores { + if data.score.MustFloat64() <= score { + rank -= i + break + } } // calculate the pairing scores variance @@ -97,7 +100,7 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid if variance < varianceThreshold { chainClusterRes.OverallPerformance = lowVariance } else { - if pairingScores[rank] > lavaslices.Percentile(pairingScores, percentileRank) { + if pairingScores[len(pairingScores)-rank] > lavaslices.Percentile(pairingScores, percentileRank) { chainClusterRes.OverallPerformance = goodScore } else { chainClusterRes.OverallPerformance = badScore diff --git a/x/pairing/keeper/grpc_query_provider_reputation_test.go b/x/pairing/keeper/grpc_query_provider_reputation_test.go index f7b3094011..7016b82e71 100644 --- a/x/pairing/keeper/grpc_query_provider_reputation_test.go +++ b/x/pairing/keeper/grpc_query_provider_reputation_test.go @@ -10,10 +10,89 @@ import ( "github.com/stretchr/testify/require" ) +// TestProviderReputation tests the provider-reputation query func TestProviderReputation(t *testing.T) { + ts := newTester(t) + ts.setupForPayments(4, 0, 0) // 4 providers + + _, p1 := ts.GetAccount(common.PROVIDER, 0) + _, p2 := ts.GetAccount(common.PROVIDER, 1) + _, p3 := ts.GetAccount(common.PROVIDER, 2) + _, p4 := ts.GetAccount(common.PROVIDER, 3) + + specs := []string{"spec1", "spec2", "spec1", "spec1", "spec1", "spec2", "spec2"} + clusters := []string{"cluster1", "cluster1", "cluster2", "cluster1", "cluster1", "cluster1", "cluster2"} + providers := []string{p1, p1, p1, p2, p3, p3, p4} + + // Reputation score setup: + // spec1 + cluster1: p1=1, p2=4, p3=5 + // spec1 + cluster2: p1=3 + // spec2 + cluster1: p1=2, p3=6 + // spec2 + cluster2: p4=7 + for i := range providers { + err := ts.Keepers.Pairing.SetReputationScore(ts.Ctx, specs[i], clusters[i], providers[i], sdk.NewDec(int64(i+1))) + require.NoError(t, err) + } + // test only on p1 + tests := []struct { + name string + chain string + cluster string + expected []types.ReputationData + }{ + { + "spec1+cluster1", "spec1", "cluster1", []types.ReputationData{ + {Rank: 3, Providers: 3, OverallPerformance: "bad", ChainID: "spec1", Cluster: "cluster1"}, + }, + }, + { + "spec1", "spec1", "*", []types.ReputationData{ + {Rank: 3, Providers: 3, OverallPerformance: "bad", ChainID: "spec1", Cluster: "cluster1"}, + {Rank: 1, Providers: 1, OverallPerformance: "low_variance", ChainID: "spec1", Cluster: "cluster2"}, + }, + }, + { + "cluster1", "*", "cluster1", []types.ReputationData{ + {Rank: 3, Providers: 3, OverallPerformance: "bad", ChainID: "spec1", Cluster: "cluster1"}, + {Rank: 2, Providers: 2, OverallPerformance: "bad", ChainID: "spec2", Cluster: "cluster2"}, + }, + }, + { + "all", "*", "*", []types.ReputationData{ + {Rank: 3, Providers: 3, OverallPerformance: "bad", ChainID: "spec1", Cluster: "cluster1"}, + {Rank: 2, Providers: 2, OverallPerformance: "bad", ChainID: "spec2", Cluster: "cluster2"}, + {Rank: 1, Providers: 1, OverallPerformance: "low_variance", ChainID: "spec1", Cluster: "cluster2"}, + }, + }, + { + "spec2+cluster2 (p1 not exist)", "spec2", "cluster2", []types.ReputationData{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := ts.QueryPairingProviderReputation(p1, tt.chain, tt.cluster) + require.NoError(t, err) + for _, data := range res.Data { + foundChainCluster := false + for _, expected := range tt.expected { + if data.ChainID == expected.ChainID && data.Cluster == expected.Cluster { + foundChainCluster = true + require.Equal(t, expected.Rank, data.Rank) + require.Equal(t, expected.Providers, data.Providers) + require.Equal(t, expected.OverallPerformance, data.OverallPerformance) + } + } + if !foundChainCluster { + require.FailNow(t, "could not find chain cluster pair on-chain") + } + } + }) + } } +// TestProviderReputationDetails tests the provider-reputation-details query func TestProviderReputationDetails(t *testing.T) { ts := newTester(t) ts.setupForPayments(2, 0, 0) // 2 providers From 8a34d7476fa702b8c2b5e166964e13b1b91d66e4 Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 4 Sep 2024 12:25:14 +0300 Subject: [PATCH 18/33] CNS-1004: fix after merge --- x/pairing/types/QualityOfServiceReport.go | 2 +- x/pairing/types/relay.pb.go | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/x/pairing/types/QualityOfServiceReport.go b/x/pairing/types/QualityOfServiceReport.go index e06b1d7550..51b836e967 100644 --- a/x/pairing/types/QualityOfServiceReport.go +++ b/x/pairing/types/QualityOfServiceReport.go @@ -5,7 +5,7 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/lavanet/lava/v2/utils" + "github.com/lavanet/lava/v3/utils" ) func (qos *QualityOfServiceReport) ComputeQoS() (sdk.Dec, error) { diff --git a/x/pairing/types/relay.pb.go b/x/pairing/types/relay.pb.go index df0b7b802d..c9eb9831bb 100644 --- a/x/pairing/types/relay.pb.go +++ b/x/pairing/types/relay.pb.go @@ -765,9 +765,14 @@ func (m *RelayReply) GetMetadata() []Metadata { } type QualityOfServiceReport struct { - Latency github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=latency,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"latency" yaml:"Latency"` + // Latency of provider answers in milliseconds, range 0-inf, lower is better + Latency github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=latency,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"latency" yaml:"Latency"` + // Percentage of times the provider returned a non-error response, range 0-1, higher is better Availability github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=availability,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"availability" yaml:"availability"` - Sync github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=sync,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"sync" yaml:"sync"` + // Amount of time the provider is not synced (have the latest block) in milliseconds, range 0-inf, lower is better. + // Example: in ETH we have 15sec block time. So sync = 15000 means that the provider is one block + // behind the actual latest block. + Sync github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=sync,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"sync" yaml:"sync"` } func (m *QualityOfServiceReport) Reset() { *m = QualityOfServiceReport{} } From e374c8b82be5429c40c3b8c0baac490653d0523b Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 5 Dec 2024 15:16:03 +0200 Subject: [PATCH 19/33] small fixes --- x/pairing/keeper/msg_server_relay_payment.go | 2 +- x/pairing/keeper/msg_server_relay_payment_test.go | 2 +- x/pairing/types/QualityOfServiceReport.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 8c1415317b..8aa5acfa9b 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -204,7 +204,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen utils.LogAttr("provider", relay.Provider), ) } - effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.EffectiveStake()) + effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.TotalStake()) // note the current weight used is by relay num. In the future, it might change k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum), effectiveStake) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 1505596d6c..e4051ccd0f 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1122,7 +1122,7 @@ func TestUpdateReputationEpochQosScore(t *testing.T) { require.True(t, epochScore1.LT(epochScore2)) // score is lower because QoS is excellent require.True(t, variance1.GT(variance2)) // variance is higher because the QoS is significantly differnet from DefaultQos - entry, found := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, provider1) + entry, found := ts.Keepers.Epochstorage.GetStakeEntryCurrent(ts.Ctx, ts.spec.Index, provider1) require.True(t, found) require.True(t, entry.Stake.IsEqual(r1.Stake)) } diff --git a/x/pairing/types/QualityOfServiceReport.go b/x/pairing/types/QualityOfServiceReport.go index 51b836e967..063a8f8836 100644 --- a/x/pairing/types/QualityOfServiceReport.go +++ b/x/pairing/types/QualityOfServiceReport.go @@ -5,7 +5,7 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/lavanet/lava/v3/utils" + "github.com/lavanet/lava/v4/utils" ) func (qos *QualityOfServiceReport) ComputeQoS() (sdk.Dec, error) { From 5ad9aaed01322d63d9e93b108410e91fa8aed42a Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 5 Jan 2025 14:33:44 +0200 Subject: [PATCH 20/33] pr fix --- x/pairing/keeper/msg_server_relay_payment.go | 71 ++++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 8aa5acfa9b..be6234a93a 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -173,41 +173,17 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen // update the reputation's epoch QoS score // the excellece QoS report can be nil when the provider and consumer geolocations are not equal if relay.QosExcellenceReport != nil { - sub, found := k.subscriptionKeeper.GetSubscription(ctx, project.Subscription) - if !found { - return nil, utils.LavaFormatError("RelayPayment: could not get cluster for reputation score update", fmt.Errorf("relay consumer's subscription not found"), - utils.LogAttr("consumer", clientAddr), - utils.LogAttr("project", project.Index), - utils.LogAttr("subscription", project.Subscription), - utils.LogAttr("chain", relay.SpecId), - utils.LogAttr("provider", relay.Provider), - ) - } - - syncFactor := k.ReputationLatencyOverSyncFactor(ctx) - score, err := relay.QosExcellenceReport.ComputeQosExcellenceForReputation(syncFactor) + err = k.updateReputationEpochQosScore(ctx, project.Subscription, relay) if err != nil { - return nil, utils.LavaFormatWarning("RelayPayment: could not compute qos excellence score", err, - utils.LogAttr("consumer", clientAddr), + return nil, utils.LavaFormatWarning("RelayPayment: could not update reputation epoch QoS score", err, + utils.LogAttr("consumer", project.Subscription), + utils.LogAttr("project", project.Index), utils.LogAttr("chain", relay.SpecId), utils.LogAttr("provider", relay.Provider), utils.LogAttr("qos_excellence_report", relay.QosExcellenceReport.String()), - utils.LogAttr("sync_factor", syncFactor.String()), + utils.LogAttr("sync_factor", k.ReputationLatencyOverSyncFactor(ctx).String()), ) } - - stakeEntry, found := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, relay.SpecId, relay.Provider) - if !found { - return nil, utils.LavaFormatWarning("RelayPayment: could not get stake entry for reputation", fmt.Errorf("stake entry not found"), - utils.LogAttr("consumer", clientAddr), - utils.LogAttr("chain", relay.SpecId), - utils.LogAttr("provider", relay.Provider), - ) - } - effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.TotalStake()) - - // note the current weight used is by relay num. In the future, it might change - k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum), effectiveStake) } // TODO: add support for spec changes @@ -513,3 +489,40 @@ func (k Keeper) handleBadgeCu(ctx sdk.Context, badgeData BadgeData, provider str badgeUsedCuMapEntry.UsedCu += relayCuSum k.SetBadgeUsedCu(ctx, badgeUsedCuMapEntry) } + +func (k Keeper) updateReputationEpochQosScore(ctx sdk.Context, subscription string, relay *types.RelaySession) error { + sub, found := k.subscriptionKeeper.GetSubscription(ctx, subscription) + if !found { + return utils.LavaFormatError("RelayPayment: could not get cluster for reputation score update", fmt.Errorf("relay consumer's subscription not found"), + utils.LogAttr("subscription", subscription), + utils.LogAttr("chain", relay.SpecId), + utils.LogAttr("provider", relay.Provider), + ) + } + + syncFactor := k.ReputationLatencyOverSyncFactor(ctx) + score, err := relay.QosExcellenceReport.ComputeQosExcellenceForReputation(syncFactor) + if err != nil { + return utils.LavaFormatWarning("RelayPayment: could not compute qos excellence score", err, + utils.LogAttr("consumer", subscription), + utils.LogAttr("chain", relay.SpecId), + utils.LogAttr("provider", relay.Provider), + utils.LogAttr("qos_excellence_report", relay.QosExcellenceReport.String()), + utils.LogAttr("sync_factor", syncFactor.String()), + ) + } + + stakeEntry, found := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, relay.SpecId, relay.Provider) + if !found { + return utils.LavaFormatWarning("RelayPayment: could not get stake entry for reputation", fmt.Errorf("stake entry not found"), + utils.LogAttr("consumer", subscription), + utils.LogAttr("chain", relay.SpecId), + utils.LogAttr("provider", relay.Provider), + ) + } + effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.TotalStake()) + + // note the current weight used is by relay num. In the future, it might change + k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum), effectiveStake) + return nil +} From 0b0e7193701728b2ede6ee92b6544be76cfca8fb Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 5 Jan 2025 14:50:12 +0200 Subject: [PATCH 21/33] remove panics from reputation update failure --- x/pairing/keeper/reputation.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 8c6f91386c..3ec8bb3ea5 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -134,7 +134,7 @@ func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { // note, the map is already sorted by QoS score in ascending order. scores, err := k.UpdateReputationsForEpochStart(ctx) if err != nil { - panic(utils.LavaFormatError("UpdateReputationQosScore: could not update providers QoS scores", err)) + utils.LavaFormatError("critical: UpdateReputationQosScore: could not update providers QoS scores", err) } // sort keys @@ -153,13 +153,13 @@ func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { // get benchmark score value benchmark, err := k.GetBenchmarkReputationScore(stakeProvidersScore) if err != nil { - panic(utils.LavaFormatError("UpdateReputationQosScore: could not get benchmark QoS score", err)) + utils.LavaFormatError("critical: UpdateReputationQosScore: could not get benchmark QoS score", err) } // set reputation pairing score by the benchmark err = k.setReputationPairingScoreByBenchmark(ctx, chainID, cluster, benchmark, stakeProvidersScore.ProviderScores) if err != nil { - panic(utils.LavaFormatError("UpdateReputationQosScore: could not set repuatation pairing scores", err)) + utils.LavaFormatError("critical: UpdateReputationQosScore: could not set repuatation pairing scores", err) } } } From 094ee32996d49feb4cfe2a9f51f23b2c4964b90e Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 5 Jan 2025 15:10:58 +0200 Subject: [PATCH 22/33] various commnets and small fixes --- x/pairing/keeper/reputation.go | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 3ec8bb3ea5..d8e565bf6a 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -150,7 +150,11 @@ func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { split := strings.Split(chainCluster, " ") chainID, cluster := split[0], split[1] - // get benchmark score value + // get benchmark score value. It's used as a percentile score to determine the reputation pairing score + // of each provider in a scale of [MinReputationPairingScore, MaxReputationPairingScore] (currently 0.5-2). + // to clarify, providers score are determined by their QoS score compared to the other providers that share the same chain ID and cluster. + // the benchmark score is the score of the provider that has the lowest QoS score within the 90th percentile + // of the providers in the chain ID and cluster. benchmark, err := k.GetBenchmarkReputationScore(stakeProvidersScore) if err != nil { utils.LavaFormatError("critical: UpdateReputationQosScore: could not get benchmark QoS score", err) @@ -200,6 +204,16 @@ func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]Stak ) } + if reputation.EpochScore == types.ZeroQosScore { + // if the epoch score is zero, we don't need to update the reputation + utils.LavaFormatWarning("updateReputationsScores: epoch score is zero, skipping update", nil, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", provider), + ) + continue + } + // apply time decay on current score and add the epoch score (which is reset right after) reputation, err = reputation.ApplyTimeDecayAndUpdateScore(halfLifeFactor, currentTime) if err != nil { @@ -227,6 +241,10 @@ func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]Stak scores[chainID+" "+cluster] = providerScores } + // in the provider scoring process, each provider is scored by its QoS score compared to the other providers + // that share the same chain ID and cluster. + // sortProviderScores() sorts the providers by their QoS score in ascending order so that the best score is first + // (low is better). This allows us to get the benchmark score more easily. sortProviderScores(scores) return scores, nil } @@ -322,7 +340,7 @@ func (k Keeper) setReputationPairingScoreByBenchmark(ctx sdk.Context, chainID st } if score.IsNegative() { - utils.LavaFormatError("setReputationPairingScoreByBenchmark: invalid provider score", fmt.Errorf("score is negative"), + return utils.LavaFormatError("setReputationPairingScoreByBenchmark: invalid provider score", fmt.Errorf("score is negative"), utils.LogAttr("chain_id", chainID), utils.LogAttr("cluster", cluster), utils.LogAttr("provider", providerScore.Provider), @@ -332,6 +350,8 @@ func (k Keeper) setReputationPairingScoreByBenchmark(ctx sdk.Context, chainID st scaledScore := types.MinReputationPairingScore if score.IsZero() || score.LTE(benchmark) { + // since the benchmark is a very high percentile score, we set the scaled score to the max + // for providers that have a score lower than the benchmark. scaledScore = types.MaxReputationPairingScore } else if score.GT(benchmark) { scaledScore = types.MinReputationPairingScore.Add((benchmark.Quo(score)).Mul(scale)) From 0989d8df387017b25d6fe2ccf0588a8c0e192ef6 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 5 Jan 2025 15:30:10 +0200 Subject: [PATCH 23/33] avoid string parsing --- .../keeper/msg_server_relay_payment_test.go | 6 ++--- x/pairing/keeper/reputation.go | 23 +++++++++---------- x/pairing/types/reputation.go | 9 ++++++++ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 16e9bd5634..08a6a2d4d6 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1365,8 +1365,8 @@ func TestUpdateReputationScoresSortedMap(t *testing.T) { } // create expected map (supposed to be sorted by score) - expected := map[string]keeper.StakeProviderScores{ - "mockspec cluster": { + expected := map[types.ReputationChainClusterKey]keeper.StakeProviderScores{ + {ChainID: "mockspec", Cluster: "cluster"}: { TotalStake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(3)), // 1+2 ProviderScores: []keeper.ProviderQosScore{ { @@ -1382,7 +1382,7 @@ func TestUpdateReputationScoresSortedMap(t *testing.T) { }, }, - "mockspec1 cluster": { + {ChainID: "mockspec1", Cluster: "cluster"}: { TotalStake: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(12)), // 3+4+5 ProviderScores: []keeper.ProviderQosScore{ { diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index d8e565bf6a..485a79f738 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -3,7 +3,6 @@ package keeper import ( "fmt" "sort" - "strings" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -138,17 +137,18 @@ func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { } // sort keys - keys := []string{} + keys := []types.ReputationChainClusterKey{} for key := range scores { keys = append(keys, key) } - sort.Strings(keys) + sort.Slice(keys, func(i, j int) bool { + return keys[i].ChainID+" "+keys[i].Cluster < keys[j].ChainID+" "+keys[j].Cluster + }) // iterate over providers QoS scores with the same chain ID and cluster for _, chainCluster := range keys { stakeProvidersScore := scores[chainCluster] - split := strings.Split(chainCluster, " ") - chainID, cluster := split[0], split[1] + chainID, cluster := chainCluster.ChainID, chainCluster.Cluster // get benchmark score value. It's used as a percentile score to determine the reputation pairing score // of each provider in a scale of [MinReputationPairingScore, MaxReputationPairingScore] (currently 0.5-2). @@ -173,11 +173,11 @@ func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { // 2. resets the reputation epoch score // 3. updates it last update time // 4. add it to the scores map -func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]StakeProviderScores, error) { +func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[types.ReputationChainClusterKey]StakeProviderScores, error) { halfLifeFactor := k.ReputationHalfLifeFactor(ctx) currentTime := ctx.BlockTime().UTC().Unix() - scores := map[string]StakeProviderScores{} + scores := map[types.ReputationChainClusterKey]StakeProviderScores{} // iterate over all reputations iter, err := k.reputations.Iterate(ctx, nil) @@ -230,7 +230,7 @@ func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]Stak k.SetReputation(ctx, chainID, cluster, provider, reputation) // add entry to the scores map - providerScores, ok := scores[chainID+" "+cluster] + providerScores, ok := scores[types.ReputationChainClusterKey{ChainID: chainID, Cluster: cluster}] if !ok { providerScores.ProviderScores = []ProviderQosScore{{Provider: provider, Score: reputation.Score, Stake: reputation.Stake}} providerScores.TotalStake = reputation.Stake @@ -238,7 +238,7 @@ func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]Stak providerScores.ProviderScores = append(providerScores.ProviderScores, ProviderQosScore{Provider: provider, Score: reputation.Score, Stake: reputation.Stake}) providerScores.TotalStake = providerScores.TotalStake.Add(reputation.Stake) } - scores[chainID+" "+cluster] = providerScores + scores[types.ReputationChainClusterKey{ChainID: chainID, Cluster: cluster}] = providerScores } // in the provider scoring process, each provider is scored by its QoS score compared to the other providers @@ -250,10 +250,9 @@ func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[string]Stak } // sortProviderScores sorts the stakeProviderScores map score slices in ascending order -func sortProviderScores(scores map[string]StakeProviderScores) { +func sortProviderScores(scores map[types.ReputationChainClusterKey]StakeProviderScores) { for chainCluster, stakeProviderScores := range scores { - split := strings.Split(chainCluster, " ") - chainID, cluster := split[0], split[1] + chainID, cluster := chainCluster.ChainID, chainCluster.Cluster sort.Slice(stakeProviderScores.ProviderScores, func(i, j int) bool { iScore, err := stakeProviderScores.ProviderScores[i].Score.Score.Resolve() diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index f0eaef935b..7c8236b5fb 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -114,3 +114,12 @@ func (r Reputation) Validate() bool { func ReputationScoreKey(chainID string, cluster string, provider string) string { return chainID + " " + cluster + " " + provider } + +type ReputationChainClusterKey struct { + ChainID string + Cluster string +} + +func (rck ReputationChainClusterKey) String() string { + return rck.ChainID + " " + rck.Cluster +} From f160ec7c4299bf2454228ff7eb39d46cb1477a07 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 6 Jan 2025 11:53:34 +0200 Subject: [PATCH 24/33] fix bug in which TimeLastUpdated was updated every relay payment and not only on epoch start --- x/pairing/keeper/msg_server_relay_payment_test.go | 11 +++++++++++ x/pairing/keeper/reputation.go | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 08a6a2d4d6..b6e974c889 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1299,6 +1299,12 @@ func TestReputationUpdateOnEpochStart(t *testing.T) { require.NoError(t, err) ts.AdvanceEpoch() + // save reputation original time and advance hour + r, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) + require.True(t, found) + originalTime := r.TimeLastUpdated + ts.AdvanceTimeHours(1) + // send relay payment msg from provider1 relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), 10) relaySession.QosExcellenceReport = qos @@ -1312,6 +1318,11 @@ func TestReputationUpdateOnEpochStart(t *testing.T) { } ts.relayPaymentWithoutPay(payment, true) + // check that the time last updated is the same as the original time + // (a bug in which the TimeLastUpdated was updated in relay payment was fixed. + // The TimeLastUpdated should be updated only when the epoch starts) + require.Equal(t, originalTime, r.TimeLastUpdated) + // advance epoch and check reputation for expected results ts.AdvanceEpoch() reputation, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 485a79f738..98d019803f 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -109,7 +109,6 @@ func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, c // update the reputation and set r.EpochScore = updatedEpochScore - r.TimeLastUpdated = ctx.BlockTime().UTC().Unix() r.Stake = stake k.SetReputation(ctx, chainID, cluster, provider, r) } From ee2cf55eebf53a68afaeb921ed4b65905afb08be Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 6 Jan 2025 15:26:30 +0200 Subject: [PATCH 25/33] upon update calculate variance first and then the score --- x/pairing/keeper/msg_server_relay_payment_test.go | 8 ++++---- x/pairing/types/qos_score.go | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index e4051ccd0f..e6f2912ab4 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1076,9 +1076,9 @@ func TestUpdateReputationEpochQosScore(t *testing.T) { _, provider1 := ts.GetAccount(common.PROVIDER, 0) _, provider2 := ts.GetAccount(common.PROVIDER, 1) qos := &types.QualityOfServiceReport{ - Latency: sdk.ZeroDec(), - Availability: sdk.OneDec(), - Sync: sdk.ZeroDec(), + Latency: sdk.OneDec(), + Availability: sdk.NewDecWithPrec(1, 1), + Sync: sdk.OneDec(), } res, err := ts.QuerySubscriptionCurrent(consumer) @@ -1119,7 +1119,7 @@ func TestUpdateReputationEpochQosScore(t *testing.T) { require.NoError(t, err) variance2, err := r2.EpochScore.Variance.Resolve() require.NoError(t, err) - require.True(t, epochScore1.LT(epochScore2)) // score is lower because QoS is excellent + require.True(t, epochScore1.GT(epochScore2)) // score is higher because QoS is bad require.True(t, variance1.GT(variance2)) // variance is higher because the QoS is significantly differnet from DefaultQos entry, found := ts.Keepers.Epochstorage.GetStakeEntryCurrent(ts.Ctx, ts.spec.Index, provider1) diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index 5b244e6d55..51535b3e31 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -61,16 +61,16 @@ func (qs QosScore) Update(score math.LegacyDec, truncate bool, weight int64) Qos score = qs.truncate(score) } - // updated_score_num = qos_score_num + score * weight - // updated_score_denom = qos_score_denom + weight - qs.Score.Num = qs.Score.Num.Add(score.MulInt64(weight)) - qs.Score.Denom = qs.Score.Denom.Add(math.LegacyNewDec(weight)) - // updated_variance_num = qos_variance_num + (qos_score_num - score)^2 * weight // updated_score_denom = qos_score_denom + weight qs.Variance.Num = qs.Variance.Num.Add((qs.Score.Num.Sub(score)).Power(2).MulInt64(weight)) qs.Variance.Denom = qs.Variance.Denom.Add(math.LegacyNewDec(weight)) + // updated_score_num = qos_score_num + score * weight + // updated_score_denom = qos_score_denom + weight + qs.Score.Num = qs.Score.Num.Add(score.MulInt64(weight)) + qs.Score.Denom = qs.Score.Denom.Add(math.LegacyNewDec(weight)) + return qs } From e86b10c70535047ddf4785d73e8fefa1da378081 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 6 Jan 2025 15:27:49 +0200 Subject: [PATCH 26/33] fix unit test --- x/pairing/keeper/msg_server_relay_payment_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index c8c539a355..79cc09363b 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1105,14 +1105,14 @@ func TestUpdateReputationEpochQosScore(t *testing.T) { } ts.relayPaymentWithoutPay(payment, true) - // get both providers reputation: provider1 should have its epoch score and time last updated changed, + // get both providers reputation: provider1 should have its epoch score changed, // provider2 should have nothing change from the default r1, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider1) require.True(t, found) r2, found := ts.Keepers.Pairing.GetReputation(ts.Ctx, ts.spec.Index, cluster, provider2) require.True(t, found) - require.Greater(t, r1.TimeLastUpdated, r2.TimeLastUpdated) + require.Equal(t, r1.TimeLastUpdated, r2.TimeLastUpdated) epochScore1, err := r1.EpochScore.Score.Resolve() require.NoError(t, err) epochScore2, err := r2.EpochScore.Score.Resolve() From 600464ddc1ad42a235fc4161a7149733d4656a28 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 9 Jan 2025 16:13:01 +0200 Subject: [PATCH 27/33] pr fixes --- x/pairing/keeper/msg_server_relay_payment.go | 18 ++++-- .../keeper/msg_server_relay_payment_test.go | 64 ++++++++++--------- x/pairing/keeper/reputation.go | 3 +- x/pairing/types/qos_score.go | 4 +- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index be6234a93a..b06acfba22 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -47,6 +47,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen return nil, err } addressEpochBadgeMap := map[string]BadgeData{} + sessionRelaysAmount := map[uint64]int{} for _, relay := range msg.Relays { if relay.Badge != nil { mapKey := types.CreateAddressEpochBadgeMapKey(relay.Badge.Address, relay.Badge.Epoch) @@ -67,10 +68,15 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen addressEpochBadgeMap[mapKey] = badgeData } } + if _, ok := sessionRelaysAmount[relay.SessionId]; !ok { + sessionRelaysAmount[relay.SessionId] = 1 + } else { + sessionRelaysAmount[relay.SessionId]++ + } } var rejectedCu uint64 // aggregated rejected CU (due to badge CU overuse or provider double spending) - rejected_relays_num := len(msg.Relays) + rejectedRelaysNum := len(msg.Relays) for relayIdx, relay := range msg.Relays { rejectedCu += relay.CuSum providerAddr, err := sdk.AccAddressFromBech32(relay.Provider) @@ -173,7 +179,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen // update the reputation's epoch QoS score // the excellece QoS report can be nil when the provider and consumer geolocations are not equal if relay.QosExcellenceReport != nil { - err = k.updateReputationEpochQosScore(ctx, project.Subscription, relay) + err = k.aggregateReputationEpochQosScore(ctx, project.Subscription, relay, sessionRelaysAmount[relay.SessionId]) if err != nil { return nil, utils.LavaFormatWarning("RelayPayment: could not update reputation epoch QoS score", err, utils.LogAttr("consumer", project.Subscription), @@ -306,11 +312,11 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen ) } rejectedCu -= relay.CuSum - rejected_relays_num-- + rejectedRelaysNum-- } // if all relays failed, fail the TX - if rejected_relays_num != 0 { + if rejectedRelaysNum != 0 { return nil, utils.LavaFormatWarning("relay payment failed", fmt.Errorf("all relays rejected"), utils.Attribute{Key: "provider", Value: msg.Creator}, utils.Attribute{Key: "description", Value: msg.DescriptionString}, @@ -490,7 +496,7 @@ func (k Keeper) handleBadgeCu(ctx sdk.Context, badgeData BadgeData, provider str k.SetBadgeUsedCu(ctx, badgeUsedCuMapEntry) } -func (k Keeper) updateReputationEpochQosScore(ctx sdk.Context, subscription string, relay *types.RelaySession) error { +func (k Keeper) aggregateReputationEpochQosScore(ctx sdk.Context, subscription string, relay *types.RelaySession, relaysAmount int) error { sub, found := k.subscriptionKeeper.GetSubscription(ctx, subscription) if !found { return utils.LavaFormatError("RelayPayment: could not get cluster for reputation score update", fmt.Errorf("relay consumer's subscription not found"), @@ -523,6 +529,6 @@ func (k Keeper) updateReputationEpochQosScore(ctx sdk.Context, subscription stri effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.TotalStake()) // note the current weight used is by relay num. In the future, it might change - k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.RelayNum), effectiveStake) + k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(uint64(relaysAmount)), effectiveStake) return nil } diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index e6f2912ab4..02b3ea75d4 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1201,46 +1201,50 @@ func TestUpdateReputationEpochQosScoreRelayNumWeight(t *testing.T) { // these will be used to compare the score change with high/low relay numbers scoreUpdates := []sdk.Dec{} - // we set the stabilization period to 2 epochs time. Advancing one epoch means we won't truncate, - // advancing 3 means we will truncate. - relayNums := []uint64{100, 1} + // we set the number of clients to be 1 and 2 to test different relay amount in + // a session + clientsAmount := []int{2, 1} - for i := range relayNums { + for i := range clientsAmount { ts := newTester(t) - ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair - - consumerAcc, consumer := ts.GetAccount(common.CONSUMER, 0) + ts.setupForPayments(1, clientsAmount[i], 0) // 1 provider, clientsAmount[i] clients, default providers-to-pair _, provider1 := ts.GetAccount(common.PROVIDER, 0) - qos := &types.QualityOfServiceReport{ - Latency: sdk.NewDec(1000), - Availability: sdk.OneDec(), - Sync: sdk.NewDec(1000), - } + relays := []*types.RelaySession{} + cluster := "" + for j := 0; j < clientsAmount[i]; j++ { + consumerAcc, consumer := ts.GetAccount(common.CONSUMER, j) - resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) - require.NoError(t, err) - cluster := resQCurrent.Sub.Cluster + qos := &types.QualityOfServiceReport{ + Latency: sdk.NewDec(1000), + Availability: sdk.OneDec(), + Sync: sdk.NewDec(1000), + } - // set stabilization period to be 2*epoch time to avoid truncation - resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) - require.NoError(t, err) - resQParams.Params.ReputationVarianceStabilizationPeriod = int64(ts.EpochTimeDefault().Seconds()) - ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) + resQCurrent, err := ts.QuerySubscriptionCurrent(consumer) + require.NoError(t, err) + cluster = resQCurrent.Sub.Cluster - // set default reputation - ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider1, types.NewReputation(ts.Ctx)) - ts.AdvanceEpoch() + // set stabilization period to be 2*epoch time to avoid truncation + resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) + require.NoError(t, err) + resQParams.Params.ReputationVarianceStabilizationPeriod = int64(ts.EpochTimeDefault().Seconds()) + ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) - // send relay payment msg from provider1 - relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), relayNums[i]) - relaySession.QosExcellenceReport = qos - sig, err := sigs.Sign(consumerAcc.SK, *relaySession) - require.NoError(t, err) - relaySession.Sig = sig + // set default reputation + ts.Keepers.Pairing.SetReputation(ts.Ctx, ts.spec.Index, cluster, provider1, types.NewReputation(ts.Ctx)) + ts.AdvanceEpoch() + // send relay payment msg from provider1 + relaySession := ts.newRelaySession(provider1, 0, 100, ts.BlockHeight(), uint64(j)) + relaySession.QosExcellenceReport = qos + sig, err := sigs.Sign(consumerAcc.SK, *relaySession) + require.NoError(t, err) + relaySession.Sig = sig + relays = append(relays, relaySession) + } payment := types.MsgRelayPayment{ Creator: provider1, - Relays: []*types.RelaySession{relaySession}, + Relays: relays, } ts.relayPaymentWithoutPay(payment, true) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index d4164eef71..f303813fc2 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -114,10 +114,9 @@ func (k Keeper) UpdateReputationEpochQosScore(ctx sdk.Context, chainID string, c } // calculate the updated QoS epoch score - updatedEpochScore := r.EpochScore.Update(score, truncate, weight) + r.EpochScore.Update(score, truncate, weight) // update the reputation and set - r.EpochScore = updatedEpochScore r.TimeLastUpdated = ctx.BlockTime().UTC().Unix() r.Stake = stake k.SetReputation(ctx, chainID, cluster, provider, r) diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index 51535b3e31..443e1eba6a 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -56,7 +56,7 @@ func (qs QosScore) Validate() bool { // Update updates a QosScore with a new score from the QoS excellence report. The new score is truncated by the // current variance. Then, it's updated using the weight (which is currently the relay num) -func (qs QosScore) Update(score math.LegacyDec, truncate bool, weight int64) QosScore { +func (qs *QosScore) Update(score math.LegacyDec, truncate bool, weight int64) { if truncate { score = qs.truncate(score) } @@ -70,8 +70,6 @@ func (qs QosScore) Update(score math.LegacyDec, truncate bool, weight int64) Qos // updated_score_denom = qos_score_denom + weight qs.Score.Num = qs.Score.Num.Add(score.MulInt64(weight)) qs.Score.Denom = qs.Score.Denom.Add(math.LegacyNewDec(weight)) - - return qs } // Truncate truncates the QoS excellece report score by the current QoS score variance From 5073c3860aece3abc12152434b3a1000d8a6a630 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 9 Jan 2025 16:24:22 +0200 Subject: [PATCH 28/33] small PR fixes --- x/pairing/keeper/keeper.go | 2 +- x/pairing/keeper/reputation.go | 4 +-- x/pairing/keeper/scores/qos_req.go | 49 ------------------------------ 3 files changed, 3 insertions(+), 52 deletions(-) delete mode 100644 x/pairing/keeper/scores/qos_req.go diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index 8de518362b..fc04212302 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -133,7 +133,7 @@ func (k Keeper) BeginBlock(ctx sdk.Context) { // reset pairing query cache every epoch *k.pairingQueryCache = map[string][]epochstoragetypes.StakeEntry{} // update reputations by QoS scores - k.UpdateReputationQosScore(ctx) + k.UpdateAllReputationQosScore(ctx) // remove old session payments k.RemoveOldEpochPayments(ctx) // unstake/jail unresponsive providers diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index b764a3e2ac..b6e9259698 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -123,8 +123,8 @@ type StakeProviderScores struct { TotalStake sdk.Coin } -// UpdateReputationQosScore updates all the reputations on epoch start with the epoch score aggregated over the epoch -func (k Keeper) UpdateReputationQosScore(ctx sdk.Context) { +// UpdateAllReputationQosScore updates all the reputations on epoch start with the epoch score aggregated over the epoch +func (k Keeper) UpdateAllReputationQosScore(ctx sdk.Context) { // scores is a map of "chainID cluster" -> stakeProviderScores // it will be used to compare providers QoS scores within the same chain ID and cluster and determine // the providers' reputation pairing score. diff --git a/x/pairing/keeper/scores/qos_req.go b/x/pairing/keeper/scores/qos_req.go deleted file mode 100644 index ed86dfed9c..0000000000 --- a/x/pairing/keeper/scores/qos_req.go +++ /dev/null @@ -1,49 +0,0 @@ -package scores - -import ( - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - pairingtypes "github.com/lavanet/lava/v4/x/pairing/types" - planstypes "github.com/lavanet/lava/v4/x/plans/types" -) - -const qosReqName = "qos-req" - -type QosGetter interface { - GetQos(ctx sdk.Context, chainID string, cluster string, provider string) (pairingtypes.QualityOfServiceReport, error) -} - -// QosReq implements the ScoreReq interface for provider staking requirement(s) -type QosReq struct{} - -func (qr QosReq) Init(policy planstypes.Policy) bool { - return true -} - -// Score calculates the the provider's qos score -func (qr QosReq) Score(score PairingScore) math.LegacyDec { - // TODO: update Qos in providerQosFS properly and uncomment this code below - // Also, the qos score should range between 0.5-2 - - // qosScore, err := score.QosExcellenceReport.ComputeQoS() - // if err != nil { - // return math.NewUint(1) - // } - - // return math.Uint(qosScore) - return math.LegacyOneDec() -} - -func (qr QosReq) GetName() string { - return qosReqName -} - -// Equal used to compare slots to determine slot groups. -// Equal always returns true (there are no different "types" of qos) -func (qr QosReq) Equal(other ScoreReq) bool { - return true -} - -func (qr QosReq) GetReqForSlot(policy planstypes.Policy, slotIdx int) ScoreReq { - return qr -} From 23033489cfdb0424df81bab6e3c42b2ccef5a0ca Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 9 Jan 2025 16:36:46 +0200 Subject: [PATCH 29/33] change half life param to be uint64 --- proto/lavanet/lava/pairing/params.proto | 2 +- x/pairing/keeper/helpers_test.go | 2 +- .../keeper/msg_server_relay_payment_test.go | 2 +- x/pairing/keeper/params.go | 2 +- x/pairing/keeper/reputation.go | 2 +- x/pairing/types/params.go | 6 +- x/pairing/types/params.pb.go | 84 +++++++++---------- 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/proto/lavanet/lava/pairing/params.proto b/proto/lavanet/lava/pairing/params.proto index 5a082cb6f6..ba9dd23175 100644 --- a/proto/lavanet/lava/pairing/params.proto +++ b/proto/lavanet/lava/pairing/params.proto @@ -23,6 +23,6 @@ message Params { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; - int64 reputation_half_life_factor = 17 [(gogoproto.moretags) = "yaml:\"reputation_half_life_factor\""]; + uint64 reputation_half_life_factor = 17 [(gogoproto.moretags) = "yaml:\"reputation_half_life_factor\""]; uint64 reputation_relay_failure_cost = 18 [(gogoproto.moretags) = "yaml:\"reputation_relay_failure_cost\""]; } \ No newline at end of file diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 178bf07924..64c1fd8f59 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -170,7 +170,7 @@ func (ts *tester) setupForReputation(modifyHalfLifeFactor bool) (*tester, []pair // set half life factor to be epoch time resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &pairingtypes.QueryParamsRequest{}) require.NoError(ts.T, err) - resQParams.Params.ReputationHalfLifeFactor = int64(ts.EpochTimeDefault().Seconds()) + resQParams.Params.ReputationHalfLifeFactor = uint64(ts.EpochTimeDefault().Seconds()) ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) } diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index b5328b8fb1..dc21205160 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1288,7 +1288,7 @@ func TestReputationUpdateOnEpochStart(t *testing.T) { // set half life factor to be epoch time resQParams, err := ts.Keepers.Pairing.Params(ts.GoCtx, &types.QueryParamsRequest{}) require.NoError(t, err) - resQParams.Params.ReputationHalfLifeFactor = int64(ts.EpochTimeDefault().Seconds()) + resQParams.Params.ReputationHalfLifeFactor = uint64(ts.EpochTimeDefault().Seconds()) ts.Keepers.Pairing.SetParams(ts.Ctx, resQParams.Params) // set default reputation and keep some properties for future comparison diff --git a/x/pairing/keeper/params.go b/x/pairing/keeper/params.go index 38914328aa..9614a6c349 100644 --- a/x/pairing/keeper/params.go +++ b/x/pairing/keeper/params.go @@ -71,7 +71,7 @@ func (k Keeper) ReputationLatencyOverSyncFactor(ctx sdk.Context) (res math.Legac } // ReputationHalfLifeFactor returns the ReputationHalfLifeFactor param -func (k Keeper) ReputationHalfLifeFactor(ctx sdk.Context) (res int64) { +func (k Keeper) ReputationHalfLifeFactor(ctx sdk.Context) (res uint64) { k.paramstore.Get(ctx, types.KeyReputationHalfLifeFactor, &res) return } diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index b6e9259698..0a55e6c48a 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -213,7 +213,7 @@ func (k Keeper) UpdateReputationsForEpochStart(ctx sdk.Context) (map[types.Reput } // apply time decay on current score and add the epoch score (which is reset right after) - reputation, err = reputation.ApplyTimeDecayAndUpdateScore(halfLifeFactor, currentTime) + reputation, err = reputation.ApplyTimeDecayAndUpdateScore(utils.SafeUint64ToInt64Convert(halfLifeFactor), currentTime) if err != nil { return nil, utils.LavaFormatError("updateReputationsScores: apply time decay and update reputation", err, utils.LogAttr("chain_id", chainID), diff --git a/x/pairing/types/params.go b/x/pairing/types/params.go index bbc76ee1ff..7e65f2d35a 100644 --- a/x/pairing/types/params.go +++ b/x/pairing/types/params.go @@ -38,8 +38,8 @@ var ( ) var ( - KeyReputationHalfLifeFactor = []byte("ReputationHalfLifeFactor") - DefaultReputationHalfLifeFactor int64 = 12 * 30 * 24 * 60 * 60 // year in seconds + KeyReputationHalfLifeFactor = []byte("ReputationHalfLifeFactor") + DefaultReputationHalfLifeFactor uint64 = 12 * 30 * 24 * 60 * 60 // year in seconds ) var ( @@ -59,7 +59,7 @@ func NewParams( recommendedEpochNumToCollectPayment uint64, reputationVarianceStabilizationPeriod int64, reputationLatencyOverSyncFactor math.LegacyDec, - reputationHalfLifeFactor int64, + reputationHalfLifeFactor uint64, reputationRelayFailureCost uint64, ) Params { return Params{ diff --git a/x/pairing/types/params.pb.go b/x/pairing/types/params.pb.go index a4311ca79b..07bf7c4eb6 100644 --- a/x/pairing/types/params.pb.go +++ b/x/pairing/types/params.pb.go @@ -31,7 +31,7 @@ type Params struct { RecommendedEpochNumToCollectPayment uint64 `protobuf:"varint,14,opt,name=recommendedEpochNumToCollectPayment,proto3" json:"recommendedEpochNumToCollectPayment,omitempty" yaml:"recommended_epoch_num_to_collect_payment"` ReputationVarianceStabilizationPeriod int64 `protobuf:"varint,15,opt,name=reputation_variance_stabilization_period,json=reputationVarianceStabilizationPeriod,proto3" json:"reputation_variance_stabilization_period,omitempty" yaml:"reputation_variance_stabilization_period"` ReputationLatencyOverSyncFactor github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,16,opt,name=reputation_latency_over_sync_factor,json=reputationLatencyOverSyncFactor,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"reputation_latency_over_sync_factor" yaml:"reputation_latency_over_sync_factor"` - ReputationHalfLifeFactor int64 `protobuf:"varint,17,opt,name=reputation_half_life_factor,json=reputationHalfLifeFactor,proto3" json:"reputation_half_life_factor,omitempty" yaml:"reputation_half_life_factor"` + ReputationHalfLifeFactor uint64 `protobuf:"varint,17,opt,name=reputation_half_life_factor,json=reputationHalfLifeFactor,proto3" json:"reputation_half_life_factor,omitempty" yaml:"reputation_half_life_factor"` ReputationRelayFailureCost uint64 `protobuf:"varint,18,opt,name=reputation_relay_failure_cost,json=reputationRelayFailureCost,proto3" json:"reputation_relay_failure_cost,omitempty" yaml:"reputation_relay_failure_cost"` } @@ -88,7 +88,7 @@ func (m *Params) GetReputationVarianceStabilizationPeriod() int64 { return 0 } -func (m *Params) GetReputationHalfLifeFactor() int64 { +func (m *Params) GetReputationHalfLifeFactor() uint64 { if m != nil { return m.ReputationHalfLifeFactor } @@ -109,45 +109,45 @@ func init() { func init() { proto.RegisterFile("lavanet/lava/pairing/params.proto", fileDescriptor_fc338fce33b3b67a) } var fileDescriptor_fc338fce33b3b67a = []byte{ - // 607 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x41, 0x6f, 0xd3, 0x30, - 0x14, 0xc7, 0x9b, 0xcd, 0xeb, 0xbc, 0x6c, 0x83, 0x10, 0xed, 0x10, 0x6d, 0x22, 0x19, 0x01, 0xa6, - 0x6a, 0x12, 0xcd, 0x61, 0x9c, 0x76, 0xec, 0xc6, 0x84, 0xa2, 0x89, 0x95, 0x0c, 0x81, 0x84, 0x90, - 0x2c, 0xd7, 0x75, 0x5b, 0x6b, 0x4e, 0x1c, 0x39, 0x6e, 0x21, 0xdc, 0xb9, 0x71, 0xe0, 0xc8, 0x91, - 0x2b, 0x7c, 0x92, 0x1d, 0x77, 0x44, 0x1c, 0x22, 0xb4, 0x7e, 0x83, 0x7e, 0x02, 0x54, 0xa7, 0xac, - 0x1d, 0x05, 0x69, 0x9c, 0x5e, 0x94, 0xf7, 0xfb, 0xbf, 0xff, 0xb3, 0x9f, 0x6d, 0xf3, 0x1e, 0xc7, - 0x03, 0x9c, 0x50, 0x15, 0x8c, 0x63, 0x90, 0x62, 0x26, 0x59, 0xd2, 0x0d, 0x52, 0x2c, 0x71, 0x9c, - 0xd5, 0x53, 0x29, 0x94, 0xb0, 0x37, 0x26, 0x48, 0x7d, 0x1c, 0xeb, 0x13, 0x64, 0x73, 0xa3, 0x2b, - 0xba, 0x42, 0x03, 0xc1, 0xf8, 0xab, 0x64, 0xfd, 0xaf, 0xcb, 0x66, 0xb5, 0xa9, 0xc5, 0xf6, 0x89, - 0x69, 0xd3, 0x54, 0x90, 0x5e, 0x83, 0x0b, 0x72, 0x96, 0x9d, 0x0c, 0xa8, 0xe4, 0x38, 0x75, 0xe0, - 0xb6, 0x51, 0x03, 0x0d, 0x6f, 0x54, 0x78, 0x5b, 0x39, 0x8e, 0xf9, 0xbe, 0xaf, 0x19, 0xd4, 0xd2, - 0x10, 0x12, 0x25, 0xe5, 0x47, 0x7f, 0x91, 0xda, 0x89, 0xb9, 0xf2, 0x5c, 0x9c, 0xbe, 0xa2, 0xac, - 0xdb, 0x53, 0xce, 0xfa, 0xb6, 0x51, 0x5b, 0x69, 0x34, 0xcf, 0x0b, 0xaf, 0xf2, 0xa3, 0xf0, 0x76, - 0xba, 0x4c, 0xf5, 0xfa, 0xad, 0x3a, 0x11, 0x71, 0x40, 0x44, 0x16, 0x8b, 0x6c, 0x12, 0x1e, 0x65, - 0xed, 0xb3, 0x40, 0xe5, 0x29, 0xcd, 0xea, 0x87, 0x94, 0x8c, 0x0a, 0xcf, 0x2d, 0x5d, 0xdb, 0x58, - 0x61, 0x24, 0x29, 0x67, 0xb8, 0xc5, 0x38, 0x53, 0x39, 0x92, 0xf4, 0x2d, 0x96, 0x6d, 0x3f, 0x9a, - 0x5a, 0xd8, 0x1f, 0x0c, 0xf3, 0xbe, 0xa4, 0x44, 0xc4, 0x31, 0x4d, 0xda, 0xb4, 0xfd, 0x64, 0xdc, - 0xd1, 0xb3, 0x7e, 0xfc, 0x42, 0x1c, 0x08, 0xce, 0x29, 0x51, 0x4d, 0x9c, 0xc7, 0x34, 0x51, 0xce, - 0x2d, 0xbd, 0xa4, 0xbd, 0x51, 0xe1, 0x05, 0x65, 0xf1, 0x19, 0x11, 0x2a, 0x97, 0x97, 0xf4, 0x63, - 0xa4, 0x04, 0x22, 0xa5, 0x10, 0xa5, 0xa5, 0xd2, 0x8f, 0x6e, 0x52, 0xdf, 0xfe, 0x68, 0x98, 0x35, - 0x49, 0xd3, 0xbe, 0xc2, 0x8a, 0x89, 0x04, 0x0d, 0xb0, 0x64, 0x38, 0x21, 0x14, 0x65, 0x4a, 0x37, - 0xff, 0xbe, 0xfc, 0x9d, 0x52, 0xc9, 0x44, 0xdb, 0xb9, 0xbd, 0x6d, 0xd4, 0x16, 0xaf, 0x37, 0x73, - 0x33, 0xa5, 0x1f, 0x3d, 0x9c, 0xa2, 0x2f, 0x27, 0xe4, 0xe9, 0x2c, 0xd8, 0xd4, 0x9c, 0xfd, 0x4d, - 0x6f, 0xcb, 0x55, 0x51, 0x8e, 0x15, 0x4d, 0x48, 0xae, 0x47, 0x87, 0xb2, 0x3c, 0x21, 0xa8, 0x83, - 0x89, 0x12, 0xd2, 0xb1, 0xf4, 0x84, 0xde, 0xfc, 0xf7, 0x84, 0x76, 0xe7, 0xfa, 0xfe, 0x97, 0x85, - 0x1f, 0x79, 0x53, 0xea, 0xb8, 0x84, 0xc6, 0x87, 0xe5, 0x34, 0x4f, 0xc8, 0x91, 0x26, 0x6c, 0x6a, - 0x6e, 0xcd, 0x14, 0xea, 0x61, 0xde, 0x41, 0x9c, 0x75, 0xe8, 0xef, 0x1e, 0xef, 0xe8, 0xdd, 0xda, - 0x19, 0x15, 0x9e, 0x3f, 0xe7, 0xfa, 0x27, 0xec, 0x47, 0xce, 0x34, 0xfb, 0x14, 0xf3, 0xce, 0x31, - 0xeb, 0xd0, 0x89, 0xcd, 0x99, 0x79, 0x77, 0x46, 0x29, 0x29, 0xc7, 0x39, 0xea, 0x60, 0xc6, 0xfb, - 0x92, 0x22, 0x22, 0x32, 0xe5, 0xd8, 0xfa, 0x8c, 0xd4, 0x46, 0x85, 0xf7, 0x60, 0xce, 0x68, 0x1e, - 0xf7, 0xa3, 0xcd, 0x69, 0x3e, 0x1a, 0xa7, 0x8f, 0xca, 0xec, 0x81, 0xc8, 0xd4, 0x3e, 0xf8, 0xfc, - 0xc5, 0xab, 0x84, 0x00, 0x1a, 0xd6, 0x42, 0x08, 0xe0, 0x82, 0xb5, 0x18, 0x02, 0xb8, 0x68, 0x81, - 0x10, 0x40, 0x60, 0x2d, 0x85, 0x00, 0x2e, 0x59, 0xd5, 0x10, 0xc0, 0xaa, 0xb5, 0x1c, 0x02, 0xb8, - 0x6c, 0xc1, 0x10, 0xc0, 0x15, 0xcb, 0x0c, 0x01, 0x34, 0xad, 0xd5, 0x10, 0xc0, 0x55, 0x6b, 0x2d, - 0x04, 0x70, 0xcd, 0x5a, 0x6f, 0x1c, 0x9e, 0x5f, 0xba, 0xc6, 0xc5, 0xa5, 0x6b, 0xfc, 0xbc, 0x74, - 0x8d, 0x4f, 0x43, 0xb7, 0x72, 0x31, 0x74, 0x2b, 0xdf, 0x87, 0x6e, 0xe5, 0xf5, 0xee, 0xcc, 0xb0, - 0xae, 0xbd, 0x0f, 0x83, 0xc7, 0xc1, 0xbb, 0xab, 0x47, 0x42, 0x0f, 0xad, 0x55, 0xd5, 0x17, 0x7f, - 0xef, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2e, 0x47, 0xb1, 0x29, 0x49, 0x04, 0x00, 0x00, + // 606 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0xe3, 0xf6, 0x9a, 0x5e, 0xdd, 0x16, 0x8c, 0xd5, 0xc1, 0x6a, 0x85, 0x5d, 0x0c, 0x54, + 0x51, 0x25, 0xe2, 0xa1, 0x4c, 0x1d, 0xd3, 0x52, 0x21, 0xab, 0xa2, 0xc1, 0x45, 0x20, 0x21, 0xa4, + 0xd3, 0xe5, 0x72, 0x49, 0x4e, 0x3d, 0xfb, 0xac, 0xf3, 0x25, 0x60, 0x76, 0x36, 0x06, 0x46, 0x46, + 0x56, 0xf8, 0x24, 0x1d, 0x3b, 0x22, 0x06, 0x0b, 0x35, 0xdf, 0x20, 0x9f, 0x00, 0xe5, 0x1c, 0x9a, + 0x94, 0x80, 0x54, 0xa6, 0x17, 0xe5, 0xfd, 0xfe, 0xef, 0xff, 0xce, 0x7f, 0xfb, 0xcc, 0x7b, 0x1c, + 0x0f, 0x70, 0x42, 0x55, 0x30, 0xae, 0x41, 0x8a, 0x99, 0x64, 0x49, 0x37, 0x48, 0xb1, 0xc4, 0x71, + 0x56, 0x4f, 0xa5, 0x50, 0xc2, 0xde, 0x98, 0x20, 0xf5, 0x71, 0xad, 0x4f, 0x90, 0xcd, 0x8d, 0xae, + 0xe8, 0x0a, 0x0d, 0x04, 0xe3, 0x5f, 0x25, 0xeb, 0x7f, 0x5d, 0x36, 0xab, 0x4d, 0x2d, 0xb6, 0x4f, + 0x4c, 0x9b, 0xa6, 0x82, 0xf4, 0x1a, 0x5c, 0x90, 0xb3, 0xec, 0x64, 0x40, 0x25, 0xc7, 0xa9, 0x03, + 0xb7, 0x8d, 0x1a, 0x68, 0x78, 0xa3, 0xc2, 0xdb, 0xca, 0x71, 0xcc, 0xf7, 0x7d, 0xcd, 0xa0, 0x96, + 0x86, 0x90, 0x28, 0x29, 0x3f, 0xfa, 0x8b, 0xd4, 0x4e, 0xcc, 0x95, 0xe7, 0xe2, 0xf4, 0x15, 0x65, + 0xdd, 0x9e, 0x72, 0xd6, 0xb7, 0x8d, 0xda, 0x4a, 0xa3, 0x79, 0x5e, 0x78, 0x95, 0x1f, 0x85, 0xb7, + 0xd3, 0x65, 0xaa, 0xd7, 0x6f, 0xd5, 0x89, 0x88, 0x03, 0x22, 0xb2, 0x58, 0x64, 0x93, 0xf2, 0x28, + 0x6b, 0x9f, 0x05, 0x2a, 0x4f, 0x69, 0x56, 0x3f, 0xa4, 0x64, 0x54, 0x78, 0x6e, 0xe9, 0xda, 0xc6, + 0x0a, 0x23, 0x49, 0x39, 0xc3, 0x2d, 0xc6, 0x99, 0xca, 0x91, 0xa4, 0x6f, 0xb1, 0x6c, 0xfb, 0xd1, + 0xd4, 0xc2, 0xfe, 0x60, 0x98, 0xf7, 0x25, 0x25, 0x22, 0x8e, 0x69, 0xd2, 0xa6, 0xed, 0x27, 0xe3, + 0x8d, 0x9e, 0xf5, 0xe3, 0x17, 0xe2, 0x40, 0x70, 0x4e, 0x89, 0x6a, 0xe2, 0x3c, 0xa6, 0x89, 0x72, + 0x6e, 0xe9, 0x23, 0xed, 0x8d, 0x0a, 0x2f, 0x28, 0x87, 0xcf, 0x88, 0x50, 0x79, 0xbc, 0xa4, 0x1f, + 0x23, 0x25, 0x10, 0x29, 0x85, 0x28, 0x2d, 0x95, 0x7e, 0x74, 0x93, 0xf9, 0xf6, 0x47, 0xc3, 0xac, + 0x49, 0x9a, 0xf6, 0x15, 0x56, 0x4c, 0x24, 0x68, 0x80, 0x25, 0xc3, 0x09, 0xa1, 0x28, 0x53, 0x7a, + 0xf9, 0xf7, 0xe5, 0xdf, 0x29, 0x95, 0x4c, 0xb4, 0x9d, 0xdb, 0xdb, 0x46, 0x6d, 0xf1, 0xfa, 0x32, + 0x37, 0x53, 0xfa, 0xd1, 0xc3, 0x29, 0xfa, 0x72, 0x42, 0x9e, 0xce, 0x82, 0x4d, 0xcd, 0xd9, 0xdf, + 0xf4, 0x63, 0xb9, 0x1a, 0xca, 0xb1, 0xa2, 0x09, 0xc9, 0x75, 0x74, 0x28, 0xcb, 0x13, 0x82, 0x3a, + 0x98, 0x28, 0x21, 0x1d, 0x4b, 0x27, 0xf4, 0xe6, 0xbf, 0x13, 0xda, 0x9d, 0xdb, 0xfb, 0x5f, 0x16, + 0x7e, 0xe4, 0x4d, 0xa9, 0xe3, 0x12, 0x1a, 0xbf, 0x2c, 0xa7, 0x79, 0x42, 0x8e, 0x34, 0x61, 0x53, + 0x73, 0x6b, 0x66, 0x50, 0x0f, 0xf3, 0x0e, 0xe2, 0xac, 0x43, 0x7f, 0xef, 0x78, 0x47, 0x47, 0xb7, + 0x33, 0x2a, 0x3c, 0x7f, 0xce, 0xf5, 0x4f, 0xd8, 0x8f, 0x9c, 0x69, 0xf7, 0x29, 0xe6, 0x9d, 0x63, + 0xd6, 0xa1, 0x13, 0x9b, 0x33, 0xf3, 0xee, 0x8c, 0x52, 0x52, 0x8e, 0x73, 0xd4, 0xc1, 0x8c, 0xf7, + 0x25, 0x45, 0x44, 0x64, 0xca, 0xb1, 0xb5, 0x51, 0x6d, 0x54, 0x78, 0x0f, 0xe6, 0x8c, 0xe6, 0x71, + 0x3f, 0xda, 0x9c, 0xf6, 0xa3, 0x71, 0xfb, 0xa8, 0xec, 0x1e, 0x88, 0x4c, 0xed, 0x83, 0xcf, 0x5f, + 0xbc, 0x4a, 0x08, 0xa0, 0x61, 0x2d, 0x84, 0x00, 0x2e, 0x58, 0x8b, 0x21, 0x80, 0x8b, 0x16, 0x08, + 0x01, 0x04, 0xd6, 0x52, 0x08, 0xe0, 0x92, 0x55, 0x0d, 0x01, 0xac, 0x5a, 0xcb, 0x21, 0x80, 0xcb, + 0x16, 0x0c, 0x01, 0x5c, 0xb1, 0xcc, 0x10, 0x40, 0xd3, 0x5a, 0x0d, 0x01, 0x5c, 0xb5, 0xd6, 0x42, + 0x00, 0xd7, 0xac, 0xf5, 0xc6, 0xe1, 0xf9, 0xa5, 0x6b, 0x5c, 0x5c, 0xba, 0xc6, 0xcf, 0x4b, 0xd7, + 0xf8, 0x34, 0x74, 0x2b, 0x17, 0x43, 0xb7, 0xf2, 0x7d, 0xe8, 0x56, 0x5e, 0xef, 0xce, 0x84, 0x75, + 0xed, 0x7e, 0x18, 0x3c, 0x0e, 0xde, 0x5d, 0x5d, 0x12, 0x3a, 0xb4, 0x56, 0x55, 0x7f, 0xf8, 0x7b, + 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x90, 0x7b, 0x61, 0x25, 0x49, 0x04, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -437,7 +437,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.ReputationHalfLifeFactor |= int64(b&0x7F) << shift + m.ReputationHalfLifeFactor |= uint64(b&0x7F) << shift if b < 0x80 { break } From 87fb3405266d441a56787a656792a486969d2983 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 12 Jan 2025 13:44:48 +0200 Subject: [PATCH 30/33] delete pairing query cache --- x/pairing/keeper/keeper.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index b4983e560e..5f93ceeddf 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -126,8 +126,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) BeginBlock(ctx sdk.Context) { if k.epochStorageKeeper.IsEpochStart(ctx) { - // reset pairing query cache every epoch - *k.pairingQueryCache = map[string][]epochstoragetypes.StakeEntry{} // update reputations by QoS scores k.UpdateAllReputationQosScore(ctx) // remove old session payments From b919b1e234f77dedf72fce32839360619937e4eb Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 12 Jan 2025 15:51:34 +0200 Subject: [PATCH 31/33] calculate exp without floats --- utils/math.go | 40 ++++++++++++++++++++++++++++++++++- x/pairing/types/reputation.go | 16 ++------------ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/utils/math.go b/utils/math.go index ad8d06a39b..87737bac64 100644 --- a/utils/math.go +++ b/utils/math.go @@ -1,6 +1,14 @@ package utils -import "golang.org/x/exp/constraints" +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "golang.org/x/exp/constraints" +) + +const ( + DecayFactorNaturalBaseString = "2.71828182845904523536028747135266249775724709369995957496696763" +) func Min[T constraints.Ordered](x, y T) T { if x < y { @@ -15,3 +23,33 @@ func Max[T constraints.Ordered](x, y T) T { } return y } + +// NaturalBaseExponentFraction calculates an exponent of the +// natural base e using a sdk.Dec. using the formula: e^(numerator / denominator) +// since it is not possible to directly calculate a power of a fraction, +// we're doing it in three steps: +// 1. Calculate e^numerator +// 2. Take the denominatorth root +// 3. Take the reciprocal (if negative=true) +func NaturalBaseExponentFraction(numerator, denominator int64, negative bool) math.LegacyDec { + numeratorUint64 := uint64(numerator) + denominatorUint64 := uint64(denominator) + + e := sdk.MustNewDecFromStr(DecayFactorNaturalBaseString) + + // Step 1: Calculate e^a + eToA := e.Power(numeratorUint64) + + // Step 2: Take the bth root + result, err := eToA.ApproxRoot(denominatorUint64) + if err != nil { + panic(err) + } + + if negative { + // Step 3: Take the reciprocal + result = sdk.OneDec().Quo(result) + } + + return result +} diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 7c8236b5fb..3e6302712d 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -2,7 +2,6 @@ package types import ( "fmt" - stdMath "math" "cosmossdk.io/collections" "cosmossdk.io/math" @@ -69,19 +68,8 @@ func (r Reputation) calcDecayFactor(halfLifeFactor int64, currentTime int64) mat return math.LegacyZeroDec() } - exponent := float64(timeSinceLastUpdate / halfLifeFactor) - decayFactorFloat := stdMath.Exp(exponent) - decayFactorString := fmt.Sprintf("%.18f", decayFactorFloat) - decayFactor, err := math.LegacyNewDecFromStr(decayFactorString) - if err != nil { - utils.LavaFormatError("calcDecayFactor: calculate reputation decay factor failed, invalid decay factor string", err, - utils.LogAttr("decay_factor_string", decayFactorString), - utils.LogAttr("time_since_last_update", timeSinceLastUpdate), - utils.LogAttr("half_life_factor", halfLifeFactor), - ) - return math.LegacyZeroDec() - } - return decayFactor + // Calculate the decay factor using the natural base e: e^(-timeSinceLastUpdate / halfLifeFactor) + return utils.NaturalBaseExponentFraction(timeSinceLastUpdate, halfLifeFactor, true) } func (r Reputation) ApplyTimeDecayAndUpdateScore(halfLifeFactor int64, currentTime int64) (Reputation, error) { From 859642d18100b6103fbc860c04ae4261a1e15b98 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 12 Jan 2025 15:54:31 +0200 Subject: [PATCH 32/33] change query arg name --- proto/lavanet/lava/pairing/query.proto | 4 +- testutil/common/tester.go | 6 +- .../client/cli/query_provider_reputation.go | 6 +- .../keeper/grpc_query_provider_reputation.go | 2 +- x/pairing/types/query.pb.go | 286 +++++++++--------- x/pairing/types/query.pb.gw.go | 18 +- 6 files changed, 161 insertions(+), 161 deletions(-) diff --git a/proto/lavanet/lava/pairing/query.proto b/proto/lavanet/lava/pairing/query.proto index b126e4b0bc..0d282d9794 100644 --- a/proto/lavanet/lava/pairing/query.proto +++ b/proto/lavanet/lava/pairing/query.proto @@ -87,7 +87,7 @@ service Query { // Queries a for a provider reputation. rpc ProviderReputation(QueryProviderReputationRequest) returns (QueryProviderReputationResponse) { - option (google.api.http).get = "/lavanet/lava/pairing/provider_reputation/{address}/{chainID}/{cluster}"; + option (google.api.http).get = "/lavanet/lava/pairing/provider_reputation/{provider}/{chainID}/{cluster}"; } // Queries a for a provider reputation's details (mainly for developers). @@ -252,7 +252,7 @@ message ProviderCuInfo { } message QueryProviderReputationRequest { - string address = 1; + string provider = 1; string chainID = 2; string cluster = 3; } diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 970ade89f8..a0a3dddac8 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -925,9 +925,9 @@ func (ts *Tester) QueryPairingProviderEpochCu(provider string, project string, c // QueryPairingProviderReputation implements 'q pairing provider-reputation' func (ts *Tester) QueryPairingProviderReputation(provider string, chainID string, cluster string) (*pairingtypes.QueryProviderReputationResponse, error) { msg := &pairingtypes.QueryProviderReputationRequest{ - Address: provider, - ChainID: chainID, - Cluster: cluster, + Provider: provider, + ChainID: chainID, + Cluster: cluster, } return ts.Keepers.Pairing.ProviderReputation(ts.GoCtx, msg) } diff --git a/x/pairing/client/cli/query_provider_reputation.go b/x/pairing/client/cli/query_provider_reputation.go index c19f70bf8a..526a2b64b3 100644 --- a/x/pairing/client/cli/query_provider_reputation.go +++ b/x/pairing/client/cli/query_provider_reputation.go @@ -45,9 +45,9 @@ func CmdProviderReputation() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) params := &types.QueryProviderReputationRequest{ - Address: address, - ChainID: chainID, - Cluster: cluster, + Provider: address, + ChainID: chainID, + Cluster: cluster, } res, err := queryClient.ProviderReputation(cmd.Context(), params) diff --git a/x/pairing/keeper/grpc_query_provider_reputation.go b/x/pairing/keeper/grpc_query_provider_reputation.go index 61a90465e0..ac65fb2484 100644 --- a/x/pairing/keeper/grpc_query_provider_reputation.go +++ b/x/pairing/keeper/grpc_query_provider_reputation.go @@ -48,7 +48,7 @@ func (k Keeper) ProviderReputation(goCtx context.Context, req *types.QueryProvid requestedProviderData := []chainClusterScore{} for _, chainID := range chains { for _, cluster := range clusters { - score, found := k.GetReputationScore(ctx, chainID, cluster, req.Address) + score, found := k.GetReputationScore(ctx, chainID, cluster, req.Provider) if !found { continue } diff --git a/x/pairing/types/query.pb.go b/x/pairing/types/query.pb.go index 6c2f737c2f..a8e958f3d0 100644 --- a/x/pairing/types/query.pb.go +++ b/x/pairing/types/query.pb.go @@ -1544,9 +1544,9 @@ func (m *ProviderCuInfo) GetCu() uint64 { } type QueryProviderReputationRequest struct { - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - ChainID string `protobuf:"bytes,2,opt,name=chainID,proto3" json:"chainID,omitempty"` - Cluster string `protobuf:"bytes,3,opt,name=cluster,proto3" json:"cluster,omitempty"` + Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"` + ChainID string `protobuf:"bytes,2,opt,name=chainID,proto3" json:"chainID,omitempty"` + Cluster string `protobuf:"bytes,3,opt,name=cluster,proto3" json:"cluster,omitempty"` } func (m *QueryProviderReputationRequest) Reset() { *m = QueryProviderReputationRequest{} } @@ -1582,9 +1582,9 @@ func (m *QueryProviderReputationRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryProviderReputationRequest proto.InternalMessageInfo -func (m *QueryProviderReputationRequest) GetAddress() string { +func (m *QueryProviderReputationRequest) GetProvider() string { if m != nil { - return m.Address + return m.Provider } return "" } @@ -1938,137 +1938,137 @@ func init() { func init() { proto.RegisterFile("lavanet/lava/pairing/query.proto", fileDescriptor_9e149ce9d21da0d8) } var fileDescriptor_9e149ce9d21da0d8 = []byte{ - // 2068 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x5f, 0x6f, 0x1c, 0x57, - 0x15, 0xcf, 0xac, 0xd7, 0x8e, 0x7d, 0x92, 0x38, 0xe1, 0xc6, 0x76, 0xec, 0xc5, 0xdd, 0x38, 0x93, - 0xa6, 0x75, 0xe2, 0x74, 0xa7, 0x76, 0x93, 0x36, 0x4a, 0xdd, 0x40, 0x6d, 0x27, 0x91, 0x43, 0x20, - 0xf6, 0x9a, 0x80, 0x54, 0x21, 0x8d, 0xae, 0x67, 0xef, 0xae, 0xa7, 0x9e, 0x9d, 0xbb, 0x9d, 0xb9, - 0xb3, 0xb1, 0xb1, 0x16, 0x24, 0xf8, 0x02, 0x48, 0x80, 0x10, 0x4f, 0xbc, 0x54, 0xea, 0x53, 0xbf, - 0x01, 0x6f, 0x48, 0xa8, 0x0f, 0x3c, 0x54, 0xf0, 0x82, 0x10, 0xaa, 0x50, 0xc2, 0x33, 0x88, 0x0f, - 0x80, 0x84, 0xe6, 0xde, 0x33, 0x3b, 0x33, 0xeb, 0xd9, 0xd9, 0x75, 0x52, 0x5e, 0xe2, 0xbd, 0xf7, - 0x9e, 0x73, 0xcf, 0xef, 0xfc, 0xbd, 0xe7, 0x4c, 0x60, 0xc1, 0xa1, 0x6d, 0xea, 0x32, 0x61, 0x84, - 0x7f, 0x8d, 0x16, 0xb5, 0x3d, 0xdb, 0x6d, 0x18, 0x9f, 0x04, 0xcc, 0x3b, 0xac, 0xb4, 0x3c, 0x2e, - 0x38, 0x99, 0x42, 0x8a, 0x4a, 0xf8, 0xb7, 0x82, 0x14, 0xa5, 0xa9, 0x06, 0x6f, 0x70, 0x49, 0x60, - 0x84, 0xbf, 0x14, 0x6d, 0x69, 0xbe, 0xc1, 0x79, 0xc3, 0x61, 0x06, 0x6d, 0xd9, 0x06, 0x75, 0x5d, - 0x2e, 0xa8, 0xb0, 0xb9, 0xeb, 0xe3, 0xe9, 0x0d, 0x8b, 0xfb, 0x4d, 0xee, 0x1b, 0xbb, 0xd4, 0x67, - 0x4a, 0x84, 0xd1, 0x5e, 0xde, 0x65, 0x82, 0x2e, 0x1b, 0x2d, 0xda, 0xb0, 0x5d, 0x49, 0x8c, 0xb4, - 0x57, 0x32, 0x71, 0xb5, 0xa8, 0x47, 0x9b, 0xd1, 0x75, 0xd7, 0x32, 0x49, 0x3c, 0xd6, 0x0a, 0x44, - 0xf2, 0xa6, 0xf9, 0x14, 0x99, 0xdf, 0x62, 0x96, 0xfc, 0x07, 0x4f, 0x2f, 0xa7, 0x2f, 0x71, 0xa8, - 0xeb, 0x1b, 0x2d, 0xee, 0xd8, 0x16, 0xaa, 0x5f, 0x5a, 0x4a, 0x11, 0xb0, 0x16, 0xb7, 0xf6, 0x7c, - 0xc1, 0x3d, 0xda, 0x60, 0x86, 0x2f, 0xe8, 0x3e, 0x33, 0x99, 0x2b, 0x22, 0x5b, 0x95, 0x6e, 0xa6, - 0x65, 0x05, 0xbb, 0xbe, 0xe5, 0xd9, 0xad, 0x10, 0x4c, 0x6a, 0x81, 0xd4, 0x57, 0xd3, 0xb2, 0x3d, - 0xfe, 0x31, 0xb3, 0x84, 0x1f, 0xfd, 0x40, 0xa2, 0x37, 0x53, 0x44, 0x35, 0xfe, 0xcc, 0x15, 0x76, - 0x93, 0x19, 0xed, 0xe5, 0xee, 0x6f, 0x45, 0xa8, 0x4f, 0x01, 0xd9, 0x0e, 0x6d, 0xba, 0x25, 0x6d, - 0x54, 0x65, 0x9f, 0x04, 0xcc, 0x17, 0xfa, 0x36, 0x5c, 0x4c, 0xed, 0xfa, 0x2d, 0xee, 0xfa, 0x8c, - 0xdc, 0x85, 0x31, 0x65, 0xcb, 0x59, 0x6d, 0x41, 0x5b, 0x3c, 0xb3, 0x32, 0x5f, 0xc9, 0xf2, 0x72, - 0x45, 0x71, 0xad, 0x15, 0xbf, 0xf8, 0xea, 0xf2, 0xa9, 0x2a, 0x72, 0xe8, 0xdb, 0x30, 0xad, 0xae, - 0xf4, 0x78, 0xdb, 0xae, 0x31, 0x2f, 0x92, 0x45, 0x66, 0xe1, 0xb4, 0xb5, 0x47, 0x6d, 0x77, 0x73, - 0x43, 0xde, 0x3a, 0x51, 0x8d, 0x96, 0xa4, 0x0c, 0xe0, 0xef, 0xf1, 0x67, 0x0f, 0x3c, 0xfe, 0x63, - 0xe6, 0xce, 0x16, 0x16, 0xb4, 0xc5, 0xf1, 0x6a, 0x62, 0x47, 0xdf, 0x87, 0x99, 0xde, 0x2b, 0x11, - 0xe8, 0x77, 0x00, 0xa4, 0x99, 0xef, 0x87, 0x56, 0x9e, 0xd5, 0x16, 0x46, 0x16, 0xcf, 0xac, 0x5c, - 0x4b, 0x83, 0x4d, 0xfa, 0xa4, 0xb2, 0xd3, 0x25, 0x46, 0xd4, 0x09, 0xf6, 0x47, 0xc5, 0xf1, 0xc2, - 0x85, 0x11, 0xfd, 0x11, 0x4c, 0xa5, 0x84, 0x25, 0xe0, 0xd3, 0x5a, 0xcd, 0x63, 0xbe, 0x1f, 0xc1, - 0xc7, 0x65, 0x52, 0xb1, 0x42, 0x4a, 0x31, 0x7d, 0xaf, 0xc7, 0x16, 0x5d, 0xdc, 0x4f, 0xe0, 0x6c, - 0x57, 0xb0, 0xcd, 0xfc, 0x97, 0x41, 0x9e, 0xba, 0x40, 0x7f, 0x84, 0x26, 0x7a, 0xc8, 0xc4, 0x96, - 0xf2, 0xce, 0x60, 0xb3, 0xcf, 0xc0, 0x98, 0xe5, 0xd8, 0xcc, 0x15, 0x08, 0x1b, 0x57, 0xfa, 0xe7, - 0x05, 0xb8, 0x74, 0xec, 0x32, 0x04, 0xbe, 0x09, 0x13, 0xad, 0xc8, 0x0b, 0x2f, 0x83, 0x3a, 0xe6, - 0x26, 0x57, 0xe1, 0x9c, 0x15, 0x78, 0x1e, 0x73, 0x85, 0x29, 0x79, 0x24, 0x8a, 0x62, 0xf5, 0x2c, - 0x6e, 0xde, 0x0f, 0xf7, 0xc8, 0x1d, 0x98, 0x0b, 0x83, 0xd8, 0x74, 0x58, 0x5d, 0x98, 0x82, 0x9b, - 0x2e, 0x3b, 0x10, 0x26, 0xc6, 0xdf, 0xec, 0x88, 0x64, 0x98, 0x0e, 0x09, 0x1e, 0xb3, 0xba, 0xf8, - 0x3e, 0xff, 0x1e, 0x3b, 0x88, 0x10, 0x93, 0xdb, 0x70, 0x29, 0x4c, 0x64, 0xd3, 0xa1, 0xbe, 0x30, - 0x83, 0x56, 0x8d, 0x0a, 0x56, 0x33, 0x77, 0x1d, 0x6e, 0xed, 0xcf, 0x16, 0x25, 0xdf, 0x54, 0x78, - 0xfc, 0x98, 0xfa, 0xe2, 0xa9, 0x3a, 0x5c, 0x0b, 0xcf, 0xc8, 0x32, 0x4c, 0x4b, 0x22, 0x93, 0xd7, - 0xd3, 0xc2, 0x46, 0x25, 0x13, 0x91, 0x87, 0x4f, 0xea, 0x09, 0x49, 0xfa, 0x4f, 0x61, 0x4e, 0x9a, - 0xeb, 0x07, 0xcc, 0xb3, 0xeb, 0x87, 0xaf, 0x6a, 0x7e, 0x52, 0x82, 0xf1, 0xc8, 0x48, 0x52, 0xc3, - 0x89, 0x6a, 0x77, 0x4d, 0xa6, 0x60, 0x34, 0xa9, 0x82, 0x5a, 0xe8, 0x9f, 0x6a, 0x50, 0xca, 0x42, - 0x80, 0x3e, 0x9b, 0x82, 0xd1, 0x36, 0x75, 0xec, 0x9a, 0x04, 0x30, 0x5e, 0x55, 0x0b, 0x72, 0x1d, - 0x2e, 0x84, 0xaa, 0xb1, 0x9a, 0x19, 0x3b, 0x54, 0x19, 0xf4, 0xbc, 0xda, 0xef, 0x66, 0x1b, 0x59, - 0x80, 0xb3, 0x56, 0x60, 0xb6, 0x98, 0x87, 0x8e, 0x52, 0xc2, 0xc1, 0x0a, 0xb6, 0x98, 0xa7, 0xdc, - 0xf4, 0x1a, 0x00, 0xd6, 0x25, 0xd3, 0xae, 0x49, 0x53, 0x4d, 0x48, 0x57, 0x87, 0x3b, 0x9b, 0x35, - 0xcc, 0xac, 0x5f, 0x6b, 0x70, 0x25, 0x95, 0x0e, 0x08, 0x74, 0x7d, 0x8f, 0xba, 0x16, 0x8b, 0x0c, - 0x96, 0x54, 0x5f, 0xeb, 0x51, 0xbf, 0x6f, 0xa6, 0x91, 0x05, 0x38, 0xd3, 0x60, 0xdc, 0xe1, 0x96, - 0xac, 0xed, 0x52, 0x91, 0xd1, 0x6a, 0x72, 0x4b, 0xf2, 0x3a, 0x81, 0x2f, 0x98, 0x27, 0xf1, 0x87, - 0xbc, 0x6a, 0xa9, 0x3b, 0xa0, 0xe7, 0xc1, 0x42, 0x2b, 0x3e, 0x80, 0x31, 0x4b, 0xee, 0x28, 0x54, - 0x6b, 0x95, 0x30, 0x9e, 0xff, 0xf6, 0xd5, 0xe5, 0x37, 0x1a, 0xb6, 0xd8, 0x0b, 0x76, 0x2b, 0x16, - 0x6f, 0x1a, 0xf8, 0x82, 0xa9, 0x3f, 0x6f, 0xf9, 0xb5, 0x7d, 0x43, 0x1c, 0xb6, 0x98, 0x5f, 0xd9, - 0x60, 0x56, 0x15, 0xb9, 0x75, 0x8a, 0x35, 0xe1, 0xa9, 0xcf, 0x3c, 0x99, 0x19, 0xaf, 0x50, 0x60, - 0xe2, 0x78, 0x18, 0x49, 0xc6, 0xc3, 0x33, 0x2c, 0x06, 0x09, 0x11, 0xa8, 0xc4, 0x43, 0x18, 0xb7, - 0xb8, 0xeb, 0x07, 0x4d, 0x34, 0xee, 0x09, 0xb3, 0xb7, 0xcb, 0x1c, 0x0a, 0x6e, 0xd2, 0x83, 0xf5, - 0xa7, 0x98, 0xb4, 0x6a, 0xa1, 0xbf, 0x0f, 0x97, 0xa5, 0xe0, 0x9d, 0xf0, 0x89, 0xb5, 0xba, 0x01, - 0xf4, 0xd8, 0xf6, 0xc5, 0xc0, 0x7c, 0xd0, 0x9b, 0xb0, 0xd0, 0x9f, 0xf9, 0x6b, 0x2f, 0x3f, 0xfa, - 0x36, 0x7c, 0x53, 0x8a, 0xbb, 0x5f, 0xaf, 0x33, 0x4b, 0xd8, 0x6d, 0xb6, 0x25, 0xdf, 0xf5, 0x44, - 0x18, 0xa6, 0x2c, 0x35, 0x91, 0x50, 0x7e, 0x06, 0xc6, 0xc2, 0xda, 0xd1, 0x75, 0x07, 0xae, 0xc2, - 0x00, 0x9f, 0xcf, 0xbe, 0x13, 0xe1, 0xaf, 0xc0, 0x98, 0xea, 0x1e, 0xd0, 0xf8, 0xa5, 0x9e, 0x77, - 0x35, 0xec, 0x2f, 0x2a, 0xc8, 0x83, 0x94, 0xe4, 0x43, 0x98, 0x6c, 0x31, 0xb7, 0x66, 0xbb, 0x0d, - 0x13, 0x79, 0x0b, 0x03, 0x79, 0xcf, 0x21, 0x87, 0x5a, 0xea, 0xff, 0xd1, 0xb0, 0xa0, 0xef, 0xd4, - 0xf6, 0x7b, 0x8b, 0xc3, 0x43, 0x38, 0x1d, 0x55, 0x38, 0x85, 0xe9, 0xad, 0xec, 0xb7, 0xbe, 0xcf, - 0x83, 0x50, 0x8d, 0xb8, 0xc9, 0x34, 0x8c, 0x35, 0xe9, 0x81, 0x69, 0x05, 0xc9, 0x90, 0x08, 0xc8, - 0x12, 0x14, 0x43, 0xeb, 0xc8, 0x00, 0x3d, 0xb3, 0x72, 0x29, 0x7d, 0xb9, 0xec, 0xb4, 0x76, 0x5a, - 0xcc, 0xaa, 0x4a, 0x22, 0xb2, 0x09, 0xe7, 0xa3, 0xb6, 0xc5, 0xc4, 0x06, 0xa4, 0x28, 0xf9, 0x16, - 0xd2, 0x7c, 0xdd, 0xde, 0xa6, 0xbd, 0x8c, 0x4d, 0x48, 0x75, 0x32, 0xda, 0x53, 0x6b, 0xfd, 0x5b, - 0x3d, 0xb5, 0xe6, 0xbb, 0xdc, 0x15, 0x7b, 0xce, 0xe1, 0x16, 0x3d, 0xe4, 0x81, 0x18, 0xa2, 0xd6, - 0xe8, 0xfb, 0x40, 0x76, 0x12, 0x4d, 0x99, 0x62, 0x24, 0x3a, 0x9c, 0x4d, 0xb6, 0x6a, 0xc8, 0x95, - 0xda, 0x23, 0x73, 0x30, 0x2e, 0x63, 0x3a, 0x2c, 0x85, 0xa9, 0x7c, 0xad, 0x85, 0x91, 0x43, 0x9b, - 0x3c, 0x70, 0x05, 0x26, 0x2c, 0xae, 0xf4, 0x9f, 0xf4, 0x94, 0xa0, 0x1e, 0xb4, 0x71, 0x21, 0x17, - 0x5c, 0x50, 0x47, 0x4a, 0x2d, 0x56, 0xd5, 0x82, 0xac, 0xc1, 0xe9, 0x1a, 0x13, 0xd4, 0x76, 0xfc, - 0xd9, 0x82, 0xcc, 0x88, 0xc5, 0x6c, 0x0f, 0x1e, 0xd7, 0xa6, 0x1a, 0x31, 0xea, 0x1b, 0x30, 0x19, - 0x57, 0x3f, 0xa9, 0x68, 0x5e, 0x19, 0x8e, 0xb5, 0x28, 0xa4, 0xb4, 0xf8, 0x18, 0xce, 0xad, 0xab, - 0x64, 0xc6, 0x4b, 0x92, 0x96, 0xd0, 0xd2, 0x96, 0xb8, 0x17, 0xc6, 0x5d, 0x48, 0x14, 0xa1, 0x7e, - 0xbd, 0x4f, 0x8f, 0x99, 0x82, 0x55, 0x8d, 0x98, 0xf4, 0x75, 0xb8, 0xa6, 0x42, 0x3a, 0xa1, 0x55, - 0x3f, 0x1f, 0xf7, 0x4b, 0x64, 0xbd, 0x03, 0x6f, 0x0c, 0xba, 0x24, 0xd7, 0xf4, 0x1f, 0xf4, 0x9a, - 0xfe, 0x6a, 0xb6, 0x12, 0x29, 0xab, 0xc4, 0x56, 0x2f, 0x63, 0xb9, 0xe8, 0xd6, 0x3a, 0xf9, 0x98, - 0xae, 0x07, 0x51, 0x77, 0x6e, 0xc2, 0x6b, 0x7d, 0xce, 0x11, 0xd5, 0x3d, 0x28, 0xda, 0x6e, 0x9d, - 0x63, 0x25, 0x1c, 0x60, 0xc1, 0xf5, 0x60, 0xd3, 0xad, 0x73, 0x2c, 0x84, 0x92, 0x4f, 0x5f, 0x8d, - 0xdd, 0xae, 0x4e, 0x73, 0xdd, 0x3e, 0x09, 0x85, 0x6e, 0x76, 0x17, 0xac, 0x40, 0x77, 0xa1, 0xdc, - 0xd3, 0xdd, 0x46, 0xb3, 0xd5, 0xab, 0x3c, 0x69, 0x89, 0x77, 0x7a, 0x24, 0xfd, 0x4e, 0x7f, 0xa6, - 0xc1, 0x64, 0x2c, 0x63, 0x83, 0x0a, 0x4a, 0x08, 0x14, 0x3d, 0xea, 0xee, 0xa3, 0x57, 0xe4, 0x6f, - 0x32, 0x9f, 0x7c, 0x23, 0x14, 0xda, 0x44, 0xd7, 0x69, 0xc0, 0x45, 0xde, 0x66, 0x1e, 0x75, 0x9c, - 0xb0, 0xa1, 0xa9, 0x73, 0xaf, 0x29, 0xdf, 0x74, 0x25, 0x8a, 0xe0, 0xd1, 0x56, 0x7c, 0x92, 0x44, - 0x5a, 0xec, 0x8b, 0x74, 0x34, 0x8d, 0x94, 0xe2, 0x3b, 0x98, 0x65, 0x99, 0xd8, 0x75, 0x35, 0x2a, - 0x68, 0xbe, 0xeb, 0xd2, 0xda, 0x46, 0xae, 0x0b, 0xf9, 0xf4, 0x00, 0xe3, 0xff, 0xb8, 0x88, 0x0d, - 0x15, 0x5d, 0xff, 0x1f, 0x1f, 0xfc, 0x57, 0x83, 0x6f, 0x24, 0x45, 0xb5, 0xa5, 0x1b, 0x1e, 0x00, - 0xc4, 0x83, 0x35, 0xbe, 0x23, 0x0b, 0x83, 0x54, 0x8a, 0x26, 0xb0, 0x98, 0x93, 0x38, 0x30, 0x1b, - 0xaf, 0xa2, 0xce, 0xdb, 0xf4, 0x2d, 0xee, 0x31, 0x7c, 0xf5, 0x6e, 0x0e, 0xba, 0x15, 0xdf, 0xa7, - 0x9d, 0x90, 0x07, 0x25, 0xcc, 0x78, 0x99, 0xa7, 0x2f, 0xe5, 0xd9, 0x7d, 0xac, 0x18, 0x39, 0x66, - 0x47, 0x07, 0x7f, 0x98, 0x72, 0xf0, 0x9b, 0x03, 0x1d, 0xac, 0x4c, 0x99, 0xf4, 0xf1, 0xca, 0x6f, - 0x66, 0x60, 0x54, 0x4a, 0x23, 0x3f, 0xd7, 0x60, 0x4c, 0x3d, 0x6c, 0x64, 0x31, 0xe7, 0x7d, 0x4e, - 0x0d, 0xf7, 0xa5, 0xeb, 0x43, 0x50, 0x2a, 0xb0, 0xfa, 0xeb, 0x3f, 0xfb, 0xcb, 0x3f, 0x7f, 0x59, - 0x28, 0x93, 0x79, 0x23, 0xe7, 0xc3, 0x0a, 0xf9, 0xad, 0x06, 0x13, 0xf1, 0x54, 0xb0, 0x94, 0x77, - 0x7d, 0xcf, 0xf0, 0x5f, 0xba, 0x39, 0x1c, 0x31, 0xc2, 0x59, 0x96, 0x70, 0x96, 0xc8, 0xf5, 0x3e, - 0x70, 0x22, 0x06, 0xe3, 0x08, 0x3d, 0xd6, 0x21, 0xbf, 0xd3, 0x60, 0x3c, 0xba, 0x88, 0xdc, 0x18, - 0x42, 0x5a, 0x84, 0x6c, 0x69, 0x28, 0x5a, 0x04, 0x76, 0x57, 0x02, 0xbb, 0x45, 0x56, 0xf2, 0x81, - 0x19, 0x47, 0x98, 0x63, 0x9d, 0x04, 0xc2, 0xcf, 0x34, 0x80, 0xb8, 0x81, 0x22, 0x37, 0x87, 0xec, - 0xb3, 0x14, 0xca, 0x93, 0x75, 0x65, 0xfa, 0xaa, 0xc4, 0xf9, 0x2e, 0xb9, 0x95, 0x8d, 0xb3, 0xc1, - 0xba, 0x73, 0x6d, 0x0c, 0xd0, 0x38, 0x52, 0x03, 0x68, 0x87, 0xfc, 0x51, 0x83, 0x73, 0xa9, 0x51, - 0x92, 0x18, 0x39, 0xe2, 0xb3, 0xc6, 0xde, 0xd2, 0xdb, 0xc3, 0x33, 0x20, 0xe4, 0xaa, 0x84, 0xfc, - 0x98, 0x3c, 0xca, 0x86, 0xdc, 0x96, 0x4c, 0x39, 0xa8, 0x8d, 0xa3, 0xc8, 0xfa, 0x1d, 0xe3, 0x48, - 0xce, 0x41, 0x1d, 0xf2, 0x2f, 0x0d, 0xa6, 0x33, 0xa7, 0x3a, 0xf2, 0xde, 0x10, 0x5e, 0xcf, 0x1a, - 0x4f, 0x4b, 0x77, 0x4e, 0xce, 0x88, 0x0a, 0xee, 0x4a, 0x05, 0x7f, 0x44, 0x3e, 0xca, 0x8f, 0x9d, - 0x6e, 0xd9, 0x53, 0xf3, 0x62, 0x4a, 0xad, 0x58, 0xe9, 0xc4, 0x64, 0x2b, 0x4d, 0x20, 0xab, 0x53, - 0x87, 0x7c, 0xaa, 0xc1, 0x44, 0x77, 0xea, 0xcb, 0xcd, 0xd0, 0xde, 0xf1, 0x33, 0x37, 0x43, 0x8f, - 0x0d, 0x92, 0x83, 0x02, 0x2c, 0xf0, 0x99, 0xa7, 0x3e, 0x7d, 0x66, 0xa6, 0xc2, 0x1f, 0x34, 0xb8, - 0x98, 0x31, 0xe6, 0x91, 0xdb, 0x39, 0x18, 0xfa, 0xcf, 0x94, 0xa5, 0x77, 0x4f, 0xca, 0x86, 0x4a, - 0x7c, 0x20, 0x95, 0x78, 0x8f, 0xdc, 0xce, 0x56, 0xc2, 0x97, 0xac, 0xf1, 0xe7, 0x11, 0xd3, 0xb1, - 0x7d, 0x91, 0xd0, 0xe2, 0xf7, 0x1a, 0x9c, 0xef, 0x99, 0xf4, 0xc8, 0x72, 0x0e, 0x94, 0xec, 0x49, - 0xb3, 0xb4, 0x72, 0x12, 0x16, 0x44, 0xbe, 0x26, 0x91, 0xaf, 0x92, 0xbb, 0xd9, 0xc8, 0x59, 0xc4, - 0x86, 0x23, 0xa3, 0x71, 0x14, 0xb5, 0xbc, 0x1d, 0xe3, 0x48, 0x0d, 0xab, 0x1d, 0xf2, 0xa7, 0x44, - 0x72, 0xa4, 0x9a, 0xde, 0xa1, 0x92, 0x23, 0xab, 0xd7, 0x1e, 0x2a, 0x39, 0x32, 0xfb, 0x6b, 0xfd, - 0xdb, 0x52, 0xa1, 0xbb, 0xe4, 0xce, 0x80, 0xe4, 0x68, 0x2a, 0x6e, 0x53, 0x8d, 0x01, 0x89, 0xe4, - 0x20, 0x7f, 0xd7, 0x60, 0xae, 0x6f, 0x1f, 0x4f, 0xde, 0xcf, 0x0b, 0x91, 0x01, 0x23, 0x44, 0x69, - 0xf5, 0xe5, 0x98, 0x51, 0xb5, 0x0d, 0xa9, 0xda, 0x3d, 0xb2, 0xda, 0x27, 0xca, 0x12, 0x17, 0x1c, - 0x53, 0xaf, 0xeb, 0x36, 0xf2, 0x2b, 0x0d, 0x20, 0x1e, 0xdf, 0xbf, 0xc6, 0xd7, 0xe3, 0xf8, 0x37, - 0x01, 0xfd, 0xba, 0x44, 0x7c, 0x95, 0x5c, 0xe9, 0x83, 0xb8, 0xb6, 0x1f, 0x15, 0x29, 0xf2, 0xb9, - 0x06, 0x17, 0x7a, 0xc7, 0x13, 0xb2, 0x32, 0xcc, 0x63, 0x9f, 0x9e, 0x75, 0x4a, 0xef, 0x9c, 0x88, - 0x07, 0x81, 0xbe, 0x2d, 0x81, 0xde, 0x20, 0x8b, 0x03, 0xfa, 0x04, 0xf5, 0xdd, 0xd2, 0xb4, 0x02, - 0xf2, 0x67, 0x0d, 0xc8, 0xf1, 0xde, 0x8d, 0xdc, 0x1a, 0xaa, 0x09, 0xe8, 0x19, 0x6f, 0x4a, 0xb7, - 0x4f, 0xc8, 0x85, 0xa8, 0x9f, 0x48, 0xd4, 0x9b, 0xe4, 0xe1, 0x80, 0x58, 0x8f, 0xdb, 0xd6, 0xac, - 0x22, 0x9a, 0xa8, 0xfa, 0xff, 0xd6, 0x60, 0xae, 0x6f, 0x43, 0x9a, 0x1b, 0xfa, 0x83, 0xa6, 0x87, - 0xdc, 0xd0, 0x1f, 0xd8, 0x03, 0xeb, 0x3f, 0x94, 0x9a, 0x6e, 0x93, 0x27, 0x43, 0x6b, 0x6a, 0xe2, - 0x6c, 0x9c, 0xaf, 0xf1, 0xda, 0xc6, 0x17, 0xcf, 0xcb, 0xda, 0x97, 0xcf, 0xcb, 0xda, 0x3f, 0x9e, - 0x97, 0xb5, 0x5f, 0xbc, 0x28, 0x9f, 0xfa, 0xf2, 0x45, 0xf9, 0xd4, 0x5f, 0x5f, 0x94, 0x4f, 0x7d, - 0x74, 0x23, 0xf1, 0x39, 0x36, 0x25, 0xb4, 0x7d, 0xcb, 0x38, 0xe8, 0x4a, 0x96, 0x9f, 0x65, 0x77, - 0xc7, 0xe4, 0x7f, 0x8d, 0xbd, 0xf3, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x54, 0xb3, 0x85, 0xe2, - 0xe6, 0x1c, 0x00, 0x00, + // 2071 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x5f, 0x6f, 0x1c, 0x57, + 0x15, 0xcf, 0x6c, 0xd6, 0x8e, 0x7d, 0x92, 0x38, 0xe1, 0xc6, 0x76, 0xec, 0xc5, 0xdd, 0x38, 0x93, + 0xa6, 0x75, 0xe2, 0x74, 0xa7, 0x76, 0x93, 0x36, 0x4a, 0xdd, 0x40, 0x6d, 0x27, 0xc1, 0x26, 0x10, + 0x7b, 0x4d, 0x40, 0xaa, 0x90, 0x46, 0xe3, 0xd9, 0xbb, 0xeb, 0xa9, 0x67, 0xe7, 0x4e, 0x67, 0xee, + 0x6c, 0x6c, 0xac, 0x05, 0x09, 0xbe, 0x00, 0x12, 0x20, 0xc1, 0x13, 0x2f, 0x95, 0xfa, 0xd4, 0x6f, + 0xc0, 0x1b, 0x12, 0xea, 0x03, 0x0f, 0x95, 0xfa, 0x82, 0x10, 0xaa, 0x50, 0xc2, 0x33, 0x88, 0x0f, + 0x80, 0x84, 0xe6, 0xde, 0x33, 0xff, 0xd6, 0xb3, 0xb3, 0xeb, 0xa4, 0x2f, 0xf1, 0xde, 0x99, 0x73, + 0xee, 0xf9, 0x9d, 0xff, 0xe7, 0x4c, 0x60, 0xde, 0x36, 0x3a, 0x86, 0x43, 0xb9, 0x16, 0xfe, 0xd5, + 0x5c, 0xc3, 0xf2, 0x2c, 0xa7, 0xa5, 0x7d, 0x12, 0x50, 0xef, 0xb0, 0xe6, 0x7a, 0x8c, 0x33, 0x32, + 0x89, 0x14, 0xb5, 0xf0, 0x6f, 0x0d, 0x29, 0x2a, 0x93, 0x2d, 0xd6, 0x62, 0x82, 0x40, 0x0b, 0x7f, + 0x49, 0xda, 0xca, 0x5c, 0x8b, 0xb1, 0x96, 0x4d, 0x35, 0xc3, 0xb5, 0x34, 0xc3, 0x71, 0x18, 0x37, + 0xb8, 0xc5, 0x1c, 0x1f, 0xdf, 0xde, 0x34, 0x99, 0xdf, 0x66, 0xbe, 0xb6, 0x6b, 0xf8, 0x54, 0x8a, + 0xd0, 0x3a, 0x4b, 0xbb, 0x94, 0x1b, 0x4b, 0x9a, 0x6b, 0xb4, 0x2c, 0x47, 0x10, 0x23, 0xed, 0xd5, + 0x5c, 0x5c, 0xae, 0xe1, 0x19, 0xed, 0xe8, 0xba, 0xeb, 0xb9, 0x24, 0x1e, 0x75, 0x03, 0x9e, 0xbe, + 0x69, 0x2e, 0x43, 0xe6, 0xbb, 0xd4, 0x14, 0xff, 0xe0, 0xdb, 0x2b, 0xd9, 0x4b, 0x6c, 0xc3, 0xf1, + 0x35, 0x97, 0xd9, 0x96, 0x89, 0xea, 0x57, 0x16, 0x33, 0x04, 0xd4, 0x65, 0xe6, 0x9e, 0xcf, 0x99, + 0x67, 0xb4, 0xa8, 0xe6, 0x73, 0x63, 0x9f, 0xea, 0xd4, 0xe1, 0x91, 0xad, 0x2a, 0xb7, 0xb2, 0xb2, + 0x82, 0x5d, 0xdf, 0xf4, 0x2c, 0x37, 0x04, 0x93, 0x39, 0x20, 0xf5, 0xb5, 0xac, 0x6c, 0x8f, 0x7d, + 0x4c, 0x4d, 0xee, 0x47, 0x3f, 0x90, 0xe8, 0xcd, 0x0c, 0x51, 0x83, 0x3d, 0x73, 0xb8, 0xd5, 0xa6, + 0x5a, 0x67, 0x29, 0xfe, 0x2d, 0x09, 0xd5, 0x49, 0x20, 0xdb, 0xa1, 0x4d, 0xb7, 0x84, 0x8d, 0xea, + 0xf4, 0x93, 0x80, 0xfa, 0x5c, 0xdd, 0x86, 0x4b, 0x99, 0xa7, 0xbe, 0xcb, 0x1c, 0x9f, 0x92, 0x7b, + 0x30, 0x2a, 0x6d, 0x39, 0xa3, 0xcc, 0x2b, 0x0b, 0x67, 0x97, 0xe7, 0x6a, 0x79, 0x5e, 0xae, 0x49, + 0xae, 0xd5, 0xf2, 0x17, 0x5f, 0x5f, 0x39, 0x55, 0x47, 0x0e, 0x75, 0x1b, 0xa6, 0xe4, 0x95, 0x1e, + 0xeb, 0x58, 0x0d, 0xea, 0x45, 0xb2, 0xc8, 0x0c, 0x9c, 0x31, 0xf7, 0x0c, 0xcb, 0xd9, 0x58, 0x17, + 0xb7, 0x8e, 0xd7, 0xa3, 0x23, 0xa9, 0x02, 0xf8, 0x7b, 0xec, 0xd9, 0x43, 0x8f, 0xfd, 0x8c, 0x3a, + 0x33, 0xa5, 0x79, 0x65, 0x61, 0xac, 0x9e, 0x7a, 0xa2, 0xee, 0xc3, 0x74, 0xef, 0x95, 0x08, 0xf4, + 0xfb, 0x00, 0xc2, 0xcc, 0x0f, 0x42, 0x2b, 0xcf, 0x28, 0xf3, 0xa7, 0x17, 0xce, 0x2e, 0x5f, 0xcf, + 0x82, 0x4d, 0xfb, 0xa4, 0xb6, 0x13, 0x13, 0x23, 0xea, 0x14, 0xfb, 0x66, 0x79, 0xac, 0x74, 0xf1, + 0xb4, 0xba, 0x09, 0x93, 0x19, 0x61, 0x29, 0xf8, 0x46, 0xa3, 0xe1, 0x51, 0xdf, 0x8f, 0xe0, 0xe3, + 0x31, 0xad, 0x58, 0x29, 0xa3, 0x98, 0xba, 0xd7, 0x63, 0x8b, 0x18, 0xf7, 0x13, 0x38, 0x17, 0x0b, + 0xb6, 0xa8, 0xff, 0x32, 0xc8, 0x33, 0x17, 0xa8, 0x9b, 0x68, 0xa2, 0x47, 0x94, 0x6f, 0x49, 0xef, + 0x0c, 0x36, 0xfb, 0x34, 0x8c, 0x9a, 0xb6, 0x45, 0x1d, 0x8e, 0xb0, 0xf1, 0xa4, 0x7e, 0x5e, 0x82, + 0xcb, 0xc7, 0x2e, 0x43, 0xe0, 0x1b, 0x30, 0xee, 0x46, 0x5e, 0x78, 0x19, 0xd4, 0x09, 0x37, 0xb9, + 0x06, 0xe7, 0xcd, 0xc0, 0xf3, 0xa8, 0xc3, 0x75, 0xc1, 0x23, 0x50, 0x94, 0xeb, 0xe7, 0xf0, 0xe1, + 0x83, 0xf0, 0x19, 0xb9, 0x0b, 0xb3, 0x61, 0x10, 0xeb, 0x36, 0x6d, 0x72, 0x9d, 0x33, 0xdd, 0xa1, + 0x07, 0x5c, 0xc7, 0xf8, 0x9b, 0x39, 0x2d, 0x18, 0xa6, 0x42, 0x82, 0xc7, 0xb4, 0xc9, 0x7f, 0xc4, + 0x7e, 0x48, 0x0f, 0x22, 0xc4, 0xe4, 0x0e, 0x5c, 0x0e, 0x13, 0x59, 0xb7, 0x0d, 0x9f, 0xeb, 0x81, + 0xdb, 0x30, 0x38, 0x6d, 0xe8, 0xbb, 0x36, 0x33, 0xf7, 0x67, 0xca, 0x82, 0x6f, 0x32, 0x7c, 0xfd, + 0xd8, 0xf0, 0xf9, 0x53, 0xf9, 0x72, 0x35, 0x7c, 0x47, 0x96, 0x60, 0x4a, 0x10, 0xe9, 0xac, 0x99, + 0x15, 0x36, 0x22, 0x98, 0x88, 0x78, 0xf9, 0xa4, 0x99, 0x92, 0xa4, 0xfe, 0x02, 0x66, 0x85, 0xb9, + 0x7e, 0x4c, 0x3d, 0xab, 0x79, 0xf8, 0xaa, 0xe6, 0x27, 0x15, 0x18, 0x8b, 0x8c, 0x24, 0x34, 0x1c, + 0xaf, 0xc7, 0x67, 0x32, 0x09, 0x23, 0x69, 0x15, 0xe4, 0x41, 0xfd, 0x54, 0x81, 0x4a, 0x1e, 0x02, + 0xf4, 0xd9, 0x24, 0x8c, 0x74, 0x0c, 0xdb, 0x6a, 0x08, 0x00, 0x63, 0x75, 0x79, 0x20, 0x37, 0xe0, + 0x62, 0xa8, 0x1a, 0x6d, 0xe8, 0x89, 0x43, 0xa5, 0x41, 0x2f, 0xc8, 0xe7, 0x71, 0xb6, 0x91, 0x79, + 0x38, 0x67, 0x06, 0xba, 0x4b, 0x3d, 0x74, 0x94, 0x14, 0x0e, 0x66, 0xb0, 0x45, 0x3d, 0xe9, 0xa6, + 0xd7, 0x00, 0xb0, 0x2e, 0xe9, 0x56, 0x43, 0x98, 0x6a, 0x5c, 0xb8, 0x3a, 0x7c, 0xb2, 0xd1, 0xc0, + 0xcc, 0xfa, 0x9d, 0x02, 0x57, 0x33, 0xe9, 0x80, 0x40, 0xd7, 0xf6, 0x0c, 0xc7, 0xa4, 0x91, 0xc1, + 0xd2, 0xea, 0x2b, 0x3d, 0xea, 0xf7, 0xcd, 0x34, 0x32, 0x0f, 0x67, 0x5b, 0x94, 0xd9, 0xcc, 0x14, + 0xb5, 0x5d, 0x28, 0x32, 0x52, 0x4f, 0x3f, 0x12, 0xbc, 0x76, 0xe0, 0x73, 0xea, 0x09, 0xfc, 0x21, + 0xaf, 0x3c, 0xaa, 0x36, 0xa8, 0x45, 0xb0, 0xd0, 0x8a, 0x0f, 0x61, 0xd4, 0x14, 0x4f, 0x24, 0xaa, + 0xd5, 0x5a, 0x18, 0xcf, 0x7f, 0xff, 0xfa, 0xca, 0x1b, 0x2d, 0x8b, 0xef, 0x05, 0xbb, 0x35, 0x93, + 0xb5, 0x35, 0xec, 0x60, 0xf2, 0xcf, 0x5b, 0x7e, 0x63, 0x5f, 0xe3, 0x87, 0x2e, 0xf5, 0x6b, 0xeb, + 0xd4, 0xac, 0x23, 0xb7, 0x6a, 0x60, 0x4d, 0x78, 0xea, 0x53, 0x4f, 0x64, 0xc6, 0x2b, 0x14, 0x98, + 0x24, 0x1e, 0x4e, 0xa7, 0xe3, 0xe1, 0x19, 0x16, 0x83, 0x94, 0x08, 0x54, 0xe2, 0x11, 0x8c, 0x99, + 0xcc, 0xf1, 0x83, 0x36, 0x1a, 0xf7, 0x84, 0xd9, 0x1b, 0x33, 0x87, 0x82, 0xdb, 0xc6, 0xc1, 0xda, + 0x53, 0x4c, 0x5a, 0x79, 0x50, 0xdf, 0x87, 0x2b, 0x42, 0xf0, 0x4e, 0xd8, 0x62, 0xcd, 0x38, 0x80, + 0x1e, 0x5b, 0x3e, 0x1f, 0x98, 0x0f, 0x6a, 0x1b, 0xe6, 0xfb, 0x33, 0x7f, 0xe3, 0xe5, 0x47, 0xdd, + 0x86, 0x6f, 0x0b, 0x71, 0x0f, 0x9a, 0x4d, 0x6a, 0x72, 0xab, 0x43, 0xb7, 0x44, 0x5f, 0x4f, 0x85, + 0x61, 0xc6, 0x52, 0xe3, 0x29, 0xe5, 0xa7, 0x61, 0x34, 0xac, 0x1d, 0xb1, 0x3b, 0xf0, 0x14, 0x06, + 0xf8, 0x5c, 0xfe, 0x9d, 0x08, 0x7f, 0x19, 0x46, 0xe5, 0xf4, 0x80, 0xc6, 0xaf, 0xf4, 0xf4, 0xd5, + 0x70, 0xbe, 0xa8, 0x21, 0x0f, 0x52, 0x92, 0x0f, 0x61, 0xc2, 0xa5, 0x4e, 0xc3, 0x72, 0x5a, 0x3a, + 0xf2, 0x96, 0x06, 0xf2, 0x9e, 0x47, 0x0e, 0x79, 0x54, 0xff, 0xab, 0x60, 0x41, 0xdf, 0x69, 0xec, + 0xf7, 0x16, 0x87, 0x47, 0x70, 0x26, 0xaa, 0x70, 0x12, 0xd3, 0x5b, 0xf9, 0xbd, 0xbe, 0x4f, 0x43, + 0xa8, 0x47, 0xdc, 0x64, 0x0a, 0x46, 0xdb, 0xc6, 0x81, 0x6e, 0x06, 0xe9, 0x90, 0x08, 0xc8, 0x22, + 0x94, 0x43, 0xeb, 0x88, 0x00, 0x3d, 0xbb, 0x7c, 0x39, 0x7b, 0xb9, 0x98, 0xb4, 0x76, 0x5c, 0x6a, + 0xd6, 0x05, 0x11, 0xd9, 0x80, 0x0b, 0xd1, 0xd8, 0xa2, 0xe3, 0x00, 0x52, 0x16, 0x7c, 0xf3, 0x59, + 0xbe, 0x78, 0xb6, 0xe9, 0x2c, 0xe1, 0x10, 0x52, 0x9f, 0x88, 0x9e, 0xc9, 0xb3, 0xfa, 0x9d, 0x9e, + 0x5a, 0xf3, 0x03, 0xe6, 0xf0, 0x3d, 0xfb, 0x70, 0xcb, 0x38, 0x64, 0x01, 0x1f, 0xa2, 0xd6, 0xa8, + 0xfb, 0x40, 0x76, 0x52, 0x43, 0x99, 0x64, 0x24, 0x2a, 0x9c, 0x4b, 0x8f, 0x6a, 0xc8, 0x95, 0x79, + 0x46, 0x66, 0x61, 0x4c, 0xc4, 0x74, 0x58, 0x0a, 0x33, 0xf9, 0xda, 0x08, 0x23, 0xc7, 0x68, 0xb3, + 0xc0, 0xe1, 0x98, 0xb0, 0x78, 0x52, 0x7f, 0xde, 0x53, 0x82, 0x7a, 0xd0, 0x26, 0x85, 0x9c, 0x33, + 0x6e, 0xd8, 0x42, 0x6a, 0xb9, 0x2e, 0x0f, 0x64, 0x15, 0xce, 0x34, 0x28, 0x37, 0x2c, 0xdb, 0x9f, + 0x29, 0x89, 0x8c, 0x58, 0xc8, 0xf7, 0xe0, 0x71, 0x6d, 0xea, 0x11, 0xa3, 0xba, 0x0e, 0x13, 0x49, + 0xf5, 0x13, 0x8a, 0x16, 0x95, 0xe1, 0x44, 0x8b, 0x52, 0x46, 0x8b, 0x8f, 0xe1, 0xfc, 0x9a, 0x4c, + 0x66, 0xbc, 0x24, 0x6d, 0x09, 0x25, 0x6b, 0x89, 0xfb, 0x61, 0xdc, 0x85, 0x44, 0x11, 0xea, 0xd7, + 0xfb, 0xcc, 0x98, 0x19, 0x58, 0xf5, 0x88, 0x49, 0x5d, 0x83, 0xeb, 0x32, 0xa4, 0x53, 0x5a, 0xf5, + 0xf3, 0x71, 0xbf, 0x44, 0x56, 0xbb, 0xf0, 0xc6, 0xa0, 0x4b, 0x0a, 0x4d, 0xff, 0x41, 0xaf, 0xe9, + 0xaf, 0xe5, 0x2b, 0x91, 0xb1, 0x4a, 0x62, 0xf5, 0x2a, 0x96, 0x8b, 0xb8, 0xd6, 0x89, 0x66, 0xba, + 0x16, 0x44, 0xd3, 0xb9, 0x0e, 0xaf, 0xf5, 0x79, 0x8f, 0xa8, 0xee, 0x43, 0xd9, 0x72, 0x9a, 0x0c, + 0x2b, 0xe1, 0x00, 0x0b, 0xae, 0x05, 0x1b, 0x4e, 0x93, 0x61, 0x21, 0x14, 0x7c, 0xea, 0x4a, 0xe2, + 0x76, 0xf9, 0xb6, 0xd0, 0xed, 0x13, 0x50, 0x8a, 0xb3, 0xbb, 0x64, 0x06, 0xaa, 0x0b, 0xd5, 0x9e, + 0xe9, 0x36, 0xda, 0xad, 0x5e, 0xad, 0x97, 0xa7, 0x3a, 0xf5, 0xe9, 0x6c, 0xa7, 0xfe, 0x4c, 0x81, + 0x89, 0x44, 0xca, 0xba, 0xc1, 0x0d, 0x42, 0xa0, 0xec, 0x19, 0xce, 0x3e, 0xfa, 0x45, 0xfc, 0x26, + 0x73, 0xe9, 0x2e, 0x21, 0xf1, 0xa6, 0xe6, 0x4e, 0x0d, 0x2e, 0xb1, 0x0e, 0xf5, 0x0c, 0xdb, 0x0e, + 0x47, 0x9a, 0x26, 0xf3, 0xda, 0xa2, 0xab, 0x4b, 0x51, 0x04, 0x5f, 0x6d, 0x25, 0x6f, 0xd2, 0x48, + 0xcb, 0x7d, 0x91, 0x8e, 0x64, 0x91, 0x1a, 0xd8, 0x09, 0xf3, 0x6c, 0x93, 0x38, 0xaf, 0x61, 0x70, + 0xa3, 0xd8, 0x79, 0x59, 0x6d, 0x23, 0xe7, 0x85, 0x7c, 0x6a, 0x80, 0x19, 0x70, 0x5c, 0xc4, 0xba, + 0x8c, 0xaf, 0x57, 0x19, 0x2c, 0xfa, 0xfb, 0xe0, 0x7f, 0x0a, 0x7c, 0x2b, 0x2d, 0xaa, 0x23, 0xdc, + 0xf0, 0x10, 0x20, 0x59, 0xad, 0xb1, 0x93, 0xcc, 0x0f, 0x52, 0x29, 0xda, 0xc1, 0x12, 0x4e, 0x62, + 0xc3, 0x4c, 0x72, 0x8a, 0x66, 0x6f, 0xdd, 0x37, 0x99, 0x47, 0xb1, 0xef, 0xdd, 0x1a, 0x74, 0x2b, + 0x76, 0xa8, 0x9d, 0x90, 0x07, 0x25, 0x4c, 0x7b, 0xb9, 0x6f, 0x5f, 0xca, 0xb3, 0xfb, 0x58, 0x33, + 0x0a, 0xcc, 0x8e, 0x0e, 0xfe, 0x30, 0xe3, 0xe0, 0x37, 0x07, 0x3a, 0x58, 0x9a, 0x32, 0xed, 0xe3, + 0xe5, 0xdf, 0x4f, 0xc3, 0x88, 0x90, 0x46, 0x7e, 0xa5, 0xc0, 0xa8, 0x6c, 0x6d, 0x64, 0xa1, 0xa0, + 0x43, 0x67, 0xd6, 0xfb, 0xca, 0x8d, 0x21, 0x28, 0x25, 0x58, 0xf5, 0xf5, 0x5f, 0x7e, 0xf5, 0xaf, + 0xdf, 0x94, 0xaa, 0x64, 0x4e, 0x2b, 0xf8, 0xb4, 0x42, 0xfe, 0xa0, 0xc0, 0x78, 0xb2, 0x17, 0x2c, + 0x16, 0x5d, 0xdf, 0xb3, 0xfe, 0x57, 0x6e, 0x0d, 0x47, 0x8c, 0x70, 0x96, 0x04, 0x9c, 0x45, 0x72, + 0xa3, 0x0f, 0x9c, 0x88, 0x41, 0x3b, 0x42, 0x8f, 0x75, 0xc9, 0x1f, 0x15, 0x18, 0x8b, 0x2e, 0x22, + 0x37, 0x87, 0x90, 0x16, 0x21, 0x5b, 0x1c, 0x8a, 0x16, 0x81, 0xdd, 0x13, 0xc0, 0x6e, 0x93, 0xe5, + 0x62, 0x60, 0xda, 0x11, 0xe6, 0x58, 0x37, 0x85, 0xf0, 0x33, 0x05, 0x20, 0x19, 0xa1, 0xc8, 0xad, + 0x21, 0x27, 0x2d, 0x89, 0xf2, 0x64, 0x73, 0x99, 0xba, 0x22, 0x70, 0xbe, 0x4b, 0x6e, 0xe7, 0xe3, + 0x6c, 0xd1, 0x78, 0xb3, 0x4d, 0x00, 0x6a, 0x47, 0x72, 0x05, 0xed, 0x92, 0xbf, 0x28, 0x70, 0x3e, + 0xb3, 0x4c, 0x12, 0xad, 0x40, 0x7c, 0xde, 0xe2, 0x5b, 0x79, 0x7b, 0x78, 0x06, 0x84, 0x5c, 0x17, + 0x90, 0x1f, 0x93, 0xcd, 0x7c, 0xc8, 0x1d, 0xc1, 0x54, 0x80, 0x5a, 0x3b, 0x8a, 0xac, 0xdf, 0xd5, + 0x8e, 0xc4, 0x26, 0xd4, 0x25, 0xff, 0x56, 0x60, 0x2a, 0x77, 0xaf, 0x23, 0xef, 0x0d, 0xe1, 0xf5, + 0xbc, 0x05, 0xb5, 0x72, 0xf7, 0xe4, 0x8c, 0xa8, 0xe0, 0xae, 0x50, 0xf0, 0xa7, 0xe4, 0xa3, 0xe2, + 0xd8, 0x89, 0xcb, 0x9e, 0xdc, 0x18, 0x33, 0x6a, 0x25, 0x4a, 0xa7, 0x76, 0x5b, 0x61, 0x02, 0x51, + 0x9d, 0xba, 0xe4, 0x53, 0x05, 0xc6, 0xe3, 0xbd, 0xaf, 0x30, 0x43, 0x7b, 0x17, 0xd0, 0xc2, 0x0c, + 0x3d, 0xb6, 0x4a, 0x0e, 0x0a, 0xb0, 0xc0, 0xa7, 0x9e, 0xfc, 0xf8, 0x99, 0x9b, 0x0a, 0x7f, 0x56, + 0xe0, 0x52, 0xce, 0xa2, 0x47, 0xee, 0x14, 0x60, 0xe8, 0xbf, 0x55, 0x56, 0xde, 0x3d, 0x29, 0x1b, + 0x2a, 0xf1, 0x81, 0x50, 0xe2, 0x3d, 0x72, 0x27, 0x5f, 0x09, 0x5f, 0xb0, 0x26, 0x1f, 0x48, 0x74, + 0xdb, 0xf2, 0x79, 0x4a, 0x8b, 0x3f, 0x29, 0x70, 0xa1, 0x67, 0xd7, 0x23, 0x4b, 0x05, 0x50, 0xf2, + 0x77, 0xcd, 0xca, 0xf2, 0x49, 0x58, 0x10, 0xf9, 0xaa, 0x40, 0xbe, 0x42, 0xee, 0xe5, 0x23, 0xa7, + 0x11, 0x1b, 0x2e, 0x8d, 0xda, 0x51, 0x34, 0xf4, 0x76, 0xb5, 0x23, 0xb9, 0xae, 0x76, 0xc9, 0x5f, + 0x53, 0xc9, 0x91, 0x19, 0x7b, 0x87, 0x4a, 0x8e, 0xbc, 0x69, 0x7b, 0xa8, 0xe4, 0xc8, 0x9d, 0xb0, + 0xd5, 0xef, 0x0a, 0x85, 0xee, 0x91, 0xbb, 0x03, 0x92, 0xa3, 0x2d, 0xb9, 0x75, 0xb9, 0x08, 0xa4, + 0x92, 0x83, 0xfc, 0x43, 0x81, 0xd9, 0xbe, 0x93, 0x3c, 0x79, 0xbf, 0x28, 0x44, 0x06, 0x2c, 0x11, + 0x95, 0x95, 0x97, 0x63, 0x46, 0xd5, 0xd6, 0x85, 0x6a, 0xf7, 0xc9, 0x4a, 0x9f, 0x28, 0x4b, 0x5d, + 0x70, 0x4c, 0xbd, 0xd8, 0x6d, 0xe4, 0xb7, 0x0a, 0x40, 0xb2, 0xc0, 0x7f, 0x83, 0xdd, 0xe3, 0xf8, + 0x57, 0x01, 0xf5, 0x86, 0x40, 0x7c, 0x8d, 0x5c, 0xed, 0x83, 0xb8, 0xb1, 0x1f, 0x15, 0x29, 0xf2, + 0xb9, 0x02, 0x17, 0x7b, 0x17, 0x14, 0xb2, 0x3c, 0x4c, 0xb3, 0xcf, 0x6e, 0x3b, 0x95, 0x77, 0x4e, + 0xc4, 0x83, 0x40, 0xdf, 0x16, 0x40, 0x6f, 0x92, 0x85, 0x01, 0x73, 0x82, 0xfc, 0x72, 0xa9, 0x9b, + 0x01, 0xf9, 0x4a, 0x01, 0x72, 0x7c, 0x76, 0x23, 0xb7, 0x87, 0x1a, 0x02, 0x7a, 0x16, 0x9c, 0xca, + 0x9d, 0x13, 0x72, 0x21, 0xea, 0x2d, 0x81, 0x7a, 0x93, 0x7c, 0x6f, 0x40, 0xac, 0x27, 0x63, 0x6b, + 0x9f, 0x26, 0x10, 0x97, 0xfd, 0xff, 0x28, 0x30, 0xdb, 0x77, 0x22, 0x2d, 0x8c, 0xfd, 0x41, 0xeb, + 0x43, 0x61, 0xec, 0x0f, 0x1c, 0x82, 0xd5, 0x9f, 0x08, 0x55, 0xb7, 0xc9, 0x93, 0xa1, 0x55, 0xd5, + 0x71, 0x3d, 0xce, 0xeb, 0x1b, 0x89, 0xc6, 0xab, 0xeb, 0x5f, 0x3c, 0xaf, 0x2a, 0x5f, 0x3e, 0xaf, + 0x2a, 0xff, 0x7c, 0x5e, 0x55, 0x7e, 0xfd, 0xa2, 0x7a, 0xea, 0xcb, 0x17, 0xd5, 0x53, 0x7f, 0x7b, + 0x51, 0x3d, 0xf5, 0xd1, 0xcd, 0xd4, 0x17, 0xd9, 0x8c, 0xd0, 0xce, 0x6d, 0xed, 0x20, 0x96, 0x2c, + 0xbe, 0xcc, 0xee, 0x8e, 0x8a, 0xff, 0x1d, 0x7b, 0xe7, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x13, + 0x5b, 0x16, 0xf6, 0xe9, 0x1c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3856,10 +3856,10 @@ func (m *QueryProviderReputationRequest) MarshalToSizedBuffer(dAtA []byte) (int, i-- dAtA[i] = 0x12 } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + if len(m.Provider) > 0 { + i -= len(m.Provider) + copy(dAtA[i:], m.Provider) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Provider))) i-- dAtA[i] = 0xa } @@ -4597,7 +4597,7 @@ func (m *QueryProviderReputationRequest) Size() (n int) { } var l int _ = l - l = len(m.Address) + l = len(m.Provider) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -7862,7 +7862,7 @@ func (m *QueryProviderReputationRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Provider", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7890,7 +7890,7 @@ func (m *QueryProviderReputationRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.Provider = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { diff --git a/x/pairing/types/query.pb.gw.go b/x/pairing/types/query.pb.gw.go index 9f73baeea1..555593a107 100644 --- a/x/pairing/types/query.pb.gw.go +++ b/x/pairing/types/query.pb.gw.go @@ -912,15 +912,15 @@ func request_Query_ProviderReputation_0(ctx context.Context, marshaler runtime.M _ = err ) - val, ok = pathParams["address"] + val, ok = pathParams["provider"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "provider") } - protoReq.Address, err = runtime.String(val) + protoReq.Provider, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "provider", err) } val, ok = pathParams["chainID"] @@ -961,15 +961,15 @@ func local_request_Query_ProviderReputation_0(ctx context.Context, marshaler run _ = err ) - val, ok = pathParams["address"] + val, ok = pathParams["provider"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "provider") } - protoReq.Address, err = runtime.String(val) + protoReq.Provider, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "provider", err) } val, ok = pathParams["chainID"] @@ -1819,7 +1819,7 @@ var ( pattern_Query_ProvidersEpochCu_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"lavanet", "lava", "pairing", "providers_epoch_cu"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_ProviderReputation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lavanet", "lava", "pairing", "provider_reputation", "address", "chainID", "cluster"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ProviderReputation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lavanet", "lava", "pairing", "provider_reputation", "provider", "chainID", "cluster"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ProviderReputationDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"lavanet", "lava", "pairing", "provider_reputation_details", "address", "chainID", "cluster"}, "", runtime.AssumeColonVerbOpt(false))) ) From 062ae0d9fed67df0a9ed9ccd4b6938649f330d7d Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 13 Jan 2025 17:26:55 +0200 Subject: [PATCH 33/33] weigh epoch qos score by cu (revert by relay num) --- x/pairing/keeper/msg_server_relay_payment.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index b06acfba22..9eb2017373 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -47,7 +47,6 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen return nil, err } addressEpochBadgeMap := map[string]BadgeData{} - sessionRelaysAmount := map[uint64]int{} for _, relay := range msg.Relays { if relay.Badge != nil { mapKey := types.CreateAddressEpochBadgeMapKey(relay.Badge.Address, relay.Badge.Epoch) @@ -68,11 +67,6 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen addressEpochBadgeMap[mapKey] = badgeData } } - if _, ok := sessionRelaysAmount[relay.SessionId]; !ok { - sessionRelaysAmount[relay.SessionId] = 1 - } else { - sessionRelaysAmount[relay.SessionId]++ - } } var rejectedCu uint64 // aggregated rejected CU (due to badge CU overuse or provider double spending) @@ -179,7 +173,7 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen // update the reputation's epoch QoS score // the excellece QoS report can be nil when the provider and consumer geolocations are not equal if relay.QosExcellenceReport != nil { - err = k.aggregateReputationEpochQosScore(ctx, project.Subscription, relay, sessionRelaysAmount[relay.SessionId]) + err = k.aggregateReputationEpochQosScore(ctx, project.Subscription, relay) if err != nil { return nil, utils.LavaFormatWarning("RelayPayment: could not update reputation epoch QoS score", err, utils.LogAttr("consumer", project.Subscription), @@ -496,7 +490,7 @@ func (k Keeper) handleBadgeCu(ctx sdk.Context, badgeData BadgeData, provider str k.SetBadgeUsedCu(ctx, badgeUsedCuMapEntry) } -func (k Keeper) aggregateReputationEpochQosScore(ctx sdk.Context, subscription string, relay *types.RelaySession, relaysAmount int) error { +func (k Keeper) aggregateReputationEpochQosScore(ctx sdk.Context, subscription string, relay *types.RelaySession) error { sub, found := k.subscriptionKeeper.GetSubscription(ctx, subscription) if !found { return utils.LavaFormatError("RelayPayment: could not get cluster for reputation score update", fmt.Errorf("relay consumer's subscription not found"), @@ -528,7 +522,7 @@ func (k Keeper) aggregateReputationEpochQosScore(ctx sdk.Context, subscription s } effectiveStake := sdk.NewCoin(stakeEntry.Stake.Denom, stakeEntry.TotalStake()) - // note the current weight used is by relay num. In the future, it might change - k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(uint64(relaysAmount)), effectiveStake) + // note the current weight used is by cu. In the future, it might change + k.UpdateReputationEpochQosScore(ctx, relay.SpecId, sub.Cluster, relay.Provider, score, utils.SafeUint64ToInt64Convert(relay.CuSum), effectiveStake) return nil }