Skip to content

Commit

Permalink
implement message update verification flags
Browse files Browse the repository at this point in the history
  • Loading branch information
lumtis committed Apr 7, 2024
1 parent bcb005d commit 78f4dd5
Show file tree
Hide file tree
Showing 17 changed files with 1,035 additions and 13 deletions.
1 change: 1 addition & 0 deletions docs/cli/zetacored/zetacored_tx_lightclient.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ zetacored tx lightclient [flags]
### SEE ALSO

* [zetacored tx](zetacored_tx.md) - Transactions subcommands
* [zetacored tx lightclient update-verification-flags](zetacored_tx_lightclient_update-verification-flags.md) - Update verification flags

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# tx lightclient update-verification-flags

Update verification flags

```
zetacored tx lightclient update-verification-flags [eth-type-chain-enabled] [btc-type-chain-enabled] [flags]
```

### Options

```
-a, --account-number uint The account number of the signing account (offline mode only)
--aux Generate aux signer data instead of sending a tx
-b, --broadcast-mode string Transaction broadcasting mode (sync|async|block)
--dry-run ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)
--fee-granter string Fee granter grants fees for the transaction
--fee-payer string Fee payer pays fees for the transaction instead of deducting from the signer
--fees string Fees to pay along with transaction; eg: 10uatom
--from string Name or address of private key with which to sign
--gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000)
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
--gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
--generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)
-h, --help help for update-verification-flags
--keyring-backend string Select keyring's backend (os|file|kwallet|pass|test|memory)
--keyring-dir string The client Keyring directory; if omitted, the default 'home' directory will be used
--ledger Use a connected Ledger device
--node string [host]:[port] to tendermint rpc interface for this chain
--note string Note to add a description to the transaction (previously --memo)
--offline Offline mode (does not allow any online functionality)
-o, --output string Output format (text|json)
-s, --sequence uint The sequence number of the signing account (offline mode only)
--sign-mode string Choose sign mode (direct|amino-json|direct-aux), this is an advanced feature
--timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height
--tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator
-y, --yes Skip tx broadcasting prompt confirmation
```

### Options inherited from parent commands

```
--chain-id string The network chain ID
--home string directory for config and data
--log_format string The logging format (json|plain)
--log_level string The logging level (trace|debug|info|warn|error|fatal|panic)
--trace print out full stack trace on errors
```

### SEE ALSO

* [zetacored tx lightclient](zetacored_tx_lightclient.md) - lightclient transactions subcommands

2 changes: 2 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54361,6 +54361,8 @@ definitions:
type: string
format: byte
title: ChainState defines the overall state of the block headers for a given chain
lightclientMsgUpdateVerificationFlagsResponse:
type: object
lightclientQueryAllChainStateResponse:
type: object
properties:
Expand Down
14 changes: 14 additions & 0 deletions docs/spec/lightclient/messages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Messages

## MsgUpdateVerificationFlags

UpdateVerificationFlags updates the crosschain related flags.
Emergency group can disable flags while operation group can enable/disable

```proto
message MsgUpdateVerificationFlags {
string creator = 1;
VerificationFlags verification_flags = 2;
}
```

12 changes: 11 additions & 1 deletion proto/lightclient/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@ syntax = "proto3";
package zetachain.zetacore.lightclient;

import "gogoproto/gogo.proto";
import "lightclient/verification_flags.proto";

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

// Msg defines the Msg service.
service Msg {}
service Msg {
rpc UpdateVerificationFlags(MsgUpdateVerificationFlags) returns (MsgUpdateVerificationFlagsResponse);
}

message MsgUpdateVerificationFlags {
string creator = 1;
VerificationFlags verification_flags = 2 [(gogoproto.nullable) = false];
}

message MsgUpdateVerificationFlagsResponse {}
1 change: 1 addition & 0 deletions typescript/lightclient/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./chain_state_pb";
export * from "./genesis_pb";
export * from "./query_pb";
export * from "./tx_pb";
export * from "./verification_flags_pb";
57 changes: 57 additions & 0 deletions typescript/lightclient/tx_pb.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @generated by protoc-gen-es v1.3.0 with parameter "target=dts"
// @generated from file lightclient/tx.proto (package zetachain.zetacore.lightclient, 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 { VerificationFlags } from "./verification_flags_pb.js";

