Skip to content

Commit

Permalink
Merge pull request #945 from lavanet/CNS-668-let-users-see-pending-po…
Browse files Browse the repository at this point in the history
…licy-changes

CNS-668: let users see pending policy changes
  • Loading branch information
Yaroms authored Nov 9, 2023
2 parents c168a04 + 47b5813 commit 7be36f7
Show file tree
Hide file tree
Showing 10 changed files with 523 additions and 147 deletions.
2 changes: 1 addition & 1 deletion proto/lavanet/lava/pairing/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ message QueryVerifyPairingResponse {

message QueryGetUniquePaymentStorageClientProviderRequest {
string index = 1;

}

message QueryGetUniquePaymentStorageClientProviderResponse {
Expand Down Expand Up @@ -233,6 +232,7 @@ message QueryEffectivePolicyRequest {

message QueryEffectivePolicyResponse {
lavanet.lava.plans.Policy policy = 1;
lavanet.lava.plans.Policy pending_policy = 2;
}

// this line is used by starport scaffolding # 3
Expand Down
2 changes: 2 additions & 0 deletions proto/lavanet/lava/projects/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ message QueryInfoRequest {

message QueryInfoResponse {
Project project = 1;
Project pending_project = 2;
}

message QueryDeveloperRequest {
Expand All @@ -51,6 +52,7 @@ message QueryDeveloperRequest {

message QueryDeveloperResponse {
Project project = 1;
Project pending_project = 2;
}

// this line is used by starport scaffolding # 3
11 changes: 10 additions & 1 deletion testutil/common/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,16 @@ func (ts *Tester) QueryPairingVerifyPairing(chainID, client, provider string, bl
return ts.Keepers.Pairing.VerifyPairing(ts.GoCtx, msg)
}

// QueryPairingMonthlyPayout implements 'q pairing verfy-pairing'
// QueryPairingEffectivePolicy implements 'q pairing effective-policy'
func (ts *Tester) QueryPairingEffectivePolicy(chainID, consumer string) (*pairingtypes.QueryEffectivePolicyResponse, error) {
msg := &pairingtypes.QueryEffectivePolicyRequest{
SpecID: chainID,
Consumer: consumer,
}
return ts.Keepers.Pairing.EffectivePolicy(ts.GoCtx, msg)
}

// QueryPairingMonthlyPayout implements 'q pairing monthly-payout'
func (ts *Tester) QueryPairingMonthlyPayout(provider string) (*pairingtypes.QueryMonthlyPayoutResponse, error) {
msg := &pairingtypes.QueryMonthlyPayoutRequest{
Provider: provider,
Expand Down
40 changes: 35 additions & 5 deletions x/pairing/keeper/grpc_query_effective_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/lavanet/lava/x/pairing/types"
projectstypes "github.com/lavanet/lava/x/projects/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand All @@ -17,15 +18,44 @@ func (k Keeper) EffectivePolicy(goCtx context.Context, req *types.QueryEffective

ctx := sdk.UnwrapSDKContext(goCtx)

project, err := k.projectsKeeper.GetProjectForDeveloper(ctx, req.Consumer, uint64(ctx.BlockHeight()))
project, err := k.getProjectByDeveloperOrIndex(ctx, req.Consumer, uint64(ctx.BlockHeight()))
if err != nil {
return nil, err
}
strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, req.SpecID)
if err != nil {
return nil, err
}

// try getting pending policy changes (applied in next epoch)
nextEpoch, err := k.epochStorageKeeper.GetNextEpoch(ctx, uint64(ctx.BlockHeight()))
if err != nil {
return nil, fmt.Errorf("cannot get pending project policy. errors: %s", err.Error())
}

pendingProject, err := k.getProjectByDeveloperOrIndex(ctx, req.Consumer, nextEpoch)
if err != nil {
return nil, err
}

if pendingProject.Equal(project) {
return &types.QueryEffectivePolicyResponse{Policy: strictestPolicy}, err
} else {
pendingPolicy, _, err := k.GetProjectStrictestPolicy(ctx, pendingProject, req.SpecID)
return &types.QueryEffectivePolicyResponse{Policy: strictestPolicy, PendingPolicy: pendingPolicy}, err
}
}

func (k Keeper) getProjectByDeveloperOrIndex(ctx sdk.Context, idOrDeveloper string, block uint64) (projectstypes.Project, error) {
project, err := k.projectsKeeper.GetProjectForDeveloper(ctx, idOrDeveloper, block)
if err != nil {
origErr := err
// support giving a project-id
project, err = k.projectsKeeper.GetProjectForBlock(ctx, req.Consumer, uint64(ctx.BlockHeight()))
project, err = k.projectsKeeper.GetProjectForBlock(ctx, idOrDeveloper, block)
if err != nil {
return nil, fmt.Errorf("failed getting project for key %s errors %s, %s", req.Consumer, origErr, err)
return projectstypes.Project{}, fmt.Errorf("failed getting project for key %s errors %s, %s", idOrDeveloper, origErr, err)
}
}
strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, req.SpecID)
return &types.QueryEffectivePolicyResponse{Policy: strictestPolicy}, err

return project, nil
}
92 changes: 92 additions & 0 deletions x/pairing/keeper/grpc_query_effective_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package keeper_test

import (
"testing"

"github.com/lavanet/lava/testutil/common"
planstypes "github.com/lavanet/lava/x/plans/types"
"github.com/stretchr/testify/require"
)

// Test effective policy query
func TestEffectivePolicy(t *testing.T) {
ts := newTester(t)
ts.setupForPayments(1, 1, 0) // 1 client, 1 provider

_, clientAddr := ts.GetAccount(common.CONSUMER, 0)

project, err := ts.GetProjectDeveloperData(clientAddr, ts.BlockHeight())
require.Nil(t, err)

// the auto-created project from setupForPayments is subject to the mock plan policy
// the mock policy assumed in this test is (implemented by common.CreateMockPolicy()):
//
// plantypes.Policy{
// TotalCuLimit: 100000,
// EpochCuLimit: 10000,
// MaxProvidersToPair: 3,
// GeolocationProfile: 1,
// }
//
// when testing the effective policy, this will be the policy in mind

adminPolicy := planstypes.Policy{
TotalCuLimit: 99000,
EpochCuLimit: 10000,
MaxProvidersToPair: 3,
GeolocationProfile: 1,
}
_, err = ts.TxProjectSetPolicy(project.ProjectID, clientAddr, adminPolicy)
require.Nil(t, err)

subPolicy := planstypes.Policy{
TotalCuLimit: 100000,
EpochCuLimit: 9900,
MaxProvidersToPair: 2,
GeolocationProfile: planstypes.Geolocation_value["GL"],
}
_, err = ts.TxProjectSetSubscriptionPolicy(project.ProjectID, clientAddr, subPolicy)
require.Nil(t, err)

// the effective policy function calcaulates the effective chain policy within it
// if there is no chain policy in any of the policies, it makes one using this function
chainPolicy, allowed := planstypes.GetStrictestChainPolicyForSpec(ts.spec.Index, []*planstypes.Policy{&adminPolicy, &subPolicy, &ts.plan.PlanPolicy})
require.True(t, allowed)

expectedEffectivePolicy := planstypes.Policy{
ChainPolicies: []planstypes.ChainPolicy{chainPolicy},
TotalCuLimit: 99000,
EpochCuLimit: 9900,
MaxProvidersToPair: 2,
GeolocationProfile: 1,
}

// apply the policy changes
ts.AdvanceEpoch()

res, err := ts.QueryPairingEffectivePolicy(ts.spec.Index, clientAddr)
require.Nil(t, err)
require.True(t, expectedEffectivePolicy.Equal(res.Policy))
require.Nil(t, res.PendingPolicy) // there should be no pending policy

// set a new policy without applying it (no advanceEpoch)
_, err = ts.TxProjectSetPolicy(project.ProjectID, clientAddr, planstypes.Policy{
TotalCuLimit: 80000,
EpochCuLimit: 5000,
MaxProvidersToPair: 3,
GeolocationProfile: 1,
})
require.Nil(t, err)
res, err = ts.QueryPairingEffectivePolicy(ts.spec.Index, clientAddr)
require.Nil(t, err)
require.True(t, expectedEffectivePolicy.Equal(res.Policy)) // policy should still be the original one

// there should be a new pending policy
require.True(t, res.PendingPolicy.Equal(planstypes.Policy{
ChainPolicies: expectedEffectivePolicy.ChainPolicies,
TotalCuLimit: 80000,
EpochCuLimit: 5000,
MaxProvidersToPair: 2,
GeolocationProfile: 1,
}))
}
Loading

0 comments on commit 7be36f7

Please sign in to comment.