Skip to content

Commit

Permalink
Merge pull request lavanet#1134 from lavanet/CNS-806-make-projects-of…
Browse files Browse the repository at this point in the history
…-expired-subscription-delete-immediately

CNS-806: align subscription deletion and CU tracker start to next epoch
  • Loading branch information
Yaroms authored Jan 22, 2024
2 parents b093d06 + c3efa1c commit f49d7bf
Show file tree
Hide file tree
Showing 16 changed files with 431 additions and 67 deletions.
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,12 +750,12 @@ func New(
slashingtypes.ModuleName,
govtypes.ModuleName,
crisistypes.ModuleName,
dualstakingmoduletypes.ModuleName,
genutiltypes.ModuleName,
evidencetypes.ModuleName,
ibctransfertypes.ModuleName,
ibcexported.ModuleName,
specmoduletypes.ModuleName,
dualstakingmoduletypes.ModuleName,
subscriptionmoduletypes.ModuleName,
downtimemoduletypes.ModuleName,
pairingmoduletypes.ModuleName,
Expand Down
7 changes: 7 additions & 0 deletions proto/lavanet/lava/subscription/cu_tracker.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ syntax = "proto3";
package lavanet.lava.subscription;

option go_package = "github.com/lavanet/lava/x/subscription/types";
import "cosmos/base/v1beta1/coin.proto";
import "gogoproto/gogo.proto";

message TrackedCu {
uint64 cu = 1; // CU counter for CU after QoS consideration
}

message CuTrackerTimerData {
uint64 block = 1; // sub block
cosmos.base.v1beta1.Coin credit = 2 [(gogoproto.nullable) = false]; // credit to be used for rewards
}
2 changes: 1 addition & 1 deletion scripts/init_chain.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ lavad add-genesis-account validators_rewards_allocation_pool 30000000000000ulava
lavad add-genesis-account providers_rewards_allocation_pool 30000000000000ulava --module-account
lavad gentx alice 10000000000000ulava --chain-id lava
lavad collect-gentxs
lavad start --pruning=nothing
lavad start --pruning=nothing
4 changes: 2 additions & 2 deletions testutil/common/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,10 @@ func (ts *Tester) TxSubscriptionAddProject(creator string, pd projectstypes.Proj
}

// TxSubscriptionDelProject: implement 'tx subscription del-project'
func (ts *Tester) TxSubscriptionDelProject(creator, projectID string) error {
func (ts *Tester) TxSubscriptionDelProject(creator, projectName string) error {
msg := &subscriptiontypes.MsgDelProject{
Creator: creator,
Name: projectID,
Name: projectName,
}
_, err := ts.Servers.SubscriptionServer.DelProject(ts.GoCtx, msg)
return err
Expand Down
5 changes: 5 additions & 0 deletions x/pairing/keeper/cu_tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,15 @@ func TestTrackedCuWithQos(t *testing.T) {

// advance month + blocksToSave + 1 to trigger the provider monthly payment
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

balance1 := ts.GetBalance(provider1Acc.Addr)
balance2 := ts.GetBalance(provider2Acc.Addr)

reward, err := ts.QueryDualstakingDelegatorRewards(provider1Acc.Addr.String(), provider1Acc.Addr.String(), ts.spec.Index)
require.Nil(ts.T, err)
require.Len(t, reward.Rewards, 1)
require.Equal(ts.T, tt.p1ExpectedReward, reward.Rewards[0].Amount.Amount.Int64())
_, err = ts.TxDualstakingClaimRewards(provider1Acc.Addr.String(), provider1Acc.Addr.String())
require.Nil(ts.T, err)
Expand Down Expand Up @@ -363,6 +365,7 @@ func TestTrackedCuPlanPriceChange(t *testing.T) {

// advance month + blocksToSave + 1 to trigger the provider monthly payment
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

reward, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), ts.spec.Index)
Expand Down Expand Up @@ -606,6 +609,7 @@ func TestProviderMonthlyPayoutQueryWithContributor(t *testing.T) {
require.NoError(t, err)

ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

_, err = ts.TxDualstakingClaimRewards(providerAcct.Addr.String(), providerAcct.Addr.String())
Expand Down Expand Up @@ -646,6 +650,7 @@ func TestFrozenProviderGetReward(t *testing.T) {

// advance month + blocksToSave + 1 to trigger the provider monthly payment
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

planPrice := ts.plan.Price.Amount.Int64()
Expand Down
1 change: 1 addition & 0 deletions x/pairing/keeper/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ func (ts *tester) payAndVerifyBalance(

// advance month + blocksToSave + 1 to trigger the provider monthly payment
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

// verify provider's balance
Expand Down
1 change: 1 addition & 0 deletions x/pairing/keeper/msg_server_relay_payment_gov_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestRelayPaymentGovQosWeightChange(t *testing.T) {

// advance month + blocksToSave + 1 to trigger the provider monthly payment
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

_, err = ts.TxDualstakingClaimRewards(providerAcct.Addr.String(), providerAcct.Addr.String())
Expand Down
1 change: 1 addition & 0 deletions x/pairing/keeper/msg_server_relay_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ func TestRelayPaymentUnstakingProviderForUnresponsivenessWithBadDataInput(t *tes
_, err := ts.TxPairingRelayPayment(provider1Addr, relays...)
require.NoError(t, err)
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

// reward + before == after
Expand Down
10 changes: 7 additions & 3 deletions x/projects/keeper/creation.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func (k Keeper) CreateProject(ctx sdk.Context, subAddr string, projectData types
}

// project name per subscription is unique: check for duplicates
// we also check !isDeleted because when a new subscription is created
// in the same epoch that a subscription from the same creator was expired,
// we'll find the old admin project but since it's deleted we want to ignore
// it and allow creating a new admin project
var emptyProject types.Project
if found := k.projectsFS.FindEntry(ctx, project.Index, epoch, &emptyProject); found {
return utils.LavaFormatWarning("create project failed",
Expand Down Expand Up @@ -160,7 +164,7 @@ func (k Keeper) DeleteProject(ctx sdk.Context, creator, projectID string) error
}

for _, projectKey := range project.GetProjectKeys() {
err = k.unregisterKey(ctx, projectKey, &project, nextEpoch)
err := k.unregisterKey(ctx, projectKey, &project, nextEpoch)
if err != nil {
return err
}
Expand Down Expand Up @@ -195,8 +199,6 @@ func (k Keeper) registerKey(ctx sdk.Context, key types.ProjectKey, project *type
)
}

project.AppendKey(types.ProjectDeveloperKey(key.Key))

// by now, the key was either not found, or found and belongs to us already.
// if the former, then we surely need to add it.
if !found {
Expand All @@ -212,6 +214,8 @@ func (k Keeper) registerKey(ctx sdk.Context, key types.ProjectKey, project *type
)
}
}

project.AppendKey(types.ProjectDeveloperKey(key.Key))
}

return nil
Expand Down
12 changes: 12 additions & 0 deletions x/rewards/keeper/providers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func TestBasicBoostProvidersRewards(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -110,6 +111,7 @@ func TestSpecAllocationProvidersRewards(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -155,6 +157,7 @@ func TestProvidersDiminishingRewards(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -203,6 +206,7 @@ func TestProvidersEndRewards(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -262,6 +266,7 @@ func Test2SpecsZeroShares(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -325,6 +330,7 @@ func Test2SpecsDoubleShares(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -385,6 +391,7 @@ func TestBonusRewards3Providers(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc1.Addr.String(), "", "")
Expand Down Expand Up @@ -474,6 +481,7 @@ func TestValidatorsAndCommunityParticipation(t *testing.T) {

// first months there are no bonus rewards, just payment from the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

expectedReward := sdk.NewIntFromUint64(baserewards * subscription.LIMIT_TOKEN_PER_CU)
Expand Down Expand Up @@ -523,6 +531,7 @@ func TestBonusReward49months(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

res, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), "")
Expand Down Expand Up @@ -574,6 +583,7 @@ func TestBonusRewardsEquall5Providers(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

for _, providerAcc := range providerAccs {
Expand Down Expand Up @@ -640,6 +650,7 @@ func TestBonusRewards5Providers(t *testing.T) {

// first months there are no bonus rewards, just payment ffrom the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

for _, providerAcc := range providerAccs {
Expand Down Expand Up @@ -714,6 +725,7 @@ func TestCommunityTaxOne(t *testing.T) {

// first months there are no bonus rewards, just payment from the subscription
ts.AdvanceMonths(1)
ts.AdvanceEpoch()
ts.AdvanceBlocks(ts.BlocksToSave() + 1)

expectedReward := sdk.NewIntFromUint64(baserewards * subscription.LIMIT_TOKEN_PER_CU)
Expand Down
66 changes: 23 additions & 43 deletions x/subscription/keeper/cu_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,18 @@ type trackedCuInfo struct {
block uint64
}

func (k Keeper) GetSubTrackedCuInfo(ctx sdk.Context, sub string, subBlockStr string) (trackedCuList []trackedCuInfo, totalCuTracked uint64) {
func (k Keeper) GetSubTrackedCuInfo(ctx sdk.Context, sub string, block uint64) (trackedCuList []trackedCuInfo, totalCuTracked uint64) {
keys := k.GetAllSubTrackedCuIndices(ctx, sub)

for _, key := range keys {
_, provider, chainID := types.DecodeCuTrackerKey(key)
block, err := strconv.ParseUint(subBlockStr, 10, 64)
if err != nil {
utils.LavaFormatError("cannot remove cu tracker", err,
utils.Attribute{Key: "sub", Value: sub},
utils.Attribute{Key: "provider", Value: provider},
utils.Attribute{Key: "chain_id", Value: chainID},
utils.Attribute{Key: "block_str", Value: subBlockStr},
)
continue
}

cu, found, _ := k.GetTrackedCu(ctx, sub, provider, chainID, block)
if !found {
utils.LavaFormatWarning("cannot remove cu tracker", legacyerrors.ErrKeyNotFound,
utils.Attribute{Key: "sub", Value: sub},
utils.Attribute{Key: "provider", Value: provider},
utils.Attribute{Key: "chain_id", Value: chainID},
utils.Attribute{Key: "block", Value: subBlockStr},
utils.Attribute{Key: "block", Value: strconv.FormatUint(block, 10)},
)
continue
}
Expand All @@ -124,39 +113,27 @@ func (k Keeper) GetSubTrackedCuInfo(ctx sdk.Context, sub string, subBlockStr str
// remove only before the sub is deleted
func (k Keeper) RewardAndResetCuTracker(ctx sdk.Context, cuTrackerTimerKeyBytes []byte, cuTrackerTimerData []byte) {
sub := string(cuTrackerTimerKeyBytes)
blockStr := string(cuTrackerTimerData)
_, err := strconv.ParseUint(blockStr, 10, 64)
var timerData types.CuTrackerTimerData
err := k.cdc.Unmarshal(cuTrackerTimerData, &timerData)
if err != nil {
utils.LavaFormatError(types.ErrCuTrackerPayoutFailed.Error(), err,
utils.Attribute{Key: "blockStr", Value: blockStr},
utils.LavaFormatError(types.ErrCuTrackerPayoutFailed.Error(), fmt.Errorf("invalid data from cu tracker timer"),
utils.Attribute{Key: "timer_data", Value: timerData.String()},
utils.Attribute{Key: "consumer", Value: sub},
)
return
}
trackedCuList, totalCuTracked := k.GetSubTrackedCuInfo(ctx, sub, blockStr)
trackedCuList, totalCuTracked := k.GetSubTrackedCuInfo(ctx, sub, timerData.Block)

var block uint64
if len(trackedCuList) == 0 || totalCuTracked == 0 {
// no tracked CU for this sub, nothing to do
return
}

// Note: We take the subscription from the FixationStore, based on the given block.
// So, even if the plan changed during the month, we still take the original plan, based on the given block.
block = trackedCuList[0].block
subObj, _, found := k.GetSubscriptionForBlock(ctx, sub, block)
if !found {
utils.LavaFormatError("cannot find subscription's plan", types.ErrCuTrackerPayoutFailed,
utils.Attribute{Key: "sub_consumer", Value: sub},
)
return
}
block := trackedCuList[0].block

var totalTokenAmount math.Int
if subObj.DurationLeft == 0 {
totalTokenAmount = subObj.Credit.Amount
} else {
totalTokenAmount = subObj.Credit.Amount.QuoRaw(int64(subObj.DurationLeft))
}
totalTokenAmount := timerData.Credit.Amount
if totalTokenAmount.Quo(sdk.NewIntFromUint64(totalCuTracked)).GT(sdk.NewIntFromUint64(LIMIT_TOKEN_PER_CU)) {
totalTokenAmount = sdk.NewIntFromUint64(LIMIT_TOKEN_PER_CU * totalCuTracked)
}
Expand Down Expand Up @@ -241,23 +218,21 @@ func (k Keeper) RewardAndResetCuTracker(ctx sdk.Context, cuTrackerTimerKeyBytes
)
} else {
utils.LogLavaEvent(ctx, k.Logger(ctx), types.MonthlyCuTrackerProviderRewardEventName, map[string]string{
"provider": provider,
"sub": sub,
"plan": subObj.PlanIndex,
"tracked_cu": strconv.FormatUint(trackedCu, 10),
"credit_used": creditToSub.String(),
"credit_remaining": subObj.Credit.String(),
"reward": providerReward.String(),
"block": strconv.FormatInt(ctx.BlockHeight(), 10),
"adjustment_raw": providerAdjustment.String(),
"provider": provider,
"sub": sub,
"tracked_cu": strconv.FormatUint(trackedCu, 10),
"credit_used": creditToSub.String(),
"reward": providerReward.String(),
"block": strconv.FormatInt(ctx.BlockHeight(), 10),
"adjustment_raw": providerAdjustment.String(),
}, "Provider got monthly reward successfully")
}
}

rewardsRemainder := totalTokenAmount.Sub(totalTokenRewarded)

var latestSub types.Subscription
latestEntryBlock, _, _, found := k.subsFS.FindEntryDetailed(ctx, subObj.Consumer, uint64(ctx.BlockHeight()), &latestSub)
latestEntryBlock, _, _, found := k.subsFS.FindEntryDetailed(ctx, sub, uint64(ctx.BlockHeight()), &latestSub)
if found {
// return rewards remainder to credit
if !rewardsRemainder.IsZero() {
Expand All @@ -284,6 +259,11 @@ func (k Keeper) RewardAndResetCuTracker(ctx sdk.Context, cuTrackerTimerKeyBytes
}
}
}
utils.LogLavaEvent(ctx, k.Logger(ctx), types.RemainingCreditEventName, map[string]string{
"sub": sub,
"credit_remaining": latestSub.Credit.String(),
"block": strconv.FormatInt(ctx.BlockHeight(), 10),
}, "CU tracker reward and reset executed successfully, printing remaining subscription credit")
}

func (k Keeper) CalcTotalMonthlyReward(ctx sdk.Context, totalAmount math.Int, trackedCu uint64, totalCuUsedBySub uint64) math.Int {
Expand Down
2 changes: 1 addition & 1 deletion x/subscription/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type (
subsTS timerstoretypes.TimerStore

cuTrackerFS fixationtypes.FixationStore // key: "<sub> <provider>", value: month aggregated CU
cuTrackerTS timerstoretypes.TimerStore
cuTrackerTS timerstoretypes.TimerStore // key: sub, value: credit for reward
}
)

Expand Down
Loading

0 comments on commit f49d7bf

Please sign in to comment.