Skip to content

Commit

Permalink
Merge pull request lavanet#1047 from lavanet/CNS-767-implement-advanc…
Browse files Browse the repository at this point in the history
…e-plan-buy

CNS - 767: Implement advance plan buy
  • Loading branch information
Yaroms authored Dec 24, 2023
2 parents 7bc670b + a536a17 commit d11373d
Show file tree
Hide file tree
Showing 25 changed files with 1,533 additions and 262 deletions.
8 changes: 8 additions & 0 deletions proto/lavanet/lava/subscription/subscription.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ message Subscription {
string cluster = 13; // cluster key
uint64 duration_total = 14; // continous subscription usage
bool auto_renewal = 15; // automatic renewal when the subscription expires
FutureSubscription future_subscription = 16; // future subscription made with buy --advance-purchase
}

message FutureSubscription {
string creator = 1; // creator pays for the future subscription. Will replace the original one once activated
string plan_index = 2; // index (name) of plan
uint64 plan_block = 3; // when the plan was created
uint64 duration_bought = 4; // total requested duration in months
}
1 change: 1 addition & 0 deletions proto/lavanet/lava/subscription/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ message MsgBuy {
string index = 3;
uint64 duration = 4; // in months
bool auto_renewal = 6;
bool advance_purchase = 7;
}

