From 95fb0382d676954c7570fca271a9d3bf01aec89d Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 31 Jul 2024 14:01:46 +0300 Subject: [PATCH 01/66] CNS-1002: collect raw qos data --- protocol/lavaprotocol/request_builder.go | 2 +- .../lavasession/consumer_session_manager.go | 3 +- protocol/lavasession/consumer_types.go | 17 ++++----- .../lavasession/single_consumer_session.go | 3 +- .../provideroptimizer/provider_optimizer.go | 35 ++++++++++++------- .../provider_optimizer_test.go | 7 ++-- utils/score/decay_score.go | 11 ++++-- 7 files changed, 51 insertions(+), 27 deletions(-) diff --git a/protocol/lavaprotocol/request_builder.go b/protocol/lavaprotocol/request_builder.go index 76fab9e7dc..c991f07c79 100644 --- a/protocol/lavaprotocol/request_builder.go +++ b/protocol/lavaprotocol/request_builder.go @@ -76,7 +76,7 @@ func ConstructRelaySession(lavaChainID string, relayRequestData *pairingtypes.Re } copiedQOS := copyQoSServiceReport(singleConsumerSession.QoSInfo.LastQoSReport) - copiedExcellenceQOS := copyQoSServiceReport(singleConsumerSession.QoSInfo.LastExcellenceQoSReport) + copiedExcellenceQOS := copyQoSServiceReport(singleConsumerSession.QoSInfo.LastExcellenceQoSReportRaw) // copy raw report for the node return &pairingtypes.RelaySession{ SpecId: chainID, diff --git a/protocol/lavasession/consumer_session_manager.go b/protocol/lavasession/consumer_session_manager.go index c0df759646..64d9769ea2 100644 --- a/protocol/lavasession/consumer_session_manager.go +++ b/protocol/lavasession/consumer_session_manager.go @@ -533,7 +533,8 @@ func (csm *ConsumerSessionManager) GetSessions(ctx context.Context, cuNeededForS sessionInfo.QoSSummeryResult = consumerSession.getQosComputedResultOrZero() sessions[providerAddress] = sessionInfo - consumerSession.SetUsageForSession(cuNeededForSession, csm.providerOptimizer.GetExcellenceQoSReportForProvider(providerAddress), usedProviders) + qosReport, rawQosReport := csm.providerOptimizer.GetExcellenceQoSReportForProvider(providerAddress) + consumerSession.SetUsageForSession(cuNeededForSession, qosReport, rawQosReport, usedProviders) // We successfully added provider, we should ignore it if we need to fetch new tempIgnoredProviders.providers[providerAddress] = struct{}{} if len(sessions) == wantedSession { diff --git a/protocol/lavasession/consumer_types.go b/protocol/lavasession/consumer_types.go index 0614ddae97..b5411808f7 100644 --- a/protocol/lavasession/consumer_types.go +++ b/protocol/lavasession/consumer_types.go @@ -73,7 +73,7 @@ type ProviderOptimizer interface { AppendRelayFailure(providerAddress string) AppendRelayData(providerAddress string, latency time.Duration, isHangingApi bool, cu, syncBlock uint64) ChooseProvider(allAddresses []string, ignoredProviders map[string]struct{}, cu uint64, requestedBlock int64, perturbationPercentage float64) (addresses []string) - GetExcellenceQoSReportForProvider(string) *pairingtypes.QualityOfServiceReport + GetExcellenceQoSReportForProvider(string) (*pairingtypes.QualityOfServiceReport, *pairingtypes.QualityOfServiceReport) Strategy() provideroptimizer.Strategy } @@ -83,13 +83,14 @@ type ignoredProviders struct { } type QoSReport struct { - LastQoSReport *pairingtypes.QualityOfServiceReport - LastExcellenceQoSReport *pairingtypes.QualityOfServiceReport - LatencyScoreList []sdk.Dec - SyncScoreSum int64 - TotalSyncScore int64 - TotalRelays uint64 - AnsweredRelays uint64 + LastQoSReport *pairingtypes.QualityOfServiceReport + LastExcellenceQoSReport *pairingtypes.QualityOfServiceReport + LastExcellenceQoSReportRaw *pairingtypes.QualityOfServiceReport + LatencyScoreList []sdk.Dec + SyncScoreSum int64 + TotalSyncScore int64 + TotalRelays uint64 + AnsweredRelays uint64 } type DataReliabilitySession struct { diff --git a/protocol/lavasession/single_consumer_session.go b/protocol/lavasession/single_consumer_session.go index 57665f7a90..33ca1e94f3 100644 --- a/protocol/lavasession/single_consumer_session.go +++ b/protocol/lavasession/single_consumer_session.go @@ -101,12 +101,13 @@ func (cs *SingleConsumerSession) CalculateQoS(latency, expectedLatency time.Dura } } -func (scs *SingleConsumerSession) SetUsageForSession(cuNeededForSession uint64, qoSExcellenceReport *pairingtypes.QualityOfServiceReport, usedProviders UsedProvidersInf) error { +func (scs *SingleConsumerSession) SetUsageForSession(cuNeededForSession uint64, qoSExcellenceReport *pairingtypes.QualityOfServiceReport, rawQoSExcellenceReport *pairingtypes.QualityOfServiceReport, usedProviders UsedProvidersInf) error { scs.LatestRelayCu = cuNeededForSession // set latestRelayCu scs.RelayNum += RelayNumberIncrement // increase relayNum if scs.RelayNum > 1 { // we only set excellence for sessions with more than one successful relays, this guarantees data within the epoch exists scs.QoSInfo.LastExcellenceQoSReport = qoSExcellenceReport + scs.QoSInfo.LastExcellenceQoSReportRaw = rawQoSExcellenceReport } scs.relayProcessor = usedProviders return nil diff --git a/protocol/provideroptimizer/provider_optimizer.go b/protocol/provideroptimizer/provider_optimizer.go index 9ffd9d923c..f67e5fee0c 100644 --- a/protocol/provideroptimizer/provider_optimizer.go +++ b/protocol/provideroptimizer/provider_optimizer.go @@ -57,6 +57,8 @@ type ProviderData struct { Latency score.ScoreStore // will be used to calculate the latency score Sync score.ScoreStore // will be used to calculate the sync score for spectypes.LATEST_BLOCK/spectypes.NOT_APPLICABLE requests SyncBlock uint64 // will be used to calculate the probability of block error + LatencyRaw score.ScoreStore // will be used when reporting reputation to the node (Latency = LatencyRaw / baseLatency) + SyncRaw score.ScoreStore // will be used when reporting reputation to the node (Sync = SyncRaw / baseSync) } type Strategy int @@ -90,14 +92,14 @@ func (po *ProviderOptimizer) appendRelayData(providerAddress string, latency tim if isHangingApi { baseLatency += po.averageBlockTime / 2 // hanging apis take longer } - providerData = po.updateProbeEntryLatency(providerData, latency, baseLatency, RELAY_UPDATE_WEIGHT, halfTime, sampleTime) + providerData = po.updateProbeEntryLatency(providerData, latency, baseLatency, RELAY_UPDATE_WEIGHT, halfTime, sampleTime, isHangingApi) } if syncBlock > providerData.SyncBlock { // do not allow providers to go back providerData.SyncBlock = syncBlock } syncLag := po.calculateSyncLag(latestSync, timeSync, providerData.SyncBlock, sampleTime) - providerData = po.updateProbeEntrySync(providerData, syncLag, po.averageBlockTime, halfTime, sampleTime) + providerData = po.updateProbeEntrySync(providerData, syncLag, po.averageBlockTime, halfTime, sampleTime, isHangingApi) } po.providersStorage.Set(providerAddress, providerData, 1) po.updateRelayTime(providerAddress, sampleTime) @@ -113,7 +115,7 @@ func (po *ProviderOptimizer) AppendProbeRelayData(providerAddress string, latenc providerData = po.updateProbeEntryAvailability(providerData, success, PROBE_UPDATE_WEIGHT, halfTime, sampleTime) if success && latency > 0 { // base latency for a probe is the world latency - providerData = po.updateProbeEntryLatency(providerData, latency, po.baseWorldLatency, PROBE_UPDATE_WEIGHT, halfTime, sampleTime) + providerData = po.updateProbeEntryLatency(providerData, latency, po.baseWorldLatency, PROBE_UPDATE_WEIGHT, halfTime, sampleTime, true) } po.providersStorage.Set(providerAddress, providerData, 1) if debug { @@ -353,10 +355,10 @@ func (po *ProviderOptimizer) getProviderData(providerAddress string) (providerDa return providerData, found } -func (po *ProviderOptimizer) updateProbeEntrySync(providerData ProviderData, sync, baseSync, halfTime time.Duration, sampleTime time.Time) ProviderData { +func (po *ProviderOptimizer) updateProbeEntrySync(providerData ProviderData, sync, baseSync, halfTime time.Duration, sampleTime time.Time, isHangingApi bool) ProviderData { newScore := score.NewScoreStore(sync.Seconds(), baseSync.Seconds(), sampleTime) oldScore := providerData.Sync - providerData.Sync = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, RELAY_UPDATE_WEIGHT, sampleTime) + providerData.Sync, providerData.SyncRaw = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, RELAY_UPDATE_WEIGHT, sampleTime, isHangingApi) return providerData } @@ -368,15 +370,15 @@ func (po *ProviderOptimizer) updateProbeEntryAvailability(providerData ProviderD } oldScore := providerData.Availability newScore := score.NewScoreStore(newNumerator, 1, sampleTime) // denom is 1, entry time is now - providerData.Availability = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, weight, sampleTime) + providerData.Availability, _ = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, weight, sampleTime, true) return providerData } // update latency data, base latency is the latency for the api defined in the spec -func (po *ProviderOptimizer) updateProbeEntryLatency(providerData ProviderData, latency, baseLatency time.Duration, weight float64, halfTime time.Duration, sampleTime time.Time) ProviderData { +func (po *ProviderOptimizer) updateProbeEntryLatency(providerData ProviderData, latency, baseLatency time.Duration, weight float64, halfTime time.Duration, sampleTime time.Time, isHangingApi bool) ProviderData { newScore := score.NewScoreStore(latency.Seconds(), baseLatency.Seconds(), sampleTime) oldScore := providerData.Latency - providerData.Latency = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, weight, sampleTime) + providerData.Latency, providerData.LatencyRaw = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, weight, sampleTime, isHangingApi) return providerData } @@ -464,10 +466,10 @@ func pertrubWithNormalGaussian(orig, percentage float64) float64 { return orig + perturb } -func (po *ProviderOptimizer) GetExcellenceQoSReportForProvider(providerAddress string) *pairingtypes.QualityOfServiceReport { +func (po *ProviderOptimizer) GetExcellenceQoSReportForProvider(providerAddress string) (qosReport *pairingtypes.QualityOfServiceReport, rawQosReport *pairingtypes.QualityOfServiceReport) { providerData, found := po.getProviderData(providerAddress) if !found { - return nil + return nil, nil } precision := WANTED_PRECISION latencyScore := turnFloatToDec(providerData.Latency.Num/providerData.Latency.Denom, precision) @@ -482,10 +484,19 @@ func (po *ProviderOptimizer) GetExcellenceQoSReportForProvider(providerAddress s Availability: availabilityScore, Sync: syncScore, } + + latencyScoreRaw := turnFloatToDec(providerData.LatencyRaw.Num/providerData.LatencyRaw.Denom, precision) + syncScoreRaw := turnFloatToDec(providerData.SyncRaw.Num/providerData.SyncRaw.Denom, precision) + rawQosReport = &pairingtypes.QualityOfServiceReport{ + Latency: latencyScoreRaw, + Availability: availabilityScore, + Sync: syncScoreRaw, + } + if debug { - utils.LavaFormatDebug("QoS Excellence for provider", utils.Attribute{Key: "address", Value: providerAddress}, utils.Attribute{Key: "Report", Value: ret}) + utils.LavaFormatDebug("QoS Excellence for provider", utils.Attribute{Key: "address", Value: providerAddress}, utils.Attribute{Key: "Report", Value: ret}, utils.Attribute{Key: "raw_report", Value: rawQosReport}) } - return ret + return ret, rawQosReport } func turnFloatToDec(floatNum float64, precision int64) sdk.Dec { diff --git a/protocol/provideroptimizer/provider_optimizer_test.go b/protocol/provideroptimizer/provider_optimizer_test.go index 79d118dc2c..fac0252b33 100644 --- a/protocol/provideroptimizer/provider_optimizer_test.go +++ b/protocol/provideroptimizer/provider_optimizer_test.go @@ -536,11 +536,14 @@ func TestExcellence(t *testing.T) { } time.Sleep(4 * time.Millisecond) } - report := providerOptimizer.GetExcellenceQoSReportForProvider(providersGen.providersAddresses[0]) + report, rawReport := providerOptimizer.GetExcellenceQoSReportForProvider(providersGen.providersAddresses[0]) require.NotNil(t, report) - report2 := providerOptimizer.GetExcellenceQoSReportForProvider(providersGen.providersAddresses[1]) + require.NotNil(t, rawReport) + report2, rawReport2 := providerOptimizer.GetExcellenceQoSReportForProvider(providersGen.providersAddresses[1]) require.NotNil(t, report2) require.Equal(t, report, report2) + require.NotNil(t, rawReport2) + require.Equal(t, rawReport, rawReport2) } func TestPerturbationWithNormalGaussianOnConcurrentComputation(t *testing.T) { diff --git a/utils/score/decay_score.go b/utils/score/decay_score.go index 2337b896d7..0b6ee96228 100644 --- a/utils/score/decay_score.go +++ b/utils/score/decay_score.go @@ -29,12 +29,19 @@ func NewScoreStore(num, denom float64, inpTime time.Time) ScoreStore { // where now is the current time. // // Note that the returned ScoreStore has a new Time field set to the current time. -func CalculateTimeDecayFunctionUpdate(oldScore, newScore ScoreStore, halfLife time.Duration, updateWeight float64, sampleTime time.Time) ScoreStore { +func CalculateTimeDecayFunctionUpdate(oldScore, newScore ScoreStore, halfLife time.Duration, updateWeight float64, sampleTime time.Time, isHanging bool) (normalizedScoreStore ScoreStore, rawScoreStore ScoreStore) { oldDecayExponent := math.Ln2 * sampleTime.Sub(oldScore.Time).Seconds() / halfLife.Seconds() oldDecayFactor := math.Exp(-oldDecayExponent) newDecayExponent := math.Ln2 * sampleTime.Sub(newScore.Time).Seconds() / halfLife.Seconds() newDecayFactor := math.Exp(-newDecayExponent) updatedNum := oldScore.Num*oldDecayFactor + newScore.Num*newDecayFactor*updateWeight updatedDenom := oldScore.Denom*oldDecayFactor + newScore.Denom*newDecayFactor*updateWeight - return NewScoreStore(updatedNum, updatedDenom, sampleTime) + + // calculate raw denom for reputation for non-hanging API. + // Raw denom = denom not divided by benchmark value (=denom of a new ScoreStore) + updatedRawDenom := oldDecayFactor + if !isHanging { + updatedRawDenom += newDecayFactor * updateWeight // removed newScore.Denom from update to get raw data + } + return NewScoreStore(updatedNum, updatedDenom, sampleTime), NewScoreStore(updatedNum, updatedRawDenom, sampleTime) } From a6c389b4af4adffe08342c872d612542b4116a23 Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 31 Jul 2024 15:26:23 +0300 Subject: [PATCH 02/66] CNS-1002: fix isHangingApi arg --- protocol/provideroptimizer/provider_optimizer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/provideroptimizer/provider_optimizer.go b/protocol/provideroptimizer/provider_optimizer.go index f67e5fee0c..605b0610d6 100644 --- a/protocol/provideroptimizer/provider_optimizer.go +++ b/protocol/provideroptimizer/provider_optimizer.go @@ -115,7 +115,7 @@ func (po *ProviderOptimizer) AppendProbeRelayData(providerAddress string, latenc providerData = po.updateProbeEntryAvailability(providerData, success, PROBE_UPDATE_WEIGHT, halfTime, sampleTime) if success && latency > 0 { // base latency for a probe is the world latency - providerData = po.updateProbeEntryLatency(providerData, latency, po.baseWorldLatency, PROBE_UPDATE_WEIGHT, halfTime, sampleTime, true) + providerData = po.updateProbeEntryLatency(providerData, latency, po.baseWorldLatency, PROBE_UPDATE_WEIGHT, halfTime, sampleTime, false) } po.providersStorage.Set(providerAddress, providerData, 1) if debug { @@ -370,7 +370,7 @@ func (po *ProviderOptimizer) updateProbeEntryAvailability(providerData ProviderD } oldScore := providerData.Availability newScore := score.NewScoreStore(newNumerator, 1, sampleTime) // denom is 1, entry time is now - providerData.Availability, _ = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, weight, sampleTime, true) + providerData.Availability, _ = score.CalculateTimeDecayFunctionUpdate(oldScore, newScore, halfTime, weight, sampleTime, false) return providerData } From 63022373b3da214e1219223f49e9bdc68ba065cc Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 31 Jul 2024 16:54:07 +0300 Subject: [PATCH 03/66] CNS-1003: install collections --- go.mod | 32 ++++----- go.sum | 99 ++++++--------------------- utils/collcompat/collcompat.go | 118 +++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 97 deletions(-) create mode 100644 utils/collcompat/collcompat.go diff --git a/go.mod b/go.mod index 8a01ee3c69..f1f0831e30 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.20 require ( github.com/99designs/keyring v1.2.1 // indirect - github.com/btcsuite/btcd v0.23.2 github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.8.0 github.com/confio/ics23/go v0.9.0 // indirect @@ -26,8 +25,11 @@ require ( ) require ( + cosmossdk.io/collections v0.4.0 + cosmossdk.io/core v0.10.0 cosmossdk.io/errors v1.0.1 cosmossdk.io/math v1.3.0 + github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/cosmos/cosmos-proto v1.0.0-beta.4 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3 @@ -55,36 +57,28 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.5 // indirect cloud.google.com/go/storage v1.30.1 // indirect - cosmossdk.io/api v0.3.1 // indirect - cosmossdk.io/core v0.5.1 // indirect + cosmossdk.io/api v0.7.0 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/log v1.3.1 // indirect cosmossdk.io/tools/rosetta v0.2.1 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/aead/siphash v1.0.1 // indirect + github.com/DataDog/zstd v1.5.5 // indirect github.com/aws/aws-sdk-go v1.44.203 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/btcutil v1.1.2 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect - github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect - github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect - github.com/btcsuite/winsvc v1.0.0 // indirect github.com/bufbuild/protocompile v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/errors v1.10.0 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b // indirect github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cosmos/cosmos-db v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect github.com/creachadair/taskgroup v0.4.2 // indirect - github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect - github.com/decred/dcrd/lru v1.0.0 // indirect github.com/getsentry/sentry-go v0.23.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -103,10 +97,7 @@ require ( github.com/hashicorp/go-version v1.6.0 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/orderedmap v0.2.0 // indirect - github.com/jessevdk/go-flags v1.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jrick/logrotate v1.0.0 // indirect - github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/linxGnu/grocksdb v1.7.16 // indirect @@ -198,8 +189,8 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rakyll/statik v0.1.7 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect @@ -240,3 +231,8 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 replace github.com/cosmos/cosmos-sdk => github.com/lavanet/cosmos-sdk v0.47.10-lava-cosmos // branch: v0.47.10-lava + +replace ( + cosmossdk.io/api => cosmossdk.io/api v0.3.1 + golang.org/x/exp => golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb +) diff --git a/go.sum b/go.sum index c41eb348d0..0e3e13e4b8 100644 --- a/go.sum +++ b/go.sum @@ -193,8 +193,10 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= -cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= -cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= +cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= +cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= +cosmossdk.io/core v0.10.0 h1:NP28Ol9YyRODmZLJg2ko/mUl40hMegeMzhJnG+XPkcY= +cosmossdk.io/core v0.10.0/go.mod h1:MygXNld9DvMgYY4yE76DM/mdZpgfeyRjy6FPjEEehlY= cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc= cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= @@ -205,7 +207,6 @@ cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -220,13 +221,13 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -243,7 +244,6 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= -github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -297,41 +297,27 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= -github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd v0.22.2 h1:vBZ+lGGd1XubpOWO67ITJpAEsICWhA0YzqkcpkgNBfo= -github.com/btcsuite/btcd v0.22.2/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd v0.23.2 h1:/YOgUp25sdCnP5ho6Hl3s0E438zlX+Kak7E6TgBgoT0= -github.com/btcsuite/btcd v0.23.2/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= -github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= -github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= -github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= @@ -377,15 +363,16 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU= github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b h1:LCs8gDhg6vt8A3dN7AEJxmCoETZ4qkySoVJVm3rcSJk= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= @@ -408,6 +395,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= +github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0E= +github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= @@ -422,8 +411,6 @@ github.com/cosmos/iavl v0.20.1 h1:rM1kqeG3/HBT85vsZdoSNsehciqUQPWrR4BYmqE2+zg= github.com/cosmos/iavl v0.20.1/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3 h1:MZGDMETv72suFpTAD6VPGqSIm1FJcChtk2HmVh9D+Bo= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3/go.mod h1:UvDmcGIWJPIytq+Q78/ff5NTOsuX/7IrNgEugTW5i0s= -github.com/cosmos/ibc-go/v7 v7.3.1 h1:bil1IjnHdyWDASFYKfwdRiNtFP6WK3osW7QFEAgU4I8= -github.com/cosmos/ibc-go/v7 v7.3.1/go.mod h1:wvx4pPBofe5ZdMNV3OFRxSI4auEP5Qfqf8JXLLNV04g= github.com/cosmos/ibc-go/v7 v7.4.0 h1:8FqYMptvksgMvlbN4UW9jFxTXzsPyfAzEZurujXac8M= github.com/cosmos/ibc-go/v7 v7.4.0/go.mod h1:L/KaEhzV5TGUCTfGysVgMBQtl5Dm7hHitfpk+GIeoAo= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= @@ -454,7 +441,6 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= -github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= @@ -496,7 +482,6 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -515,7 +500,6 @@ github.com/fasthttp/websocket v1.5.0 h1:B4zbe3xXyvIdnqjOZrafVFklCUq5ZLo/TqCt5JA1 github.com/fasthttp/websocket v1.5.0/go.mod h1:n0BlOQvJdPbTuBkZT0O5+jk/sp/1/VCzquR1BehI2F4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -549,9 +533,6 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -569,7 +550,6 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -600,8 +580,6 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/fiber/v2 v2.34.0/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= -github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw= -github.com/gofiber/fiber/v2 v2.50.0/go.mod h1:21eytvay9Is7S6z+OgPi7c7n4++tnClWmhpimVHMimw= github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/websocket/v2 v2.0.22 h1:aR2PomjLYRoQdFLFq5dH4OqJ93NiVfrfQTJqi1zxthU= @@ -721,8 +699,6 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= @@ -853,10 +829,7 @@ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7Bd github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= -github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -871,7 +844,6 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -879,7 +851,6 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= @@ -891,7 +862,6 @@ github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -900,8 +870,6 @@ github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -1004,7 +972,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= @@ -1079,7 +1046,6 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1107,8 +1073,8 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1117,8 +1083,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1162,7 +1128,6 @@ github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71e github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899 h1:Orn7s+r1raRTBKLSc9DmbktTT04sL+vkzsbRD2Q8rOI= github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899/go.mod h1:oejLrk1Y/5zOF+c/aHtXqn3TFlzzbAgPWg8zBiAHDas= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= @@ -1269,13 +1234,10 @@ github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.33.0/go.mod h1:KJRK/MXx0J+yd0c5hlR+s1tIHD72sniU8ZJjl97LIw4= github.com/valyala/fasthttp v1.37.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= -github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -1359,28 +1321,13 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1393,21 +1340,19 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1545,7 +1490,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1665,7 +1609,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1674,9 +1617,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1693,7 +1634,6 @@ golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1725,6 +1665,7 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/utils/collcompat/collcompat.go b/utils/collcompat/collcompat.go new file mode 100644 index 0000000000..c2d4588166 --- /dev/null +++ b/utils/collcompat/collcompat.go @@ -0,0 +1,118 @@ +package utils + +import ( + "context" + + collcodec "cosmossdk.io/collections/codec" + "cosmossdk.io/core/store" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/gogo/protobuf/proto" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func NewKVStoreService(storeKey storetypes.StoreKey) store.KVStoreService { + return &kvStoreService{key: storeKey} +} + +type kvStoreService struct { + key storetypes.StoreKey +} + +func (k kvStoreService) OpenKVStore(ctx context.Context) store.KVStore { + return newKVStore(sdk.UnwrapSDKContext(ctx).KVStore(k.key)) +} + +// CoreKVStore is a wrapper of Core/Store kvstore interface +// Remove after https://github.com/cosmos/cosmos-sdk/issues/14714 is closed +type coreKVStore struct { + kvStore storetypes.KVStore +} + +// NewKVStore returns a wrapper of Core/Store kvstore interface +// Remove once store migrates to core/store kvstore interface +func newKVStore(store storetypes.KVStore) store.KVStore { + return coreKVStore{kvStore: store} +} + +// Get returns nil iff key doesn't exist. Errors on nil key. +func (store coreKVStore) Get(key []byte) ([]byte, error) { + return store.kvStore.Get(key), nil +} + +// Has checks if a key exists. Errors on nil key. +func (store coreKVStore) Has(key []byte) (bool, error) { + return store.kvStore.Has(key), nil +} + +// Set sets the key. Errors on nil key or value. +func (store coreKVStore) Set(key, value []byte) error { + store.kvStore.Set(key, value) + return nil +} + +// Delete deletes the key. Errors on nil key. +func (store coreKVStore) Delete(key []byte) error { + store.kvStore.Delete(key) + return nil +} + +// Iterator iterates over a domain of keys in ascending order. End is exclusive. +// Start must be less than end, or the Iterator is invalid. +// Iterator must be closed by caller. +// To iterate over entire domain, use store.Iterator(nil, nil) +// CONTRACT: No writes may happen within a domain while an iterator exists over it. +// Exceptionally allowed for cachekv.Store, safe to write in the modules. +func (store coreKVStore) Iterator(start, end []byte) (store.Iterator, error) { + return store.kvStore.Iterator(start, end), nil +} + +func (store coreKVStore) ReverseIterator(start, end []byte) (store.Iterator, error) { + return store.kvStore.ReverseIterator(start, end), nil +} + +type protoMessage[T any] interface { + *T + codec.ProtoMarshaler +} + +// ProtoValue inits a collections.ValueCodec for a generic gogo protobuf message. +func ProtoValue[T any, PT protoMessage[T]](cdc codec.BinaryCodec) collcodec.ValueCodec[T] { + c, ok := cdc.(codec.Codec) + if !ok { + return &collValue[T, PT]{} + } + return &collValue[T, PT]{c, proto.MessageName(PT(new(T)))} +} + +type collValue[T any, PT protoMessage[T]] struct { + cdc codec.Codec + messageName string +} + +func (c collValue[T, PT]) Encode(value T) ([]byte, error) { + return c.cdc.Marshal(PT(&value)) +} + +func (c collValue[T, PT]) Decode(b []byte) (value T, err error) { + err = c.cdc.Unmarshal(b, PT(&value)) + return value, err +} + +func (c collValue[T, PT]) EncodeJSON(value T) ([]byte, error) { + return c.cdc.MarshalJSON(PT(&value)) +} + +func (c collValue[T, PT]) DecodeJSON(b []byte) (value T, err error) { + err = c.cdc.UnmarshalJSON(b, PT(&value)) + return +} + +func (c collValue[T, PT]) Stringify(value T) string { + return PT(&value).String() +} + +func (c collValue[T, PT]) ValueType() string { + return "github.com/cosmos/gogoproto/" + c.messageName +} From 40f818745d9827a6539a38b104827b28ef545504 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 1 Aug 2024 11:38:18 +0300 Subject: [PATCH 04/66] CNS-1003: implemented reputation --- proto/lavanet/lava/pairing/genesis.proto | 9 + proto/lavanet/lava/pairing/reputation.proto | 41 + x/pairing/README.md | 12 +- x/pairing/genesis.go | 5 + x/pairing/genesis_test.go | 15 + x/pairing/keeper/keeper.go | 25 + x/pairing/keeper/qos_excellence.go | 26 - x/pairing/keeper/reputation.go | 104 ++ x/pairing/keeper/reputation_test.go | 71 ++ x/pairing/types/genesis.go | 11 + x/pairing/types/genesis.pb.go | 481 ++++++++- x/pairing/types/genesis_test.go | 35 + x/pairing/types/qos_score.go | 26 + x/pairing/types/reputation.go | 58 + x/pairing/types/reputation.pb.go | 1074 +++++++++++++++++++ 15 files changed, 1917 insertions(+), 76 deletions(-) create mode 100644 proto/lavanet/lava/pairing/reputation.proto delete mode 100644 x/pairing/keeper/qos_excellence.go create mode 100644 x/pairing/keeper/reputation.go create mode 100644 x/pairing/keeper/reputation_test.go create mode 100644 x/pairing/types/qos_score.go create mode 100644 x/pairing/types/reputation.go create mode 100644 x/pairing/types/reputation.pb.go diff --git a/proto/lavanet/lava/pairing/genesis.proto b/proto/lavanet/lava/pairing/genesis.proto index 51c94e8f8e..a6317dd512 100644 --- a/proto/lavanet/lava/pairing/genesis.proto +++ b/proto/lavanet/lava/pairing/genesis.proto @@ -6,6 +6,7 @@ import "lavanet/lava/pairing/params.proto"; import "lavanet/lava/pairing/epoch_cu.proto"; import "lavanet/lava/fixationstore/fixation.proto"; import "lavanet/lava/timerstore/timer.proto"; +import "lavanet/lava/pairing/reputation.proto"; // this line is used by starport scaffolding # genesis/proto/import @@ -29,6 +30,7 @@ message GenesisState { repeated ProviderEpochCuGenesis provider_epoch_cus = 9 [(gogoproto.nullable) = false]; repeated ProviderEpochComplainerCuGenesis provider_epoch_complained_cus = 10 [(gogoproto.nullable) = false]; repeated ProviderConsumerEpochCuGenesis provider_consumer_epoch_cus = 11 [(gogoproto.nullable) = false]; + repeated ReputationGenesis reputations = 12 [(gogoproto.nullable) = false]; // this line is used by starport scaffolding # genesis/proto/state } @@ -60,4 +62,11 @@ message ProviderConsumerEpochCuGenesis { string project = 3; string chain_id = 4; ProviderConsumerEpochCu provider_consumer_epoch_cu = 5 [(gogoproto.nullable) = false]; +} + +message ReputationGenesis { + string chain_id = 1; + string cluster = 2; + string provider = 3; + Reputation reputation = 4 [(gogoproto.nullable) = false]; } \ No newline at end of file diff --git a/proto/lavanet/lava/pairing/reputation.proto b/proto/lavanet/lava/pairing/reputation.proto new file mode 100644 index 0000000000..3b34b07c67 --- /dev/null +++ b/proto/lavanet/lava/pairing/reputation.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; +package lavanet.lava.pairing; + +option go_package = "github.com/lavanet/lava/x/pairing/types"; +import "gogoproto/gogo.proto"; + +// Frac is a fracture struct that helps calculating and updating weighted average on the go +message Frac { + string num = 1 [(gogoproto.moretags) = "yaml:\"num\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false]; // weighted average numerator (w1*s1+w2*s2+...) + string denom = 2 [(gogoproto.moretags) = "yaml:\"denom\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false]; // weighted denominator (w1+w2+...) +} + +// QosScore holds the QoS score from a QoS excellence report. The score and its variance are updated over time using a weighted average. +// Currently, the weight is the amount of relays that are associated with the QoS report. +message QosScore { + Frac score = 1 [(gogoproto.nullable) = false]; + Frac variance = 2 [(gogoproto.nullable) = false]; +} + +// Reputation keeps the QosScore of a provider for a specific cluster for in the provider's geolocation. +// The store key is provider+chain+cluster. +// The epoch_score is a QosScore object that is aggregated over an epoch. When an epoch ends, the "score" field is updated +// with the epoch_score and the epoch_score is reset. +// The time_last_updated is used to calculate the appropriate time decay upon update. +// The creation_time is used to determine if the variance stabilization period has passed and score can be truncated. +message Reputation { + QosScore score = 1 [(gogoproto.nullable) = false]; + QosScore epoch_score = 2 [(gogoproto.nullable) = false]; + uint64 time_last_updated = 3; + uint64 creation_time = 4; +} + +// ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. +// The score is ranged between [0.5-2]. It's kept in the providerQosFs fixation store with a provider+chain+cluster key. +message ReputationPairingScore { + string score = 1 [(gogoproto.moretags) = "yaml:\"score\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false]; +} + diff --git a/x/pairing/README.md b/x/pairing/README.md index 6b6af6910c..13875e5281 100644 --- a/x/pairing/README.md +++ b/x/pairing/README.md @@ -21,6 +21,8 @@ The pairing module is one of Lava's core modules and is closely connected to the * [Filters](#filters) * [Scores](#scores) * [Quality Of Service](#quality-of-service) + * [Reputation](#reputation) + * [Passable QoS](#passable-qos) * [Pairing Verification](#pairing-verification) * [Unresponsiveness](#unresponsiveness) * [Static Providers](#static-providers) @@ -187,17 +189,17 @@ Finally, we calculate the score of each provider for a specific slot and select #### Quality Of Service -##### Excellence QoS +##### Reputation -The Lava Network places a strong emphasis on delivering exceptional Quality of Service (QoS) to its consumers. To ensure this, consumers actively participate in monitoring and customizing their QoS metrics. They gauge provider performance by measuring latency in provider responses relative to a benchmark, assessing data freshness in comparison to the fastest provider, and evaluating the percentage of error or timeout responses in the availability metric. These scores are diligently recorded and sent on-chain alongside the relay proofs of service, creating a transparent and accountable system. +The Lava Network places a strong emphasis on delivering exceptional Quality of Service (QoS) to its consumers. To ensure this, consumers actively participate in monitoring and customizing their QoS excellence metrics. They gauge provider performance by measuring latency in provider responses relative to a benchmark, assessing data freshness in comparison to the fastest provider, and evaluating the percentage of error or timeout responses in the availability metric. These scores are diligently recorded and sent on-chain alongside the relay proofs of service, creating a transparent and accountable system. The provider's performance metric is called "Reputation". Higher reputation indicates higher QoS scores. To further enhance the integrity of the QoS scores, updates are aggregated across all consumers in a manner that safeguards against false reports. Negative reports are weighted by usage, meaning that a consumer must actively use and pay a provider to diminish their QoS score. This mechanism discourages users from artificially lowering a provider's score. -These QoS excellence metrics only affect pairings and are aggregated over time with a decay function that favors the latest data, meaning providers can improve, and those providers that their service fails will be impacted to affect fewer users. This approach ensures that the QoS system remains dynamic and responsive, benefiting providers striving to enhance their services while minimizing the impact of service failures on a broader scale. +The Reputation metric only affect pairings and is aggregated over time with a decay function that favors the latest data, meaning providers can improve, and those providers that their service fails will be impacted to affect fewer users. This approach ensures that the reputation system remains dynamic and responsive, benefiting providers striving to enhance their services while minimizing the impact of service failures on a broader scale. -##### QoS +##### Passable QoS -In the Lava Network, alongside the comprehensive Quality of Service of Excellence metrics, there exists an additional metric known as Passable QoS. Unlike Excellence QoS, which offers a broad range of values, Passable QoS operates on a binary scale, either assigning a value of 0 or 1, averaged over relays. This metric simplifies the evaluation of service quality to a binary determination, indicating whether a relay meets the Passable QoS threshold, meaning it provides a level of service deemed acceptable for use. +In the Lava Network, alongside the comprehensive Reputation metric (which is calculated using QoS excellence reports), there exists an additional metric known as Passable QoS. Unlike Reputation, which offers a broad range of values, Passable QoS operates on a binary scale, either assigning a value of 0 or 1, averaged over relays. This metric simplifies the evaluation of service quality to a binary determination, indicating whether a relay meets the Passable QoS threshold, meaning it provides a level of service deemed acceptable for use. The Passable QoS score directly influences the total payout for a specific payment; however, it's important to note that only 50% of the payout is exposed to this metric (can be changed via governance). This allocation ensures a balance between incentivizing excellent service and discouraging poor performance. diff --git a/x/pairing/genesis.go b/x/pairing/genesis.go index be5aa45283..f4f0ffd994 100644 --- a/x/pairing/genesis.go +++ b/x/pairing/genesis.go @@ -29,6 +29,10 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, elem := range genState.BadgeUsedCuList { k.SetBadgeUsedCu(ctx, elem) } + // Set all the reputations + for _, elem := range genState.Reputations { + k.SetReputation(ctx, elem.ChainId, elem.Cluster, elem.Provider, elem.Reputation) + } k.InitBadgeTimers(ctx, genState.BadgesTS) k.InitProviderQoS(ctx, genState.ProviderQosFS) @@ -45,6 +49,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.ProviderEpochComplainedCus = k.GetAllProviderEpochComplainerCuStore(ctx) genesis.ProviderConsumerEpochCus = k.GetAllProviderConsumerEpochCuStore(ctx) genesis.BadgeUsedCuList = k.GetAllBadgeUsedCu(ctx) + genesis.Reputations = k.GetAllReputation(ctx) genesis.BadgesTS = k.ExportBadgesTimers(ctx) genesis.ProviderQosFS = k.ExportProviderQoS(ctx) // this line is used by starport scaffolding # genesis/module/export diff --git a/x/pairing/genesis_test.go b/x/pairing/genesis_test.go index 2dbc5b612a..e70965ed0a 100644 --- a/x/pairing/genesis_test.go +++ b/x/pairing/genesis_test.go @@ -82,6 +82,20 @@ func TestGenesis(t *testing.T) { BadgeUsedCuKey: []byte{byte(1)}, }, }, + Reputations: []types.ReputationGenesis{ + { + ChainId: "0", + Cluster: "0", + Provider: "0", + Reputation: types.Reputation{}, + }, + { + ChainId: "1", + Cluster: "1", + Provider: "1", + Reputation: types.Reputation{}, + }, + }, // this line is used by starport scaffolding # genesis/test/state } @@ -97,5 +111,6 @@ func TestGenesis(t *testing.T) { require.ElementsMatch(t, genesisState.ProviderEpochCus, got.ProviderEpochCus) require.ElementsMatch(t, genesisState.ProviderConsumerEpochCus, got.ProviderConsumerEpochCus) require.ElementsMatch(t, genesisState.BadgeUsedCuList, got.BadgeUsedCuList) + require.ElementsMatch(t, genesisState.Reputations, got.Reputations) // this line is used by starport scaffolding # genesis/test/assert } diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index ee8bce49ff..135170bb4d 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -3,6 +3,9 @@ package keeper import ( "fmt" + "cosmossdk.io/collections" + collcompat "github.com/lavanet/lava/utils/collcompat" + storetypes "github.com/cosmos/cosmos-sdk/store/types" timerstoretypes "github.com/lavanet/lava/x/timerstore/types" @@ -34,6 +37,10 @@ type ( downtimeKeeper types.DowntimeKeeper dualstakingKeeper types.DualstakingKeeper stakingKeeper types.StakingKeeper + + schema collections.Schema + reputations *collections.IndexedMap[collections.Triple[string, string, string], types.Reputation, types.ReputationRefIndexes] // save qos info per provider, chain and cluster + reputationRefKeys collections.KeySet[collections.Pair[string, string]] } ) @@ -71,6 +78,8 @@ func NewKeeper( ps = ps.WithKeyTable(types.ParamKeyTable()) } + sb := collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)) + keeper := &Keeper{ cdc: cdc, storeKey: storeKey, @@ -86,6 +95,16 @@ func NewKeeper( downtimeKeeper: downtimeKeeper, dualstakingKeeper: dualstakingKeeper, stakingKeeper: stakingKeeper, + + reputations: collections.NewIndexedMap(sb, types.ReputationPrefix, "reputations", + collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.StringKey), + collcompat.ProtoValue[types.Reputation](cdc), + types.NewReputationRefIndexes(sb), + ), + + reputationRefKeys: collections.NewKeySet(sb, types.ReputationRefKeysPrefix, "reputations_ref_keys", + collections.PairKeyCodec(collections.StringKey, collections.StringKey), + ), } // note that the timer and badgeUsedCu keys are the same (so we can use only the second arg) @@ -98,6 +117,12 @@ func NewKeeper( keeper.providerQosFS = *fixationStoreKeeper.NewFixationStore(storeKey, types.ProviderQosStorePrefix) + schema, err := sb.Build() + if err != nil { + panic(err) + } + keeper.schema = schema + return keeper } diff --git a/x/pairing/keeper/qos_excellence.go b/x/pairing/keeper/qos_excellence.go deleted file mode 100644 index eca781c944..0000000000 --- a/x/pairing/keeper/qos_excellence.go +++ /dev/null @@ -1,26 +0,0 @@ -package keeper - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/lavanet/lava/utils" - pairingtypes "github.com/lavanet/lava/x/pairing/types" -) - -// TODO: implement UpdateProviderQos(payments) - -// GetQos gets a provider's QoS excellence report from the providerQosFS -func (k Keeper) GetQos(ctx sdk.Context, chainID string, cluster string, provider string) (pairingtypes.QualityOfServiceReport, error) { - var qos pairingtypes.QualityOfServiceReport - key := pairingtypes.ProviderQosKey(provider, chainID, cluster) - found := k.providerQosFS.FindEntry(ctx, key, uint64(ctx.BlockHeight()), &qos) - if !found { - return qos, utils.LavaFormatWarning("provider of chain and cluster was not found in the store", fmt.Errorf("qos not found"), - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, - utils.Attribute{Key: "cluster", Value: cluster}, - ) - } - return qos, nil -} diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go new file mode 100644 index 0000000000..dfb52a38a1 --- /dev/null +++ b/x/pairing/keeper/reputation.go @@ -0,0 +1,104 @@ +package keeper + +import ( + "fmt" + + "cosmossdk.io/collections" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/utils" + "github.com/lavanet/lava/x/pairing/types" +) + +/* + +Reputation is a provider performance metric calculated using QoS excellence reports that are retrieved from relay payments. + +The reputations are kept within an indexed map called "reputations" in the keeper. An indexed map allows accessing map +entries using two type of keys: primary keys and reference keys. The primary keys are the regular map keys, each point +to a single entry. The reference keys can be of various types: unique, multi, and more. In this case, the reputations +indexed map holds "multi" type reference keys. This means that a single reference key returns a group of entries that +fit the reference key. + +The map's primary keys are a collection of the chain ID, cluster, and the provider address. +The map's reference keys are a collection of the chain ID and cluster. Using a reference key, we can get a group of entries +that share the same chain ID and cluster. + +Since the collections package doesn't support getting the full list of reference keys from an indexed map, we save a KeySet +of the reference keys in the keeper in the "reputationRefKeys" field. + +*/ + +// 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) + r, err := k.reputations.Get(ctx, key) + if err != nil { + utils.LavaFormatWarning("GetReputation: reputation not found", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", provider), + ) + return types.Reputation{}, false + } + + return r, true +} + +// SetReputation sets a Reputation in the store +func (k Keeper) SetReputation(ctx sdk.Context, chainID string, cluster string, provider string, r types.Reputation) { + key := types.ReputationKey(chainID, cluster, provider) + err := k.reputations.Set(ctx, key, r) + if err != nil { + panic(fmt.Errorf("SetReputation: failed to set entry with key %v, error: %w", key, err)) + } + chainClusterKey := collections.Join(chainID, cluster) + err = k.reputationRefKeys.Set(ctx, chainClusterKey) + if err != nil { + panic(err) + } +} + +// RemoveReputation removes a Reputation from the store +func (k Keeper) RemoveReputation(ctx sdk.Context, chainID string, cluster string, provider string) { + key := types.ReputationKey(chainID, cluster, provider) + err := k.reputations.Remove(ctx, key) + if err != nil { + panic(fmt.Errorf("RemoveReputation: failed to remove entry with key %v, error: %w", key, err)) + } +} + +// GetAllReputation gets all the reputation entries from the store for genesis +func (k Keeper) GetAllReputation(ctx sdk.Context) []types.ReputationGenesis { + iter, err := k.reputations.Iterate(ctx, nil) + if err != nil { + panic(fmt.Errorf("GetAllReputation: Failed to create iterator, error: %w", err)) + } + defer iter.Close() + + entries := []types.ReputationGenesis{} + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + panic(fmt.Errorf("GetAllReputation: Failed to get key from iterator, error: %w", err)) + } + + entry, err := k.reputations.Get(ctx, key) + if err != nil { + panic(fmt.Errorf("GetAllReputation: Failed to get entry with key %v, error: %w", key, err)) + } + + entries = append(entries, types.ReputationGenesis{ + ChainId: key.K1(), + Cluster: key.K2(), + Provider: key.K3(), + Reputation: entry, + }) + } + + return entries +} diff --git a/x/pairing/keeper/reputation_test.go b/x/pairing/keeper/reputation_test.go new file mode 100644 index 0000000000..40007646e8 --- /dev/null +++ b/x/pairing/keeper/reputation_test.go @@ -0,0 +1,71 @@ +package keeper_test + +import ( + "strconv" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + keepertest "github.com/lavanet/lava/testutil/keeper" + "github.com/lavanet/lava/x/pairing/keeper" + "github.com/lavanet/lava/x/pairing/types" + "github.com/stretchr/testify/require" +) + +func createNReputations(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Reputation { + items := make([]types.Reputation, n) + for i := range items { + decIndex := math.LegacyNewDec(int64(i + 1)) + strIndex := strconv.Itoa(i) + items[i] = types.Reputation{ + Score: types.QosScore{ + Score: types.Frac{Num: decIndex, Denom: decIndex}, + Variance: types.Frac{Num: decIndex, Denom: decIndex}, + }, + EpochScore: types.QosScore{ + Score: types.Frac{Num: decIndex, Denom: decIndex}, + Variance: types.Frac{Num: decIndex, Denom: decIndex}, + }, + TimeLastUpdated: uint64(i), + CreationTime: uint64(i), + } + keeper.SetReputation(ctx, strIndex, strIndex, strIndex, items[i]) + } + return items +} + +func TestGetReputation(t *testing.T) { + keeper, ctx := keepertest.PairingKeeper(t) + items := createNReputations(keeper, ctx, 10) + for i, item := range items { + strIndex := strconv.Itoa(i) + entry, found := keeper.GetReputation(ctx, strIndex, strIndex, strIndex) + require.True(t, found) + require.True(t, item.Equal(entry)) + } + + _, found := keeper.GetReputation(ctx, "dummy", "dummy", "dummy") + require.False(t, found) +} + +func TestRemoveReputation(t *testing.T) { + keeper, ctx := keepertest.PairingKeeper(t) + items := createNReputations(keeper, ctx, 10) + for i := range items { + strIndex := strconv.Itoa(i) + keeper.RemoveReputation(ctx, strIndex, strIndex, strIndex) + _, found := keeper.GetReputation(ctx, strIndex, strIndex, strIndex) + require.False(t, found) + } + + require.Panics(t, func() { keeper.RemoveReputation(ctx, "dummy", "dummy", "dummy") }) +} + +func TestGetAllReputations(t *testing.T) { + keeper, ctx := keepertest.PairingKeeper(t) + items := createNReputations(keeper, ctx, 10) + genEntries := keeper.GetAllReputation(ctx) + for i := range genEntries { + require.True(t, items[i].Equal(genEntries[i].Reputation)) + } +} diff --git a/x/pairing/types/genesis.go b/x/pairing/types/genesis.go index 224077aabd..2711288bbd 100644 --- a/x/pairing/types/genesis.go +++ b/x/pairing/types/genesis.go @@ -2,6 +2,7 @@ package types import ( "fmt" + "strings" fixationtypes "github.com/lavanet/lava/x/fixationstore/types" timerstoretypes "github.com/lavanet/lava/x/timerstore/types" @@ -17,6 +18,7 @@ func DefaultGenesis() *GenesisState { ProviderEpochCus: []ProviderEpochCuGenesis{}, ProviderConsumerEpochCus: []ProviderConsumerEpochCuGenesis{}, BadgeUsedCuList: []BadgeUsedCu{}, + Reputations: []ReputationGenesis{}, BadgesTS: *timerstoretypes.DefaultGenesis(), ProviderQosFS: *fixationtypes.DefaultGenesis(), // this line is used by starport scaffolding # genesis/types/default @@ -73,6 +75,15 @@ func (gs GenesisState) Validate() error { return fmt.Errorf("badgeUsedCuList is not empty") } + reputationsIndexMap := map[string]struct{}{} + for _, elem := range gs.Reputations { + index := strings.Join([]string{elem.ChainId, elem.Cluster, elem.Provider}, " ") + if _, ok := reputationsIndexMap[index]; ok { + return fmt.Errorf("duplicated index for Reputations") + } + reputationsIndexMap[index] = struct{}{} + } + // this line is used by starport scaffolding # genesis/types/validate return gs.Params.Validate() diff --git a/x/pairing/types/genesis.pb.go b/x/pairing/types/genesis.pb.go index e8b319a8b9..b579746966 100644 --- a/x/pairing/types/genesis.pb.go +++ b/x/pairing/types/genesis.pb.go @@ -87,6 +87,7 @@ type GenesisState struct { ProviderEpochCus []ProviderEpochCuGenesis `protobuf:"bytes,9,rep,name=provider_epoch_cus,json=providerEpochCus,proto3" json:"provider_epoch_cus"` ProviderEpochComplainedCus []ProviderEpochComplainerCuGenesis `protobuf:"bytes,10,rep,name=provider_epoch_complained_cus,json=providerEpochComplainedCus,proto3" json:"provider_epoch_complained_cus"` ProviderConsumerEpochCus []ProviderConsumerEpochCuGenesis `protobuf:"bytes,11,rep,name=provider_consumer_epoch_cus,json=providerConsumerEpochCus,proto3" json:"provider_consumer_epoch_cus"` + Reputations []ReputationGenesis `protobuf:"bytes,12,rep,name=reputations,proto3" json:"reputations"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -178,6 +179,13 @@ func (m *GenesisState) GetProviderConsumerEpochCus() []ProviderConsumerEpochCuGe return nil } +func (m *GenesisState) GetReputations() []ReputationGenesis { + if m != nil { + return m.Reputations + } + return nil +} + type UniqueEpochSessionGenesis struct { Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"` @@ -466,6 +474,74 @@ func (m *ProviderConsumerEpochCuGenesis) GetProviderConsumerEpochCu() ProviderCo return ProviderConsumerEpochCu{} } +type ReputationGenesis struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Cluster string `protobuf:"bytes,2,opt,name=cluster,proto3" json:"cluster,omitempty"` + Provider string `protobuf:"bytes,3,opt,name=provider,proto3" json:"provider,omitempty"` + Reputation Reputation `protobuf:"bytes,4,opt,name=reputation,proto3" json:"reputation"` +} + +func (m *ReputationGenesis) Reset() { *m = ReputationGenesis{} } +func (m *ReputationGenesis) String() string { return proto.CompactTextString(m) } +func (*ReputationGenesis) ProtoMessage() {} +func (*ReputationGenesis) Descriptor() ([]byte, []int) { + return fileDescriptor_dbd1e49b8b57595b, []int{6} +} +func (m *ReputationGenesis) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReputationGenesis) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReputationGenesis.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 *ReputationGenesis) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReputationGenesis.Merge(m, src) +} +func (m *ReputationGenesis) XXX_Size() int { + return m.Size() +} +func (m *ReputationGenesis) XXX_DiscardUnknown() { + xxx_messageInfo_ReputationGenesis.DiscardUnknown(m) +} + +var xxx_messageInfo_ReputationGenesis proto.InternalMessageInfo + +func (m *ReputationGenesis) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *ReputationGenesis) GetCluster() string { + if m != nil { + return m.Cluster + } + return "" +} + +func (m *ReputationGenesis) GetProvider() string { + if m != nil { + return m.Provider + } + return "" +} + +func (m *ReputationGenesis) GetReputation() Reputation { + if m != nil { + return m.Reputation + } + return Reputation{} +} + func init() { proto.RegisterType((*BadgeUsedCu)(nil), "lavanet.lava.pairing.BadgeUsedCu") proto.RegisterType((*GenesisState)(nil), "lavanet.lava.pairing.GenesisState") @@ -473,6 +549,7 @@ func init() { proto.RegisterType((*ProviderEpochCuGenesis)(nil), "lavanet.lava.pairing.ProviderEpochCuGenesis") proto.RegisterType((*ProviderEpochComplainerCuGenesis)(nil), "lavanet.lava.pairing.ProviderEpochComplainerCuGenesis") proto.RegisterType((*ProviderConsumerEpochCuGenesis)(nil), "lavanet.lava.pairing.ProviderConsumerEpochCuGenesis") + proto.RegisterType((*ReputationGenesis)(nil), "lavanet.lava.pairing.ReputationGenesis") } func init() { @@ -480,51 +557,55 @@ func init() { } var fileDescriptor_dbd1e49b8b57595b = []byte{ - // 693 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x41, 0x53, 0xd3, 0x40, - 0x18, 0x6d, 0x68, 0x5a, 0xca, 0x57, 0xd4, 0xb2, 0xa2, 0x84, 0x0a, 0xb1, 0xc4, 0x71, 0x2c, 0x33, - 0x9a, 0xcc, 0xa0, 0xe3, 0xc1, 0x9b, 0x30, 0xca, 0x80, 0x1e, 0xa4, 0x85, 0x71, 0xc6, 0x4b, 0x4c, - 0x93, 0xb5, 0xac, 0xd2, 0xec, 0x9a, 0x4d, 0x18, 0x7a, 0xf2, 0x2f, 0x78, 0xf3, 0xec, 0x1f, 0xf1, - 0xcc, 0x91, 0xa3, 0x27, 0xc7, 0x81, 0x83, 0xbf, 0xc1, 0x9b, 0x93, 0xcd, 0xb6, 0x34, 0x25, 0x41, - 0x71, 0x1c, 0x4f, 0xc9, 0x66, 0xdf, 0xf7, 0xde, 0xf7, 0xb2, 0xef, 0x9b, 0x05, 0x63, 0xcf, 0xd9, - 0x77, 0x7c, 0x1c, 0x5a, 0xf1, 0xd3, 0x62, 0x0e, 0x09, 0x88, 0xdf, 0xb5, 0xba, 0xd8, 0xc7, 0x9c, - 0x70, 0x93, 0x05, 0x34, 0xa4, 0x68, 0x56, 0x62, 0xcc, 0xf8, 0x69, 0x4a, 0x4c, 0x7d, 0xb6, 0x4b, - 0xbb, 0x54, 0x00, 0xac, 0xf8, 0x2d, 0xc1, 0xd6, 0x97, 0x32, 0xf9, 0x98, 0x13, 0x38, 0x3d, 0x49, - 0x57, 0xbf, 0x95, 0x09, 0xc1, 0x8c, 0xba, 0xbb, 0xb6, 0x1b, 0x49, 0xd0, 0x72, 0x0a, 0xf4, 0x86, - 0x1c, 0x38, 0x21, 0xa1, 0x3e, 0x0f, 0x69, 0x80, 0x87, 0xab, 0x4c, 0xbe, 0x90, 0xf4, 0x70, 0x90, - 0xe0, 0xc4, 0x6b, 0x02, 0x32, 0xb6, 0xa0, 0xba, 0xea, 0x78, 0x5d, 0xbc, 0xc3, 0xb1, 0xb7, 0x16, - 0xa1, 0x65, 0x98, 0xe9, 0xc4, 0x4b, 0x3b, 0xe2, 0xd8, 0xb3, 0xdd, 0xc8, 0x7e, 0x87, 0xfb, 0x9a, - 0xd2, 0x50, 0x9a, 0xd3, 0xad, 0xcb, 0x9d, 0x53, 0xdc, 0x33, 0xdc, 0x47, 0x73, 0x30, 0x29, 0x41, - 0xda, 0x44, 0x43, 0x69, 0xaa, 0xad, 0x72, 0x24, 0xf6, 0x8c, 0x4f, 0x65, 0x98, 0x5e, 0x4f, 0x7e, - 0x54, 0x3b, 0x74, 0x42, 0x8c, 0x1e, 0x41, 0x39, 0x31, 0x2a, 0x98, 0xaa, 0x2b, 0x0b, 0x66, 0xd6, - 0x8f, 0x33, 0x5f, 0x08, 0xcc, 0xaa, 0x7a, 0xf8, 0xed, 0x66, 0xa1, 0x25, 0x2b, 0xd0, 0x16, 0x5c, - 0x19, 0xd1, 0x7d, 0x4e, 0x78, 0xa8, 0x95, 0x1a, 0xc5, 0x66, 0x75, 0x65, 0x29, 0x9b, 0x64, 0xc4, - 0x8c, 0x64, 0x1a, 0xaf, 0x47, 0xeb, 0x50, 0x11, 0x9f, 0xf8, 0x76, 0x5b, 0x2b, 0x8b, 0x86, 0x6e, - 0xa7, 0xb9, 0x4e, 0x7f, 0x95, 0x39, 0xea, 0x43, 0xf2, 0x0d, 0x8b, 0xd1, 0x36, 0x5c, 0x62, 0x01, - 0xdd, 0x27, 0x1e, 0x0e, 0xb6, 0x28, 0x7f, 0xda, 0xd6, 0x26, 0x05, 0x5b, 0x33, 0xcd, 0x96, 0x3a, - 0xa3, 0x2c, 0xc2, 0x34, 0x09, 0x22, 0x70, 0x2d, 0xf2, 0xc9, 0xfb, 0x08, 0xdb, 0xc9, 0xd1, 0x73, - 0xcc, 0x79, 0x5c, 0xae, 0x55, 0x84, 0x6f, 0x2b, 0xdb, 0xf7, 0x8e, 0x28, 0x79, 0x12, 0x57, 0xb4, - 0x93, 0x02, 0xa9, 0x24, 0x45, 0xae, 0x46, 0x67, 0x00, 0x1c, 0xbd, 0x06, 0x34, 0xd0, 0xb6, 0x07, - 0x39, 0xe3, 0xda, 0x94, 0xd0, 0xb9, 0x9b, 0x73, 0x48, 0x12, 0x2f, 0x88, 0xd6, 0xa2, 0xb4, 0x48, - 0x8d, 0xa5, 0x77, 0x39, 0xfa, 0x00, 0x8b, 0xe3, 0x0a, 0xb4, 0xc7, 0xf6, 0x1c, 0xe2, 0x8b, 0xe4, - 0x70, 0x0d, 0x84, 0xd8, 0xc3, 0x3f, 0x11, 0x1b, 0x14, 0x06, 0xe3, 0xb2, 0x75, 0x96, 0x89, 0xf3, - 0xe2, 0x06, 0xfa, 0x70, 0x63, 0xd8, 0x80, 0x4b, 0x7d, 0x1e, 0xf5, 0x52, 0x5e, 0xab, 0x42, 0xfe, - 0xc1, 0xf9, 0xf2, 0x6b, 0xb2, 0x2e, 0xd3, 0xb3, 0xc6, 0xb2, 0x51, 0x7c, 0x53, 0xad, 0x4c, 0xd4, - 0x8a, 0x9b, 0x6a, 0xa5, 0x58, 0x53, 0x37, 0xd5, 0x8a, 0x5a, 0x2b, 0x19, 0x9f, 0x15, 0x98, 0xcf, - 0x3d, 0x28, 0x34, 0x0b, 0x25, 0xd1, 0x98, 0x98, 0x12, 0xb5, 0x95, 0x2c, 0x50, 0x1d, 0x2a, 0x03, - 0x05, 0x31, 0x67, 0x53, 0xad, 0xe1, 0x1a, 0x69, 0x30, 0xc9, 0x02, 0xfa, 0x16, 0xbb, 0xa1, 0x56, - 0x14, 0x5b, 0x83, 0x25, 0x9a, 0x87, 0x8a, 0xbb, 0xeb, 0x10, 0xdf, 0x26, 0x9e, 0xa6, 0x26, 0x5b, - 0x62, 0xbd, 0xe1, 0xa1, 0x45, 0x00, 0x19, 0xa9, 0x78, 0xb3, 0x24, 0xb4, 0xa6, 0xe4, 0x97, 0x0d, - 0xcf, 0xf8, 0xa2, 0xc0, 0xf5, 0xec, 0x43, 0xfe, 0x8b, 0x06, 0x47, 0xdb, 0x28, 0xa6, 0xdb, 0x78, - 0x09, 0x33, 0x67, 0xb2, 0x27, 0x5a, 0x3d, 0x33, 0x8e, 0x39, 0xd1, 0x1b, 0x8c, 0xf7, 0x58, 0xe6, - 0x8c, 0x1f, 0x0a, 0x34, 0x7e, 0x17, 0x9c, 0x7f, 0x6b, 0x65, 0x1f, 0x16, 0xf2, 0x42, 0x1e, 0x9c, - 0xba, 0xb2, 0x2e, 0x98, 0x71, 0xe9, 0x6f, 0x9e, 0xe5, 0x01, 0x8c, 0x9f, 0x0a, 0xe8, 0xe7, 0x67, - 0xf4, 0x7f, 0x65, 0x8a, 0x41, 0x3d, 0x7f, 0xca, 0x44, 0xc6, 0xaa, 0x2b, 0xf7, 0x2e, 0x34, 0x64, - 0xd2, 0xfd, 0x5c, 0xce, 0x74, 0xad, 0x3e, 0x3e, 0x3c, 0xd6, 0x95, 0xa3, 0x63, 0x5d, 0xf9, 0x7e, - 0xac, 0x2b, 0x1f, 0x4f, 0xf4, 0xc2, 0xd1, 0x89, 0x5e, 0xf8, 0x7a, 0xa2, 0x17, 0x5e, 0xdd, 0xe9, - 0x92, 0x70, 0x37, 0xea, 0x98, 0x2e, 0xed, 0x59, 0xa9, 0x1b, 0xf0, 0x60, 0x78, 0xa7, 0x86, 0x7d, - 0x86, 0x79, 0xa7, 0x2c, 0x6e, 0xc0, 0xfb, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x79, 0x43, 0xa2, - 0x96, 0xeb, 0x07, 0x00, 0x00, + // 767 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x4f, 0x13, 0x41, + 0x14, 0xef, 0xd2, 0xed, 0x1f, 0x5e, 0x51, 0xcb, 0x88, 0x32, 0x54, 0xa8, 0x65, 0x0d, 0xa1, 0x24, + 0xda, 0x26, 0x68, 0x3c, 0x78, 0x13, 0x22, 0x04, 0x34, 0x51, 0x5a, 0x88, 0x89, 0x97, 0xba, 0xdd, + 0x1d, 0xcb, 0x28, 0xdd, 0x1d, 0x77, 0x76, 0x09, 0x3d, 0xf9, 0x15, 0xfc, 0x0a, 0xde, 0xfd, 0x0c, + 0x9e, 0x39, 0x72, 0xf4, 0x64, 0x0c, 0x1c, 0xf4, 0x2b, 0x78, 0x33, 0x3b, 0x3b, 0xfd, 0x33, 0xed, + 0x16, 0xc4, 0x18, 0x4f, 0xbb, 0x6f, 0xe7, 0xf7, 0x7e, 0xbf, 0xf7, 0x66, 0x7e, 0x6f, 0x33, 0x60, + 0x1c, 0x98, 0x87, 0xa6, 0x43, 0xfc, 0x6a, 0xf8, 0xac, 0x32, 0x93, 0x7a, 0xd4, 0x69, 0x55, 0x5b, + 0xc4, 0x21, 0x9c, 0xf2, 0x0a, 0xf3, 0x5c, 0xdf, 0x45, 0x33, 0x12, 0x53, 0x09, 0x9f, 0x15, 0x89, + 0x29, 0xcc, 0xb4, 0xdc, 0x96, 0x2b, 0x00, 0xd5, 0xf0, 0x2d, 0xc2, 0x16, 0x16, 0x63, 0xf9, 0x98, + 0xe9, 0x99, 0x6d, 0x49, 0x57, 0xb8, 0x13, 0x0b, 0x21, 0xcc, 0xb5, 0xf6, 0x1b, 0x56, 0x20, 0x41, + 0x2b, 0x0a, 0xe8, 0x0d, 0x3d, 0x32, 0x7d, 0xea, 0x3a, 0xdc, 0x77, 0x3d, 0xd2, 0x8b, 0x62, 0xf9, + 0x7c, 0xda, 0x26, 0x5e, 0x84, 0x13, 0xaf, 0x12, 0xb4, 0x14, 0x2b, 0xea, 0x11, 0x16, 0xf8, 0x03, + 0x5c, 0xc6, 0x0e, 0xe4, 0xd6, 0x4c, 0xbb, 0x45, 0xf6, 0x38, 0xb1, 0xd7, 0x03, 0xb4, 0x02, 0xd3, + 0xcd, 0x30, 0x6c, 0x04, 0x9c, 0xd8, 0x0d, 0x2b, 0x68, 0xbc, 0x23, 0x1d, 0xac, 0x95, 0xb4, 0xf2, + 0x54, 0xed, 0x6a, 0xb3, 0x8f, 0x7b, 0x4a, 0x3a, 0x68, 0x16, 0x32, 0x12, 0x84, 0x27, 0x4a, 0x5a, + 0x59, 0xaf, 0xa5, 0x03, 0xb1, 0x66, 0xfc, 0x4c, 0xc3, 0xd4, 0x66, 0xb4, 0x9f, 0x75, 0xdf, 0xf4, + 0x09, 0x7a, 0x04, 0xe9, 0x68, 0x3f, 0x04, 0x53, 0x6e, 0x75, 0xbe, 0x12, 0xb7, 0xbf, 0x95, 0x17, + 0x02, 0xb3, 0xa6, 0x1f, 0x7f, 0xbb, 0x9d, 0xa8, 0xc9, 0x0c, 0xb4, 0x03, 0xd7, 0x06, 0x74, 0x9f, + 0x51, 0xee, 0xe3, 0x54, 0x29, 0x59, 0xce, 0xad, 0x2e, 0xc6, 0x93, 0x0c, 0x34, 0x23, 0x99, 0x86, + 0xf3, 0xd1, 0x26, 0x64, 0xc5, 0x27, 0xbe, 0x5b, 0xc7, 0x69, 0x51, 0xd0, 0x92, 0xca, 0xd5, 0xdf, + 0xd1, 0xca, 0x60, 0x1f, 0x92, 0xaf, 0x97, 0x8c, 0x76, 0xe1, 0x0a, 0xf3, 0xdc, 0x43, 0x6a, 0x13, + 0x6f, 0xc7, 0xe5, 0x1b, 0x75, 0x9c, 0x11, 0x6c, 0x65, 0x95, 0x4d, 0x39, 0xca, 0x38, 0x42, 0x95, + 0x04, 0x51, 0xb8, 0x11, 0x38, 0xf4, 0x7d, 0x40, 0x1a, 0x91, 0x43, 0x38, 0xe1, 0x3c, 0x4c, 0xc7, + 0x59, 0xd1, 0x77, 0x35, 0xbe, 0xef, 0x3d, 0x91, 0xf2, 0x24, 0xcc, 0xa8, 0x47, 0x09, 0x52, 0x49, + 0x8a, 0x5c, 0x0f, 0x46, 0x00, 0x1c, 0xbd, 0x06, 0xd4, 0xd5, 0x6e, 0x74, 0xed, 0xc8, 0xf1, 0xa4, + 0xd0, 0xb9, 0x3b, 0xe6, 0x90, 0x24, 0x5e, 0x10, 0xad, 0x07, 0xaa, 0x48, 0x9e, 0xa9, 0xab, 0x1c, + 0x7d, 0x80, 0x85, 0x61, 0x05, 0xb7, 0xcd, 0x0e, 0x4c, 0xea, 0x08, 0xe7, 0x70, 0x0c, 0x42, 0xec, + 0xe1, 0x9f, 0x88, 0x75, 0x13, 0xbd, 0x61, 0xd9, 0x02, 0x8b, 0xc5, 0xd9, 0x61, 0x01, 0x1d, 0xb8, + 0xd5, 0x2b, 0xc0, 0x72, 0x1d, 0x1e, 0xb4, 0x95, 0x5e, 0x73, 0x42, 0xfe, 0xc1, 0xf9, 0xf2, 0xeb, + 0x32, 0x2f, 0xb6, 0x67, 0xcc, 0xe2, 0x51, 0x1c, 0x3d, 0x87, 0x5c, 0x7f, 0xdc, 0x38, 0x9e, 0x12, + 0x52, 0xcb, 0xf1, 0x52, 0xb5, 0x1e, 0x50, 0x65, 0x1f, 0x64, 0xd8, 0xd6, 0xb3, 0x13, 0xf9, 0xe4, + 0xb6, 0x9e, 0x4d, 0xe6, 0xf5, 0x6d, 0x3d, 0xab, 0xe7, 0x53, 0xc6, 0x27, 0x0d, 0xe6, 0xc6, 0x9e, + 0x3c, 0x9a, 0x81, 0x94, 0xe8, 0x54, 0x8c, 0x9d, 0x5e, 0x8b, 0x02, 0x54, 0x80, 0x6c, 0xb7, 0x64, + 0x31, 0xb8, 0x93, 0xb5, 0x5e, 0x8c, 0x30, 0x64, 0x98, 0xe7, 0xbe, 0x25, 0x96, 0x8f, 0x93, 0x62, + 0xa9, 0x1b, 0xa2, 0x39, 0xc8, 0x5a, 0xfb, 0x26, 0x75, 0x1a, 0xd4, 0xc6, 0x7a, 0xb4, 0x24, 0xe2, + 0x2d, 0x1b, 0x2d, 0x00, 0x48, 0x8f, 0x86, 0x8b, 0x29, 0xa1, 0x35, 0x29, 0xbf, 0x6c, 0xd9, 0xc6, + 0x17, 0x0d, 0x6e, 0xc6, 0xbb, 0xe6, 0x2f, 0x0a, 0x1c, 0x2c, 0x23, 0xa9, 0x96, 0xf1, 0x12, 0xa6, + 0x47, 0xcc, 0x2c, 0x4a, 0x1d, 0x99, 0xef, 0x31, 0x5e, 0xee, 0xfe, 0x2f, 0x86, 0x4c, 0x6c, 0xfc, + 0xd0, 0xa0, 0x74, 0x91, 0x13, 0xff, 0x6d, 0x2b, 0x87, 0x30, 0x3f, 0x6e, 0x6a, 0xbc, 0x7e, 0x57, + 0xd5, 0x4b, 0x0e, 0x8d, 0xec, 0x6f, 0x8e, 0x8d, 0x03, 0x18, 0xbf, 0x34, 0x28, 0x9e, 0x6f, 0xfa, + 0xff, 0xe5, 0x29, 0x06, 0x85, 0xf1, 0x63, 0x2b, 0x3c, 0x96, 0x5b, 0xbd, 0x77, 0xa9, 0xa9, 0x95, + 0xdd, 0xcf, 0x8e, 0x19, 0x57, 0xe3, 0xb3, 0x06, 0xd3, 0x23, 0x53, 0xa8, 0x94, 0xa8, 0xa9, 0x25, + 0x62, 0xc8, 0x58, 0x07, 0x01, 0xf7, 0x7b, 0x2d, 0x77, 0x43, 0x65, 0x37, 0x92, 0x43, 0xbb, 0xb1, + 0x01, 0xd0, 0x1f, 0x69, 0x79, 0x90, 0xa5, 0x8b, 0xfe, 0x09, 0xb2, 0xf6, 0x81, 0xcc, 0xb5, 0xc7, + 0xc7, 0xa7, 0x45, 0xed, 0xe4, 0xb4, 0xa8, 0x7d, 0x3f, 0x2d, 0x6a, 0x1f, 0xcf, 0x8a, 0x89, 0x93, + 0xb3, 0x62, 0xe2, 0xeb, 0x59, 0x31, 0xf1, 0x6a, 0xb9, 0x45, 0xfd, 0xfd, 0xa0, 0x59, 0xb1, 0xdc, + 0x76, 0x55, 0xb9, 0x03, 0x1c, 0xf5, 0x6e, 0x01, 0x7e, 0x87, 0x11, 0xde, 0x4c, 0x8b, 0x1b, 0xc0, + 0xfd, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x29, 0x8c, 0x17, 0xc4, 0x12, 0x09, 0x00, 0x00, } func (m *BadgeUsedCu) Marshal() (dAtA []byte, err error) { @@ -582,6 +663,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Reputations) > 0 { + for iNdEx := len(m.Reputations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Reputations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + } if len(m.ProviderConsumerEpochCus) > 0 { for iNdEx := len(m.ProviderConsumerEpochCus) - 1; iNdEx >= 0; iNdEx-- { { @@ -902,6 +997,60 @@ func (m *ProviderConsumerEpochCuGenesis) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *ReputationGenesis) 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 *ReputationGenesis) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReputationGenesis) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Reputation.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.Provider) > 0 { + i -= len(m.Provider) + copy(dAtA[i:], m.Provider) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Provider))) + i-- + dAtA[i] = 0x1a + } + if len(m.Cluster) > 0 { + i -= len(m.Cluster) + copy(dAtA[i:], m.Cluster) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Cluster))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -971,6 +1120,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.Reputations) > 0 { + for _, e := range m.Reputations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -1071,6 +1226,29 @@ func (m *ProviderConsumerEpochCuGenesis) Size() (n int) { return n } +func (m *ReputationGenesis) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Cluster) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Provider) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Reputation.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1478,6 +1656,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reputations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reputations = append(m.Reputations, ReputationGenesis{}) + if err := m.Reputations[len(m.Reputations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) @@ -2213,6 +2425,185 @@ func (m *ProviderConsumerEpochCuGenesis) Unmarshal(dAtA []byte) error { } return nil } +func (m *ReputationGenesis) 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 ErrIntOverflowGenesis + } + 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: ReputationGenesis: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReputationGenesis: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + 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 ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cluster = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Provider", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Provider = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + 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 ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Reputation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipGenesis(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/pairing/types/genesis_test.go b/x/pairing/types/genesis_test.go index 416d467cb9..50b8b1311c 100644 --- a/x/pairing/types/genesis_test.go +++ b/x/pairing/types/genesis_test.go @@ -82,6 +82,20 @@ func TestGenesisState_Validate(t *testing.T) { ProviderConsumerEpochCu: types.ProviderConsumerEpochCu{Cu: 20}, }, }, + Reputations: []types.ReputationGenesis{ + { + ChainId: "0", + Cluster: "0", + Provider: "0", + Reputation: types.Reputation{}, + }, + { + ChainId: "1", + Cluster: "1", + Provider: "1", + Reputation: types.Reputation{}, + }, + }, // this line is used by starport scaffolding # types/genesis/validField }, valid: true, @@ -175,6 +189,27 @@ func TestGenesisState_Validate(t *testing.T) { }, valid: false, }, + { + desc: "duplicated reputations", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + Reputations: []types.ReputationGenesis{ + { + ChainId: "0", + Cluster: "0", + Provider: "0", + Reputation: types.Reputation{}, + }, + { + ChainId: "0", + Cluster: "0", + Provider: "0", + Reputation: types.Reputation{}, + }, + }, + }, + valid: false, + }, // this line is used by starport scaffolding # types/genesis/testcase } { t.Run(tc.desc, func(t *testing.T) { diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go new file mode 100644 index 0000000000..236cd6c538 --- /dev/null +++ b/x/pairing/types/qos_score.go @@ -0,0 +1,26 @@ +package types + +import ( + "fmt" + + "cosmossdk.io/math" +) + +func NewFrac(num math.LegacyDec, denom math.LegacyDec) (Frac, error) { + if denom.Equal(math.LegacyZeroDec()) { + return Frac{}, fmt.Errorf("cannot create Frac with zero denomination") + } + return Frac{Num: num, Denom: denom}, nil +} + +func (f Frac) Equal(other Frac) bool { + return f.Num.Equal(other.Num) && f.Denom.Equal(other.Denom) +} + +func NewQosScore(score Frac, variance Frac) QosScore { + return QosScore{Score: score, Variance: variance} +} + +func (qs QosScore) Equal(other QosScore) bool { + return qs.Score.Equal(other.Score) && qs.Variance.Equal(other.Variance) +} diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go new file mode 100644 index 0000000000..facdc6310f --- /dev/null +++ b/x/pairing/types/reputation.go @@ -0,0 +1,58 @@ +package types + +import ( + "cosmossdk.io/collections" + "cosmossdk.io/collections/indexes" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/utils" +) + +var ( + ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) + ReputationRefKeysPrefix = collections.NewPrefix([]byte("ReputationRefKeys/")) + ReputationRefKeysIteratorPrefix = collections.NewPrefix([]byte("ReputationRefKeysIterator/")) +) + +type ReputationRefIndexes struct { + Index *indexes.Multi[collections.Pair[string, string], collections.Triple[string, string, string], Reputation] +} + +func (rri ReputationRefIndexes) IndexesList() []collections.Index[collections.Triple[string, string, string], Reputation] { + return []collections.Index[collections.Triple[string, string, string], Reputation]{rri.Index} +} + +func NewReputationRefIndexes(sb *collections.SchemaBuilder) ReputationRefIndexes { + return ReputationRefIndexes{ + Index: indexes.NewMulti(sb, ReputationRefKeysIteratorPrefix, "reputation_ref_keys_iterator", + collections.PairKeyCodec(collections.StringKey, collections.StringKey), + collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.StringKey), + func(pk collections.Triple[string, string, string], _ Reputation) (collections.Pair[string, string], error) { + return collections.Join(pk.K1(), pk.K2()), nil + }, + ), + } +} + +func ReputationKey(chainID string, cluster string, provider string) collections.Triple[string, string, string] { + return collections.Join3(chainID, cluster, provider) +} + +func NewReputation(ctx sdk.Context) (Reputation, error) { + timestamp := ctx.BlockTime().UTC().Unix() + zeroFrac, err := NewFrac(math.LegacyZeroDec(), math.LegacyOneDec()) + if err != nil { + return Reputation{}, utils.LavaFormatError("NewReputation: zero Frac creation failed", err) + } + return Reputation{ + Score: NewQosScore(zeroFrac, zeroFrac), + EpochScore: NewQosScore(zeroFrac, zeroFrac), + TimeLastUpdated: uint64(timestamp), + CreationTime: uint64(timestamp), + }, nil +} + +func (r Reputation) Equal(other Reputation) bool { + return r.Score.Equal(other.Score) && r.EpochScore.Equal(other.EpochScore) && + r.TimeLastUpdated == other.TimeLastUpdated && r.CreationTime == other.CreationTime +} diff --git a/x/pairing/types/reputation.pb.go b/x/pairing/types/reputation.pb.go new file mode 100644 index 0000000000..28bab7019f --- /dev/null +++ b/x/pairing/types/reputation.pb.go @@ -0,0 +1,1074 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lavanet/lava/pairing/reputation.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Frac is a fracture struct that helps calculating and updating weighted average on the go +type Frac struct { + Num github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=num,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"num" yaml:"num"` + Denom github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=denom,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"denom" yaml:"denom"` +} + +func (m *Frac) Reset() { *m = Frac{} } +func (m *Frac) String() string { return proto.CompactTextString(m) } +func (*Frac) ProtoMessage() {} +func (*Frac) Descriptor() ([]byte, []int) { + return fileDescriptor_38105d47def04072, []int{0} +} +func (m *Frac) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Frac) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Frac.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 *Frac) XXX_Merge(src proto.Message) { + xxx_messageInfo_Frac.Merge(m, src) +} +func (m *Frac) XXX_Size() int { + return m.Size() +} +func (m *Frac) XXX_DiscardUnknown() { + xxx_messageInfo_Frac.DiscardUnknown(m) +} + +var xxx_messageInfo_Frac proto.InternalMessageInfo + +// QosScore holds the QoS score from a QoS excellence report. The score and its variance are updated over time using a weighted average. +// Currently, the weight is the amount of relays that are associated with the QoS report. +type QosScore struct { + Score Frac `protobuf:"bytes,1,opt,name=score,proto3" json:"score"` + Variance Frac `protobuf:"bytes,2,opt,name=variance,proto3" json:"variance"` +} + +func (m *QosScore) Reset() { *m = QosScore{} } +func (m *QosScore) String() string { return proto.CompactTextString(m) } +func (*QosScore) ProtoMessage() {} +func (*QosScore) Descriptor() ([]byte, []int) { + return fileDescriptor_38105d47def04072, []int{1} +} +func (m *QosScore) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QosScore) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QosScore.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 *QosScore) XXX_Merge(src proto.Message) { + xxx_messageInfo_QosScore.Merge(m, src) +} +func (m *QosScore) XXX_Size() int { + return m.Size() +} +func (m *QosScore) XXX_DiscardUnknown() { + xxx_messageInfo_QosScore.DiscardUnknown(m) +} + +var xxx_messageInfo_QosScore proto.InternalMessageInfo + +func (m *QosScore) GetScore() Frac { + if m != nil { + return m.Score + } + return Frac{} +} + +func (m *QosScore) GetVariance() Frac { + if m != nil { + return m.Variance + } + return Frac{} +} + +// Reputation keeps the QosScore of a provider for a specific cluster for in the provider's geolocation. +// The store key is provider+chain+cluster. +// The epoch_score is a QosScore object that is aggregated over an epoch. When an epoch ends, the "score" field is updated +// with the epoch_score and the epoch_score is reset. +// The time_last_updated is used to calculate the appropriate time decay upon update. +// The creation_time is used to determine if the variance stabilization period has passed and score can be truncated. +type Reputation struct { + Score QosScore `protobuf:"bytes,1,opt,name=score,proto3" json:"score"` + EpochScore QosScore `protobuf:"bytes,2,opt,name=epoch_score,json=epochScore,proto3" json:"epoch_score"` + TimeLastUpdated uint64 `protobuf:"varint,3,opt,name=time_last_updated,json=timeLastUpdated,proto3" json:"time_last_updated,omitempty"` + CreationTime uint64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` +} + +func (m *Reputation) Reset() { *m = Reputation{} } +func (m *Reputation) String() string { return proto.CompactTextString(m) } +func (*Reputation) ProtoMessage() {} +func (*Reputation) Descriptor() ([]byte, []int) { + return fileDescriptor_38105d47def04072, []int{2} +} +func (m *Reputation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Reputation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Reputation.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 *Reputation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Reputation.Merge(m, src) +} +func (m *Reputation) XXX_Size() int { + return m.Size() +} +func (m *Reputation) XXX_DiscardUnknown() { + xxx_messageInfo_Reputation.DiscardUnknown(m) +} + +var xxx_messageInfo_Reputation proto.InternalMessageInfo + +func (m *Reputation) GetScore() QosScore { + if m != nil { + return m.Score + } + return QosScore{} +} + +func (m *Reputation) GetEpochScore() QosScore { + if m != nil { + return m.EpochScore + } + return QosScore{} +} + +func (m *Reputation) GetTimeLastUpdated() uint64 { + if m != nil { + return m.TimeLastUpdated + } + return 0 +} + +func (m *Reputation) GetCreationTime() uint64 { + if m != nil { + return m.CreationTime + } + return 0 +} + +// ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. +// The score is ranged between [0.5-2]. It's kept in the providerQosFs fixation store with a provider+chain+cluster key. +type ReputationPairingScore struct { + Score github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=score,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"score" yaml:"score"` +} + +func (m *ReputationPairingScore) Reset() { *m = ReputationPairingScore{} } +func (m *ReputationPairingScore) String() string { return proto.CompactTextString(m) } +func (*ReputationPairingScore) ProtoMessage() {} +func (*ReputationPairingScore) Descriptor() ([]byte, []int) { + return fileDescriptor_38105d47def04072, []int{3} +} +func (m *ReputationPairingScore) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReputationPairingScore) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReputationPairingScore.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 *ReputationPairingScore) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReputationPairingScore.Merge(m, src) +} +func (m *ReputationPairingScore) XXX_Size() int { + return m.Size() +} +func (m *ReputationPairingScore) XXX_DiscardUnknown() { + xxx_messageInfo_ReputationPairingScore.DiscardUnknown(m) +} + +var xxx_messageInfo_ReputationPairingScore proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Frac)(nil), "lavanet.lava.pairing.Frac") + proto.RegisterType((*QosScore)(nil), "lavanet.lava.pairing.QosScore") + proto.RegisterType((*Reputation)(nil), "lavanet.lava.pairing.Reputation") + proto.RegisterType((*ReputationPairingScore)(nil), "lavanet.lava.pairing.ReputationPairingScore") +} + +func init() { + proto.RegisterFile("lavanet/lava/pairing/reputation.proto", fileDescriptor_38105d47def04072) +} + +var fileDescriptor_38105d47def04072 = []byte{ + // 414 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0xc1, 0xaa, 0x13, 0x31, + 0x14, 0x86, 0x27, 0xf7, 0xce, 0x95, 0x6b, 0x5a, 0x11, 0x87, 0x22, 0x43, 0x17, 0xd3, 0x12, 0x51, + 0x8b, 0xe0, 0x0c, 0x28, 0xb8, 0x28, 0x45, 0xb0, 0xa8, 0x2b, 0x11, 0x1d, 0xeb, 0xc6, 0xcd, 0x90, + 0x66, 0xc2, 0x74, 0xb0, 0x49, 0x86, 0x49, 0xa6, 0xd8, 0x9d, 0x8f, 0xe0, 0x83, 0xf8, 0x20, 0x5d, + 0x76, 0x29, 0x2e, 0x4a, 0x69, 0xdf, 0xc0, 0x27, 0x90, 0x24, 0xd3, 0xda, 0x42, 0x17, 0x96, 0xbb, + 0x3a, 0x21, 0xf9, 0xcf, 0x77, 0xfe, 0x73, 0x72, 0xe0, 0xc3, 0x29, 0x9e, 0x61, 0x4e, 0x55, 0xa4, + 0x63, 0x54, 0xe0, 0xbc, 0xcc, 0x79, 0x16, 0x95, 0xb4, 0xa8, 0x14, 0x56, 0xb9, 0xe0, 0x61, 0x51, + 0x0a, 0x25, 0xbc, 0x56, 0x2d, 0x0b, 0x75, 0x0c, 0x6b, 0x59, 0xbb, 0x95, 0x89, 0x4c, 0x18, 0x41, + 0xa4, 0x4f, 0x56, 0x8b, 0x7e, 0x02, 0xe8, 0xbe, 0x2d, 0x31, 0xf1, 0xde, 0xc3, 0x4b, 0x5e, 0x31, + 0x1f, 0x74, 0x41, 0xef, 0xf6, 0x70, 0xb0, 0x58, 0x75, 0x9c, 0xdf, 0xab, 0xce, 0xa3, 0x2c, 0x57, + 0x93, 0x6a, 0x1c, 0x12, 0xc1, 0x22, 0x22, 0x24, 0x13, 0xb2, 0x0e, 0x4f, 0x65, 0xfa, 0x35, 0x52, + 0xf3, 0x82, 0xca, 0xf0, 0x35, 0x25, 0x7f, 0x56, 0x1d, 0x38, 0xc7, 0x6c, 0xda, 0x47, 0xbc, 0x62, + 0x28, 0xd6, 0x20, 0x6f, 0x04, 0xaf, 0x52, 0xca, 0x05, 0xf3, 0x2f, 0x0c, 0xf1, 0xe5, 0xd9, 0xc4, + 0xa6, 0x25, 0x1a, 0x08, 0x8a, 0x2d, 0x0c, 0x7d, 0x07, 0xf0, 0xfa, 0xa3, 0x90, 0x9f, 0x88, 0x28, + 0xa9, 0xf7, 0x02, 0x5e, 0x49, 0x7d, 0x30, 0xa6, 0x1b, 0xcf, 0xda, 0xe1, 0xa9, 0xbe, 0x43, 0xdd, + 0xdd, 0xd0, 0xd5, 0xe5, 0x63, 0x2b, 0xf7, 0x06, 0xf0, 0x7a, 0x86, 0xcb, 0x1c, 0x73, 0x42, 0x8d, + 0xbb, 0xff, 0x49, 0xdd, 0x67, 0xa0, 0x35, 0x80, 0x30, 0xde, 0x8f, 0xdc, 0xeb, 0x1f, 0x9b, 0x08, + 0x4e, 0x93, 0x76, 0x9e, 0x8f, 0x8d, 0xbc, 0x81, 0x0d, 0x5a, 0x08, 0x32, 0x49, 0x2c, 0xe1, 0xe2, + 0x0c, 0x02, 0x34, 0x89, 0x76, 0x0e, 0x4f, 0xe0, 0x3d, 0x95, 0x33, 0x9a, 0x4c, 0xb1, 0x54, 0x49, + 0x55, 0xa4, 0x58, 0xd1, 0xd4, 0xbf, 0xec, 0x82, 0x9e, 0x1b, 0xdf, 0xd5, 0x0f, 0xef, 0xb0, 0x54, + 0x9f, 0xed, 0xb5, 0xf7, 0x00, 0xde, 0x21, 0x25, 0x35, 0xd6, 0x13, 0xfd, 0xe6, 0xbb, 0x46, 0xd7, + 0xdc, 0x5d, 0x8e, 0x72, 0x46, 0x11, 0x87, 0xf7, 0xff, 0x75, 0xf8, 0xc1, 0x1a, 0xb0, 0xa5, 0x46, + 0x87, 0xdd, 0xde, 0xe0, 0x57, 0x0d, 0x04, 0xd5, 0x73, 0x18, 0xbe, 0x5a, 0x6c, 0x02, 0xb0, 0xdc, + 0x04, 0x60, 0xbd, 0x09, 0xc0, 0x8f, 0x6d, 0xe0, 0x2c, 0xb7, 0x81, 0xf3, 0x6b, 0x1b, 0x38, 0x5f, + 0x1e, 0x1f, 0x80, 0x8f, 0x96, 0xff, 0xdb, 0x7e, 0xfd, 0x0d, 0x7d, 0x7c, 0xcb, 0xac, 0xf3, 0xf3, + 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xa3, 0x5c, 0xd7, 0x23, 0x03, 0x00, 0x00, +} + +func (m *Frac) 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 *Frac) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Frac) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Denom.Size() + i -= size + if _, err := m.Denom.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.Num.Size() + i -= size + if _, err := m.Num.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QosScore) 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 *QosScore) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QosScore) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Variance.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Score.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Reputation) 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 *Reputation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Reputation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CreationTime != 0 { + i = encodeVarintReputation(dAtA, i, uint64(m.CreationTime)) + i-- + dAtA[i] = 0x20 + } + if m.TimeLastUpdated != 0 { + i = encodeVarintReputation(dAtA, i, uint64(m.TimeLastUpdated)) + i-- + dAtA[i] = 0x18 + } + { + size, err := m.EpochScore.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Score.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ReputationPairingScore) 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 *ReputationPairingScore) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReputationPairingScore) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Score.Size() + i -= size + if _, err := m.Score.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintReputation(dAtA []byte, offset int, v uint64) int { + offset -= sovReputation(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Frac) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Num.Size() + n += 1 + l + sovReputation(uint64(l)) + l = m.Denom.Size() + n += 1 + l + sovReputation(uint64(l)) + return n +} + +func (m *QosScore) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Score.Size() + n += 1 + l + sovReputation(uint64(l)) + l = m.Variance.Size() + n += 1 + l + sovReputation(uint64(l)) + return n +} + +func (m *Reputation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Score.Size() + n += 1 + l + sovReputation(uint64(l)) + l = m.EpochScore.Size() + n += 1 + l + sovReputation(uint64(l)) + if m.TimeLastUpdated != 0 { + n += 1 + sovReputation(uint64(m.TimeLastUpdated)) + } + if m.CreationTime != 0 { + n += 1 + sovReputation(uint64(m.CreationTime)) + } + return n +} + +func (m *ReputationPairingScore) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Score.Size() + n += 1 + l + sovReputation(uint64(l)) + return n +} + +func sovReputation(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozReputation(x uint64) (n int) { + return sovReputation(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Frac) 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 ErrIntOverflowReputation + } + 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: Frac: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Frac: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Num", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + 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 ErrInvalidLengthReputation + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Num.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + 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 ErrInvalidLengthReputation + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Denom.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReputation(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReputation + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QosScore) 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 ErrIntOverflowReputation + } + 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: QosScore: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QosScore: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Score", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReputation + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Score.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Variance", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReputation + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Variance.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReputation(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReputation + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Reputation) 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 ErrIntOverflowReputation + } + 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: Reputation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Reputation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Score", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReputation + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Score.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochScore", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReputation + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.EpochScore.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeLastUpdated", wireType) + } + m.TimeLastUpdated = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TimeLastUpdated |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreationTime", wireType) + } + m.CreationTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreationTime |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipReputation(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReputation + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ReputationPairingScore) 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 ErrIntOverflowReputation + } + 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: ReputationPairingScore: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReputationPairingScore: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Score", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + 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 ErrInvalidLengthReputation + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Score.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReputation(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReputation + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipReputation(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReputation + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReputation + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReputation + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthReputation + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupReputation + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthReputation + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthReputation = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowReputation = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupReputation = fmt.Errorf("proto: unexpected end of group") +) From 95355482d2cc27226068cf7189b56a0ecb15dc55 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 1 Aug 2024 11:56:36 +0300 Subject: [PATCH 05/66] CNS-1003: rename providerQosFs to reputationsFS --- app/upgrades/empty_upgrades.go | 2 +- proto/lavanet/lava/pairing/genesis.proto | 6 +- proto/lavanet/lava/pairing/reputation.proto | 2 +- x/pairing/genesis.go | 4 +- x/pairing/keeper/keeper.go | 12 +- x/pairing/types/genesis.go | 2 +- x/pairing/types/genesis.pb.go | 185 ++++++++++---------- x/pairing/types/reputation.pb.go | 2 +- 8 files changed, 107 insertions(+), 108 deletions(-) diff --git a/app/upgrades/empty_upgrades.go b/app/upgrades/empty_upgrades.go index 571e1275d1..7735864208 100644 --- a/app/upgrades/empty_upgrades.go +++ b/app/upgrades/empty_upgrades.go @@ -77,7 +77,7 @@ func v0_23_0_UpgradeHandler( lk *keepers.LavaKeepers, ) upgradetypes.UpgradeHandler { return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - lk.PairingKeeper.InitProviderQoS(ctx, *fixationtypes.DefaultGenesis()) + lk.PairingKeeper.InitReputations(ctx, *fixationtypes.DefaultGenesis()) return m.RunMigrations(ctx, c, vm) } } diff --git a/proto/lavanet/lava/pairing/genesis.proto b/proto/lavanet/lava/pairing/genesis.proto index a6317dd512..39a63e6a24 100644 --- a/proto/lavanet/lava/pairing/genesis.proto +++ b/proto/lavanet/lava/pairing/genesis.proto @@ -19,18 +19,16 @@ message BadgeUsedCu { // GenesisState defines the pairing module's genesis state. message GenesisState { + reserved 2,3,4,7; Params params = 1 [(gogoproto.nullable) = false]; - reserved 2; - reserved 3; - reserved 4; repeated BadgeUsedCu badgeUsedCuList = 5 [(gogoproto.nullable) = false]; lavanet.lava.timerstore.GenesisState badgesTS = 6 [(gogoproto.nullable) = false]; - lavanet.lava.fixationstore.GenesisState providerQosFS = 7 [(gogoproto.nullable) = false]; repeated UniqueEpochSessionGenesis unique_epoch_sessions = 8 [(gogoproto.nullable) = false]; repeated ProviderEpochCuGenesis provider_epoch_cus = 9 [(gogoproto.nullable) = false]; repeated ProviderEpochComplainerCuGenesis provider_epoch_complained_cus = 10 [(gogoproto.nullable) = false]; repeated ProviderConsumerEpochCuGenesis provider_consumer_epoch_cus = 11 [(gogoproto.nullable) = false]; repeated ReputationGenesis reputations = 12 [(gogoproto.nullable) = false]; + lavanet.lava.fixationstore.GenesisState reputation_scores = 13 [(gogoproto.nullable) = false]; // this line is used by starport scaffolding # genesis/proto/state } diff --git a/proto/lavanet/lava/pairing/reputation.proto b/proto/lavanet/lava/pairing/reputation.proto index 3b34b07c67..d0de3278cc 100644 --- a/proto/lavanet/lava/pairing/reputation.proto +++ b/proto/lavanet/lava/pairing/reputation.proto @@ -33,7 +33,7 @@ message Reputation { } // ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. -// The score is ranged between [0.5-2]. It's kept in the providerQosFs fixation store with a provider+chain+cluster key. +// The score is ranged between [0.5-2]. It's kept in the reputations fixation store with a provider+chain+cluster key. message ReputationPairingScore { string score = 1 [(gogoproto.moretags) = "yaml:\"score\"", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; diff --git a/x/pairing/genesis.go b/x/pairing/genesis.go index f4f0ffd994..c27707511d 100644 --- a/x/pairing/genesis.go +++ b/x/pairing/genesis.go @@ -35,7 +35,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) } k.InitBadgeTimers(ctx, genState.BadgesTS) - k.InitProviderQoS(ctx, genState.ProviderQosFS) + k.InitReputations(ctx, genState.ReputationScores) // this line is used by starport scaffolding # genesis/module/init k.SetParams(ctx, genState.Params) } @@ -51,7 +51,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.BadgeUsedCuList = k.GetAllBadgeUsedCu(ctx) genesis.Reputations = k.GetAllReputation(ctx) genesis.BadgesTS = k.ExportBadgesTimers(ctx) - genesis.ProviderQosFS = k.ExportProviderQoS(ctx) + genesis.ReputationScores = k.ExportReputations(ctx) // this line is used by starport scaffolding # genesis/module/export return genesis diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index 135170bb4d..2094312d7d 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -33,7 +33,7 @@ type ( subscriptionKeeper types.SubscriptionKeeper planKeeper types.PlanKeeper badgeTimerStore timerstoretypes.TimerStore - providerQosFS fixationtypes.FixationStore + reputationsFS fixationtypes.FixationStore downtimeKeeper types.DowntimeKeeper dualstakingKeeper types.DualstakingKeeper stakingKeeper types.StakingKeeper @@ -115,7 +115,7 @@ func NewKeeper( WithCallbackByBlockHeight(badgeTimerCallback) keeper.badgeTimerStore = *badgeTimerStore - keeper.providerQosFS = *fixationStoreKeeper.NewFixationStore(storeKey, types.ProviderQosStorePrefix) + keeper.reputationsFS = *fixationStoreKeeper.NewFixationStore(storeKey, types.ProviderQosStorePrefix) schema, err := sb.Build() if err != nil { @@ -143,10 +143,10 @@ func (k Keeper) BeginBlock(ctx sdk.Context) { } } -func (k Keeper) InitProviderQoS(ctx sdk.Context, gs fixationtypes.GenesisState) { - k.providerQosFS.Init(ctx, gs) +func (k Keeper) InitReputations(ctx sdk.Context, gs fixationtypes.GenesisState) { + k.reputationsFS.Init(ctx, gs) } -func (k Keeper) ExportProviderQoS(ctx sdk.Context) fixationtypes.GenesisState { - return k.providerQosFS.Export(ctx) +func (k Keeper) ExportReputations(ctx sdk.Context) fixationtypes.GenesisState { + return k.reputationsFS.Export(ctx) } diff --git a/x/pairing/types/genesis.go b/x/pairing/types/genesis.go index 2711288bbd..46b43cdadc 100644 --- a/x/pairing/types/genesis.go +++ b/x/pairing/types/genesis.go @@ -20,7 +20,7 @@ func DefaultGenesis() *GenesisState { BadgeUsedCuList: []BadgeUsedCu{}, Reputations: []ReputationGenesis{}, BadgesTS: *timerstoretypes.DefaultGenesis(), - ProviderQosFS: *fixationtypes.DefaultGenesis(), + ReputationScores: *fixationtypes.DefaultGenesis(), // this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } diff --git a/x/pairing/types/genesis.pb.go b/x/pairing/types/genesis.pb.go index b579746966..ae51c2295c 100644 --- a/x/pairing/types/genesis.pb.go +++ b/x/pairing/types/genesis.pb.go @@ -82,12 +82,12 @@ type GenesisState struct { Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` BadgeUsedCuList []BadgeUsedCu `protobuf:"bytes,5,rep,name=badgeUsedCuList,proto3" json:"badgeUsedCuList"` BadgesTS types.GenesisState `protobuf:"bytes,6,opt,name=badgesTS,proto3" json:"badgesTS"` - ProviderQosFS types1.GenesisState `protobuf:"bytes,7,opt,name=providerQosFS,proto3" json:"providerQosFS"` UniqueEpochSessions []UniqueEpochSessionGenesis `protobuf:"bytes,8,rep,name=unique_epoch_sessions,json=uniqueEpochSessions,proto3" json:"unique_epoch_sessions"` ProviderEpochCus []ProviderEpochCuGenesis `protobuf:"bytes,9,rep,name=provider_epoch_cus,json=providerEpochCus,proto3" json:"provider_epoch_cus"` ProviderEpochComplainedCus []ProviderEpochComplainerCuGenesis `protobuf:"bytes,10,rep,name=provider_epoch_complained_cus,json=providerEpochComplainedCus,proto3" json:"provider_epoch_complained_cus"` ProviderConsumerEpochCus []ProviderConsumerEpochCuGenesis `protobuf:"bytes,11,rep,name=provider_consumer_epoch_cus,json=providerConsumerEpochCus,proto3" json:"provider_consumer_epoch_cus"` Reputations []ReputationGenesis `protobuf:"bytes,12,rep,name=reputations,proto3" json:"reputations"` + ReputationScores types1.GenesisState `protobuf:"bytes,13,opt,name=reputation_scores,json=reputationScores,proto3" json:"reputation_scores"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -144,13 +144,6 @@ func (m *GenesisState) GetBadgesTS() types.GenesisState { return types.GenesisState{} } -func (m *GenesisState) GetProviderQosFS() types1.GenesisState { - if m != nil { - return m.ProviderQosFS - } - return types1.GenesisState{} -} - func (m *GenesisState) GetUniqueEpochSessions() []UniqueEpochSessionGenesis { if m != nil { return m.UniqueEpochSessions @@ -186,6 +179,13 @@ func (m *GenesisState) GetReputations() []ReputationGenesis { return nil } +func (m *GenesisState) GetReputationScores() types1.GenesisState { + if m != nil { + return m.ReputationScores + } + return types1.GenesisState{} +} + type UniqueEpochSessionGenesis struct { Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"` @@ -557,55 +557,56 @@ func init() { } var fileDescriptor_dbd1e49b8b57595b = []byte{ - // 767 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x4f, 0x13, 0x41, - 0x14, 0xef, 0xd2, 0xed, 0x1f, 0x5e, 0x51, 0xcb, 0x88, 0x32, 0x54, 0xa8, 0x65, 0x0d, 0xa1, 0x24, - 0xda, 0x26, 0x68, 0x3c, 0x78, 0x13, 0x22, 0x04, 0x34, 0x51, 0x5a, 0x88, 0x89, 0x97, 0xba, 0xdd, - 0x1d, 0xcb, 0x28, 0xdd, 0x1d, 0x77, 0x76, 0x09, 0x3d, 0xf9, 0x15, 0xfc, 0x0a, 0xde, 0xfd, 0x0c, - 0x9e, 0x39, 0x72, 0xf4, 0x64, 0x0c, 0x1c, 0xf4, 0x2b, 0x78, 0x33, 0x3b, 0x3b, 0xfd, 0x33, 0xed, - 0x16, 0xc4, 0x18, 0x4f, 0xbb, 0x6f, 0xe7, 0xf7, 0x7e, 0xbf, 0xf7, 0x66, 0x7e, 0x6f, 0x33, 0x60, - 0x1c, 0x98, 0x87, 0xa6, 0x43, 0xfc, 0x6a, 0xf8, 0xac, 0x32, 0x93, 0x7a, 0xd4, 0x69, 0x55, 0x5b, - 0xc4, 0x21, 0x9c, 0xf2, 0x0a, 0xf3, 0x5c, 0xdf, 0x45, 0x33, 0x12, 0x53, 0x09, 0x9f, 0x15, 0x89, - 0x29, 0xcc, 0xb4, 0xdc, 0x96, 0x2b, 0x00, 0xd5, 0xf0, 0x2d, 0xc2, 0x16, 0x16, 0x63, 0xf9, 0x98, - 0xe9, 0x99, 0x6d, 0x49, 0x57, 0xb8, 0x13, 0x0b, 0x21, 0xcc, 0xb5, 0xf6, 0x1b, 0x56, 0x20, 0x41, - 0x2b, 0x0a, 0xe8, 0x0d, 0x3d, 0x32, 0x7d, 0xea, 0x3a, 0xdc, 0x77, 0x3d, 0xd2, 0x8b, 0x62, 0xf9, - 0x7c, 0xda, 0x26, 0x5e, 0x84, 0x13, 0xaf, 0x12, 0xb4, 0x14, 0x2b, 0xea, 0x11, 0x16, 0xf8, 0x03, - 0x5c, 0xc6, 0x0e, 0xe4, 0xd6, 0x4c, 0xbb, 0x45, 0xf6, 0x38, 0xb1, 0xd7, 0x03, 0xb4, 0x02, 0xd3, - 0xcd, 0x30, 0x6c, 0x04, 0x9c, 0xd8, 0x0d, 0x2b, 0x68, 0xbc, 0x23, 0x1d, 0xac, 0x95, 0xb4, 0xf2, - 0x54, 0xed, 0x6a, 0xb3, 0x8f, 0x7b, 0x4a, 0x3a, 0x68, 0x16, 0x32, 0x12, 0x84, 0x27, 0x4a, 0x5a, - 0x59, 0xaf, 0xa5, 0x03, 0xb1, 0x66, 0xfc, 0x4c, 0xc3, 0xd4, 0x66, 0xb4, 0x9f, 0x75, 0xdf, 0xf4, - 0x09, 0x7a, 0x04, 0xe9, 0x68, 0x3f, 0x04, 0x53, 0x6e, 0x75, 0xbe, 0x12, 0xb7, 0xbf, 0x95, 0x17, - 0x02, 0xb3, 0xa6, 0x1f, 0x7f, 0xbb, 0x9d, 0xa8, 0xc9, 0x0c, 0xb4, 0x03, 0xd7, 0x06, 0x74, 0x9f, - 0x51, 0xee, 0xe3, 0x54, 0x29, 0x59, 0xce, 0xad, 0x2e, 0xc6, 0x93, 0x0c, 0x34, 0x23, 0x99, 0x86, - 0xf3, 0xd1, 0x26, 0x64, 0xc5, 0x27, 0xbe, 0x5b, 0xc7, 0x69, 0x51, 0xd0, 0x92, 0xca, 0xd5, 0xdf, - 0xd1, 0xca, 0x60, 0x1f, 0x92, 0xaf, 0x97, 0x8c, 0x76, 0xe1, 0x0a, 0xf3, 0xdc, 0x43, 0x6a, 0x13, - 0x6f, 0xc7, 0xe5, 0x1b, 0x75, 0x9c, 0x11, 0x6c, 0x65, 0x95, 0x4d, 0x39, 0xca, 0x38, 0x42, 0x95, - 0x04, 0x51, 0xb8, 0x11, 0x38, 0xf4, 0x7d, 0x40, 0x1a, 0x91, 0x43, 0x38, 0xe1, 0x3c, 0x4c, 0xc7, - 0x59, 0xd1, 0x77, 0x35, 0xbe, 0xef, 0x3d, 0x91, 0xf2, 0x24, 0xcc, 0xa8, 0x47, 0x09, 0x52, 0x49, - 0x8a, 0x5c, 0x0f, 0x46, 0x00, 0x1c, 0xbd, 0x06, 0xd4, 0xd5, 0x6e, 0x74, 0xed, 0xc8, 0xf1, 0xa4, - 0xd0, 0xb9, 0x3b, 0xe6, 0x90, 0x24, 0x5e, 0x10, 0xad, 0x07, 0xaa, 0x48, 0x9e, 0xa9, 0xab, 0x1c, - 0x7d, 0x80, 0x85, 0x61, 0x05, 0xb7, 0xcd, 0x0e, 0x4c, 0xea, 0x08, 0xe7, 0x70, 0x0c, 0x42, 0xec, - 0xe1, 0x9f, 0x88, 0x75, 0x13, 0xbd, 0x61, 0xd9, 0x02, 0x8b, 0xc5, 0xd9, 0x61, 0x01, 0x1d, 0xb8, - 0xd5, 0x2b, 0xc0, 0x72, 0x1d, 0x1e, 0xb4, 0x95, 0x5e, 0x73, 0x42, 0xfe, 0xc1, 0xf9, 0xf2, 0xeb, - 0x32, 0x2f, 0xb6, 0x67, 0xcc, 0xe2, 0x51, 0x1c, 0x3d, 0x87, 0x5c, 0x7f, 0xdc, 0x38, 0x9e, 0x12, - 0x52, 0xcb, 0xf1, 0x52, 0xb5, 0x1e, 0x50, 0x65, 0x1f, 0x64, 0xd8, 0xd6, 0xb3, 0x13, 0xf9, 0xe4, - 0xb6, 0x9e, 0x4d, 0xe6, 0xf5, 0x6d, 0x3d, 0xab, 0xe7, 0x53, 0xc6, 0x27, 0x0d, 0xe6, 0xc6, 0x9e, - 0x3c, 0x9a, 0x81, 0x94, 0xe8, 0x54, 0x8c, 0x9d, 0x5e, 0x8b, 0x02, 0x54, 0x80, 0x6c, 0xb7, 0x64, - 0x31, 0xb8, 0x93, 0xb5, 0x5e, 0x8c, 0x30, 0x64, 0x98, 0xe7, 0xbe, 0x25, 0x96, 0x8f, 0x93, 0x62, - 0xa9, 0x1b, 0xa2, 0x39, 0xc8, 0x5a, 0xfb, 0x26, 0x75, 0x1a, 0xd4, 0xc6, 0x7a, 0xb4, 0x24, 0xe2, - 0x2d, 0x1b, 0x2d, 0x00, 0x48, 0x8f, 0x86, 0x8b, 0x29, 0xa1, 0x35, 0x29, 0xbf, 0x6c, 0xd9, 0xc6, - 0x17, 0x0d, 0x6e, 0xc6, 0xbb, 0xe6, 0x2f, 0x0a, 0x1c, 0x2c, 0x23, 0xa9, 0x96, 0xf1, 0x12, 0xa6, - 0x47, 0xcc, 0x2c, 0x4a, 0x1d, 0x99, 0xef, 0x31, 0x5e, 0xee, 0xfe, 0x2f, 0x86, 0x4c, 0x6c, 0xfc, - 0xd0, 0xa0, 0x74, 0x91, 0x13, 0xff, 0x6d, 0x2b, 0x87, 0x30, 0x3f, 0x6e, 0x6a, 0xbc, 0x7e, 0x57, - 0xd5, 0x4b, 0x0e, 0x8d, 0xec, 0x6f, 0x8e, 0x8d, 0x03, 0x18, 0xbf, 0x34, 0x28, 0x9e, 0x6f, 0xfa, - 0xff, 0xe5, 0x29, 0x06, 0x85, 0xf1, 0x63, 0x2b, 0x3c, 0x96, 0x5b, 0xbd, 0x77, 0xa9, 0xa9, 0x95, - 0xdd, 0xcf, 0x8e, 0x19, 0x57, 0xe3, 0xb3, 0x06, 0xd3, 0x23, 0x53, 0xa8, 0x94, 0xa8, 0xa9, 0x25, - 0x62, 0xc8, 0x58, 0x07, 0x01, 0xf7, 0x7b, 0x2d, 0x77, 0x43, 0x65, 0x37, 0x92, 0x43, 0xbb, 0xb1, - 0x01, 0xd0, 0x1f, 0x69, 0x79, 0x90, 0xa5, 0x8b, 0xfe, 0x09, 0xb2, 0xf6, 0x81, 0xcc, 0xb5, 0xc7, - 0xc7, 0xa7, 0x45, 0xed, 0xe4, 0xb4, 0xa8, 0x7d, 0x3f, 0x2d, 0x6a, 0x1f, 0xcf, 0x8a, 0x89, 0x93, - 0xb3, 0x62, 0xe2, 0xeb, 0x59, 0x31, 0xf1, 0x6a, 0xb9, 0x45, 0xfd, 0xfd, 0xa0, 0x59, 0xb1, 0xdc, - 0x76, 0x55, 0xb9, 0x03, 0x1c, 0xf5, 0x6e, 0x01, 0x7e, 0x87, 0x11, 0xde, 0x4c, 0x8b, 0x1b, 0xc0, - 0xfd, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x29, 0x8c, 0x17, 0xc4, 0x12, 0x09, 0x00, 0x00, + // 782 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcd, 0x6e, 0xd3, 0x4a, + 0x14, 0x8e, 0x1b, 0x27, 0x71, 0x4f, 0x7a, 0xef, 0x4d, 0xe6, 0xf6, 0xde, 0x4e, 0x43, 0x1b, 0x52, + 0xa3, 0xaa, 0xa9, 0x04, 0x89, 0x54, 0x10, 0x0b, 0x76, 0xb4, 0x82, 0xaa, 0x01, 0x09, 0x9a, 0x50, + 0x21, 0xc1, 0xc2, 0x38, 0xf6, 0x90, 0x0e, 0x34, 0xf6, 0xe0, 0xb1, 0xab, 0x66, 0xc5, 0x2b, 0xf0, + 0x0a, 0xec, 0x79, 0x06, 0xd6, 0x5d, 0x76, 0xc9, 0x0a, 0xa1, 0x76, 0xc1, 0x13, 0xb0, 0x60, 0x87, + 0x3c, 0x9e, 0xfc, 0x38, 0x71, 0x5a, 0x8a, 0x10, 0xab, 0xe4, 0x78, 0xbe, 0xf3, 0x7d, 0xe7, 0x1c, + 0x9f, 0x6f, 0x64, 0xd0, 0x0f, 0xcc, 0x43, 0xd3, 0x21, 0x7e, 0x3d, 0xfc, 0xad, 0x33, 0x93, 0x7a, + 0xd4, 0xe9, 0xd4, 0x3b, 0xc4, 0x21, 0x9c, 0xf2, 0x1a, 0xf3, 0x5c, 0xdf, 0x45, 0xf3, 0x12, 0x53, + 0x0b, 0x7f, 0x6b, 0x12, 0x53, 0x9a, 0xef, 0xb8, 0x1d, 0x57, 0x00, 0xea, 0xe1, 0xbf, 0x08, 0x5b, + 0x5a, 0x49, 0xe4, 0x63, 0xa6, 0x67, 0x76, 0x25, 0x5d, 0xe9, 0x5a, 0x22, 0x84, 0x30, 0xd7, 0xda, + 0x37, 0xac, 0x40, 0x82, 0xd6, 0x63, 0xa0, 0x97, 0xf4, 0xc8, 0xf4, 0xa9, 0xeb, 0x70, 0xdf, 0xf5, + 0xc8, 0x20, 0x4a, 0xe4, 0xf3, 0x69, 0x97, 0x78, 0x11, 0x4e, 0xfc, 0x95, 0xa0, 0xd5, 0x44, 0x51, + 0x8f, 0xb0, 0xc0, 0x1f, 0xe1, 0xd2, 0x77, 0x21, 0xbf, 0x69, 0xda, 0x1d, 0xb2, 0xc7, 0x89, 0xbd, + 0x15, 0xa0, 0x75, 0x28, 0xb6, 0xc3, 0xd0, 0x08, 0x38, 0xb1, 0x0d, 0x2b, 0x30, 0x5e, 0x93, 0x1e, + 0x56, 0x2a, 0x4a, 0x75, 0xae, 0xf9, 0x77, 0x7b, 0x88, 0x7b, 0x40, 0x7a, 0x68, 0x01, 0x72, 0x12, + 0x84, 0x67, 0x2a, 0x4a, 0x55, 0x6d, 0x66, 0x03, 0x71, 0xa6, 0x7f, 0xcb, 0xc2, 0xdc, 0x76, 0x34, + 0xcf, 0x96, 0x6f, 0xfa, 0x04, 0xdd, 0x81, 0x6c, 0x34, 0x0f, 0xc1, 0x94, 0xdf, 0x58, 0xaa, 0x25, + 0xcd, 0xb7, 0xf6, 0x58, 0x60, 0x36, 0xd5, 0xe3, 0xcf, 0x57, 0x53, 0x4d, 0x99, 0x81, 0x76, 0xe1, + 0x9f, 0x11, 0xdd, 0x87, 0x94, 0xfb, 0x38, 0x53, 0x49, 0x57, 0xf3, 0x1b, 0x2b, 0xc9, 0x24, 0x23, + 0xcd, 0x48, 0xa6, 0xf1, 0x7c, 0xb4, 0x0d, 0x9a, 0x78, 0xc4, 0x9f, 0xb4, 0x70, 0x56, 0x14, 0xb4, + 0x1a, 0xe7, 0x1a, 0x4e, 0xb4, 0x36, 0xda, 0x87, 0xe4, 0x1b, 0x24, 0x23, 0x0a, 0xff, 0x05, 0x0e, + 0x7d, 0x13, 0x10, 0x23, 0x7a, 0x97, 0x9c, 0x70, 0x1e, 0xbe, 0x33, 0xac, 0x89, 0x0a, 0xeb, 0xc9, + 0x15, 0xee, 0x89, 0x94, 0x7b, 0x61, 0x46, 0x2b, 0x4a, 0x90, 0x22, 0x92, 0xff, 0xdf, 0x60, 0x02, + 0xc0, 0xd1, 0x0b, 0x40, 0xcc, 0x73, 0x0f, 0xa9, 0x4d, 0x3c, 0xa3, 0xbf, 0x38, 0x1c, 0xcf, 0x0a, + 0x9d, 0xeb, 0x53, 0xc6, 0x29, 0xf1, 0x82, 0x68, 0x2b, 0x88, 0x8b, 0x14, 0x58, 0xfc, 0x94, 0xa3, + 0xb7, 0xb0, 0x3c, 0xae, 0xe0, 0x76, 0xd9, 0x81, 0x49, 0x1d, 0xf1, 0x8e, 0x39, 0x06, 0x21, 0x76, + 0xfb, 0x67, 0xc4, 0xfa, 0x89, 0xde, 0xb8, 0x6c, 0x89, 0x25, 0xe2, 0xec, 0xb0, 0x80, 0x1e, 0x5c, + 0x19, 0x14, 0x60, 0xb9, 0x0e, 0x0f, 0xba, 0xb1, 0x5e, 0xf3, 0x42, 0xfe, 0xd6, 0xf9, 0xf2, 0x5b, + 0x32, 0x2f, 0xb1, 0x67, 0xcc, 0x92, 0x51, 0x1c, 0x3d, 0x82, 0xfc, 0xd0, 0x18, 0x1c, 0xcf, 0x09, + 0xa9, 0xb5, 0x64, 0xa9, 0xe6, 0x00, 0x18, 0x67, 0x1f, 0x65, 0x40, 0xcf, 0xa1, 0x38, 0x0c, 0x0d, + 0x6e, 0xb9, 0x1e, 0xe1, 0xf8, 0x2f, 0xb1, 0x6b, 0xd5, 0x38, 0x6d, 0xcc, 0xe8, 0x49, 0xeb, 0x56, + 0x18, 0x12, 0xb5, 0x04, 0x4f, 0x43, 0xd5, 0x66, 0x0a, 0xe9, 0x86, 0xaa, 0xa5, 0x0b, 0x6a, 0x43, + 0xd5, 0xd4, 0x42, 0xa6, 0xa1, 0x6a, 0xb9, 0x82, 0xa6, 0xbf, 0x57, 0x60, 0x71, 0xea, 0x72, 0xa1, + 0x79, 0xc8, 0x88, 0x61, 0x0a, 0x0f, 0xaa, 0xcd, 0x28, 0x40, 0x25, 0xd0, 0xfa, 0x53, 0x11, 0x2e, + 0x9e, 0x6d, 0x0e, 0x62, 0x84, 0x21, 0xc7, 0x3c, 0xf7, 0x15, 0xb1, 0x7c, 0x9c, 0x16, 0x47, 0xfd, + 0x10, 0x2d, 0x82, 0x66, 0xed, 0x9b, 0xd4, 0x31, 0xa8, 0x8d, 0xd5, 0xe8, 0x48, 0xc4, 0x3b, 0x36, + 0x5a, 0x06, 0x90, 0x36, 0x08, 0x0f, 0x33, 0x42, 0x6b, 0x56, 0x3e, 0xd9, 0xb1, 0xf5, 0x8f, 0x0a, + 0xfc, 0x9f, 0xbc, 0x98, 0xbf, 0x50, 0xe0, 0x68, 0x19, 0xe9, 0x78, 0x19, 0x4f, 0xa1, 0x38, 0xe1, + 0x17, 0x51, 0xea, 0x84, 0xd9, 0xa7, 0xd8, 0xa5, 0x7f, 0x79, 0x8c, 0xf9, 0x44, 0xff, 0xaa, 0x40, + 0xe5, 0xa2, 0x65, 0xff, 0xbd, 0xad, 0x1c, 0xc2, 0xd2, 0x34, 0x63, 0x7a, 0xc3, 0xae, 0xea, 0x97, + 0xf4, 0xa5, 0xec, 0x6f, 0x91, 0x4d, 0x03, 0xe8, 0xdf, 0x15, 0x28, 0x9f, 0xef, 0xab, 0x3f, 0xb5, + 0x53, 0x0c, 0x4a, 0xd3, 0x6f, 0x06, 0xb1, 0x63, 0xf9, 0x8d, 0x1b, 0x97, 0xba, 0x18, 0x64, 0xf7, + 0x0b, 0x53, 0x6e, 0x04, 0xfd, 0x83, 0x02, 0xc5, 0x09, 0xa3, 0xc7, 0x4a, 0x54, 0xe2, 0x25, 0x62, + 0xc8, 0x59, 0x07, 0x01, 0xf7, 0x07, 0x2d, 0xf7, 0xc3, 0xd8, 0x34, 0xd2, 0x63, 0xd3, 0xb8, 0x0f, + 0x30, 0x74, 0xb7, 0x7c, 0x91, 0x95, 0x8b, 0xae, 0x1d, 0x59, 0xfb, 0x48, 0xe6, 0xe6, 0xdd, 0xe3, + 0xd3, 0xb2, 0x72, 0x72, 0x5a, 0x56, 0xbe, 0x9c, 0x96, 0x95, 0x77, 0x67, 0xe5, 0xd4, 0xc9, 0x59, + 0x39, 0xf5, 0xe9, 0xac, 0x9c, 0x7a, 0xb6, 0xd6, 0xa1, 0xfe, 0x7e, 0xd0, 0xae, 0x59, 0x6e, 0xb7, + 0x1e, 0xfb, 0x20, 0x38, 0x1a, 0x7c, 0x12, 0xf8, 0x3d, 0x46, 0x78, 0x3b, 0x2b, 0x3e, 0x07, 0x6e, + 0xfe, 0x08, 0x00, 0x00, 0xff, 0xff, 0x94, 0xa5, 0x29, 0x3a, 0x1f, 0x09, 0x00, 0x00, } func (m *BadgeUsedCu) Marshal() (dAtA []byte, err error) { @@ -663,6 +664,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.ReputationScores.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a if len(m.Reputations) > 0 { for iNdEx := len(m.Reputations) - 1; iNdEx >= 0; iNdEx-- { { @@ -733,16 +744,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x42 } } - { - size, err := m.ProviderQosFS.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a { size, err := m.BadgesTS.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -1094,8 +1095,6 @@ func (m *GenesisState) Size() (n int) { } l = m.BadgesTS.Size() n += 1 + l + sovGenesis(uint64(l)) - l = m.ProviderQosFS.Size() - n += 1 + l + sovGenesis(uint64(l)) if len(m.UniqueEpochSessions) > 0 { for _, e := range m.UniqueEpochSessions { l = e.Size() @@ -1126,6 +1125,8 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + l = m.ReputationScores.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -1487,9 +1488,9 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 7: + case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderQosFS", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UniqueEpochSessions", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1516,13 +1517,14 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ProviderQosFS.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.UniqueEpochSessions = append(m.UniqueEpochSessions, UniqueEpochSessionGenesis{}) + if err := m.UniqueEpochSessions[len(m.UniqueEpochSessions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 8: + case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UniqueEpochSessions", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProviderEpochCus", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1549,14 +1551,14 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.UniqueEpochSessions = append(m.UniqueEpochSessions, UniqueEpochSessionGenesis{}) - if err := m.UniqueEpochSessions[len(m.UniqueEpochSessions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.ProviderEpochCus = append(m.ProviderEpochCus, ProviderEpochCuGenesis{}) + if err := m.ProviderEpochCus[len(m.ProviderEpochCus)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 9: + case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderEpochCus", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProviderEpochComplainedCus", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1583,14 +1585,14 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProviderEpochCus = append(m.ProviderEpochCus, ProviderEpochCuGenesis{}) - if err := m.ProviderEpochCus[len(m.ProviderEpochCus)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.ProviderEpochComplainedCus = append(m.ProviderEpochComplainedCus, ProviderEpochComplainerCuGenesis{}) + if err := m.ProviderEpochComplainedCus[len(m.ProviderEpochComplainedCus)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 10: + case 11: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderEpochComplainedCus", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProviderConsumerEpochCus", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1617,14 +1619,14 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProviderEpochComplainedCus = append(m.ProviderEpochComplainedCus, ProviderEpochComplainerCuGenesis{}) - if err := m.ProviderEpochComplainedCus[len(m.ProviderEpochComplainedCus)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.ProviderConsumerEpochCus = append(m.ProviderConsumerEpochCus, ProviderConsumerEpochCuGenesis{}) + if err := m.ProviderConsumerEpochCus[len(m.ProviderConsumerEpochCus)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 11: + case 12: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ProviderConsumerEpochCus", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Reputations", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1651,14 +1653,14 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ProviderConsumerEpochCus = append(m.ProviderConsumerEpochCus, ProviderConsumerEpochCuGenesis{}) - if err := m.ProviderConsumerEpochCus[len(m.ProviderConsumerEpochCus)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Reputations = append(m.Reputations, ReputationGenesis{}) + if err := m.Reputations[len(m.Reputations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 12: + case 13: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Reputations", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ReputationScores", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1685,8 +1687,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Reputations = append(m.Reputations, ReputationGenesis{}) - if err := m.Reputations[len(m.Reputations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ReputationScores.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/pairing/types/reputation.pb.go b/x/pairing/types/reputation.pb.go index 28bab7019f..733235e885 100644 --- a/x/pairing/types/reputation.pb.go +++ b/x/pairing/types/reputation.pb.go @@ -192,7 +192,7 @@ func (m *Reputation) GetCreationTime() uint64 { } // ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. -// The score is ranged between [0.5-2]. It's kept in the providerQosFs fixation store with a provider+chain+cluster key. +// The score is ranged between [0.5-2]. It's kept in the reputations fixation store with a provider+chain+cluster key. type ReputationPairingScore struct { Score github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=score,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"score" yaml:"score"` } From 47a5a695ccc14d5445fb50369d2fb33dc6a82bcd Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 1 Aug 2024 14:19:09 +0300 Subject: [PATCH 06/66] CNS-1003: add reputation pairing score functions --- x/pairing/keeper/reputation.go | 62 ++++++++++++++++++++++++ x/pairing/keeper/reputation_test.go | 73 +++++++++++++++++++++++++++++ x/pairing/types/reputation.go | 4 ++ 3 files changed, 139 insertions(+) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index dfb52a38a1..57ecb24ad3 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -12,6 +12,7 @@ import ( /* Reputation is a provider performance metric calculated using QoS excellence reports that are retrieved from relay payments. +Higher reputation improves the provider's chance to be picked in the pairing mechanism. The reputations are kept within an indexed map called "reputations" in the keeper. An indexed map allows accessing map entries using two type of keys: primary keys and reference keys. The primary keys are the regular map keys, each point @@ -26,6 +27,9 @@ that share the same chain ID and cluster. Since the collections package doesn't support getting the full list of reference keys from an indexed map, we save a KeySet of the reference keys in the keeper in the "reputationRefKeys" field. +The reputation's pairing score is kept in the reputations fixation store so pairing queries will be deterministic for +past blocks. + */ // TODO: remove and reimplement in future work @@ -102,3 +106,61 @@ func (k Keeper) GetAllReputation(ctx sdk.Context) []types.ReputationGenesis { return entries } + +// 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()) + key := types.ReputationScoreKey(chainID, cluster, provider) + + var score types.ReputationPairingScore + found = k.reputationsFS.FindEntry(ctx, key, block, &score) + + return 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) { + var score types.ReputationPairingScore + key := types.ReputationScoreKey(chainID, cluster, provider) + + entryBlock, _, _, found = k.reputationsFS.FindEntryDetailed(ctx, key, block, &score) + return 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 { + key := types.ReputationScoreKey(chainID, cluster, provider) + err := k.reputationsFS.AppendEntry(ctx, key, uint64(ctx.BlockHeight()), &score) + if err != nil { + return utils.LavaFormatError("SetReputationScore: set reputation pairing score failed", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", provider), + utils.LogAttr("score", score.String()), + ) + } + + return nil +} + +// RemoveReputationScore removes a reputation pairing score +func (k Keeper) RemoveReputationScore(ctx sdk.Context, chainID string, cluster string, provider string) error { + block := uint64(ctx.BlockHeight()) + nextEpoch, err := k.epochStorageKeeper.GetNextEpoch(ctx, block) + if err != nil { + return utils.LavaFormatError("RemoveReputationScore: get next epoch failed", err, + utils.LogAttr("block", block), + ) + } + key := types.ReputationScoreKey(chainID, cluster, provider) + + err = k.reputationsFS.DelEntry(ctx, key, nextEpoch) + if err != nil { + return utils.LavaFormatError("RemoveReputationScore: delete score failed", err, + utils.LogAttr("chain_id", chainID), + utils.LogAttr("cluster", cluster), + utils.LogAttr("provider", provider), + ) + } + return nil +} diff --git a/x/pairing/keeper/reputation_test.go b/x/pairing/keeper/reputation_test.go index 40007646e8..a95d0a401c 100644 --- a/x/pairing/keeper/reputation_test.go +++ b/x/pairing/keeper/reputation_test.go @@ -69,3 +69,76 @@ func TestGetAllReputations(t *testing.T) { require.True(t, items[i].Equal(genEntries[i].Reputation)) } } + +func createNReputationsScores(keeper *keeper.Keeper, ctx sdk.Context, n int) ([]types.ReputationPairingScore, sdk.Context) { + items := make([]types.ReputationPairingScore, 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) + if err != nil { + panic(err) + } + + items[i] = rps + height++ + ctx = ctx.WithBlockHeight(height) + } + return items, ctx +} + +func TestGetReputationScore(t *testing.T) { + keeper, ctx := keepertest.PairingKeeper(t) + items, ctx := createNReputationsScores(keeper, ctx, 10) + for i, item := range items { + strIndex := strconv.Itoa(i) + entry, found := keeper.GetReputationScore(ctx, strIndex, strIndex, strIndex) + require.True(t, found) + require.True(t, item.Score.Equal(entry.Score)) + } + + _, found := keeper.GetReputationScore(ctx, "dummy", "dummy", "dummy") + require.False(t, found) +} + +func TestGetReputationScoreForBlock(t *testing.T) { + keeper, ctx := keepertest.PairingKeeper(t) + items, ctx := createNReputationsScores(keeper, ctx, 10) + for i, item := range items { + 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.Equal(t, uint64(i), entryBlock) + } + + _, _, found := keeper.GetReputationScoreForBlock(ctx, "dummy", "dummy", "dummy", uint64(ctx.BlockHeight())) + require.False(t, found) + _, _, found = keeper.GetReputationScoreForBlock(ctx, "2", "2", "2", 1) + require.False(t, found) +} + +func TestRemoveReputationScore(t *testing.T) { + ts := newTester(t) + keeper, ctx := ts.Keepers.Pairing, ts.Ctx + items, ctx := createNReputationsScores(&keeper, ctx, 10) + for i := range items { + strIndex := strconv.Itoa(i) + err := keeper.RemoveReputationScore(ctx, strIndex, strIndex, strIndex) + require.NoError(t, err) + _, found := keeper.GetReputationScore(ctx, strIndex, strIndex, strIndex) + require.True(t, found) + } + + ts.AdvanceEpoch() // removal applied + ts.AdvanceEpochUntilStale() // deletion happens + + for i := range items { + strIndex := strconv.Itoa(i) + _, found := keeper.GetReputationScore(ctx, strIndex, strIndex, strIndex) + require.False(t, found) + } +} diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index facdc6310f..7c6bccc9e5 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -56,3 +56,7 @@ func (r Reputation) Equal(other Reputation) bool { return r.Score.Equal(other.Score) && r.EpochScore.Equal(other.EpochScore) && r.TimeLastUpdated == other.TimeLastUpdated && r.CreationTime == other.CreationTime } + +func ReputationScoreKey(chainID string, cluster string, provider string) string { + return chainID + " " + cluster + " " + provider +} From 68b1c3f77c38ec7285e5978f86ae376bfe19a1c3 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 4 Aug 2024 14:56:08 +0300 Subject: [PATCH 07/66] CNS-1003: minor changes --- proto/lavanet/lava/pairing/reputation.proto | 4 +- x/pairing/keeper/reputation_test.go | 4 +- x/pairing/types/qos_score.go | 17 ++++++ x/pairing/types/reputation.go | 21 +++---- x/pairing/types/reputation.pb.go | 66 ++++++++++----------- 5 files changed, 63 insertions(+), 49 deletions(-) diff --git a/proto/lavanet/lava/pairing/reputation.proto b/proto/lavanet/lava/pairing/reputation.proto index d0de3278cc..f24f1f657f 100644 --- a/proto/lavanet/lava/pairing/reputation.proto +++ b/proto/lavanet/lava/pairing/reputation.proto @@ -28,8 +28,8 @@ message QosScore { message Reputation { QosScore score = 1 [(gogoproto.nullable) = false]; QosScore epoch_score = 2 [(gogoproto.nullable) = false]; - uint64 time_last_updated = 3; - uint64 creation_time = 4; + int64 time_last_updated = 3; + int64 creation_time = 4; } // ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. diff --git a/x/pairing/keeper/reputation_test.go b/x/pairing/keeper/reputation_test.go index a95d0a401c..bf34b5408e 100644 --- a/x/pairing/keeper/reputation_test.go +++ b/x/pairing/keeper/reputation_test.go @@ -26,8 +26,8 @@ func createNReputations(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.R Score: types.Frac{Num: decIndex, Denom: decIndex}, Variance: types.Frac{Num: decIndex, Denom: decIndex}, }, - TimeLastUpdated: uint64(i), - CreationTime: uint64(i), + TimeLastUpdated: int64(i), + CreationTime: int64(i), } keeper.SetReputation(ctx, strIndex, strIndex, strIndex, items[i]) } diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index 236cd6c538..6cf7929650 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -4,6 +4,15 @@ import ( "fmt" "cosmossdk.io/math" + "github.com/lavanet/lava/utils" +) + +var ( + // default QoS score is: score = 1.25, var = 0 + DefaultQosScore = QosScore{ + Score: Frac{Num: math.LegacyNewDec(5), Denom: math.LegacyNewDec(4)}, + Variance: Frac{Num: math.LegacyZeroDec(), Denom: math.LegacySmallestDec()}, + } ) func NewFrac(num math.LegacyDec, denom math.LegacyDec) (Frac, error) { @@ -17,6 +26,14 @@ func (f Frac) Equal(other Frac) bool { return f.Num.Equal(other.Num) && f.Denom.Equal(other.Denom) } +func (f Frac) Resolve() (math.LegacyDec, error) { + if f.Denom.IsZero() { + return math.LegacyZeroDec(), utils.LavaFormatError("Frac Resolve: resolve failed", fmt.Errorf("frac has zero denom")) + } + + return f.Num.Quo(f.Denom), nil +} + func NewQosScore(score Frac, variance Frac) QosScore { return QosScore{Score: score, Variance: variance} } diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 7c6bccc9e5..7e989f331a 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -3,9 +3,7 @@ package types import ( "cosmossdk.io/collections" "cosmossdk.io/collections/indexes" - "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/lavanet/lava/utils" ) var ( @@ -14,6 +12,8 @@ var ( ReputationRefKeysIteratorPrefix = collections.NewPrefix([]byte("ReputationRefKeysIterator/")) ) +// ReputationRefIndexes are defined as a "multi" index that can reference several reputations +// The ref indices are chain+cluser. The primary indices are chain+cluster+provider. type ReputationRefIndexes struct { Index *indexes.Multi[collections.Pair[string, string], collections.Triple[string, string, string], Reputation] } @@ -34,22 +34,19 @@ func NewReputationRefIndexes(sb *collections.SchemaBuilder) ReputationRefIndexes } } +// ReputationKey returns a key to the reputations indexed map func ReputationKey(chainID string, cluster string, provider string) collections.Triple[string, string, string] { return collections.Join3(chainID, cluster, provider) } -func NewReputation(ctx sdk.Context) (Reputation, error) { +func NewReputation(ctx sdk.Context) Reputation { timestamp := ctx.BlockTime().UTC().Unix() - zeroFrac, err := NewFrac(math.LegacyZeroDec(), math.LegacyOneDec()) - if err != nil { - return Reputation{}, utils.LavaFormatError("NewReputation: zero Frac creation failed", err) - } return Reputation{ - Score: NewQosScore(zeroFrac, zeroFrac), - EpochScore: NewQosScore(zeroFrac, zeroFrac), - TimeLastUpdated: uint64(timestamp), - CreationTime: uint64(timestamp), - }, nil + Score: DefaultQosScore, + EpochScore: DefaultQosScore, + TimeLastUpdated: timestamp, + CreationTime: timestamp, + } } func (r Reputation) Equal(other Reputation) bool { diff --git a/x/pairing/types/reputation.pb.go b/x/pairing/types/reputation.pb.go index 733235e885..e6446549fa 100644 --- a/x/pairing/types/reputation.pb.go +++ b/x/pairing/types/reputation.pb.go @@ -126,8 +126,8 @@ func (m *QosScore) GetVariance() Frac { type Reputation struct { Score QosScore `protobuf:"bytes,1,opt,name=score,proto3" json:"score"` EpochScore QosScore `protobuf:"bytes,2,opt,name=epoch_score,json=epochScore,proto3" json:"epoch_score"` - TimeLastUpdated uint64 `protobuf:"varint,3,opt,name=time_last_updated,json=timeLastUpdated,proto3" json:"time_last_updated,omitempty"` - CreationTime uint64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` + TimeLastUpdated int64 `protobuf:"varint,3,opt,name=time_last_updated,json=timeLastUpdated,proto3" json:"time_last_updated,omitempty"` + CreationTime int64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` } func (m *Reputation) Reset() { *m = Reputation{} } @@ -177,14 +177,14 @@ func (m *Reputation) GetEpochScore() QosScore { return QosScore{} } -func (m *Reputation) GetTimeLastUpdated() uint64 { +func (m *Reputation) GetTimeLastUpdated() int64 { if m != nil { return m.TimeLastUpdated } return 0 } -func (m *Reputation) GetCreationTime() uint64 { +func (m *Reputation) GetCreationTime() int64 { if m != nil { return m.CreationTime } @@ -242,33 +242,33 @@ func init() { } var fileDescriptor_38105d47def04072 = []byte{ - // 414 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0xc1, 0xaa, 0x13, 0x31, - 0x14, 0x86, 0x27, 0xf7, 0xce, 0x95, 0x6b, 0x5a, 0x11, 0x87, 0x22, 0x43, 0x17, 0xd3, 0x12, 0x51, - 0x8b, 0xe0, 0x0c, 0x28, 0xb8, 0x28, 0x45, 0xb0, 0xa8, 0x2b, 0x11, 0x1d, 0xeb, 0xc6, 0xcd, 0x90, - 0x66, 0xc2, 0x74, 0xb0, 0x49, 0x86, 0x49, 0xa6, 0xd8, 0x9d, 0x8f, 0xe0, 0x83, 0xf8, 0x20, 0x5d, - 0x76, 0x29, 0x2e, 0x4a, 0x69, 0xdf, 0xc0, 0x27, 0x90, 0x24, 0xd3, 0xda, 0x42, 0x17, 0x96, 0xbb, - 0x3a, 0x21, 0xf9, 0xcf, 0x77, 0xfe, 0x73, 0x72, 0xe0, 0xc3, 0x29, 0x9e, 0x61, 0x4e, 0x55, 0xa4, - 0x63, 0x54, 0xe0, 0xbc, 0xcc, 0x79, 0x16, 0x95, 0xb4, 0xa8, 0x14, 0x56, 0xb9, 0xe0, 0x61, 0x51, - 0x0a, 0x25, 0xbc, 0x56, 0x2d, 0x0b, 0x75, 0x0c, 0x6b, 0x59, 0xbb, 0x95, 0x89, 0x4c, 0x18, 0x41, - 0xa4, 0x4f, 0x56, 0x8b, 0x7e, 0x02, 0xe8, 0xbe, 0x2d, 0x31, 0xf1, 0xde, 0xc3, 0x4b, 0x5e, 0x31, - 0x1f, 0x74, 0x41, 0xef, 0xf6, 0x70, 0xb0, 0x58, 0x75, 0x9c, 0xdf, 0xab, 0xce, 0xa3, 0x2c, 0x57, - 0x93, 0x6a, 0x1c, 0x12, 0xc1, 0x22, 0x22, 0x24, 0x13, 0xb2, 0x0e, 0x4f, 0x65, 0xfa, 0x35, 0x52, - 0xf3, 0x82, 0xca, 0xf0, 0x35, 0x25, 0x7f, 0x56, 0x1d, 0x38, 0xc7, 0x6c, 0xda, 0x47, 0xbc, 0x62, - 0x28, 0xd6, 0x20, 0x6f, 0x04, 0xaf, 0x52, 0xca, 0x05, 0xf3, 0x2f, 0x0c, 0xf1, 0xe5, 0xd9, 0xc4, - 0xa6, 0x25, 0x1a, 0x08, 0x8a, 0x2d, 0x0c, 0x7d, 0x07, 0xf0, 0xfa, 0xa3, 0x90, 0x9f, 0x88, 0x28, - 0xa9, 0xf7, 0x02, 0x5e, 0x49, 0x7d, 0x30, 0xa6, 0x1b, 0xcf, 0xda, 0xe1, 0xa9, 0xbe, 0x43, 0xdd, - 0xdd, 0xd0, 0xd5, 0xe5, 0x63, 0x2b, 0xf7, 0x06, 0xf0, 0x7a, 0x86, 0xcb, 0x1c, 0x73, 0x42, 0x8d, - 0xbb, 0xff, 0x49, 0xdd, 0x67, 0xa0, 0x35, 0x80, 0x30, 0xde, 0x8f, 0xdc, 0xeb, 0x1f, 0x9b, 0x08, - 0x4e, 0x93, 0x76, 0x9e, 0x8f, 0x8d, 0xbc, 0x81, 0x0d, 0x5a, 0x08, 0x32, 0x49, 0x2c, 0xe1, 0xe2, - 0x0c, 0x02, 0x34, 0x89, 0x76, 0x0e, 0x4f, 0xe0, 0x3d, 0x95, 0x33, 0x9a, 0x4c, 0xb1, 0x54, 0x49, - 0x55, 0xa4, 0x58, 0xd1, 0xd4, 0xbf, 0xec, 0x82, 0x9e, 0x1b, 0xdf, 0xd5, 0x0f, 0xef, 0xb0, 0x54, - 0x9f, 0xed, 0xb5, 0xf7, 0x00, 0xde, 0x21, 0x25, 0x35, 0xd6, 0x13, 0xfd, 0xe6, 0xbb, 0x46, 0xd7, - 0xdc, 0x5d, 0x8e, 0x72, 0x46, 0x11, 0x87, 0xf7, 0xff, 0x75, 0xf8, 0xc1, 0x1a, 0xb0, 0xa5, 0x46, - 0x87, 0xdd, 0xde, 0xe0, 0x57, 0x0d, 0x04, 0xd5, 0x73, 0x18, 0xbe, 0x5a, 0x6c, 0x02, 0xb0, 0xdc, - 0x04, 0x60, 0xbd, 0x09, 0xc0, 0x8f, 0x6d, 0xe0, 0x2c, 0xb7, 0x81, 0xf3, 0x6b, 0x1b, 0x38, 0x5f, - 0x1e, 0x1f, 0x80, 0x8f, 0x96, 0xff, 0xdb, 0x7e, 0xfd, 0x0d, 0x7d, 0x7c, 0xcb, 0xac, 0xf3, 0xf3, - 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xa3, 0x5c, 0xd7, 0x23, 0x03, 0x00, 0x00, + // 413 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0xc1, 0xca, 0x13, 0x31, + 0x10, 0xc7, 0x37, 0x5f, 0xfb, 0x49, 0x4d, 0x2b, 0xe2, 0x52, 0x64, 0xe9, 0x61, 0x5b, 0x22, 0x6a, + 0x11, 0xdc, 0x05, 0x05, 0x0f, 0xa5, 0x08, 0x16, 0xf5, 0x24, 0xa2, 0x6b, 0xbd, 0x78, 0x59, 0xd2, + 0x6c, 0xd8, 0x2e, 0x36, 0xc9, 0xb2, 0xc9, 0x16, 0x7b, 0xf3, 0x11, 0x7c, 0x10, 0x1f, 0xa4, 0xc7, + 0x1e, 0xc5, 0x43, 0x29, 0xed, 0x1b, 0xf8, 0x04, 0x92, 0x64, 0x5b, 0x5b, 0xe8, 0xc1, 0xf2, 0x9d, + 0x26, 0x24, 0xff, 0xf9, 0xcd, 0x7f, 0x26, 0x03, 0x1f, 0xce, 0xf0, 0x1c, 0x73, 0xaa, 0x42, 0x1d, + 0xc3, 0x1c, 0x67, 0x45, 0xc6, 0xd3, 0xb0, 0xa0, 0x79, 0xa9, 0xb0, 0xca, 0x04, 0x0f, 0xf2, 0x42, + 0x28, 0xe1, 0xb6, 0x2b, 0x59, 0xa0, 0x63, 0x50, 0xc9, 0x3a, 0xed, 0x54, 0xa4, 0xc2, 0x08, 0x42, + 0x7d, 0xb2, 0x5a, 0xf4, 0x13, 0xc0, 0xfa, 0xdb, 0x02, 0x13, 0xf7, 0x3d, 0xac, 0xf1, 0x92, 0x79, + 0xa0, 0x07, 0xfa, 0xb7, 0x47, 0xc3, 0xe5, 0xba, 0xeb, 0xfc, 0x5e, 0x77, 0x1f, 0xa5, 0x99, 0x9a, + 0x96, 0x93, 0x80, 0x08, 0x16, 0x12, 0x21, 0x99, 0x90, 0x55, 0x78, 0x2a, 0x93, 0xaf, 0xa1, 0x5a, + 0xe4, 0x54, 0x06, 0xaf, 0x29, 0xf9, 0xb3, 0xee, 0xc2, 0x05, 0x66, 0xb3, 0x01, 0xe2, 0x25, 0x43, + 0x91, 0x06, 0xb9, 0x63, 0x78, 0x9d, 0x50, 0x2e, 0x98, 0x77, 0x65, 0x88, 0x2f, 0x2f, 0x26, 0xb6, + 0x2c, 0xd1, 0x40, 0x50, 0x64, 0x61, 0xe8, 0x3b, 0x80, 0x8d, 0x8f, 0x42, 0x7e, 0x22, 0xa2, 0xa0, + 0xee, 0x0b, 0x78, 0x2d, 0xf5, 0xc1, 0x98, 0x6e, 0x3e, 0xeb, 0x04, 0xe7, 0xfa, 0x0e, 0x74, 0x77, + 0xa3, 0xba, 0x2e, 0x1f, 0x59, 0xb9, 0x3b, 0x84, 0x8d, 0x39, 0x2e, 0x32, 0xcc, 0x09, 0x35, 0xee, + 0xfe, 0x27, 0xf5, 0x90, 0x81, 0x36, 0x00, 0xc2, 0xe8, 0x30, 0x72, 0x77, 0x70, 0x6a, 0xc2, 0x3f, + 0x4f, 0xda, 0x7b, 0x3e, 0x35, 0xf2, 0x06, 0x36, 0x69, 0x2e, 0xc8, 0x34, 0xb6, 0x84, 0xab, 0x0b, + 0x08, 0xd0, 0x24, 0xda, 0x39, 0x3c, 0x81, 0xf7, 0x54, 0xc6, 0x68, 0x3c, 0xc3, 0x52, 0xc5, 0x65, + 0x9e, 0x60, 0x45, 0x13, 0xaf, 0xd6, 0x03, 0xfd, 0x5a, 0x74, 0x57, 0x3f, 0xbc, 0xc3, 0x52, 0x7d, + 0xb6, 0xd7, 0xee, 0x03, 0x78, 0x87, 0x14, 0xd4, 0x58, 0x8f, 0xf5, 0x9b, 0x57, 0x37, 0xba, 0xd6, + 0xfe, 0x72, 0x9c, 0x31, 0x8a, 0x38, 0xbc, 0xff, 0xaf, 0xc3, 0x0f, 0xd6, 0x80, 0x2d, 0x35, 0x3e, + 0xee, 0xf6, 0x06, 0xbf, 0x6a, 0x20, 0xa8, 0x9a, 0xc3, 0xe8, 0xd5, 0x72, 0xeb, 0x83, 0xd5, 0xd6, + 0x07, 0x9b, 0xad, 0x0f, 0x7e, 0xec, 0x7c, 0x67, 0xb5, 0xf3, 0x9d, 0x5f, 0x3b, 0xdf, 0xf9, 0xf2, + 0xf8, 0x08, 0x7c, 0xb2, 0xfc, 0xdf, 0x0e, 0xeb, 0x6f, 0xe8, 0x93, 0x5b, 0x66, 0x9d, 0x9f, 0xff, + 0x0d, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xdc, 0xeb, 0x16, 0x23, 0x03, 0x00, 0x00, } func (m *Frac) Marshal() (dAtA []byte, err error) { @@ -859,7 +859,7 @@ func (m *Reputation) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.TimeLastUpdated |= uint64(b&0x7F) << shift + m.TimeLastUpdated |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -878,7 +878,7 @@ func (m *Reputation) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.CreationTime |= uint64(b&0x7F) << shift + m.CreationTime |= int64(b&0x7F) << shift if b < 0x80 { break } From c047f2dc955aa053b151d9f3b584a13c860e466c Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 4 Aug 2024 15:11:48 +0300 Subject: [PATCH 08/66] CNS-1003: add small comment --- x/pairing/types/reputation.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 7e989f331a..9d34cd91cc 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -54,6 +54,7 @@ func (r Reputation) Equal(other Reputation) bool { r.TimeLastUpdated == other.TimeLastUpdated && r.CreationTime == other.CreationTime } +// ReputationScoreKey returns a key for the reputations fixation store (reputationsFS) func ReputationScoreKey(chainID string, cluster string, provider string) string { return chainID + " " + cluster + " " + provider } From 618c0ab18bdb7487df52750b707acd2ea3d7bdbb Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 4 Aug 2024 15:47:17 +0300 Subject: [PATCH 09/66] CNS-1002: report qos excellence for reputation only if consumer geo == provider geo --- protocol/lavasession/consumer_session_manager.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/protocol/lavasession/consumer_session_manager.go b/protocol/lavasession/consumer_session_manager.go index 64d9769ea2..7eacd080ab 100644 --- a/protocol/lavasession/consumer_session_manager.go +++ b/protocol/lavasession/consumer_session_manager.go @@ -534,6 +534,13 @@ func (csm *ConsumerSessionManager) GetSessions(ctx context.Context, cuNeededForS sessions[providerAddress] = sessionInfo qosReport, rawQosReport := csm.providerOptimizer.GetExcellenceQoSReportForProvider(providerAddress) + if csm.rpcEndpoint.Geolocation == uint64(endpoint.endpoint.Geolocation) { + // rawQosReport is used only when building the relay payment message to be used to update + // the provider's reputation on-chain. If the consumer and provider don't share geolocation + // (consumer geo: csm.rpcEndpoint.Geolocation, provider geo: endpoint.endpoint.Geolocation) + // we don't want to update the reputation by it, so we null the rawQosReport + rawQosReport = nil + } consumerSession.SetUsageForSession(cuNeededForSession, qosReport, rawQosReport, usedProviders) // We successfully added provider, we should ignore it if we need to fetch new tempIgnoredProviders.providers[providerAddress] = struct{}{} From 54a01366608e7276c467834d2fb9d3e164cf6c75 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 5 Aug 2024 16:55:18 +0300 Subject: [PATCH 10/66] 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 11/66] 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 8613a693c8523b6ca0bceca6ac9ab930cf7ac912 Mon Sep 17 00:00:00 2001 From: Oren Date: Mon, 5 Aug 2024 17:01:23 +0300 Subject: [PATCH 12/66] CNS-1003: revert change in protoc_grpc_relay.sh --- .../lava-sdk/scripts/protoc_grpc_relay.sh | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ecosystem/lava-sdk/scripts/protoc_grpc_relay.sh b/ecosystem/lava-sdk/scripts/protoc_grpc_relay.sh index 7137a6f7de..b188943dad 100755 --- a/ecosystem/lava-sdk/scripts/protoc_grpc_relay.sh +++ b/ecosystem/lava-sdk/scripts/protoc_grpc_relay.sh @@ -36,20 +36,20 @@ protoc \ --ts_out="service=grpc-web:$OUT_DIR" \ --proto_path="$COSMOS_PROTO_DIR" \ --proto_path="$LAVA_PROTO_DIR" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/pairing/relay.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/pairing/badges.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/pairing/params.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/pairing/query.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/subscription/subscription.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/projects/project.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/plans/policy.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/pairing/epoch_cu.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/spec/spec.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/spec/api_collection.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/epochstorage/stake_entry.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/epochstorage/endpoint.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/conflict/conflict_data.proto" \ - "$LAVA_PROTO_DIR/lavanet/lava/v2/downtime/v1/downtime.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/pairing/relay.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/pairing/badges.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/pairing/params.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/pairing/query.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/subscription/subscription.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/projects/project.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/plans/policy.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/pairing/epoch_cu.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/spec/spec.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/spec/api_collection.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/epochstorage/stake_entry.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/epochstorage/endpoint.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/conflict/conflict_data.proto" \ + "$LAVA_PROTO_DIR/lavanet/lava/downtime/v1/downtime.proto" \ "$COSMOS_PROTO_DIR/gogoproto/gogo.proto" \ "$COSMOS_PROTO_DIR/google/protobuf/descriptor.proto" \ "$COSMOS_PROTO_DIR/google/protobuf/wrappers.proto" \ From 44f6f9bdbceaaf3d6fcbdd445d45b3778a5633cc Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 12:03:45 +0300 Subject: [PATCH 13/66] 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 e79b17cb93079f51de2c2e0e4a4fe4c9a83a2112 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 15:24:05 +0300 Subject: [PATCH 14/66] CNS-1003: add stake to reputation and remove ref indices --- proto/lavanet/lava/pairing/reputation.proto | 3 + x/pairing/keeper/keeper.go | 12 +- x/pairing/keeper/reputation.go | 20 +--- x/pairing/keeper/reputation_test.go | 2 + x/pairing/types/reputation.go | 32 +---- x/pairing/types/reputation.pb.go | 122 +++++++++++++++----- 6 files changed, 105 insertions(+), 86 deletions(-) diff --git a/proto/lavanet/lava/pairing/reputation.proto b/proto/lavanet/lava/pairing/reputation.proto index 04ed59929e..1ea22e235a 100644 --- a/proto/lavanet/lava/pairing/reputation.proto +++ b/proto/lavanet/lava/pairing/reputation.proto @@ -3,6 +3,7 @@ package lavanet.lava.pairing; option go_package = "github.com/lavanet/lava/v2/x/pairing/types"; import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; // Frac is a fracture struct that helps calculating and updating weighted average on the go message Frac { @@ -25,11 +26,13 @@ message QosScore { // with the epoch_score and the epoch_score is reset. // The time_last_updated is used to calculate the appropriate time decay upon update. // The creation_time is used to determine if the variance stabilization period has passed and score can be truncated. +// The stake is used when converting the reputation QoS scores to repuatation pairing score. message Reputation { QosScore score = 1 [(gogoproto.nullable) = false]; QosScore epoch_score = 2 [(gogoproto.nullable) = false]; int64 time_last_updated = 3; int64 creation_time = 4; + cosmos.base.v1beta1.Coin stake = 5 [(gogoproto.nullable) = false]; } // ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index c13c74aa84..ebfadaef7c 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -38,9 +38,8 @@ type ( dualstakingKeeper types.DualstakingKeeper stakingKeeper types.StakingKeeper - schema collections.Schema - reputations *collections.IndexedMap[collections.Triple[string, string, string], types.Reputation, types.ReputationRefIndexes] // save qos info per provider, chain and cluster - reputationRefKeys collections.KeySet[collections.Pair[string, string]] + schema collections.Schema + reputations collections.Map[collections.Triple[string, string, string], types.Reputation] // save qos info per provider, chain and cluster } ) @@ -96,14 +95,9 @@ func NewKeeper( dualstakingKeeper: dualstakingKeeper, stakingKeeper: stakingKeeper, - reputations: collections.NewIndexedMap(sb, types.ReputationPrefix, "reputations", + reputations: collections.NewMap(sb, types.ReputationPrefix, "reputations", collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.StringKey), collcompat.ProtoValue[types.Reputation](cdc), - types.NewReputationRefIndexes(sb), - ), - - reputationRefKeys: collections.NewKeySet(sb, types.ReputationRefKeysPrefix, "reputations_ref_keys", - collections.PairKeyCodec(collections.StringKey, collections.StringKey), ), } diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 5b46bc4fe8..fcc7ee14b0 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -3,7 +3,6 @@ package keeper import ( "fmt" - "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/v2/utils" "github.com/lavanet/lava/v2/x/pairing/types" @@ -14,18 +13,8 @@ import ( Reputation is a provider performance metric calculated using QoS excellence reports that are retrieved from relay payments. Higher reputation improves the provider's chance to be picked in the pairing mechanism. -The reputations are kept within an indexed map called "reputations" in the keeper. An indexed map allows accessing map -entries using two type of keys: primary keys and reference keys. The primary keys are the regular map keys, each point -to a single entry. The reference keys can be of various types: unique, multi, and more. In this case, the reputations -indexed map holds "multi" type reference keys. This means that a single reference key returns a group of entries that -fit the reference key. - -The map's primary keys are a collection of the chain ID, cluster, and the provider address. -The map's reference keys are a collection of the chain ID and cluster. Using a reference key, we can get a group of entries -that share the same chain ID and cluster. - -Since the collections package doesn't support getting the full list of reference keys from an indexed map, we save a KeySet -of the reference keys in the keeper in the "reputationRefKeys" field. +The reputations are kept within a map called "reputations" in the keeper. The map's keys are a collection of the chain ID, +cluster, and the provider address. The reputation's pairing score is kept in the reputations fixation store so pairing queries will be deterministic for past blocks. @@ -60,11 +49,6 @@ func (k Keeper) SetReputation(ctx sdk.Context, chainID string, cluster string, p if err != nil { panic(fmt.Errorf("SetReputation: failed to set entry with key %v, error: %w", key, err)) } - chainClusterKey := collections.Join(chainID, cluster) - err = k.reputationRefKeys.Set(ctx, chainClusterKey) - if err != nil { - panic(err) - } } // RemoveReputation removes a Reputation from the store diff --git a/x/pairing/keeper/reputation_test.go b/x/pairing/keeper/reputation_test.go index d242ebd8b0..a11a64aaa7 100644 --- a/x/pairing/keeper/reputation_test.go +++ b/x/pairing/keeper/reputation_test.go @@ -7,6 +7,7 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" keepertest "github.com/lavanet/lava/v2/testutil/keeper" + commontypes "github.com/lavanet/lava/v2/utils/common/types" "github.com/lavanet/lava/v2/x/pairing/keeper" "github.com/lavanet/lava/v2/x/pairing/types" "github.com/stretchr/testify/require" @@ -28,6 +29,7 @@ func createNReputations(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.R }, TimeLastUpdated: int64(i), CreationTime: int64(i), + Stake: sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(int64(i))), } keeper.SetReputation(ctx, strIndex, strIndex, strIndex, items[i]) } diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 9d34cd91cc..c791cdfdcd 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -2,38 +2,14 @@ package types import ( "cosmossdk.io/collections" - "cosmossdk.io/collections/indexes" sdk "github.com/cosmos/cosmos-sdk/types" + commontypes "github.com/lavanet/lava/v2/utils/common/types" ) var ( - ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) - ReputationRefKeysPrefix = collections.NewPrefix([]byte("ReputationRefKeys/")) - ReputationRefKeysIteratorPrefix = collections.NewPrefix([]byte("ReputationRefKeysIterator/")) + ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) ) -// ReputationRefIndexes are defined as a "multi" index that can reference several reputations -// The ref indices are chain+cluser. The primary indices are chain+cluster+provider. -type ReputationRefIndexes struct { - Index *indexes.Multi[collections.Pair[string, string], collections.Triple[string, string, string], Reputation] -} - -func (rri ReputationRefIndexes) IndexesList() []collections.Index[collections.Triple[string, string, string], Reputation] { - return []collections.Index[collections.Triple[string, string, string], Reputation]{rri.Index} -} - -func NewReputationRefIndexes(sb *collections.SchemaBuilder) ReputationRefIndexes { - return ReputationRefIndexes{ - Index: indexes.NewMulti(sb, ReputationRefKeysIteratorPrefix, "reputation_ref_keys_iterator", - collections.PairKeyCodec(collections.StringKey, collections.StringKey), - collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.StringKey), - func(pk collections.Triple[string, string, string], _ Reputation) (collections.Pair[string, string], error) { - return collections.Join(pk.K1(), pk.K2()), nil - }, - ), - } -} - // ReputationKey returns a key to the reputations indexed map func ReputationKey(chainID string, cluster string, provider string) collections.Triple[string, string, string] { return collections.Join3(chainID, cluster, provider) @@ -46,12 +22,14 @@ func NewReputation(ctx sdk.Context) Reputation { EpochScore: DefaultQosScore, TimeLastUpdated: timestamp, CreationTime: timestamp, + Stake: sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()), } } func (r Reputation) Equal(other Reputation) bool { return r.Score.Equal(other.Score) && r.EpochScore.Equal(other.EpochScore) && - r.TimeLastUpdated == other.TimeLastUpdated && r.CreationTime == other.CreationTime + r.TimeLastUpdated == other.TimeLastUpdated && r.CreationTime == other.CreationTime && + r.Stake.IsEqual(other.Stake) } // ReputationScoreKey returns a key for the reputations fixation store (reputationsFS) diff --git a/x/pairing/types/reputation.pb.go b/x/pairing/types/reputation.pb.go index 81870e8aa3..fcc2058979 100644 --- a/x/pairing/types/reputation.pb.go +++ b/x/pairing/types/reputation.pb.go @@ -6,6 +6,7 @@ package types import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" @@ -123,11 +124,13 @@ func (m *QosScore) GetVariance() Frac { // with the epoch_score and the epoch_score is reset. // The time_last_updated is used to calculate the appropriate time decay upon update. // The creation_time is used to determine if the variance stabilization period has passed and score can be truncated. +// The stake is used when converting the reputation QoS scores to repuatation pairing score. type Reputation struct { - Score QosScore `protobuf:"bytes,1,opt,name=score,proto3" json:"score"` - EpochScore QosScore `protobuf:"bytes,2,opt,name=epoch_score,json=epochScore,proto3" json:"epoch_score"` - TimeLastUpdated int64 `protobuf:"varint,3,opt,name=time_last_updated,json=timeLastUpdated,proto3" json:"time_last_updated,omitempty"` - CreationTime int64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` + Score QosScore `protobuf:"bytes,1,opt,name=score,proto3" json:"score"` + EpochScore QosScore `protobuf:"bytes,2,opt,name=epoch_score,json=epochScore,proto3" json:"epoch_score"` + TimeLastUpdated int64 `protobuf:"varint,3,opt,name=time_last_updated,json=timeLastUpdated,proto3" json:"time_last_updated,omitempty"` + CreationTime int64 `protobuf:"varint,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` + Stake types.Coin `protobuf:"bytes,5,opt,name=stake,proto3" json:"stake"` } func (m *Reputation) Reset() { *m = Reputation{} } @@ -191,6 +194,13 @@ func (m *Reputation) GetCreationTime() int64 { return 0 } +func (m *Reputation) GetStake() types.Coin { + if m != nil { + return m.Stake + } + return types.Coin{} +} + // ReputationPairingScore holds the reputation pairing score used by the reputation pairing requirement. // The score is ranged between [0.5-2]. It's kept in the reputations fixation store with a provider+chain+cluster key. type ReputationPairingScore struct { @@ -242,34 +252,37 @@ func init() { } var fileDescriptor_38105d47def04072 = []byte{ - // 417 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x93, 0xc1, 0xaa, 0xd3, 0x40, - 0x14, 0x86, 0x33, 0xb7, 0xbd, 0x72, 0x9d, 0x7b, 0x45, 0x0c, 0x45, 0x42, 0x17, 0x69, 0x19, 0x51, - 0x4a, 0xc1, 0x04, 0x2a, 0xb8, 0x28, 0xc5, 0x45, 0xa9, 0xae, 0x44, 0x34, 0xd6, 0x8d, 0x9b, 0x30, - 0x9d, 0x0c, 0x69, 0xb0, 0x33, 0x13, 0x32, 0x93, 0x62, 0x77, 0x3e, 0x82, 0x0f, 0xe2, 0x83, 0x74, - 0xd9, 0xa5, 0xb8, 0x28, 0xa5, 0x7d, 0x03, 0x9f, 0x40, 0x66, 0x26, 0xad, 0x2d, 0x74, 0x61, 0x71, - 0x75, 0x86, 0x99, 0xff, 0x7c, 0xe7, 0x3f, 0x27, 0x27, 0xf0, 0xe9, 0x0c, 0xcf, 0x31, 0xa7, 0x2a, - 0xd4, 0x31, 0xcc, 0x71, 0x56, 0x64, 0x3c, 0x0d, 0x0b, 0x9a, 0x97, 0x0a, 0xab, 0x4c, 0xf0, 0x20, - 0x2f, 0x84, 0x12, 0x6e, 0xa3, 0x92, 0x05, 0x3a, 0x06, 0x95, 0xac, 0xd9, 0x48, 0x45, 0x2a, 0x8c, - 0x20, 0xd4, 0x27, 0xab, 0x45, 0x3f, 0x00, 0xac, 0xbf, 0x29, 0x30, 0x71, 0xdf, 0xc1, 0x1a, 0x2f, - 0x99, 0x07, 0xda, 0xa0, 0x73, 0x7f, 0x38, 0x58, 0xae, 0x5b, 0xce, 0xaf, 0x75, 0xeb, 0x59, 0x9a, - 0xa9, 0x69, 0x39, 0x09, 0x88, 0x60, 0x21, 0x11, 0x92, 0x09, 0x59, 0x85, 0xe7, 0x32, 0xf9, 0x12, - 0xaa, 0x45, 0x4e, 0x65, 0x30, 0xa2, 0xe4, 0xf7, 0xba, 0x05, 0x17, 0x98, 0xcd, 0xfa, 0x88, 0x97, - 0x0c, 0x45, 0x1a, 0xe4, 0x8e, 0xe1, 0x75, 0x42, 0xb9, 0x60, 0xde, 0x95, 0x21, 0xbe, 0xba, 0x98, - 0x78, 0x67, 0x89, 0x06, 0x82, 0x22, 0x0b, 0x43, 0xdf, 0x00, 0xbc, 0xf9, 0x20, 0xe4, 0x47, 0x22, - 0x0a, 0xea, 0xbe, 0x84, 0xd7, 0x52, 0x1f, 0x8c, 0xe9, 0xdb, 0x5e, 0x33, 0x38, 0xd7, 0x77, 0xa0, - 0xbb, 0x1b, 0xd6, 0x75, 0xf9, 0xc8, 0xca, 0xdd, 0x01, 0xbc, 0x99, 0xe3, 0x22, 0xc3, 0x9c, 0x50, - 0xe3, 0xee, 0x5f, 0x52, 0x0f, 0x19, 0x68, 0x03, 0x20, 0x8c, 0x0e, 0x23, 0x77, 0xfb, 0xa7, 0x26, - 0xfc, 0xf3, 0xa4, 0xbd, 0xe7, 0x53, 0x23, 0xaf, 0xe1, 0x2d, 0xcd, 0x05, 0x99, 0xc6, 0x96, 0x70, - 0x75, 0x01, 0x01, 0x9a, 0x44, 0x3b, 0x87, 0x2e, 0x7c, 0xa4, 0x32, 0x46, 0xe3, 0x19, 0x96, 0x2a, - 0x2e, 0xf3, 0x04, 0x2b, 0x9a, 0x78, 0xb5, 0x36, 0xe8, 0xd4, 0xa2, 0x87, 0xfa, 0xe1, 0x2d, 0x96, - 0xea, 0x93, 0xbd, 0x76, 0x9f, 0xc0, 0x07, 0xa4, 0xa0, 0xc6, 0x7a, 0xac, 0xdf, 0xbc, 0xba, 0xd1, - 0xdd, 0xed, 0x2f, 0xc7, 0x19, 0xa3, 0x88, 0xc3, 0xc7, 0x7f, 0x3b, 0x7c, 0x6f, 0x0d, 0xd8, 0x52, - 0xe3, 0xe3, 0x6e, 0xff, 0xe3, 0xab, 0x1a, 0x08, 0xaa, 0xe6, 0x30, 0x1c, 0x2d, 0xb7, 0x3e, 0x58, - 0x6d, 0x7d, 0xb0, 0xd9, 0xfa, 0xe0, 0xfb, 0xce, 0x77, 0x56, 0x3b, 0xdf, 0xf9, 0xb9, 0xf3, 0x9d, - 0xcf, 0xdd, 0x23, 0xf0, 0xc9, 0xf2, 0xcf, 0x7b, 0xe1, 0xd7, 0xc3, 0x1f, 0x60, 0x0a, 0x4c, 0xee, - 0x99, 0x8d, 0x7e, 0xf1, 0x27, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xb8, 0x05, 0x47, 0x26, 0x03, 0x00, - 0x00, + // 466 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x93, 0xcf, 0x6a, 0x54, 0x31, + 0x14, 0xc6, 0xe7, 0xce, 0x1f, 0xa9, 0xa7, 0x15, 0xf1, 0x52, 0xe4, 0x3a, 0x8b, 0x4c, 0x89, 0x28, + 0xa5, 0x60, 0x42, 0x2b, 0xba, 0x28, 0xc5, 0xc5, 0x58, 0x5d, 0x89, 0xe8, 0x75, 0xdc, 0xb8, 0x19, + 0x32, 0x99, 0x30, 0x0d, 0x9d, 0x24, 0x97, 0x9b, 0xdc, 0xc1, 0xee, 0x7c, 0x04, 0x77, 0xbe, 0x84, + 0x0f, 0xd2, 0x65, 0x97, 0xe2, 0x62, 0x90, 0x99, 0x37, 0xf0, 0x09, 0x24, 0xc9, 0xed, 0xd8, 0x81, + 0x2e, 0x2c, 0xae, 0x4e, 0x48, 0xbe, 0xf3, 0xcb, 0x97, 0x93, 0x73, 0xe0, 0xd1, 0x94, 0xcd, 0x98, + 0x16, 0x8e, 0xfa, 0x48, 0x0b, 0x26, 0x4b, 0xa9, 0x27, 0xb4, 0x14, 0x45, 0xe5, 0x98, 0x93, 0x46, + 0x93, 0xa2, 0x34, 0xce, 0xa4, 0xdb, 0xb5, 0x8c, 0xf8, 0x48, 0x6a, 0x59, 0x77, 0x7b, 0x62, 0x26, + 0x26, 0x08, 0xa8, 0x5f, 0x45, 0x6d, 0x17, 0x71, 0x63, 0x95, 0xb1, 0x74, 0xc4, 0xac, 0xa0, 0xb3, + 0xfd, 0x91, 0x70, 0x6c, 0x9f, 0x72, 0x23, 0x6b, 0x16, 0xfe, 0x9e, 0x40, 0xfb, 0x75, 0xc9, 0x78, + 0xfa, 0x16, 0x5a, 0xba, 0x52, 0x59, 0xb2, 0x93, 0xec, 0xde, 0xee, 0x1f, 0x9d, 0xcf, 0x7b, 0x8d, + 0x9f, 0xf3, 0xde, 0xe3, 0x89, 0x74, 0x27, 0xd5, 0x88, 0x70, 0xa3, 0x68, 0x0d, 0x8a, 0xe1, 0x89, + 0x1d, 0x9f, 0x52, 0x77, 0x56, 0x08, 0x4b, 0x8e, 0x05, 0xff, 0x3d, 0xef, 0xc1, 0x19, 0x53, 0xd3, + 0x43, 0xac, 0x2b, 0x85, 0x73, 0x0f, 0x4a, 0x07, 0xd0, 0x19, 0x0b, 0x6d, 0x54, 0xd6, 0x0c, 0xc4, + 0x17, 0x37, 0x26, 0x6e, 0x45, 0x62, 0x80, 0xe0, 0x3c, 0xc2, 0xf0, 0x97, 0x04, 0x36, 0xde, 0x1b, + 0xfb, 0x81, 0x9b, 0x52, 0xa4, 0xcf, 0xa1, 0x63, 0xfd, 0x22, 0x98, 0xde, 0x3c, 0xe8, 0x92, 0xeb, + 0xea, 0x42, 0xfc, 0xeb, 0xfa, 0x6d, 0x7f, 0x7d, 0x1e, 0xe5, 0xe9, 0x11, 0x6c, 0xcc, 0x58, 0x29, + 0x99, 0xe6, 0x22, 0xb8, 0xfb, 0x97, 0xd4, 0x55, 0x06, 0xfe, 0xd6, 0x04, 0xc8, 0x57, 0x5f, 0x92, + 0x1e, 0xae, 0x9b, 0x40, 0xd7, 0x93, 0x2e, 0x3d, 0xaf, 0x1b, 0x79, 0x05, 0x9b, 0xa2, 0x30, 0xfc, + 0x64, 0x18, 0x09, 0xcd, 0x1b, 0x10, 0x20, 0x24, 0xc6, 0x3a, 0xec, 0xc1, 0x3d, 0x27, 0x95, 0x18, + 0x4e, 0x99, 0x75, 0xc3, 0xaa, 0x18, 0x33, 0x27, 0xc6, 0x59, 0x6b, 0x27, 0xd9, 0x6d, 0xe5, 0x77, + 0xfd, 0xc1, 0x1b, 0x66, 0xdd, 0xc7, 0xb8, 0x9d, 0x3e, 0x84, 0x3b, 0xbc, 0x14, 0xc1, 0xfa, 0xd0, + 0x9f, 0x65, 0xed, 0xa0, 0xdb, 0xba, 0xdc, 0x1c, 0x48, 0x25, 0xd2, 0x67, 0xd0, 0xb1, 0x8e, 0x9d, + 0x8a, 0xac, 0x13, 0x1c, 0x3d, 0x20, 0xf1, 0x8b, 0x88, 0x6f, 0x22, 0x52, 0x37, 0x11, 0x79, 0x69, + 0xa4, 0x5e, 0x3d, 0xc7, 0xab, 0xb1, 0x86, 0xfb, 0x7f, 0x0b, 0xf3, 0x2e, 0xfa, 0x8e, 0x0e, 0x07, + 0x57, 0x8b, 0xf4, 0x1f, 0xcd, 0x10, 0x20, 0xb8, 0x2e, 0x5f, 0xff, 0xf8, 0x7c, 0x81, 0x92, 0x8b, + 0x05, 0x4a, 0x7e, 0x2d, 0x50, 0xf2, 0x75, 0x89, 0x1a, 0x17, 0x4b, 0xd4, 0xf8, 0xb1, 0x44, 0x8d, + 0x4f, 0x7b, 0x57, 0xc0, 0x6b, 0x33, 0x35, 0x3b, 0xa0, 0x9f, 0x57, 0x83, 0x15, 0x2e, 0x18, 0xdd, + 0x0a, 0x83, 0xf0, 0xf4, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5e, 0x36, 0x12, 0x11, 0x7d, 0x03, + 0x00, 0x00, } func (m *Frac) Marshal() (dAtA []byte, err error) { @@ -378,6 +391,16 @@ func (m *Reputation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.Stake.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReputation(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if m.CreationTime != 0 { i = encodeVarintReputation(dAtA, i, uint64(m.CreationTime)) i-- @@ -497,6 +520,8 @@ func (m *Reputation) Size() (n int) { if m.CreationTime != 0 { n += 1 + sovReputation(uint64(m.CreationTime)) } + l = m.Stake.Size() + n += 1 + l + sovReputation(uint64(l)) return n } @@ -884,6 +909,39 @@ func (m *Reputation) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Stake", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReputation + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReputation + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReputation + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Stake.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipReputation(dAtA[iNdEx:]) From 883c25c0c4614333b4edf54dc19322862f57e04f Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 19:36:41 +0300 Subject: [PATCH 15/66] 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 cd3db87034ed95e651954b372e14598b471dfebd Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 19:40:05 +0300 Subject: [PATCH 16/66] CNS-1003: minor changes --- x/pairing/keeper/reputation.go | 14 ++++++++------ x/pairing/keeper/reputation_test.go | 13 ++++++------- x/pairing/types/qos_score.go | 6 ++++++ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index fcc7ee14b0..2dab8b1cc5 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/v2/utils" "github.com/lavanet/lava/v2/x/pairing/types" @@ -92,29 +93,30 @@ func (k Keeper) GetAllReputation(ctx sdk.Context) []types.ReputationGenesis { } // 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 a9b5fc9bc9..3d11a3bd99 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -13,6 +13,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) { From 32a544c6880eae5e2f3449ad8bfc684aaf7081f9 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 6 Aug 2024 19:46:30 +0300 Subject: [PATCH 17/66] 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 18/66] 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 19/66] 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 20/66] 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 21/66] 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 351ce37526ba47a14dbb9589e7d6e6b5f008fdea Mon Sep 17 00:00:00 2001 From: Oren Date: Wed, 7 Aug 2024 16:57:14 +0300 Subject: [PATCH 22/66] CNS-1003: make default QoS score zero --- x/pairing/types/qos_score.go | 6 ------ x/pairing/types/reputation.go | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index 3d11a3bd99..3a3cac71c5 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -8,12 +8,6 @@ import ( ) var ( - // default QoS score is: score = 1.25, var = 0 - DefaultQosScore = QosScore{ - 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()}, diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index c791cdfdcd..5a09cb5ac6 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -18,8 +18,8 @@ func ReputationKey(chainID string, cluster string, provider string) collections. func NewReputation(ctx sdk.Context) Reputation { timestamp := ctx.BlockTime().UTC().Unix() return Reputation{ - Score: DefaultQosScore, - EpochScore: DefaultQosScore, + Score: ZeroQosScore, + EpochScore: ZeroQosScore, TimeLastUpdated: timestamp, CreationTime: timestamp, Stake: sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()), From 36c47b3f0008b6e0be99b9a1fce0d6e37778eff1 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 11 Aug 2024 15:13:48 +0300 Subject: [PATCH 23/66] 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 24/66] 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 25/66] 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 26/66] 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 27/66] 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 28/66] 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 29/66] 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 30/66] 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 31/66] 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 32/66] 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 62eb5c0de131129cd989368f440e61e6a78492c5 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 5 Jan 2025 14:09:11 +0200 Subject: [PATCH 33/66] PR fixes --- testutil/e2e/protocolE2E.go | 6 +++--- x/pairing/keeper/reputation.go | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/testutil/e2e/protocolE2E.go b/testutil/e2e/protocolE2E.go index 61aad8e7ed..669fd03fff 100644 --- a/testutil/e2e/protocolE2E.go +++ b/testutil/e2e/protocolE2E.go @@ -715,10 +715,10 @@ func restTests(rpcURL string, testDuration time.Duration) error { errors := []string{} mostImportantApisToTest := []string{ "%s/cosmos/base/tendermint/v1beta1/blocks/latest", - "%s/lavanet/lava/v2/pairing/providers/LAV1", - "%s/lavanet/lava/v2/pairing/clients/LAV1", + "%s/lavanet/lava/pairing/providers/LAV1", + "%s/lavanet/lava/pairing/clients/LAV1", "%s/cosmos/gov/v1beta1/proposals", - "%s/lavanet/lava/v2/spec/spec", + "%s/lavanet/lava/spec/spec", "%s/cosmos/base/tendermint/v1beta1/blocks/1", } for start := time.Now(); time.Since(start) < testDuration; { diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 6c271366de..8109c2a222 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -24,7 +24,12 @@ 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 + // dummy values + return types.QualityOfServiceReport{ + Latency: sdk.NewDecWithPrec(1, 1), + Sync: sdk.NewDecWithPrec(1, 1), + Availability: sdk.NewDecWithPrec(1, 1), + }, nil } // GetReputation gets a Reputation from the store From 5ad9aaed01322d63d9e93b108410e91fa8aed42a Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 5 Jan 2025 14:33:44 +0200 Subject: [PATCH 34/66] 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 35/66] 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 36/66] 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 37/66] 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 38/66] 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 39/66] 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 40/66] 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 c30845ff370db3f68c925aaa2d27e08d36344c14 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 7 Jan 2025 11:29:08 +0200 Subject: [PATCH 41/66] fix lint and unit test --- x/pairing/keeper/reputation_test.go | 2 -- x/pairing/types/qos_score.go | 12 +++++------- x/pairing/types/reputation.go | 4 +--- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/x/pairing/keeper/reputation_test.go b/x/pairing/keeper/reputation_test.go index 6646e25081..b20b09b906 100644 --- a/x/pairing/keeper/reputation_test.go +++ b/x/pairing/keeper/reputation_test.go @@ -59,8 +59,6 @@ func TestRemoveReputation(t *testing.T) { _, found := keeper.GetReputation(ctx, strIndex, strIndex, strIndex) require.False(t, found) } - - require.Panics(t, func() { keeper.RemoveReputation(ctx, "dummy", "dummy", "dummy") }) } func TestGetAllReputations(t *testing.T) { diff --git a/x/pairing/types/qos_score.go b/x/pairing/types/qos_score.go index bcc3dd1440..eac0175d0a 100644 --- a/x/pairing/types/qos_score.go +++ b/x/pairing/types/qos_score.go @@ -7,13 +7,11 @@ import ( "github.com/lavanet/lava/v4/utils" ) -var ( - // 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()}, - } -) +// zero QoS score is: score = 0, var = 0 +var 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) { if denom.Equal(math.LegacyZeroDec()) { diff --git a/x/pairing/types/reputation.go b/x/pairing/types/reputation.go index 27a68dbe6c..5043b7ef56 100644 --- a/x/pairing/types/reputation.go +++ b/x/pairing/types/reputation.go @@ -6,9 +6,7 @@ import ( commontypes "github.com/lavanet/lava/v4/utils/common/types" ) -var ( - ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) -) +var ReputationPrefix = collections.NewPrefix([]byte("Reputation/")) // ReputationKey returns a key to the reputations indexed map func ReputationKey(chainID string, cluster string, provider string) collections.Triple[string, string, string] { From 0ccad7cd3e2a2142e3bafefa775e61c0e6b7f688 Mon Sep 17 00:00:00 2001 From: Oren Date: Tue, 7 Jan 2025 11:32:00 +0200 Subject: [PATCH 42/66] comment fix --- x/pairing/keeper/keeper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index faa54e0e0a..e9cbc00f11 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -40,7 +40,7 @@ type ( stakingKeeper types.StakingKeeper schema collections.Schema - reputations collections.Map[collections.Triple[string, string, string], types.Reputation] // save qos info per provider, chain and cluster + reputations collections.Map[collections.Triple[string, string, string], types.Reputation] // save qos info per chain, cluster, provider pairingQueryCache *map[string][]epochstoragetypes.StakeEntry } ) From 600464ddc1ad42a235fc4161a7149733d4656a28 Mon Sep 17 00:00:00 2001 From: Oren Date: Thu, 9 Jan 2025 16:13:01 +0200 Subject: [PATCH 43/66] 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 44/66] 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 45/66] 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 62190435df5f2b33e55bb59192b5bb04fb17e00c Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 12 Jan 2025 13:40:59 +0200 Subject: [PATCH 46/66] delete pairing query cache --- x/pairing/keeper/keeper.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index e9cbc00f11..dfa580dc72 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -7,7 +7,6 @@ import ( collcompat "github.com/lavanet/lava/v4/utils/collcompat" storetypes "github.com/cosmos/cosmos-sdk/store/types" - epochstoragetypes "github.com/lavanet/lava/v4/x/epochstorage/types" timerstoretypes "github.com/lavanet/lava/v4/x/timerstore/types" "github.com/cometbft/cometbft/libs/log" @@ -39,9 +38,8 @@ type ( dualstakingKeeper types.DualstakingKeeper stakingKeeper types.StakingKeeper - schema collections.Schema - reputations collections.Map[collections.Triple[string, string, string], types.Reputation] // save qos info per chain, cluster, provider - pairingQueryCache *map[string][]epochstoragetypes.StakeEntry + schema collections.Schema + reputations collections.Map[collections.Triple[string, string, string], types.Reputation] // save qos info per chain, cluster, provider } ) @@ -80,7 +78,6 @@ func NewKeeper( } sb := collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)) - emptypairingQueryCache := map[string][]epochstoragetypes.StakeEntry{} keeper := &Keeper{ cdc: cdc, @@ -102,7 +99,6 @@ func NewKeeper( collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.StringKey), collcompat.ProtoValue[types.Reputation](cdc), ), - pairingQueryCache: &emptypairingQueryCache, } // note that the timer and badgeUsedCu keys are the same (so we can use only the second arg) From 87fb3405266d441a56787a656792a486969d2983 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 12 Jan 2025 13:44:48 +0200 Subject: [PATCH 47/66] 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 48/66] 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 49/66] 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 50/66] 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 } From 03ceff2f2acc101586172c4b83a7ddb62b705987 Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 13:22:06 +0100 Subject: [PATCH 51/66] Adding endpoints support for auth --- protocol/common/endpoints.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/protocol/common/endpoints.go b/protocol/common/endpoints.go index 2379512708..098b301b57 100644 --- a/protocol/common/endpoints.go +++ b/protocol/common/endpoints.go @@ -91,6 +91,10 @@ func (nurl *NodeUrl) UrlStr() string { return parsedURL.String() } +func (url *NodeUrl) GetAuthHeaders() map[string]string { + return url.AuthConfig.AuthHeaders +} + func (url *NodeUrl) SetAuthHeaders(ctx context.Context, headerSetter func(string, string)) { for header, headerValue := range url.AuthConfig.AuthHeaders { headerSetter(header, headerValue) From 81cc0ab31de75d484a1c5b89835041698e118ad8 Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 13:22:16 +0100 Subject: [PATCH 52/66] fixing chain router test --- protocol/chainlib/chain_router_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/chainlib/chain_router_test.go b/protocol/chainlib/chain_router_test.go index db1b9fa8d6..e2fe5e1c0a 100644 --- a/protocol/chainlib/chain_router_test.go +++ b/protocol/chainlib/chain_router_test.go @@ -1175,8 +1175,8 @@ func TestMain(m *testing.M) { listener := createRPCServer() for { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - _, err := rpcclient.DialContext(ctx, listenerAddressHttp) - _, err2 := rpcclient.DialContext(ctx, listenerAddressWs) + _, err := rpcclient.DialContext(ctx, listenerAddressHttp, nil) + _, err2 := rpcclient.DialContext(ctx, listenerAddressWs, nil) if err2 != nil { utils.LavaFormatDebug("waiting for grpc server to launch") continue From 2d37d0bb9bbf2f05937a54d8b0946c37f675761b Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 13:22:28 +0100 Subject: [PATCH 53/66] adding connector capabilities for ws auth --- protocol/chainlib/chainproxy/connector.go | 27 ++++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/protocol/chainlib/chainproxy/connector.go b/protocol/chainlib/chainproxy/connector.go index 307f86915a..f5c7d51ff7 100644 --- a/protocol/chainlib/chainproxy/connector.go +++ b/protocol/chainlib/chainproxy/connector.go @@ -107,6 +107,18 @@ func (connector *Connector) numberOfUsedClients() int { return int(atomic.LoadInt64(&connector.usedClients)) } +func (connector *Connector) getRpcClient(ctx context.Context, nodeUrl common.NodeUrl) (*rpcclient.Client, error) { + authPathNodeUrl := nodeUrl.AuthConfig.AddAuthPath(nodeUrl.Url) + // origin used for auth header in the websocket case + authHeaders := nodeUrl.GetAuthHeaders() + rpcClient, err := rpcclient.DialContext(ctx, authPathNodeUrl, authHeaders) + if err != nil { + return nil, err + } + nodeUrl.SetAuthHeaders(ctx, rpcClient.SetHeader) + return rpcClient, nil +} + func (connector *Connector) createConnection(ctx context.Context, nodeUrl common.NodeUrl, currentNumberOfConnections int) (*rpcclient.Client, error) { var rpcClient *rpcclient.Client var err error @@ -124,21 +136,13 @@ func (connector *Connector) createConnection(ctx context.Context, nodeUrl common } timeout := common.AverageWorldLatency * (1 + time.Duration(numberOfConnectionAttempts)) nctx, cancel := nodeUrl.LowerContextTimeoutWithDuration(ctx, timeout) - // add auth path - authPathNodeUrl := nodeUrl.AuthConfig.AddAuthPath(nodeUrl.Url) - rpcClient, err = rpcclient.DialContext(nctx, authPathNodeUrl) + // get rpcClient + rpcClient, err = connector.getRpcClient(nctx, nodeUrl) if err != nil { - utils.LavaFormatWarning("Could not connect to the node, retrying", err, []utils.Attribute{ - {Key: "Current Number Of Connections", Value: currentNumberOfConnections}, - {Key: "Network Address", Value: authPathNodeUrl}, - {Key: "Number Of Attempts", Value: numberOfConnectionAttempts}, - {Key: "timeout", Value: timeout}, - }...) cancel() continue } cancel() - nodeUrl.SetAuthHeaders(ctx, rpcClient.SetHeader) break } @@ -178,7 +182,8 @@ func (connector *Connector) increaseNumberOfClients(ctx context.Context, numberO var err error for connectionAttempt := 0; connectionAttempt < MaximumNumberOfParallelConnectionsAttempts; connectionAttempt++ { nctx, cancel := connector.nodeUrl.LowerContextTimeoutWithDuration(ctx, common.AverageWorldLatency*2) - rpcClient, err = rpcclient.DialContext(nctx, connector.nodeUrl.Url) + // get rpcClient + rpcClient, err = connector.getRpcClient(nctx, connector.nodeUrl) if err != nil { utils.LavaFormatDebug( "could no increase number of connections to the node jsonrpc connector, retrying", From 14ee3a2cfb4c91302eea5db37c32457ffdf929cc Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 13:22:45 +0100 Subject: [PATCH 54/66] implementing client capabailities to add headers to websocket connection --- protocol/chainlib/chainproxy/rpcclient/client.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/chainlib/chainproxy/rpcclient/client.go b/protocol/chainlib/chainproxy/rpcclient/client.go index c745f82ee2..15fcdb9b73 100644 --- a/protocol/chainlib/chainproxy/rpcclient/client.go +++ b/protocol/chainlib/chainproxy/rpcclient/client.go @@ -177,14 +177,14 @@ func (op *requestOp) wait(ctx context.Context, c *Client) (*JsonrpcMessage, erro // // The client reconnects automatically if the connection is lost. func Dial(rawurl string) (*Client, error) { - return DialContext(context.Background(), rawurl) + return DialContext(context.Background(), rawurl, nil) } // DialContext creates a new RPC client, just like Dial. // // The context is used to cancel or time out the initial connection establishment. It does // not affect subsequent interactions with the client. -func DialContext(ctx context.Context, rawurl string) (*Client, error) { +func DialContext(ctx context.Context, rawurl string, wsHeaders map[string]string) (*Client, error) { u, err := url.Parse(rawurl) if err != nil { return nil, err @@ -193,7 +193,7 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) { case "http", "https": return DialHTTP(rawurl) case "ws", "wss": - return DialWebsocket(ctx, rawurl, "") + return DialWebsocket(ctx, rawurl, wsHeaders) case "stdio": return DialStdIO(ctx) case "": From 7a1988f8b54ed7eb74cbb4051c504c901e768cac Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 13:22:57 +0100 Subject: [PATCH 55/66] adding websocket capability adding websocket headers on connection --- .../chainlib/chainproxy/rpcclient/websocket.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/protocol/chainlib/chainproxy/rpcclient/websocket.go b/protocol/chainlib/chainproxy/rpcclient/websocket.go index 81566ffe0f..680d37167a 100755 --- a/protocol/chainlib/chainproxy/rpcclient/websocket.go +++ b/protocol/chainlib/chainproxy/rpcclient/websocket.go @@ -187,8 +187,8 @@ func parseOriginURL(origin string) (string, string, string, error) { // DialWebsocketWithDialer creates a new RPC client that communicates with a JSON-RPC server // that is listening on the given endpoint using the provided dialer. -func DialWebsocketWithDialer(ctx context.Context, endpoint, origin string, dialer websocket.Dialer) (*Client, error) { - endpoint, header, err := wsClientHeaders(endpoint, origin) +func DialWebsocketWithDialer(ctx context.Context, endpoint string, dialer websocket.Dialer, headers map[string]string) (*Client, error) { + endpoint, header, err := wsClientHeaders(endpoint, headers) if err != nil { return nil, err } @@ -210,23 +210,23 @@ func DialWebsocketWithDialer(ctx context.Context, endpoint, origin string, diale // // The context is used for the initial connection establishment. It does not // affect subsequent interactions with the client. -func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error) { +func DialWebsocket(ctx context.Context, endpoint string, headers map[string]string) (*Client, error) { dialer := websocket.Dialer{ ReadBufferSize: wsReadBuffer, WriteBufferSize: wsWriteBuffer, WriteBufferPool: wsBufferPool, } - return DialWebsocketWithDialer(ctx, endpoint, origin, dialer) + return DialWebsocketWithDialer(ctx, endpoint, dialer, headers) } -func wsClientHeaders(endpoint, origin string) (string, http.Header, error) { +func wsClientHeaders(endpoint string, headers map[string]string) (string, http.Header, error) { endpointURL, err := url.Parse(endpoint) if err != nil { return endpoint, nil, err } header := make(http.Header) - if origin != "" { - header.Add("origin", origin) + for headerKey, headerValue := range headers { + header.Add(headerKey, headerValue) } if endpointURL.User != nil { b64auth := base64.StdEncoding.EncodeToString([]byte(endpointURL.User.String())) From f8bd4a5342cd304d0812657fff6403e665866d85 Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 13:23:08 +0100 Subject: [PATCH 56/66] implemeting websocket test for auth headers --- .../chainlib/chainproxy/connector_test.go | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/protocol/chainlib/chainproxy/connector_test.go b/protocol/chainlib/chainproxy/connector_test.go index e408ae2062..26a8100425 100644 --- a/protocol/chainlib/chainproxy/connector_test.go +++ b/protocol/chainlib/chainproxy/connector_test.go @@ -2,6 +2,7 @@ package chainproxy import ( "context" + "encoding/json" "fmt" "log" "net" @@ -16,6 +17,7 @@ import ( "github.com/lavanet/lava/v4/utils" pb_pkg "github.com/lavanet/lava/v4/x/spec/types" "github.com/stretchr/testify/require" + "golang.org/x/net/websocket" "google.golang.org/grpc" "google.golang.org/grpc/metadata" ) @@ -185,7 +187,7 @@ func TestMain(m *testing.M) { listener := createRPCServer() for { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - _, err := rpcclient.DialContext(ctx, listenerAddressTcp) + _, err := rpcclient.DialContext(ctx, listenerAddressTcp, nil) if err != nil { utils.LavaFormatDebug("waiting for grpc server to launch") continue @@ -199,3 +201,89 @@ func TestMain(m *testing.M) { listener.Close() os.Exit(code) } + +func TestConnectorWebsocket(t *testing.T) { + // Set up auth headers we expect + expectedAuthHeader := "Bearer test-token" + + // Create WebSocket server with auth check + srv := &http.Server{ + Addr: "localhost:0", // random available port + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check auth header + authHeader := r.Header.Get("Authorization") + if authHeader != expectedAuthHeader { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + fmt.Println("connection OK!") + // Upgrade to websocket + upgrader := websocket.Server{ + Handler: websocket.Handler(func(ws *websocket.Conn) { + defer ws.Close() + // Simple echo server + for { + var msg string + err := websocket.Message.Receive(ws, &msg) + if err != nil { + break + } + websocket.Message.Send(ws, msg) + } + }), + } + upgrader.ServeHTTP(w, r) + }), + } + + // Start server + listener, err := net.Listen("tcp", "localhost:0") + require.NoError(t, err) + defer listener.Close() + + go srv.Serve(listener) + wsURL := "ws://" + listener.Addr().String() + + // Create connector with auth config + ctx := context.Background() + nodeUrl := common.NodeUrl{ + Url: wsURL, + AuthConfig: common.AuthConfig{ + AuthHeaders: map[string]string{ + "Authorization": expectedAuthHeader, + }, + }, + } + + // Create connector + conn, err := NewConnector(ctx, numberOfClients, nodeUrl) + require.NoError(t, err) + defer conn.Close() + + // Wait for connections to be established + for { + if len(conn.freeClients) == numberOfClients { + break + } + time.Sleep(10 * time.Millisecond) + } + + // Get a client and test the connection + client, err := conn.GetRpc(ctx, true) + require.NoError(t, err) + + // Test sending a message using CallContext + params := map[string]interface{}{ + "test": "value", + } + id := json.RawMessage(`1`) + _, err = client.CallContext(ctx, id, "test_method", params, true, true) + require.NoError(t, err) + + // Return the client + conn.ReturnRpc(client) + + // Verify connection pool state + require.Equal(t, int64(0), conn.usedClients) + require.Equal(t, numberOfClients, len(conn.freeClients)) +} From dcc546c8b00e661d5a4df420aacb00ef4a63d8e4 Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Thu, 16 Jan 2025 15:59:08 +0100 Subject: [PATCH 57/66] increase minimum version + protocol version to 4.2.8 / 4.2.1 --- x/protocol/types/params.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index 3bb2ddb633..435bb00d46 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,8 +12,8 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "4.2.7" - MIN_VERSION = "3.1.0" + TARGET_VERSION = "4.2.8" + MIN_VERSION = "4.2.1" ) var ( From 337bbe1874019024a49e11646b384578b622fd95 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 19 Jan 2025 10:11:38 +0200 Subject: [PATCH 58/66] Update go version to match toolchain rule See https://go.dev/doc/toolchain#version --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9f16e3b357..80bb9793f0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/lavanet/lava/v4 -go 1.23 +go 1.23.3 require ( github.com/99designs/keyring v1.2.1 // indirect From 9d39b02cf0cae718c97d66cd05cdb0c82c9be3fa Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 19 Jan 2025 10:47:49 +0200 Subject: [PATCH 59/66] fix lint --- utils/convert.go | 1 + x/pairing/keeper/msg_server_relay_payment_test.go | 2 +- x/pairing/keeper/reputation.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/convert.go b/utils/convert.go index 3a1808bda6..8ec088a7cd 100644 --- a/utils/convert.go +++ b/utils/convert.go @@ -8,6 +8,7 @@ func SafeUint64ToInt64Convert(val uint64) int64 { } return int64(val) } + func Btof(b bool) float64 { if b { return 1 diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index dc21205160..7179fac1bb 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -1618,7 +1618,7 @@ func TestReputationPairingScoreWithinRange(t *testing.T) { // advance epoch to update pairing scores ts.AdvanceEpoch() - // check results are withing the expected range + // check results are within 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) diff --git a/x/pairing/keeper/reputation.go b/x/pairing/keeper/reputation.go index 0a55e6c48a..273603cad6 100644 --- a/x/pairing/keeper/reputation.go +++ b/x/pairing/keeper/reputation.go @@ -286,7 +286,7 @@ func sortProviderScores(scores map[types.ReputationChainClusterKey]StakeProvider // 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 lowest -// score to the heighest (that input stakeProviderScores are sorted). We aggregate the providers stake until +// score to the highest (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) { From 79dd551810f78a2f9ab42dc45c5ee6d145bf0640 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 19 Jan 2025 11:03:00 +0200 Subject: [PATCH 60/66] fix ReputationHalfLifeFactor param validator --- x/pairing/types/params.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/pairing/types/params.go b/x/pairing/types/params.go index 7e65f2d35a..e654bb7073 100644 --- a/x/pairing/types/params.go +++ b/x/pairing/types/params.go @@ -205,7 +205,7 @@ func validateReputationLatencyOverSyncFactor(v interface{}) error { // validateReputationHalfLifeFactor validates the ReputationHalfLifeFactor param func validateReputationHalfLifeFactor(v interface{}) error { - reputationHalfLifeFactor, ok := v.(int64) + reputationHalfLifeFactor, ok := v.(uint64) if !ok { return fmt.Errorf("invalid parameter type: %T", v) } From b303d87a6efeeabee687c19646a68060065a9559 Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 19 Jan 2025 11:24:28 +0200 Subject: [PATCH 61/66] fix exponent func --- utils/math.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/math.go b/utils/math.go index 87737bac64..0631937ab6 100644 --- a/utils/math.go +++ b/utils/math.go @@ -7,7 +7,7 @@ import ( ) const ( - DecayFactorNaturalBaseString = "2.71828182845904523536028747135266249775724709369995957496696763" + DecayFactorNaturalBaseString = "2.718281828459045235" ) func Min[T constraints.Ordered](x, y T) T { @@ -37,15 +37,15 @@ func NaturalBaseExponentFraction(numerator, denominator int64, negative bool) ma e := sdk.MustNewDecFromStr(DecayFactorNaturalBaseString) - // Step 1: Calculate e^a - eToA := e.Power(numeratorUint64) - - // Step 2: Take the bth root - result, err := eToA.ApproxRoot(denominatorUint64) + // Step 1: Take the bth root of e + eRoot, err := e.ApproxRoot(denominatorUint64) if err != nil { panic(err) } + // Step 2: Calculate (e^(1/b))^a + result := eRoot.Power(numeratorUint64) + if negative { // Step 3: Take the reciprocal result = sdk.OneDec().Quo(result) From 349311a1e508794b875ed27d01676dbbbd52f50d Mon Sep 17 00:00:00 2001 From: Oren Date: Sun, 19 Jan 2025 12:21:33 +0200 Subject: [PATCH 62/66] temp fix for invalid qos reports --- protocol/lavaprotocol/request_builder.go | 3 +++ x/pairing/types/QualityOfServiceReport.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/protocol/lavaprotocol/request_builder.go b/protocol/lavaprotocol/request_builder.go index 194d04aba8..aa96ee8730 100644 --- a/protocol/lavaprotocol/request_builder.go +++ b/protocol/lavaprotocol/request_builder.go @@ -74,6 +74,9 @@ func ConstructRelaySession(lavaChainID string, relayRequestData *pairingtypes.Re copiedQOS := copyQoSServiceReport(singleConsumerSession.QoSInfo.LastQoSReport) copiedExcellenceQOS := copyQoSServiceReport(singleConsumerSession.QoSInfo.LastExcellenceQoSReportRaw) // copy raw report for the node + // validate and fix QoS excellence report before sending it to the node + copiedExcellenceQOS.ValidateAndFixQoSExcellence() + return &pairingtypes.RelaySession{ SpecId: chainID, ContentHash: sigs.HashMsg(relayRequestData.GetContentHashData()), diff --git a/x/pairing/types/QualityOfServiceReport.go b/x/pairing/types/QualityOfServiceReport.go index 063a8f8836..1107688549 100644 --- a/x/pairing/types/QualityOfServiceReport.go +++ b/x/pairing/types/QualityOfServiceReport.go @@ -50,3 +50,23 @@ func (qos QualityOfServiceReport) ComputeQosExcellenceForReputation(syncFactor m } return latency.Add(sync).Add(availability), nil } + +// ValidateAndFixQoSExcellence is a temporary function to validate the QoS excellence report +// TODO: remove after the optimizer refactor is merged +func (qos *QualityOfServiceReport) ValidateAndFixQoSExcellence() error { + if qos == nil { + return fmt.Errorf("QoS excellence report is nil") + } + + if qos.Availability.LT(sdk.ZeroDec()) { + qos.Availability = sdk.ZeroDec() + } + if qos.Latency.LT(sdk.ZeroDec()) { + qos.Latency = sdk.ZeroDec() + } + if qos.Sync.LT(sdk.ZeroDec()) { + qos.Sync = sdk.ZeroDec() + } + + return nil +} From 453fce83fe19d9f2d9b715aa32348aa2d5b33f09 Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Mon, 20 Jan 2025 15:34:46 +0200 Subject: [PATCH 63/66] added lava_consumer_provider_blocked metric --- .../lavasession/consumer_session_manager.go | 25 ++++++++++++ protocol/metrics/consumer_metrics_manager.go | 40 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/protocol/lavasession/consumer_session_manager.go b/protocol/lavasession/consumer_session_manager.go index c1e179edde..2b057282b6 100644 --- a/protocol/lavasession/consumer_session_manager.go +++ b/protocol/lavasession/consumer_session_manager.go @@ -102,6 +102,9 @@ func (csm *ConsumerSessionManager) UpdateAllProviders(epoch uint64, pairingList csm.reportedProviders.Reset() csm.pairingAddressesLength = uint64(pairingListLength) csm.numberOfResets = 0 + + providerAddressToEndpoint := map[string]string{} + csm.RemoveAddonAddresses("", nil) // Reset the pairingPurge. // This happens only after an entire epoch. so its impossible to have session connected to the old purged list @@ -111,12 +114,15 @@ func (csm *ConsumerSessionManager) UpdateAllProviders(epoch uint64, pairingList for idx, provider := range pairingList { csm.pairingAddresses[idx] = provider.PublicLavaAddress csm.pairing[provider.PublicLavaAddress] = provider + providerAddressToEndpoint[provider.PublicLavaAddress] = provider.Endpoints[0].NetworkAddress } csm.setValidAddressesToDefaultValue("", nil) // the starting point is that valid addresses are equal to pairing addresses. // reset session related metrics go csm.consumerMetricsManager.ResetSessionRelatedMetrics() go csm.providerOptimizer.UpdateWeights(CalcWeightsByStake(pairingList), epoch) + csm.consumerMetricsManager.ResetBlockedProvidersMetrics(csm.rpcEndpoint.ChainID, csm.rpcEndpoint.ApiInterface, providerAddressToEndpoint) + utils.LavaFormatDebug("updated providers", utils.Attribute{Key: "epoch", Value: epoch}, utils.Attribute{Key: "spec", Value: csm.rpcEndpoint.Key()}) return nil } @@ -820,6 +826,10 @@ func (csm *ConsumerSessionManager) sortBlockedProviderListByCuServed() { // removes a given address from the valid addresses list. func (csm *ConsumerSessionManager) removeAddressFromValidAddresses(address string) error { + info := csm.RPCEndpoint() + chainId := info.ChainID + apiInterface := info.ApiInterface + // cs Must be Locked here. for idx, addr := range csm.validAddresses { if addr == address { @@ -830,6 +840,13 @@ func (csm *ConsumerSessionManager) removeAddressFromValidAddresses(address strin csm.currentlyBlockedProviderAddresses = append(csm.currentlyBlockedProviderAddresses, address) // sort the blocked provider list by cu served csm.sortBlockedProviderListByCuServed() + provider, ok := csm.pairing[addr] + if ok { + go func(networkAddress string) { + csm.consumerMetricsManager.SetBlockedProvider(chainId, apiInterface, addr, networkAddress, true) + }(provider.Endpoints[0].NetworkAddress) + } + return nil } } @@ -995,6 +1012,11 @@ func (csm *ConsumerSessionManager) OnSessionFailure(consumerSession *SingleConsu func (csm *ConsumerSessionManager) validateAndReturnBlockedProviderToValidAddressesList(providerAddress string) { csm.lock.Lock() defer csm.lock.Unlock() + + info := csm.RPCEndpoint() + chainId := info.ChainID + apiInterface := info.ApiInterface + for idx, addr := range csm.currentlyBlockedProviderAddresses { if addr == providerAddress { // Remove it from the csm.currentlyBlockedProviderAddresses @@ -1006,6 +1028,9 @@ func (csm *ConsumerSessionManager) validateAndReturnBlockedProviderToValidAddres // Reset redemption status if provider, ok := csm.pairing[providerAddress]; ok { provider.atomicWriteBlockedStatus(BlockedProviderSessionUnusedStatus) + go func(networkAddress string) { + csm.consumerMetricsManager.SetBlockedProvider(chainId, apiInterface, addr, networkAddress, false) + }(provider.Endpoints[0].NetworkAddress) } return } diff --git a/protocol/metrics/consumer_metrics_manager.go b/protocol/metrics/consumer_metrics_manager.go index bb17287a47..603f04b938 100644 --- a/protocol/metrics/consumer_metrics_manager.go +++ b/protocol/metrics/consumer_metrics_manager.go @@ -54,6 +54,7 @@ type ConsumerMetricsManager struct { latencyMetric *prometheus.GaugeVec qosMetric *MappedLabelsGaugeVec qosExcellenceMetric *MappedLabelsGaugeVec + blockedProviderMetric *MappedLabelsGaugeVec LatestBlockMetric *MappedLabelsGaugeVec LatestProviderRelay *prometheus.GaugeVec virtualEpochMetric *prometheus.GaugeVec @@ -153,6 +154,17 @@ func NewConsumerMetricsManager(options ConsumerMetricsManagerOptions) *ConsumerM Help: "The latency of requests requested by the consumer over time.", }, []string{"spec", "apiInterface"}) + blockedProviderMetricLabels := []string{"spec", "apiInterface", "provider_address"} + if ShowProviderEndpointInMetrics { + blockedProviderMetricLabels = append(blockedProviderMetricLabels, "provider_endpoint") + } + + blockedProviderMetric := NewMappedLabelsGaugeVec(MappedLabelsMetricOpts{ + Name: "lava_consumer_provider_blocked", + Help: "Is provider blocked. 1-blocked, 0-not blocked", + Labels: blockedProviderMetricLabels, + }) + qosMetricLabels := []string{"spec", "apiInterface", "provider_address", "qos_metric"} if ShowProviderEndpointInMetrics { qosMetricLabels = append(qosMetricLabels, "provider_endpoint") @@ -290,6 +302,7 @@ func NewConsumerMetricsManager(options ConsumerMetricsManagerOptions) *ConsumerM latencyMetric: latencyMetric, qosMetric: qosMetric, qosExcellenceMetric: qosExcellenceMetric, + blockedProviderMetric: blockedProviderMetric, LatestBlockMetric: latestBlockMetric, LatestProviderRelay: latestProviderRelay, providerRelays: map[string]uint64{}, @@ -569,6 +582,19 @@ func (pme *ConsumerMetricsManager) ResetSessionRelatedMetrics() { pme.providerRelays = map[string]uint64{} } +func (pme *ConsumerMetricsManager) ResetBlockedProvidersMetrics(chainId, apiInterface string, providers map[string]string) { + if pme == nil { + return + } + + pme.blockedProviderMetric.Reset() + + for provider, endpoint := range providers { + labels := map[string]string{"spec": chainId, "apiInterface": apiInterface, "provider_address": provider, "provider_endpoint": endpoint} + pme.blockedProviderMetric.WithLabelValues(labels).Set(0) + } +} + func (pme *ConsumerMetricsManager) SetVersion(version string) { if pme == nil { return @@ -627,6 +653,20 @@ func (pme *ConsumerMetricsManager) SetLoLResponse(success bool) { } } +func (pme *ConsumerMetricsManager) SetBlockedProvider(chainId, apiInterface, providerAddress, providerEndpoint string, isBlocked bool) { + if pme == nil { + return + } + + var value float64 = 0 + if isBlocked { + value = 1 + } + + labels := map[string]string{"spec": chainId, "apiInterface": apiInterface, "provider_address": providerAddress, "provider_endpoint": providerEndpoint} + pme.blockedProviderMetric.WithLabelValues(labels).Set(value) +} + func (pme *ConsumerMetricsManager) handleOptimizerQoS(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) From be3ae1cee1cb5291b699bb5d6a64f9b485770947 Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Mon, 20 Jan 2025 18:28:06 +0100 Subject: [PATCH 64/66] fixing config to include archive --- .../eth_provider_with_archive_debug_trace.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml b/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml index 8c772143bb..71aee9f790 100644 --- a/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml +++ b/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml @@ -29,4 +29,20 @@ endpoints: - url: ws://my-eth-node.com/eth/archive/ws addons: - trace + - url: http://my-eth-node.com/eth/http/archive + addons: + - debug + - archive + - url: ws://my-eth-node.com/eth/archive/ws + addons: + - debug + - archive + - url: http://my-eth-node.com/eth/http/archive + addons: + - trace + - archive + - url: ws://my-eth-node.com/eth/archive/ws + addons: + - trace + - archive \ No newline at end of file From a74e406254289757d4bc2902d22d99ff0950b9ba Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Mon, 20 Jan 2025 18:28:31 +0100 Subject: [PATCH 65/66] config updated --- .../eth_provider_with_archive_debug_trace.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml b/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml index 71aee9f790..a91298b3cf 100644 --- a/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml +++ b/config/provider_examples/provider_example_cookbook/eth_provider_with_archive_debug_trace.yml @@ -2,6 +2,8 @@ # - archive # - debug # - trace +# - trace + archive +# - debug + archive # ** Replace the urls with your own node urls ** From bdafe1a5c7bb2e2174a5cc1edfd78bbde477c358 Mon Sep 17 00:00:00 2001 From: Ran Mishael Date: Mon, 20 Jan 2025 19:48:08 +0100 Subject: [PATCH 66/66] fix a few issues with locks on metrics --- .../lavasession/consumer_session_manager.go | 27 +++++++------------ protocol/metrics/consumer_metrics_manager.go | 8 +++--- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/protocol/lavasession/consumer_session_manager.go b/protocol/lavasession/consumer_session_manager.go index 2b057282b6..deaf3278eb 100644 --- a/protocol/lavasession/consumer_session_manager.go +++ b/protocol/lavasession/consumer_session_manager.go @@ -120,8 +120,7 @@ func (csm *ConsumerSessionManager) UpdateAllProviders(epoch uint64, pairingList // reset session related metrics go csm.consumerMetricsManager.ResetSessionRelatedMetrics() go csm.providerOptimizer.UpdateWeights(CalcWeightsByStake(pairingList), epoch) - - csm.consumerMetricsManager.ResetBlockedProvidersMetrics(csm.rpcEndpoint.ChainID, csm.rpcEndpoint.ApiInterface, providerAddressToEndpoint) + go csm.consumerMetricsManager.ResetBlockedProvidersMetrics(csm.rpcEndpoint.ChainID, csm.rpcEndpoint.ApiInterface, providerAddressToEndpoint) utils.LavaFormatDebug("updated providers", utils.Attribute{Key: "epoch", Value: epoch}, utils.Attribute{Key: "spec", Value: csm.rpcEndpoint.Key()}) return nil @@ -826,10 +825,6 @@ func (csm *ConsumerSessionManager) sortBlockedProviderListByCuServed() { // removes a given address from the valid addresses list. func (csm *ConsumerSessionManager) removeAddressFromValidAddresses(address string) error { - info := csm.RPCEndpoint() - chainId := info.ChainID - apiInterface := info.ApiInterface - // cs Must be Locked here. for idx, addr := range csm.validAddresses { if addr == address { @@ -842,11 +837,11 @@ func (csm *ConsumerSessionManager) removeAddressFromValidAddresses(address strin csm.sortBlockedProviderListByCuServed() provider, ok := csm.pairing[addr] if ok { - go func(networkAddress string) { - csm.consumerMetricsManager.SetBlockedProvider(chainId, apiInterface, addr, networkAddress, true) - }(provider.Endpoints[0].NetworkAddress) + info := csm.RPCEndpoint() + go func(networkAddress string, chainId string, apiInterface string, providerAddress string) { + csm.consumerMetricsManager.SetBlockedProvider(chainId, apiInterface, providerAddress, networkAddress, true) + }(provider.Endpoints[0].NetworkAddress, info.ChainID, info.ApiInterface, addr) } - return nil } } @@ -1012,11 +1007,6 @@ func (csm *ConsumerSessionManager) OnSessionFailure(consumerSession *SingleConsu func (csm *ConsumerSessionManager) validateAndReturnBlockedProviderToValidAddressesList(providerAddress string) { csm.lock.Lock() defer csm.lock.Unlock() - - info := csm.RPCEndpoint() - chainId := info.ChainID - apiInterface := info.ApiInterface - for idx, addr := range csm.currentlyBlockedProviderAddresses { if addr == providerAddress { // Remove it from the csm.currentlyBlockedProviderAddresses @@ -1027,10 +1017,11 @@ func (csm *ConsumerSessionManager) validateAndReturnBlockedProviderToValidAddres csm.RemoveAddonAddresses("", nil) // Reset redemption status if provider, ok := csm.pairing[providerAddress]; ok { + info := csm.RPCEndpoint() provider.atomicWriteBlockedStatus(BlockedProviderSessionUnusedStatus) - go func(networkAddress string) { - csm.consumerMetricsManager.SetBlockedProvider(chainId, apiInterface, addr, networkAddress, false) - }(provider.Endpoints[0].NetworkAddress) + go func(networkAddress string, chainId string, apiInterface string, providerAddress string) { + csm.consumerMetricsManager.SetBlockedProvider(chainId, apiInterface, providerAddress, networkAddress, false) + }(provider.Endpoints[0].NetworkAddress, info.ChainID, info.ApiInterface, providerAddress) } return } diff --git a/protocol/metrics/consumer_metrics_manager.go b/protocol/metrics/consumer_metrics_manager.go index 603f04b938..fe2487e389 100644 --- a/protocol/metrics/consumer_metrics_manager.go +++ b/protocol/metrics/consumer_metrics_manager.go @@ -586,9 +586,9 @@ func (pme *ConsumerMetricsManager) ResetBlockedProvidersMetrics(chainId, apiInte if pme == nil { return } - + pme.lock.Lock() + defer pme.lock.Unlock() pme.blockedProviderMetric.Reset() - for provider, endpoint := range providers { labels := map[string]string{"spec": chainId, "apiInterface": apiInterface, "provider_address": provider, "provider_endpoint": endpoint} pme.blockedProviderMetric.WithLabelValues(labels).Set(0) @@ -657,13 +657,13 @@ func (pme *ConsumerMetricsManager) SetBlockedProvider(chainId, apiInterface, pro if pme == nil { return } - var value float64 = 0 if isBlocked { value = 1 } - labels := map[string]string{"spec": chainId, "apiInterface": apiInterface, "provider_address": providerAddress, "provider_endpoint": providerEndpoint} + pme.lock.Lock() + defer pme.lock.Unlock() pme.blockedProviderMetric.WithLabelValues(labels).Set(value) }