Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add authorization list for policy transactions #2289

Merged
merged 20 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/setup_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@

app.UpgradeKeeper.SetUpgradeHandler(
constant.Version,
func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) {
func(ctx sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) {

Check warning on line 132 in app/setup_handlers.go

View check run for this annotation

Codecov / codecov/patch

app/setup_handlers.go#L132

Added line #L132 was not covered by tests
app.Logger().Info("Running upgrade handler for " + constant.Version)

var err error
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* [2287](https://github.com/zeta-chain/node/pull/2287) - implement `MsgUpdateChainInfo` message
* [2279](https://github.com/zeta-chain/node/pull/2279) - add a CCTXGateway field to chain static data
* [2275](https://github.com/zeta-chain/node/pull/2275) - add ChainInfo singleton state variable in authority
* [2289](https://github.com/zeta-chain/node/pull/2289) - add an authorization list to keep track of all authorizations on the chain

### Refactor

Expand Down
21 changes: 21 additions & 0 deletions proto/zetachain/zetacore/authority/authorization.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
syntax = "proto3";
package zetachain.zetacore.authority;

import "gogoproto/gogo.proto";
import "zetachain/zetacore/authority/policies.proto";

option go_package = "github.com/zeta-chain/zetacore/x/authority/types";

// Authorization defines the authorization required to access use a message
// which needs special permissions
message Authorization {
kingpinXD marked this conversation as resolved.
Show resolved Hide resolved
// The URL of the message that needs to be authorized
string msg_url = 1;
// The policy that is authorized to access the message
PolicyType authorized_policy = 2;
}
kingpinXD marked this conversation as resolved.
Show resolved Hide resolved

// AuthorizationList holds the list of authorizations on zetachain
message AuthorizationList {
repeated Authorization authorizations = 1 [ (gogoproto.nullable) = false ];
}
4 changes: 3 additions & 1 deletion proto/zetachain/zetacore/authority/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";
package zetachain.zetacore.authority;

import "zetachain/zetacore/authority/policies.proto";
import "zetachain/zetacore/authority/authorization.proto";
import "zetachain/zetacore/authority/chain_info.proto";
import "gogoproto/gogo.proto";

Expand All @@ -10,5 +11,6 @@ option go_package = "github.com/zeta-chain/zetacore/x/authority/types";
// GenesisState defines the authority module's genesis state.
message GenesisState {
Policies policies = 1 [ (gogoproto.nullable) = false ];
ChainInfo chain_info = 2 [ (gogoproto.nullable) = false ];
AuthorizationList authorization_list = 2 [ (gogoproto.nullable) = false ];
ChainInfo chain_info = 3 [ (gogoproto.nullable) = false ];
}
1 change: 1 addition & 0 deletions proto/zetachain/zetacore/authority/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zetachain.zetacore.authority;

import "zetachain/zetacore/authority/policies.proto";
import "zetachain/zetacore/authority/chain_info.proto";
import "zetachain/zetacore/authority/authorization.proto";
import "gogoproto/gogo.proto";

option go_package = "github.com/zeta-chain/zetacore/x/authority/types";
Expand Down
28 changes: 28 additions & 0 deletions testutil/sample/authority.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package sample

import (
"fmt"

"github.com/zeta-chain/zetacore/pkg/chains"
authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
)
Expand Down Expand Up @@ -37,3 +39,29 @@ func ChainInfo(startChainID int64) authoritytypes.ChainInfo {
},
}
}

func AuthorizationList(val string) authoritytypes.AuthorizationList {
return authoritytypes.AuthorizationList{
Authorizations: []authoritytypes.Authorization{
{
MsgUrl: fmt.Sprintf("/zetachain/%d%s", 0, val),
AuthorizedPolicy: authoritytypes.PolicyType_groupEmergency,
},
{
MsgUrl: fmt.Sprintf("/zetachain/%d%s", 1, val),
AuthorizedPolicy: authoritytypes.PolicyType_groupAdmin,
},
{
MsgUrl: fmt.Sprintf("/zetachain/%d%s", 2, val),
AuthorizedPolicy: authoritytypes.PolicyType_groupOperational,
},
},
}
}

func Authorization() authoritytypes.Authorization {
return authoritytypes.Authorization{
MsgUrl: "ABC",
AuthorizedPolicy: authoritytypes.PolicyType_groupOperational,
}
}
71 changes: 71 additions & 0 deletions typescript/zetachain/zetacore/authority/authorization_pb.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// @generated by protoc-gen-es v1.3.0 with parameter "target=dts"
// @generated from file zetachain/zetacore/authority/authorization.proto (package zetachain.zetacore.authority, syntax proto3)
/* eslint-disable */
// @ts-nocheck

import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3 } from "@bufbuild/protobuf";
import type { PolicyType } from "./policies_pb.js";

/**
* Authorization defines the authorization required to access use a message
* which needs special permissions
*
* @generated from message zetachain.zetacore.authority.Authorization
*/
export declare class Authorization extends Message<Authorization> {
/**
* The URL of the message that needs to be authorized
*
* @generated from field: string msg_url = 1;
*/
msgUrl: string;

/**
* The policy that is authorized to access the message
*
* @generated from field: zetachain.zetacore.authority.PolicyType authorized_policy = 2;
*/
authorizedPolicy: PolicyType;

constructor(data?: PartialMessage<Authorization>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.authority.Authorization";
static readonly fields: FieldList;

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Authorization;

static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Authorization;

static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Authorization;

static equals(a: Authorization | PlainMessage<Authorization> | undefined, b: Authorization | PlainMessage<Authorization> | undefined): boolean;
}

/**
* AuthorizationList holds the list of authorizations on zetachain
*
* @generated from message zetachain.zetacore.authority.AuthorizationList
*/
export declare class AuthorizationList extends Message<AuthorizationList> {
/**
* @generated from field: repeated zetachain.zetacore.authority.Authorization authorizations = 1;
*/
authorizations: Authorization[];

constructor(data?: PartialMessage<AuthorizationList>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.authority.AuthorizationList";
static readonly fields: FieldList;

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): AuthorizationList;

static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): AuthorizationList;

static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): AuthorizationList;

static equals(a: AuthorizationList | PlainMessage<AuthorizationList> | undefined, b: AuthorizationList | PlainMessage<AuthorizationList> | undefined): boolean;
}

8 changes: 7 additions & 1 deletion typescript/zetachain/zetacore/authority/genesis_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3 } from "@bufbuild/protobuf";
import type { Policies } from "./policies_pb.js";
import type { AuthorizationList } from "./authorization_pb.js";
import type { ChainInfo } from "./chain_info_pb.js";

/**
Expand All @@ -20,7 +21,12 @@ export declare class GenesisState extends Message<GenesisState> {
policies?: Policies;

/**
* @generated from field: zetachain.zetacore.authority.ChainInfo chain_info = 2;
* @generated from field: zetachain.zetacore.authority.AuthorizationList authorization_list = 2;
*/
authorizationList?: AuthorizationList;

/**
* @generated from field: zetachain.zetacore.authority.ChainInfo chain_info = 3;
*/
chainInfo?: ChainInfo;

Expand Down
1 change: 1 addition & 0 deletions typescript/zetachain/zetacore/authority/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./authorization_pb";
export * from "./chain_info_pb";
export * from "./genesis_pb";
export * from "./policies_pb";
Expand Down
5 changes: 5 additions & 0 deletions x/authority/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
k.SetPolicies(ctx, genState.Policies)
k.SetChainInfo(ctx, genState.ChainInfo)
k.SetAuthorizationList(ctx, genState.AuthorizationList)
kingpinXD marked this conversation as resolved.
Show resolved Hide resolved
}