message MsgBuyResponse {
Expand Down
14 changes: 13 additions & 1 deletion scripts/init_chain_commands.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,20 @@ echo; echo "#### Waiting 4 blocks ####"
wait_count_blocks 4
sleep 4

echo; echo "#### Sending proposal for test plans add ####"
lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE

echo; echo "#### Waiting 2 blocks ####"
wait_count_blocks 2

echo; echo "#### Voting on plans test add proposal ####"
lavad tx gov vote $(latest_vote) yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE

echo; echo "#### Waiting 4 blocks ####"
wait_count_blocks 2

echo; echo "#### Sending proposal for plans add ####"
lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/whale.json,./cookbook/plans/explorer.json,./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE
lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/explorer.json,./cookbook/plans/adventurer.json,./cookbook/plans/whale.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE

echo; echo "#### Waiting 2 blocks ####"
wait_count_blocks 2
Expand Down
13 changes: 7 additions & 6 deletions testutil/common/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,13 +446,14 @@ func (ts *Tester) TxDualstakingClaimRewards(
}

// TxSubscriptionBuy: implement 'tx subscription buy'
func (ts *Tester) TxSubscriptionBuy(creator, consumer, plan string, months int, autoRenewal bool) (*subscriptiontypes.MsgBuyResponse, error) {
func (ts *Tester) TxSubscriptionBuy(creator, consumer, plan string, months int, autoRenewal, advancePurchase bool) (*subscriptiontypes.MsgBuyResponse, error) {
msg := &subscriptiontypes.MsgBuy{
Creator: creator,
Consumer: consumer,
Index: plan,
Duration: uint64(months),
AutoRenewal: autoRenewal,
Creator: creator,
Consumer: consumer,
Index: plan,
Duration: uint64(months),
AutoRenewal: autoRenewal,
AdvancePurchase: advancePurchase,
}
return ts.Servers.SubscriptionServer.Buy(ts.GoCtx, msg)
}
Expand Down
2 changes: 1 addition & 1 deletion x/conflict/keeper/msg_server_detection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (ts *tester) setupForConflict(providersCount int) *tester {
ts.spec = ts.Spec("mock")

consumer, consumerAddr := ts.AddAccount("consumer", 0, balance)
_, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, ts.plan.Index, 1, false, false)
require.Nil(ts.T, err)
ts.consumer = consumer

Expand Down
10 changes: 5 additions & 5 deletions x/pairing/keeper/cu_tracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestAddingTrackedCuWithoutPay(t *testing.T) {
_, provider1Addr := ts.GetAccount(common.PROVIDER, 0)
_, provider2Addr := ts.GetAccount(common.PROVIDER, 1)

ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false, false) // extend by a month so the sub won't expire

res, err := ts.QuerySubscriptionCurrent(client1Addr)
require.Nil(t, err)
Expand Down Expand Up @@ -115,7 +115,7 @@ func TestTrackedCuWithExpiredSubscription(t *testing.T) {
ts.AddPlan(ts.plan.Index, ts.plan)

clientAcct, clientAddr := ts.AddAccount(common.CONSUMER, 0, testBalance)
_, err := ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 1, false, false)
require.Nil(t, err)

err = ts.addProvider(1)
Expand Down Expand Up @@ -178,7 +178,7 @@ func TestTrackedCuWithQos(t *testing.T) {
provider1Acc, provider1 := ts.GetAccount(common.PROVIDER, 0)
provider2Acc, provider2 := ts.GetAccount(common.PROVIDER, 1)

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

badQoS := &types.QualityOfServiceReport{
Latency: sdk.ZeroDec(),
Expand Down Expand Up @@ -381,7 +381,7 @@ func TestProviderMonthlyPayoutQuery(t *testing.T) {
clientAcc, client := ts.GetAccount(common.CONSUMER, 0)
providerAcct, provider := ts.GetAccount(common.PROVIDER, 0)

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

// stake the provider on an additional chain and apply pairing (advance epoch)
spec1 := ts.spec
Expand Down Expand Up @@ -657,7 +657,7 @@ func TestTrackedCuDeletion(t *testing.T) {
clientAcc, client := ts.GetAccount(common.CONSUMER, 0)
_, provider := ts.GetAccount(common.PROVIDER, 0)

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

// send relay to track CU
relayPayment := sendRelay(ts, provider, clientAcc, []string{ts.spec.Index})
Expand Down
8 changes: 4 additions & 4 deletions x/pairing/keeper/delegator_rewards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestProviderDelegatorsRewards(t *testing.T) {
_, delegator1 := ts.GetAccount(common.CONSUMER, 1)
_, delegator2 := ts.GetAccount(common.CONSUMER, 2)

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

ts.AdvanceEpoch() // to apply pairing

Expand Down Expand Up @@ -203,7 +203,7 @@ func TestDelegationLimitAffectingProviderReward(t *testing.T) {

ts.AdvanceEpoch() // to apply pairing

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

delegationAmount1 := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(uint64(testStake)/2))
delegationAmount2 := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(uint64(testStake)))
Expand Down Expand Up @@ -251,7 +251,7 @@ func TestProviderRewardWithCommission(t *testing.T) {
clientAcc, client := ts.GetAccount(common.CONSUMER, 0)
delegator1Acc, delegator1 := ts.GetAccount(common.CONSUMER, 1)

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

ts.AdvanceEpoch() // to apply pairing

Expand Down Expand Up @@ -349,7 +349,7 @@ func TestQueryDelegatorRewards(t *testing.T) {
_, delegator1 := ts.GetAccount(common.CONSUMER, 1)
_, delegator2 := ts.GetAccount(common.CONSUMER, 2) // delegates to no one

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

spec1 := common.CreateMockSpec()
spec1.Index = "mock1"
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/keeper/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (ts *tester) addClient(count int) {
start := len(ts.Accounts(common.CONSUMER))
for i := 0; i < count; i++ {
_, addr := ts.AddAccount(common.CONSUMER, start+i, testBalance)
_, err := ts.TxSubscriptionBuy(addr, addr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(addr, addr, ts.plan.Index, 1, false, false)
if err != nil {
panic("addClient: failed to buy subscription: " + err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/keeper/msg_server_relay_payment_gov_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ func TestRelayPaymentGovEpochToSaveDecrease(t *testing.T) {
client1Acct, client := ts.GetAccount(common.CONSUMER, 0)
providerAcct, providerAddr := ts.GetAccount(common.PROVIDER, 0)

ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire

epochBlocks := ts.EpochBlocks()
epochsToSave := ts.EpochsToSave()
Expand Down
2 changes: 1 addition & 1 deletion x/pairing/keeper/msg_server_relay_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ func TestBadgeUsedCuMapTimeout(t *testing.T) {
client1Acct, client1Addr := ts.GetAccount(common.CONSUMER, 0)
providerAcct, providerAddr := ts.GetAccount(common.PROVIDER, 0)

ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false) // extend by a month so the sub won't expire
ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false, false) // extend by a month so the sub won't expire

badgeAcct, _ := ts.AddAccount("badge", 0, testBalance)

Expand Down
2 changes: 1 addition & 1 deletion x/pairing/keeper/pairing_subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ func TestPairingNotChangingDueToCuOveruse(t *testing.T) {
client1Acct, client1Addr := ts.GetAccount(common.CONSUMER, 0)

// add 10 months to the subscription
_, err := ts.TxSubscriptionBuy(client1Addr, client1Addr, ts.plan.Index, 10, false)
_, err := ts.TxSubscriptionBuy(client1Addr, client1Addr, ts.plan.Index, 10, false, false)
require.Nil(t, err)

totalCuLimit := ts.plan.PlanPolicy.TotalCuLimit
Expand Down
30 changes: 15 additions & 15 deletions x/pairing/keeper/pairing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ func TestPairingUniqueness(t *testing.T) {
_, sub1Addr := ts.Account("sub1")
_, sub2Addr := ts.Account("sub2")

_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false)
require.Nil(t, err)
_, err = ts.TxSubscriptionBuy(sub2Addr, sub2Addr, ts.plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub2Addr, sub2Addr, ts.plan.Index, 1, false, false)
require.Nil(t, err)

for i := 1; i <= 1000; i++ {
Expand Down Expand Up @@ -97,7 +97,7 @@ func TestValidatePairingDeterminism(t *testing.T) {

_, sub1Addr := ts.Account("sub1")

_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false)
require.Nil(t, err)

for i := 1; i <= 10; i++ {
Expand Down Expand Up @@ -247,7 +247,7 @@ func TestPairingStatic(t *testing.T) {

ts.AdvanceEpoch()

_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false)
require.Nil(t, err)

for i := 0; i < int(ts.plan.PlanPolicy.MaxProvidersToPair)*2; i++ {
Expand Down Expand Up @@ -519,7 +519,7 @@ func TestAddonPairing(t *testing.T) {

_, sub1Addr := ts.AddAccount("sub", 0, 10000)

_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false)
require.Nil(t, err)

// get the admin project and set its policies
Expand Down Expand Up @@ -710,7 +710,7 @@ func TestSelectedProvidersPairing(t *testing.T) {

ts.AdvanceEpoch()

_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false)
require.Nil(t, err)

// get the admin project and set its policies
Expand Down Expand Up @@ -873,7 +873,7 @@ func TestPairingUniformDistribution(t *testing.T) {

// make the subscription auto-renew so it won't expire after many (pairing) epochs
err := ts.TxSubscriptionAutoRenewal(clientAddr, true)
require.Nil(t, err)
require.NoError(t, err)

weightFunc := func(p epochstoragetypes.StakeEntry) int64 { return p.Stake.Amount.Int64() }
ts.verifyPairingDistribution("uniform distribution", clientAddr, providersToPair, weightFunc)
Expand Down Expand Up @@ -1007,9 +1007,9 @@ func TestGeolocationPairingScores(t *testing.T) {
basicAcct, basicAddr := ts.GetAccount(common.CONSUMER, 1)
premiumAcct, premiumAddr := ts.GetAccount(common.CONSUMER, 2)

ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false)
ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false)
ts.TxSubscriptionBuy(premiumAddr, premiumAddr, premiumPlan.Index, 1, false)
ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false, false)
ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false, false)
ts.TxSubscriptionBuy(premiumAddr, premiumAddr, premiumPlan.Index, 1, false, false)

for geoName, geo := range planstypes.Geolocation_value {
if geoName != "GL" && geoName != "GLS" {
Expand Down Expand Up @@ -1199,7 +1199,7 @@ func TestDuplicateProviders(t *testing.T) {
require.Nil(t, err)

ts.AdvanceEpoch()
ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false)
ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false, false)

for geoName, geo := range planstypes.Geolocation_value {
if geoName != "GL" && geoName != "GLS" {
Expand Down Expand Up @@ -1247,7 +1247,7 @@ func TestNoRequiredGeo(t *testing.T) {
require.Nil(t, err)

ts.AdvanceEpoch()
ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false)
ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false, false)

// add 5 more providers that are not in US-E (the only allowed providers in the free plan)
err = ts.addProviderGeolocation(5, planstypes.Geolocation_value["AS"])
Expand Down Expand Up @@ -1929,7 +1929,7 @@ func TestExtensionAndAddonPairing(t *testing.T) {

_, sub1Addr := ts.AddAccount("sub", 0, 10000)

_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false)
require.Nil(t, err)

// get the admin project and set its policies
Expand Down Expand Up @@ -2094,7 +2094,7 @@ func TestMixSelectedProvidersAndArchivePairing(t *testing.T) {

_, sub1Addr := ts.AddAccount("sub", 0, 10000)

_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false)
require.Nil(t, err)

// get the admin project and set its policies
Expand Down Expand Up @@ -2222,7 +2222,7 @@ func TestPairingPerformance(t *testing.T) {

_, sub1Addr := ts.Account("sub1")

_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false)
_, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false)
require.Nil(t, err)

for i := 1; i <= 1000; i++ {
Expand Down
4 changes: 2 additions & 2 deletions x/plans/keeper/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ func (k Keeper) AddPlan(ctx sdk.Context, planToAdd types.Plan, modify bool) erro
var planFromStore types.Plan
block, _, _, found := k.plansFS.FindEntryDetailed(ctx, planToAdd.GetIndex(), planToAdd.Block, &planFromStore)
if found {
if planFromStore.Price.Amount.LT(planToAdd.Price.Amount) {
return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan price cannot be increased"),
if !planFromStore.Price.Amount.Equal(planToAdd.Price.Amount) {
return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan price cannot be modified"),
utils.Attribute{Key: "planToAdd", Value: planToAdd},
utils.Attribute{Key: "originalPlan", Value: planFromStore},
)
Expand Down
7 changes: 6 additions & 1 deletion x/plans/keeper/plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func TestAddAndDelete(t *testing.T) {

// TestModifyPlan checks that plan modification acts as expected:
// 1. there should be no new version in the planFS (latest plan should have the same block)
// 2. plan price cannot be increased
// 2. plan price cannot be changed
func TestModifyPlan(t *testing.T) {
ts := newTester(t)
ts.AdvanceEpoch()
Expand Down Expand Up @@ -369,4 +369,9 @@ func TestModifyPlan(t *testing.T) {
originalPlan.Price = originalPlan.Price.AddAmount(math.NewIntFromUint64(1))
err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{originalPlan}, true)
require.NotNil(t, err)

// modify the plan by decreasing its price. proposal should fail
originalPlan.Price = originalPlan.Price.SubAmount(math.NewIntFromUint64(2))
err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{originalPlan}, true)
require.NotNil(t, err)
}
6 changes: 3 additions & 3 deletions x/projects/keeper/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func TestProjectsServerAPI(t *testing.T) {
err := ts.TxProposalAddPlans(plan)
require.Nil(t, err)

_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false)
require.Nil(t, err)

projectData := types.ProjectData{
Expand Down Expand Up @@ -1050,7 +1050,7 @@ func TestSetPolicySelectedProviders(t *testing.T) {
require.NotNil(t, err)
}

_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false)
_, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false)
require.Nil(t, err)

res, err := ts.QuerySubscriptionListProjects(sub1Addr)
Expand Down Expand Up @@ -1224,7 +1224,7 @@ func TestPendingProject(t *testing.T) {

_, sub := ts.Account("sub1")

_, err := ts.TxSubscriptionBuy(sub, sub, "free", 1, false)
_, err := ts.TxSubscriptionBuy(sub, sub, "free", 1, false, false)
require.Nil(t, err)

res, err := ts.QuerySubscriptionListProjects(sub)
Expand Down
Loading

0 comments on commit d11373d

Please sign in to comment.