/**
* @generated from message zetachain.zetacore.lightclient.MsgUpdateVerificationFlags
*/
export declare class MsgUpdateVerificationFlags extends Message<MsgUpdateVerificationFlags> {
/**
* @generated from field: string creator = 1;
*/
creator: string;

/**
* @generated from field: zetachain.zetacore.lightclient.VerificationFlags verification_flags = 2;
*/
verificationFlags?: VerificationFlags;

constructor(data?: PartialMessage<MsgUpdateVerificationFlags>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.lightclient.MsgUpdateVerificationFlags";
static readonly fields: FieldList;

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

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

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

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

/**
* @generated from message zetachain.zetacore.lightclient.MsgUpdateVerificationFlagsResponse
*/
export declare class MsgUpdateVerificationFlagsResponse extends Message<MsgUpdateVerificationFlagsResponse> {
constructor(data?: PartialMessage<MsgUpdateVerificationFlagsResponse>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.lightclient.MsgUpdateVerificationFlagsResponse";
static readonly fields: FieldList;

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

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

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

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

4 changes: 3 additions & 1 deletion x/lightclient/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ func GetTxCmd() *cobra.Command {
RunE: client.ValidateCmd,
}

cmd.AddCommand()
cmd.AddCommand(
CmdUpdateVerificationFlags(),
)

return cmd
}
41 changes: 41 additions & 0 deletions x/lightclient/client/cli/tx_update_verification_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cli

import (
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/spf13/cobra"
"github.com/zeta-chain/zetacore/x/lightclient/types"
)

func CmdUpdateVerificationFlags() *cobra.Command {
cmd := &cobra.Command{
Use: "update-verification-flags [eth-type-chain-enabled] [btc-type-chain-enabled]",
Short: "Update verification flags",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
argEthEnabled, err := strconv.ParseBool(args[0])
if err != nil {
return err
}
arsBtcEnabled, err := strconv.ParseBool(args[1])
if err != nil {
return err
}
msg := types.NewMsgUpdateVerificationFlags(clientCtx.GetFromAddress().String(), argEthEnabled, arsBtcEnabled)

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
32 changes: 32 additions & 0 deletions x/lightclient/keeper/msg_server_update_verification_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package keeper

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
"github.com/zeta-chain/zetacore/x/lightclient/types"
)

// UpdateVerificationFlags updates the crosschain related flags.
// Emergency group can disable flags while operation group can enable/disable
func (k msgServer) UpdateVerificationFlags(goCtx context.Context, msg *types.MsgUpdateVerificationFlags) (
*types.MsgUpdateVerificationFlagsResponse,
error,
) {
ctx := sdk.UnwrapSDKContext(goCtx)

requiredGroup := authoritytypes.PolicyType_groupEmergency
if msg.VerificationFlags.EthTypeChainEnabled || msg.VerificationFlags.BtcTypeChainEnabled {
requiredGroup = authoritytypes.PolicyType_groupEmergency
}

// check permission
if !k.GetAuthorityKeeper().IsAuthorized(ctx, msg.Creator, requiredGroup) {
return &types.MsgUpdateVerificationFlagsResponse{}, authoritytypes.ErrUnauthorized
}

k.SetVerificationFlags(ctx, msg.VerificationFlags)

return &types.MsgUpdateVerificationFlagsResponse{}, nil
}
142 changes: 142 additions & 0 deletions x/lightclient/keeper/msg_server_update_verification_flags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package keeper_test

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
"github.com/zeta-chain/zetacore/x/lightclient/keeper"
"github.com/zeta-chain/zetacore/x/lightclient/types"
)

func TestMsgServer_UpdateVerificationFlags(t *testing.T) {
t.Run("operational group can enable verification flags", func(t *testing.T) {
k, ctx, _, _ := keepertest.LightclientKeeperWithMocks(t, keepertest.LightclientMockOptions{
UseAuthorityMock: true,
})
srv := keeper.NewMsgServerImpl(*k)
admin := sample.AccAddress()

// mock the authority keeper for authorization
authorityMock := keepertest.GetLightclientAuthorityMock(t, k)

k.SetVerificationFlags(ctx, types.VerificationFlags{
EthTypeChainEnabled: false,
BtcTypeChainEnabled: false,
})

// enable eth type chain
keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true)
_, err := srv.UpdateVerificationFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateVerificationFlags{
Creator: admin,
VerificationFlags: types.VerificationFlags{
EthTypeChainEnabled: true,
BtcTypeChainEnabled: false,
},
})
require.NoError(t, err)
vf, found := k.GetVerificationFlags(ctx)
require.True(t, found)
require.True(t, vf.EthTypeChainEnabled)
require.False(t, vf.BtcTypeChainEnabled)

// enable btc type chain
keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true)
_, err = srv.UpdateVerificationFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateVerificationFlags{
Creator: admin,
VerificationFlags: types.VerificationFlags{
EthTypeChainEnabled: false,
BtcTypeChainEnabled: true,
},
})
require.NoError(t, err)
vf, found = k.GetVerificationFlags(ctx)
require.True(t, found)
require.False(t, vf.EthTypeChainEnabled)
require.True(t, vf.BtcTypeChainEnabled)

// enable both eth and btc type chain
keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true)
_, err = srv.UpdateVerificationFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateVerificationFlags{
Creator: admin,
VerificationFlags: types.VerificationFlags{
EthTypeChainEnabled: true,
BtcTypeChainEnabled: true,
},
})
require.NoError(t, err)
vf, found = k.GetVerificationFlags(ctx)
require.True(t, found)
require.True(t, vf.EthTypeChainEnabled)
require.True(t, vf.BtcTypeChainEnabled)
})