// ExportGenesis returns the authority module's exported genesis.
Expand All @@ -21,6 +22,10 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
if found {
genesis.Policies = policies
}
authorizationList, found := k.GetAuthorizationList(ctx)
if found {
genesis.AuthorizationList = authorizationList
}

chainInfo, found := k.GetChainInfo(ctx)
if found {
Expand Down
62 changes: 35 additions & 27 deletions x/authority/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,39 @@ import (
)

func TestGenesis(t *testing.T) {
genesisState := types.GenesisState{
Policies: sample.Policies(),
ChainInfo: sample.ChainInfo(42),
}

// Init
k, ctx := keepertest.AuthorityKeeper(t)
authority.InitGenesis(ctx, *k, genesisState)

// Check policy is set
policies, found := k.GetPolicies(ctx)
require.True(t, found)
require.Equal(t, genesisState.Policies, policies)

// Check chain info is set
chainInfo, found := k.GetChainInfo(ctx)
require.True(t, found)
require.Equal(t, genesisState.ChainInfo, chainInfo)

// Export
got := authority.ExportGenesis(ctx, *k)
require.NotNil(t, got)

// Compare genesis after init and export
nullify.Fill(&genesisState)
nullify.Fill(got)
require.Equal(t, genesisState, *got)
t.Run("valid genesis", func(t *testing.T) {
genesisState := types.GenesisState{
Policies: sample.Policies(),
AuthorizationList: sample.AuthorizationList("sample"),
ChainInfo: sample.ChainInfo(42),
}

// Init
k, ctx := keepertest.AuthorityKeeper(t)
authority.InitGenesis(ctx, *k, genesisState)

// Check policy is set
policies, found := k.GetPolicies(ctx)
require.True(t, found)
require.Equal(t, genesisState.Policies, policies)

// Check authorization list is set
authorizationList, found := k.GetAuthorizationList(ctx)
require.True(t, found)
require.Equal(t, genesisState.AuthorizationList, authorizationList)

// Check chain info is set
chainInfo, found := k.GetChainInfo(ctx)
require.True(t, found)
require.Equal(t, genesisState.ChainInfo, chainInfo)

// Export
got := authority.ExportGenesis(ctx, *k)
require.NotNil(t, got)

// Compare genesis after init and export
nullify.Fill(&genesisState)
nullify.Fill(got)
require.Equal(t, genesisState, *got)
})
}
26 changes: 26 additions & 0 deletions x/authority/keeper/authorization_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package keeper

import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/zeta-chain/zetacore/x/authority/types"
)

