Skip to content

Commit

Permalink
pr changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Yarom Swisa authored and Yarom Swisa committed Mar 3, 2024
1 parent f06d3ae commit 07f4dff
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 114 deletions.
4 changes: 2 additions & 2 deletions proto/lavanet/lava/rewards/iprpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ option go_package = "github.com/lavanet/lava/x/rewards/types";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";

// list object that holds the
// object that holds the list for iprpc funcs for a specific month id
message IprpcReward {
uint64 id = 1;
uint64 id = 1; // month id
repeated Specfund spec_funds = 2 [(gogoproto.nullable) = false];
}

Expand Down
4 changes: 2 additions & 2 deletions x/pairing/keeper/pairing_next_epoch_time_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (k Keeper) calculateAverageBlockTime(ctx sdk.Context, epoch uint64) (uint64
}

// Calculate the average block time from prevEpochTimestampAndHeightList
averageBlockTime, err := calculateAverageBlockTimeFromList(ctx, prevEpochTimestampAndHeightList, sampleStep)
averageBlockTime, err := calculateAverageBlockTimeFromList(prevEpochTimestampAndHeightList, sampleStep)
if pairingtypes.NotEnoughBlocksToCalculateAverageBlockTimeError.Is(err) || pairingtypes.AverageBlockTimeIsLessOrEqualToZeroError.Is(err) {
// we shouldn't fail the get-pairing query because the average block time calculation failed (to indicate the fail, we return 0)
return 0, nil
Expand Down Expand Up @@ -126,7 +126,7 @@ func (k Keeper) getPreviousEpochTimestampsByHeight(ctx sdk.Context, epoch, sampl
return prevEpochTimestampAndHeightList, nil
}

func calculateAverageBlockTimeFromList(ctx sdk.Context, blockHeightAndTimeList []blockHeightAndTime, sampleStep uint64) (uint64, error) {
func calculateAverageBlockTimeFromList(blockHeightAndTimeList []blockHeightAndTime, sampleStep uint64) (uint64, error) {
if len(blockHeightAndTimeList) <= 1 {
return 0, utils.LavaFormatError("There isn't enough blockHeight structs in the previous epoch to calculate average block time", pairingtypes.NotEnoughBlocksToCalculateAverageBlockTimeError)
}
Expand Down
4 changes: 2 additions & 2 deletions x/pairing/keeper/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin
)
}

endpointsVerified, err := k.validateGeoLocationAndApiInterfaces(ctx, endpoints, geolocation, spec)
endpointsVerified, err := k.validateGeoLocationAndApiInterfaces(endpoints, geolocation, spec)
if err != nil {
return utils.LavaFormatWarning("invalid endpoints implementation for the given spec", err,
utils.Attribute{Key: "provider", Value: creator},
Expand Down Expand Up @@ -201,7 +201,7 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin
return err
}

func (k Keeper) validateGeoLocationAndApiInterfaces(ctx sdk.Context, endpoints []epochstoragetypes.Endpoint, geolocation int32, spec spectypes.Spec) (endpointsFormatted []epochstoragetypes.Endpoint, err error) {
func (k Keeper) validateGeoLocationAndApiInterfaces(endpoints []epochstoragetypes.Endpoint, geolocation int32, spec spectypes.Spec) (endpointsFormatted []epochstoragetypes.Endpoint, err error) {
expectedInterfaces := k.specKeeper.GetExpectedServicesForExpandedSpec(spec, true)
allowedInterfaces := k.specKeeper.GetExpectedServicesForExpandedSpec(spec, false)

Expand Down
4 changes: 2 additions & 2 deletions x/pairing/keeper/unresponsive_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (k Keeper) UnstakeUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCU

// providerPaymentStorageKeyList is not empty -> provider should be punished
if len(providerPaymentStorageKeyList) != 0 && existingProviders[providerStakeEntry.GetChain()] > minProviders {
err = k.punishUnresponsiveProvider(ctx, minPaymentBlock, providerPaymentStorageKeyList, providerStakeEntry.GetAddress(), providerStakeEntry.GetChain(), complaintCU, servicedCU)
err = k.punishUnresponsiveProvider(ctx, providerPaymentStorageKeyList, providerStakeEntry.GetAddress(), providerStakeEntry.GetChain(), complaintCU, servicedCU)
existingProviders[providerStakeEntry.GetChain()]--
if err != nil {
utils.LavaFormatError("unstake unresponsive providers failed to punish provider", err,
Expand Down Expand Up @@ -212,7 +212,7 @@ func (k Keeper) getCurrentProviderStakeStorageList(ctx sdk.Context) []epochstora
}

// Function that punishes providers. Current punishment is freeze
func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epoch uint64, providerPaymentStorageKeyList []string, providerAddress, chainID string, complaintCU uint64, servicedCU uint64) error {
func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, providerPaymentStorageKeyList []string, providerAddress, chainID string, complaintCU uint64, servicedCU uint64) error {
// freeze the unresponsive provider
err := k.FreezeProvider(ctx, providerAddress, []string{chainID}, "unresponsiveness")
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions x/rewards/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState)
for _, iprpcReward := range genState.IprpcRewards {
k.SetIprpcReward(ctx, iprpcReward)
}
k.SetIprpcRewardsCurrent(ctx, genState.IprpcRewardsCurrent)
k.SetIprpcRewardsCurrentId(ctx, genState.IprpcRewardsCurrent)
k.SetIprpcData(ctx, genState.MinIprpcCost, genState.IprpcSubscriptions)
}

Expand All @@ -35,7 +35,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
genesis.IprpcSubscriptions = k.GetAllIprpcSubscription(ctx)
genesis.MinIprpcCost = k.GetMinIprpcCost(ctx)
genesis.IprpcRewards = k.GetAllIprpcReward(ctx)
genesis.IprpcRewardsCurrent = k.GetIprpcRewardsCurrent(ctx)
genesis.IprpcRewardsCurrent = k.GetIprpcRewardsCurrentId(ctx)
// this line is used by starport scaffolding # genesis/module/export

return genesis
Expand Down
97 changes: 27 additions & 70 deletions x/rewards/keeper/iprpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package keeper

import (
"fmt"
"sort"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/lavanet/lava/utils"
Expand All @@ -11,20 +10,15 @@ import (

// handleNoIprpcRewardToProviders handles the situation in which there are no providers to send IPRPC rewards to
// so the IPRPC rewards transfer to the next month
func (k Keeper) handleNoIprpcRewardToProviders(ctx sdk.Context, iprpcReward types.IprpcReward) {
nextMonthIprpcReward, found := k.PopIprpcReward(ctx, false)
nextMonthId := k.GetIprpcRewardsCurrent(ctx)
if !found {
nextMonthIprpcReward = types.IprpcReward{Id: nextMonthId, SpecFunds: iprpcReward.SpecFunds}
} else {
nextMonthIprpcReward.SpecFunds = k.transferSpecFundsToNextMonth(iprpcReward.SpecFunds, nextMonthIprpcReward.SpecFunds)
func (k Keeper) handleNoIprpcRewardToProviders(ctx sdk.Context, iprpcFunds []types.Specfund) {
for _, fund := range iprpcFunds {
k.addSpecFunds(ctx, fund.Spec, fund.Fund, 1)
}
k.SetIprpcReward(ctx, nextMonthIprpcReward)

details := map[string]string{
"transferred_funds": iprpcReward.String(),
"next_month_updated_funds": nextMonthIprpcReward.String(),
"transferred_funds": fmt.Sprint(iprpcFunds),
}
utils.LogLavaEvent(ctx, k.Logger(ctx), types.TransferIprpcRewardToNextMonth, details,
utils.LogLavaEvent(ctx, k.Logger(ctx), types.TransferIprpcRewardToNextMonthEventName, details,
"No provider serviced an IPRPC eligible subscription, transferring current month IPRPC funds to next month")
}

Expand All @@ -34,16 +28,11 @@ func (k Keeper) countIprpcCu(specCuMap map[string]types.SpecCuType, iprpcCu uint
specCu, ok := specCuMap[spec]
if !ok {
specCuMap[spec] = types.SpecCuType{
ProvidersCu: map[string]uint64{provider: iprpcCu},
ProvidersCu: []types.ProviderCuType{{Provider: provider, CU: iprpcCu}},
TotalCu: iprpcCu,
}
} else {
_, ok := specCu.ProvidersCu[provider]
if !ok {
specCu.ProvidersCu[provider] = iprpcCu
} else {
specCu.ProvidersCu[provider] += iprpcCu
}
specCu.ProvidersCu = append(specCu.ProvidersCu, types.ProviderCuType{Provider: provider, CU: iprpcCu})
specCu.TotalCu += iprpcCu
specCuMap[spec] = specCu
}
Expand All @@ -53,7 +42,7 @@ func (k Keeper) countIprpcCu(specCuMap map[string]types.SpecCuType, iprpcCu uint
// AddSpecFunds adds funds for a specific spec for <duration> of months.
// This function is used by the fund-iprpc TX.
func (k Keeper) addSpecFunds(ctx sdk.Context, spec string, fund sdk.Coins, duration uint64) {
startID := k.GetIprpcRewardsCurrent(ctx) + 1 // fund IPRPC only from the next month for <duration> months
startID := k.GetIprpcRewardsCurrentId(ctx) + 1 // fund IPRPC only from the next month for <duration> months
for i := startID; i < startID+duration; i++ {
iprpcReward, found := k.GetIprpcReward(ctx, i)
if found {
Expand All @@ -78,92 +67,60 @@ func (k Keeper) addSpecFunds(ctx sdk.Context, spec string, fund sdk.Coins, durat
}
}

// transferSpecFundsToNextMonth transfer the specFunds to the next month's IPRPC funds
// this function is used when there are no providers that should get the monthly IPRPC reward,
// so the reward transfers to the next month
func (k Keeper) transferSpecFundsToNextMonth(specFunds []types.Specfund, nextMonthSpecFunds []types.Specfund) []types.Specfund {
// Create a slice to store leftover spec funds
var leftoverList []types.Specfund

// Loop through current spec funds
for _, current := range specFunds {
found := false

// Loop through next month spec funds
for i, next := range nextMonthSpecFunds {
// If the spec is found in next month spec funds, merge the funds
if current.Spec == next.Spec {
// Add current month's fund to next month's fund
nextMonthSpecFunds[i].Fund = nextMonthSpecFunds[i].Fund.Add(current.Fund...)
found = true
break
}
}

// If spec is not found in next month spec funds, add it to the merged list
if !found {
leftoverList = append(leftoverList, current)
}
}

// Append any remaining spec funds from next month that were not merged
return append(nextMonthSpecFunds, leftoverList...)
}

// distributeIprpcRewards is distributing the IPRPC rewards for providers according to their serviced CU
func (k Keeper) distributeIprpcRewards(ctx sdk.Context, iprpcReward types.IprpcReward, specCuMap map[string]types.SpecCuType) {
// none of the providers will get the IPRPC reward this month, transfer the funds to the next month
if len(specCuMap) == 0 {
k.handleNoIprpcRewardToProviders(ctx, iprpcReward)
k.handleNoIprpcRewardToProviders(ctx, iprpcReward.SpecFunds)
return
}

usedReward := sdk.NewCoins()
leftovers := sdk.NewCoins()
for _, specFund := range iprpcReward.SpecFunds {
// verify specCuMap holds an entry for the relevant spec
specCu, ok := specCuMap[specFund.Spec]
if !ok {
k.handleNoIprpcRewardToProviders(ctx, []types.Specfund{specFund})
utils.LavaFormatError("did not distribute iprpc rewards to providers in spec", fmt.Errorf("specCU not found"),
utils.LogAttr("spec", specFund.Spec),
utils.LogAttr("rewards", specFund.Fund.String()),
)
continue
}

// collect providers details
providers := []string{}
for provider := range specCu.ProvidersCu {
providers = append(providers, provider)
}
sort.Strings(providers)

UsedReward := sdk.NewCoins()
// distribute IPRPC reward for spec
for _, provider := range providers {
providerAddr, err := sdk.AccAddressFromBech32(provider)
for _, providerCU := range specCu.ProvidersCu {
providerAddr, err := sdk.AccAddressFromBech32(providerCU.Provider)
if err != nil {
continue
}
// calculate provider IPRPC reward
providerIprpcReward := specFund.Fund.MulInt(sdk.NewIntFromUint64(specCu.ProvidersCu[provider])).QuoInt(sdk.NewIntFromUint64(specCu.TotalCu))
providerIprpcReward := specFund.Fund.MulInt(sdk.NewIntFromUint64(providerCU.CU)).QuoInt(sdk.NewIntFromUint64(specCu.TotalCu))

UsedRewardTemp := UsedReward.Add(providerIprpcReward...)
if UsedReward.IsAnyGT(specFund.Fund) {
utils.LavaFormatError("failed to send iprpc rewards to provider", fmt.Errorf("tried to send more rewards than funded"), utils.LogAttr("provider", providerCU))
break
}
UsedReward = UsedRewardTemp

// reward the provider
_, _, err = k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, providerAddr, specFund.Spec, providerIprpcReward, string(types.IprpcPoolName), false, false, false)
if err != nil {
utils.LavaFormatError("failed to send iprpc rewards to provider", err, utils.LogAttr("provider", provider))
utils.LavaFormatError("failed to send iprpc rewards to provider", err, utils.LogAttr("provider", providerCU))
}

usedReward = usedReward.Add(providerIprpcReward...)
}

// count used rewards
usedReward = specFund.Fund.Sub(usedReward...)
leftovers = leftovers.Add(specFund.Fund.Sub(UsedReward...)...)
}

// handle leftovers
err := k.FundCommunityPoolFromModule(ctx, usedReward, string(types.IprpcPoolName))
err := k.FundCommunityPoolFromModule(ctx, leftovers, string(types.IprpcPoolName))
if err != nil {
utils.LavaFormatError("could not send iprpc leftover to community pool", err)
}

utils.LogLavaEvent(ctx, k.Logger(ctx), types.IprpcPoolEmissionEventName, map[string]string{"iprpc_rewards_leftovers": usedReward.String()}, "IPRPC monthly rewards distributed successfully")
utils.LogLavaEvent(ctx, k.Logger(ctx), types.IprpcPoolEmissionEventName, map[string]string{"iprpc_rewards_leftovers": leftovers.String()}, "IPRPC monthly rewards distributed successfully")
}
23 changes: 14 additions & 9 deletions x/rewards/keeper/iprpc_reward.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
"github.com/lavanet/lava/x/rewards/types"
)

// GetIprpcRewardsCurrent get the total number of IprpcReward
func (k Keeper) GetIprpcRewardsCurrent(ctx sdk.Context) uint64 {
// GetIprpcRewardsCurrentId get the total number of IprpcReward
func (k Keeper) GetIprpcRewardsCurrentId(ctx sdk.Context) uint64 {
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
byteKey := types.KeyPrefix(types.IprpcRewardsCurrentPrefix)
bz := store.Get(byteKey)
Expand All @@ -23,8 +23,8 @@ func (k Keeper) GetIprpcRewardsCurrent(ctx sdk.Context) uint64 {
return binary.BigEndian.Uint64(bz)
}

// SetIprpcRewardsCurrent set the total number of IprpcReward
func (k Keeper) SetIprpcRewardsCurrent(ctx sdk.Context, current uint64) {
// SetIprpcRewardsCurrentId set the total number of IprpcReward
func (k Keeper) SetIprpcRewardsCurrentId(ctx sdk.Context, current uint64) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
byteKey := types.KeyPrefix(types.IprpcRewardsCurrentPrefix)
bz := make([]byte, 8)
Expand Down Expand Up @@ -85,10 +85,15 @@ func GetIprpcRewardIDFromBytes(bz []byte) uint64 {
}

// PopIprpcReward gets the lowest id IprpcReward object and removes it
func (k Keeper) PopIprpcReward(ctx sdk.Context, advanceCurrent bool) (types.IprpcReward, bool) {
current := k.GetIprpcRewardsCurrent(ctx)
if advanceCurrent {
k.SetIprpcRewardsCurrent(ctx, current+1)
}
func (k Keeper) PopIprpcReward(ctx sdk.Context) (types.IprpcReward, bool) {
current := k.GetIprpcRewardsCurrentId(ctx)
k.SetIprpcRewardsCurrentId(ctx, current+1)
defer k.RemoveIprpcReward(ctx, current)
return k.GetIprpcReward(ctx, current)
}

// GetCurrentIprpcReward gets the lowest id IprpcReward object
func (k Keeper) GetCurrentIprpcReward(ctx sdk.Context) (types.IprpcReward, bool) {
current := k.GetIprpcRewardsCurrentId(ctx)
return k.GetIprpcReward(ctx, current)
}
9 changes: 6 additions & 3 deletions x/rewards/keeper/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import (

const DAY_SECONDS = 60 * 60 * 24

func (k Keeper) AggregateCU(ctx sdk.Context, provider string, chainID string, cu uint64) {
func (k Keeper) AggregateCU(ctx sdk.Context, subscription, provider string, chainID string, cu uint64) {
if !k.IsIprpcSubscription(ctx, subscription) {
return
}

index := types.BasePayIndex{Provider: provider, ChainID: chainID}
basepay, found := k.getBasePay(ctx, index)
if !found {
Expand Down Expand Up @@ -98,12 +102,11 @@ func (k Keeper) distributeMonthlyBonusRewards(ctx sdk.Context) {
}

// Get current month IprpcReward and use it to distribute rewards
iprpcReward, found := k.PopIprpcReward(ctx, true)
iprpcReward, found := k.PopIprpcReward(ctx)
if !found {
utils.LavaFormatError("current month iprpc reward not found", fmt.Errorf("did not reward providers IPRPC bonus"))
return
}
k.RemoveIprpcReward(ctx, iprpcReward.Id)

// distribute IPRPC rewards
k.distributeIprpcRewards(ctx, iprpcReward, specCuMap)
Expand Down
13 changes: 7 additions & 6 deletions x/rewards/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ const DefaultIndex uint64 = 1
func DefaultGenesis() *GenesisState {
return &GenesisState{
// this line is used by starport scaffolding # genesis/types/default
Params: DefaultParams(),
RefillRewardsTS: *types.DefaultGenesis(),
BasePays: []BasePayGenesis{},
IprpcSubscriptions: []string{},
MinIprpcCost: sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()),
IprpcRewards: []IprpcReward{},
Params: DefaultParams(),
RefillRewardsTS: *types.DefaultGenesis(),
BasePays: []BasePayGenesis{},
IprpcSubscriptions: []string{},
MinIprpcCost: sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()),
IprpcRewards: []IprpcReward{},
IprpcRewardsCurrent: 0,
}
}

Expand Down
13 changes: 7 additions & 6 deletions x/rewards/types/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ func TestGenesisState_Validate(t *testing.T) {
{
desc: "invalid iprpc subscriptions",
genState: &types.GenesisState{
Params: types.DefaultParams(),
RefillRewardsTS: types.DefaultGenesis().RefillRewardsTS,
BasePays: types.DefaultGenesis().BasePays,
IprpcSubscriptions: []string{"invalidAddress"},
MinIprpcCost: types.DefaultGenesis().MinIprpcCost,
IprpcRewards: types.DefaultGenesis().IprpcRewards,
Params: types.DefaultParams(),
RefillRewardsTS: types.DefaultGenesis().RefillRewardsTS,
BasePays: types.DefaultGenesis().BasePays,
IprpcSubscriptions: []string{"invalidAddress"},
MinIprpcCost: types.DefaultGenesis().MinIprpcCost,
IprpcRewards: types.DefaultGenesis().IprpcRewards,
IprpcRewardsCurrent: types.DefaultGenesis().GetIprpcRewardsCurrent(),
},
valid: false,
},
Expand Down
17 changes: 11 additions & 6 deletions x/rewards/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,20 @@ const (
// provide service on specific specs. The rewards from this pool are distributed on a monthly
// basis
const (
IprpcPoolName Pool = "iprpc_pool"
IprpcPoolEmissionEventName string = "iprpc-pool-emmission"
SetIprpcDataEventName = "set-iprpc-data"
FundIprpcEventName = "fund-iprpc"
TransferIprpcRewardToNextMonth = "transfer-iprpc-reward-to-next-month"
IprpcPoolName Pool = "iprpc_pool"
IprpcPoolEmissionEventName string = "iprpc-pool-emmission"
SetIprpcDataEventName = "set-iprpc-data"
FundIprpcEventName = "fund-iprpc"
TransferIprpcRewardToNextMonthEventName = "transfer-iprpc-reward-to-next-month"
)

// helper struct to track the serviced IPRPC CU for each spec+provider
type SpecCuType struct {
ProvidersCu map[string]uint64 // provider -> cu
ProvidersCu []ProviderCuType
TotalCu uint64
}

type ProviderCuType struct {
Provider string
CU uint64
}
Loading

0 comments on commit 07f4dff

Please sign in to comment.