t.Run("emergency group can disable verification flags", func(t *testing.T) {
k, ctx, _, _ := keepertest.LightclientKeeperWithMocks(t, keepertest.LightclientMockOptions{
UseAuthorityMock: true,
})
srv := keeper.NewMsgServerImpl(*k)
admin := sample.AccAddress()

// mock the authority keeper for authorization
authorityMock := keepertest.GetLightclientAuthorityMock(t, k)

k.SetVerificationFlags(ctx, types.VerificationFlags{
EthTypeChainEnabled: false,
BtcTypeChainEnabled: false,
})

keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupEmergency, true)
_, err := srv.UpdateVerificationFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateVerificationFlags{
Creator: admin,
VerificationFlags: types.VerificationFlags{
EthTypeChainEnabled: false,
BtcTypeChainEnabled: false,
},
})
require.NoError(t, err)
vf, found := k.GetVerificationFlags(ctx)
require.True(t, found)
require.False(t, vf.EthTypeChainEnabled)
require.False(t, vf.BtcTypeChainEnabled)
})

t.Run("cannot update if not authorized group", func(t *testing.T) {
k, ctx, _, _ := keepertest.LightclientKeeperWithMocks(t, keepertest.LightclientMockOptions{
UseAuthorityMock: true,
})
srv := keeper.NewMsgServerImpl(*k)
admin := sample.AccAddress()

// mock the authority keeper for authorization
authorityMock := keepertest.GetLightclientAuthorityMock(t, k)

k.SetVerificationFlags(ctx, types.VerificationFlags{
EthTypeChainEnabled: false,
BtcTypeChainEnabled: false,
})

keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupEmergency, true)
_, err := srv.UpdateVerificationFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateVerificationFlags{
Creator: admin,
VerificationFlags: types.VerificationFlags{
EthTypeChainEnabled: true,
BtcTypeChainEnabled: false,
},
})
require.ErrorIs(t, err, authoritytypes.ErrUnauthorized)

keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true)
_, err = srv.UpdateVerificationFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateVerificationFlags{
Creator: admin,
VerificationFlags: types.VerificationFlags{
EthTypeChainEnabled: false,
BtcTypeChainEnabled: false,
},
})
require.ErrorIs(t, err, authoritytypes.ErrUnauthorized)
})
}
Loading

0 comments on commit 78f4dd5

Please sign in to comment.