Skip to content

Commit

Permalink
feat: add authorization list for policy transactions (#2289)
Browse files Browse the repository at this point in the history
  • Loading branch information
kingpinXD authored May 31, 2024
1 parent 0e75423 commit 54de761
Show file tree
Hide file tree
Showing 20 changed files with 1,459 additions and 64 deletions.
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 @@ func SetupHandlers(app *App) {

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) {
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 {
// 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;
}

// 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)
}

// 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

0 comments on commit 54de761

Please sign in to comment.