Skip to content

Commit

Permalink
Merge pull request lavanet#496 from lavanet/CNS-371-project-keys-use-…
Browse files Browse the repository at this point in the history
…bitmap

CNS-371: project keys use bitmap
  • Loading branch information
Yaroms authored May 22, 2023
2 parents c887567 + a272067 commit a682eef
Show file tree
Hide file tree
Showing 20 changed files with 7,588 additions and 513 deletions.
19 changes: 11 additions & 8 deletions proto/projects/project.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ message Project {
}

message ProjectKey {
string key = 1; // the address of the project key

reserved 2;
reserved 3;
string key = 1; // the address of the project key
enum KEY_TYPE{ // bitmap, must only be power of 2
NONE = 0;
ADMIN = 1;
DEVELOPER = 2;
}

repeated KEY_TYPE types = 2 [(gogoproto.nullable) = false]; // the key type, determines the privilages of the key

enum Type {
NONE = 0x0;
ADMIN = 0x1;
DEVELOPER = 0x2;
}

uint32 kinds = 4;
}

// protobuf expected in YAML format: used "moretags" to simplify parsing
Expand Down
12 changes: 4 additions & 8 deletions x/pairing/keeper/msg_server_relay_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -827,10 +827,7 @@ func TestCuUsageInProjectsAndSubscription(t *testing.T) {
Description: "description",
Enabled: true,
ProjectKeys: []projecttypes.ProjectKey{
{
Key: projectAdmin1,
Types: []projecttypes.ProjectKey_KEY_TYPE{projecttypes.ProjectKey_DEVELOPER},
},
projecttypes.ProjectDeveloperKey(projectAdmin1),
},
Policy: &projecttypes.Policy{
GeolocationProfile: uint64(1),
Expand All @@ -843,10 +840,9 @@ func TestCuUsageInProjectsAndSubscription(t *testing.T) {
require.Nil(t, err)

projectData.Name = "proj2"
projectData.ProjectKeys = []projecttypes.ProjectKey{{
Key: projectAdmin2,
Types: []projecttypes.ProjectKey_KEY_TYPE{projecttypes.ProjectKey_DEVELOPER},
}}
projectData.ProjectKeys = []projecttypes.ProjectKey{
projecttypes.ProjectDeveloperKey(projectAdmin2),
}
err = subkeeper.AddProjectToSubscription(_ctx, subscriptionOwner, projectData)
require.Nil(t, err)

Expand Down
41 changes: 19 additions & 22 deletions x/pairing/keeper/pairing_subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,23 @@ func TestRelayPaymentSubscriptionCU(t *testing.T) {

consumers := []common.Account{consumerA, consumerB}

_, err := ts.servers.SubscriptionServer.Buy(ts.ctx, &subtypes.MsgBuy{Creator: consumerA.Addr.String(), Consumer: consumerA.Addr.String(), Index: ts.plan.Index, Duration: 1})
_, err := ts.servers.SubscriptionServer.Buy(ts.ctx, &subtypes.MsgBuy{
Creator: consumerA.Addr.String(),
Consumer: consumerA.Addr.String(),
Index: ts.plan.Index,
Duration: 1,
})
require.Nil(t, err)

consumerBProjectData := projectstypes.ProjectData{
Name: "consumer_b_project",
Description: "",
Enabled: true,
ProjectKeys: []projectstypes.ProjectKey{{
Key: consumerB.Addr.String(),
Types: []projectstypes.ProjectKey_KEY_TYPE{
projectstypes.ProjectKey_ADMIN,
projectstypes.ProjectKey_DEVELOPER,
},
}},
ProjectKeys: []projectstypes.ProjectKey{
projectstypes.NewProjectKey(consumerB.Addr.String()).
AddType(projectstypes.ProjectKey_ADMIN).
AddType(projectstypes.ProjectKey_DEVELOPER),
},
Policy: &ts.plan.PlanPolicy,
}
err = ts.keepers.Subscription.AddProjectToSubscription(_ctx, consumerA.Addr.String(), consumerBProjectData)
Expand Down Expand Up @@ -421,13 +424,11 @@ func TestStrictestPolicyCuPerEpoch(t *testing.T) {
Name: "low_cu_project",
Description: "project with low cu limit (per epoch)",
Enabled: true,
ProjectKeys: []projectstypes.ProjectKey{{
Key: consumerToWasteCu.Addr.String(),
Types: []projectstypes.ProjectKey_KEY_TYPE{
projectstypes.ProjectKey_DEVELOPER,
projectstypes.ProjectKey_ADMIN,
},
}},
ProjectKeys: []projectstypes.ProjectKey{
projectstypes.NewProjectKey(consumerToWasteCu.Addr.String()).
AddType(projectstypes.ProjectKey_ADMIN).
AddType(projectstypes.ProjectKey_DEVELOPER),
},
Policy: &ts.plan.PlanPolicy,
}
_, err = ts.servers.SubscriptionServer.AddProject(ts.ctx, &subtypes.MsgAddProject{
Expand Down Expand Up @@ -622,13 +623,9 @@ func TestAddProjectAfterPlanUpdate(t *testing.T) {
Description: "dummy_desc",
Enabled: true,
ProjectKeys: []projectstypes.ProjectKey{
{
Key: ts.clients[1].Addr.String(),
Types: []projectstypes.ProjectKey_KEY_TYPE{
projectstypes.ProjectKey_DEVELOPER,
projectstypes.ProjectKey_ADMIN,
},
},
projectstypes.NewProjectKey(ts.clients[1].Addr.String()).
AddType(projectstypes.ProjectKey_ADMIN).
AddType(projectstypes.ProjectKey_DEVELOPER),
},
Policy: nil,
}
Expand Down
14 changes: 4 additions & 10 deletions x/projects/client/cli/tx_add_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ func CmdAddKeys() *cobra.Command {
Long: `The add-keys command allows the project admin to add new project keys (admin/developer) to the project.
To add the keys you can optionally provide a YAML file of the new project keys (see example in cookbook/project/example_project_keys.yml).
Note that in project keys, to define the key type, you should follow the enum described in the top of example_project_keys.yml.
Another way to add keys is with the --admin and --developer flags.`,
Another way to add keys is with the --admin-key and --developer-key flags.`,
Example: `required flags: --from <admin-key> (the project's subscription address is also considered admin)
lavad tx project add-keys [project-id] [project-keys-file-path] --from <admin-key>
lavad tx project add-keys [project-id] --admin <other-admin-key> --admin <another-admin-key> --developer <developer-key> --from <admin-key>`,
lavad tx project add-keys [project-id] --admin-key <other-admin-key> --admin-key <another-admin-key> --developer-key <developer-key> --from <admin-key>`,
Args: cobra.RangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
projectID := args[0]
Expand All @@ -43,10 +43,7 @@ func CmdAddKeys() *cobra.Command {
}
var developerKeys []types.ProjectKey
for _, developerFlagValue := range developerFlagsValue {
developerKeys = append(developerKeys, types.ProjectKey{
Key: developerFlagValue,
Types: []types.ProjectKey_KEY_TYPE{types.ProjectKey_DEVELOPER},
})
developerKeys = append(developerKeys, types.ProjectDeveloperKey(developerFlagValue))
}

adminAddresses, err := cmd.Flags().GetStringSlice("admin-key")
Expand All @@ -55,10 +52,7 @@ func CmdAddKeys() *cobra.Command {
}
var adminKeys []types.ProjectKey
for _, adminAddress := range adminAddresses {
adminKeys = append(adminKeys, types.ProjectKey{
Key: adminAddress,
Types: []types.ProjectKey_KEY_TYPE{types.ProjectKey_ADMIN},
})
adminKeys = append(adminKeys, types.ProjectAdminKey(adminAddress))
}

// doing this redundant line to avoid lint issues
Expand Down
96 changes: 49 additions & 47 deletions x/projects/keeper/creation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@ import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/lavanet/lava/utils"
plantypes "github.com/lavanet/lava/x/plans/types"
"github.com/lavanet/lava/x/projects/types"
)

// add a default project to a subscription, add the subscription key as
func (k Keeper) CreateAdminProject(ctx sdk.Context, subscriptionAddress string, plan plantypes.Plan) error {
func (k Keeper) CreateAdminProject(ctx sdk.Context, subAddr string, plan plantypes.Plan) error {
projectData := types.ProjectData{
Name: types.ADMIN_PROJECT_NAME,
Description: types.ADMIN_PROJECT_DESCRIPTION,
ProjectKeys: []types.ProjectKey{types.ProjectDeveloperKey(subAddr)},
Enabled: true,
ProjectKeys: []types.ProjectKey{{Key: subscriptionAddress, Types: []types.ProjectKey_KEY_TYPE{types.ProjectKey_DEVELOPER}}},
Policy: nil,
}
return k.CreateProject(ctx, subscriptionAddress, projectData, plan)
return k.CreateProject(ctx, subAddr, projectData, plan)
}

// add a new project to the subscription
func (k Keeper) CreateProject(ctx sdk.Context, subscriptionAddress string, projectData types.ProjectData, plan plantypes.Plan) error {
project, err := types.NewProject(subscriptionAddress, projectData.GetName(), projectData.GetDescription(),
projectData.GetEnabled())
func (k Keeper) CreateProject(ctx sdk.Context, subAddr string, projectData types.ProjectData, plan plantypes.Plan) error {
project, err := types.NewProject(subAddr, projectData.GetName(), projectData.GetDescription(), projectData.GetEnabled())
if err != nil {
return err
}
Expand All @@ -33,18 +33,21 @@ func (k Keeper) CreateProject(ctx sdk.Context, subscriptionAddress string, proje
blockHeight := uint64(ctx.BlockHeight())
if found := k.projectsFS.FindEntry(ctx, project.Index, blockHeight, &emptyProject); found {
// the project with the same name already exists if no error has returned
return utils.LavaFormatWarning("project already exist for the current subscription with the same name", fmt.Errorf("could not create project"),
utils.Attribute{Key: "subscription", Value: subscriptionAddress},
return utils.LavaFormatWarning(
"project already exist for the current subscription with the same name",
fmt.Errorf("could not create project"),
utils.Attribute{Key: "subscription", Value: subAddr},
)
}

project.AdminPolicy = projectData.GetPolicy()

// projects can be created only by the subscription owner. So the subscription policy is equal to the admin policy
// projects can be created only by the subscription owner:
// clone the admin policy to use as the subscription policy too.
project.SubscriptionPolicy = project.AdminPolicy

for _, projectKey := range projectData.GetProjectKeys() {
err = k.RegisterKey(ctx, types.ProjectKey{Key: projectKey.GetKey(), Types: projectKey.GetTypes()}, &project, blockHeight)
err = k.registerKey(ctx, projectKey, &project, blockHeight)
if err != nil {
return err
}
Expand All @@ -53,59 +56,58 @@ func (k Keeper) CreateProject(ctx sdk.Context, subscriptionAddress string, proje
return k.projectsFS.AppendEntry(ctx, project.Index, blockHeight, &project)
}

func (k Keeper) RegisterKey(ctx sdk.Context, key types.ProjectKey, project *types.Project, blockHeight uint64) error {
if project == nil {
return utils.LavaFormatError("project is nil", fmt.Errorf("could not register key to project"))
func (k Keeper) registerKey(ctx sdk.Context, key types.ProjectKey, project *types.Project, blockHeight uint64) error {
if !key.IsTypeValid() {
return sdkerrors.ErrInvalidType
}

for _, keyType := range key.GetTypes() {
switch keyType {
case types.ProjectKey_ADMIN:
k.AddAdminKey(project, key.GetKey())
case types.ProjectKey_DEVELOPER:
// try to find the developer key
var developerData types.ProtoDeveloperData
found := k.developerKeysFS.FindEntry(ctx, key.GetKey(), blockHeight, &developerData)

// if we find the developer key and it belongs to a different project, return error
if found && developerData.ProjectID != project.GetIndex() {
return utils.LavaFormatWarning("key already exists", fmt.Errorf("could not register key to project"),
utils.Attribute{Key: "key", Value: key.Key},
utils.Attribute{Key: "keyTypes", Value: key.Types},
)
}
if key.IsType(types.ProjectKey_ADMIN) {
k.addAdminKey(project, key.GetKey())
}

if key.IsType(types.ProjectKey_DEVELOPER) {
var devkeyData types.ProtoDeveloperData
found := k.developerKeysFS.FindEntry(ctx, key.GetKey(), blockHeight, &devkeyData)

// the developer key may not already belong to a different project
if found && devkeyData.ProjectID != project.GetIndex() {
return utils.LavaFormatWarning("key already exists",
fmt.Errorf("could not register key to project"),
utils.Attribute{Key: "key", Value: key.Key},
utils.Attribute{Key: "keyTypes", Value: key.Kinds},
)
}

if !found {
err := k.AddDeveloperKey(ctx, key.GetKey(), project, blockHeight)
if err != nil {
return utils.LavaFormatError("adding developer key to project failed", err,
utils.Attribute{Key: "developerKey", Value: key.Key},
utils.Attribute{Key: "projectIndex", Value: project.Index},
utils.Attribute{Key: "blockHeight", Value: blockHeight},
)
}
if !found {
err := k.addDeveloperKey(ctx, key.GetKey(), project, blockHeight)
if err != nil {
return utils.LavaFormatError("adding developer key to project failed", err,
utils.Attribute{Key: "developerKey", Value: key.Key},
utils.Attribute{Key: "projectIndex", Value: project.Index},
utils.Attribute{Key: "blockHeight", Value: blockHeight},
)
}
default:
panic("requested key has an invalid type")
}
}

return nil
}

func (k Keeper) AddAdminKey(project *types.Project, adminKey string) {
project.AppendKey(types.ProjectKey{Key: adminKey, Types: []types.ProjectKey_KEY_TYPE{types.ProjectKey_ADMIN}})
func (k Keeper) addAdminKey(project *types.Project, adminKey string) {
project.AppendKey(types.ProjectAdminKey(adminKey))
}

func (k Keeper) AddDeveloperKey(ctx sdk.Context, developerKey string, project *types.Project, blockHeight uint64) error {
var developerData types.ProtoDeveloperData
developerData.ProjectID = project.GetIndex()
err := k.developerKeysFS.AppendEntry(ctx, developerKey, blockHeight, &developerData)
func (k Keeper) addDeveloperKey(ctx sdk.Context, devkey string, project *types.Project, blockHeight uint64) error {
devkeyData := types.ProtoDeveloperData{
ProjectID: project.GetIndex(),
}

err := k.developerKeysFS.AppendEntry(ctx, devkey, blockHeight, &devkeyData)
if err != nil {
return err
}

project.AppendKey(types.ProjectKey{Key: developerKey, Types: []types.ProjectKey_KEY_TYPE{types.ProjectKey_DEVELOPER}})
project.AppendKey(types.ProjectDeveloperKey(devkey))

return nil
}
Expand Down
Loading

0 comments on commit a682eef

Please sign in to comment.