// SetAuthorizationList sets the authorization list to the store.It returns an error if the list is invalid.
func (k Keeper) SetAuthorizationList(ctx sdk.Context, list types.AuthorizationList) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AuthorizationListKey))
b := k.cdc.MustMarshal(&list)
store.Set([]byte{0}, b)
}

// GetAuthorizationList returns the authorization list from the store
func (k Keeper) GetAuthorizationList(ctx sdk.Context) (val types.AuthorizationList, found bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AuthorizationListKey))
b := store.Get([]byte{0})
if b == nil {
return val, false
}
k.cdc.MustUnmarshal(b, &val)
return val, true
}
49 changes: 49 additions & 0 deletions x/authority/keeper/authorization_list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package keeper_test

import (
"testing"

"github.com/stretchr/testify/require"

keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
"github.com/zeta-chain/zetacore/x/authority/types"
)

func TestKeeper_GetAuthorizationList(t *testing.T) {
t.Run("successfully get authorizations list", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
authorizationList := sample.AuthorizationList("sample")
k.SetAuthorizationList(ctx, authorizationList)
list, found := k.GetAuthorizationList(ctx)
require.True(t, found)
require.Equal(t, authorizationList, list)
})

t.Run("get authorizations list not found", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
list, found := k.GetAuthorizationList(ctx)
require.False(t, found)
require.Equal(t, types.AuthorizationList{}, list)
})
}

func TestKeeper_SetAuthorizationList(t *testing.T) {
t.Run("successfully set authorizations list when a list already exists", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
authorizationList := sample.AuthorizationList("sample")
k.SetAuthorizationList(ctx, authorizationList)

list, found := k.GetAuthorizationList(ctx)
require.True(t, found)
require.Equal(t, authorizationList, list)

newAuthorizationList := sample.AuthorizationList("sample2")
require.NotEqual(t, authorizationList, newAuthorizationList)
k.SetAuthorizationList(ctx, newAuthorizationList)

list, found = k.GetAuthorizationList(ctx)
require.True(t, found)
require.Equal(t, newAuthorizationList, list)
})
}
Loading
Loading