Skip to content

Commit

Permalink
feat: add coordinated zetaclient restart
Browse files Browse the repository at this point in the history
  • Loading branch information
gartnera committed Dec 6, 2024
1 parent d8e4fc7 commit ca2cc9f
Show file tree
Hide file tree
Showing 20 changed files with 1,639 additions and 274 deletions.
1 change: 1 addition & 0 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {

if testAdmin {
eg.Go(adminTestRoutine(conf, deployerRunner, verbose,
e2etests.TestOperationalFlagsName,
e2etests.TestWhitelistERC20Name,
e2etests.TestPauseZRC20Name,
e2etests.TestUpdateBytecodeZRC20Name,
Expand Down
7 changes: 7 additions & 0 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const (
TestMigrateERC20CustodyFundsName = "migrate_erc20_custody_funds"
TestMigrateTSSName = "migrate_TSS"
TestSolanaWhitelistSPLName = "solana_whitelist_spl"
TestOperationalFlagsName = "operational_flags"

/*
V2 smart contract tests
Expand Down Expand Up @@ -855,6 +856,12 @@ var AllE2ETests = []runner.E2ETest{
[]runner.ArgDefinition{},
TestMigrateERC20CustodyFunds,
),
runner.NewE2ETest(
TestOperationalFlagsName,
"operational flags functionality",
[]runner.ArgDefinition{},
TestOperationalFlags,
),
/*
V2 smart contract tests
*/
Expand Down
38 changes: 38 additions & 0 deletions e2e/e2etests/test_operational_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package e2etests

import (
"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
observertypes "github.com/zeta-chain/node/x/observer/types"
)

// TestOperationalFlags tests the functionality of operations flags.
func TestOperationalFlags(r *runner.E2ERunner, _ []string) {
operationalFlagsRes, err := r.Clients.Zetacore.Observer.OperationalFlags(
r.Ctx,
&observertypes.QueryOperationalFlagsRequest{},
)
require.NoError(r, err)

// always set to low height so it's ignored by zetaclient
nextRestartHeight := operationalFlagsRes.OperationalFlags.RestartHeight + 1

updateMsg := observertypes.NewMsgUpdateOperationalFlags(
r.ZetaTxServer.MustGetAccountAddressFromName(utils.OperationalPolicyName),
observertypes.OperationalFlags{
RestartHeight: nextRestartHeight,
},
)

_, err = r.ZetaTxServer.BroadcastTx(utils.OperationalPolicyName, updateMsg)
require.NoError(r, err)

operationalFlagsRes, err = r.Clients.Zetacore.Observer.OperationalFlags(
r.Ctx,
&observertypes.QueryOperationalFlagsRequest{},
)
require.NoError(r, err)
require.Equal(r, nextRestartHeight, operationalFlagsRes.OperationalFlags.RestartHeight)
}
10 changes: 10 additions & 0 deletions proto/zetachain/zetacore/observer/operational.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";
package zetachain.zetacore.observer;

option go_package = "github.com/zeta-chain/node/x/observer/types";

message OperationalFlags {
// Height for a coordinated zetaclient restart.
// Will be ignored if missed.
int64 restart_height = 1;
}
13 changes: 13 additions & 0 deletions proto/zetachain/zetacore/observer/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import "zetachain/zetacore/observer/observer.proto";
import "zetachain/zetacore/observer/params.proto";
import "zetachain/zetacore/observer/pending_nonces.proto";
import "zetachain/zetacore/observer/tss.proto";
import "zetachain/zetacore/observer/operational.proto";
import "zetachain/zetacore/pkg/chains/chains.proto";
import "zetachain/zetacore/pkg/proofs/proofs.proto";
import "zetachain/zetacore/observer/tss_funds_migrator.proto";
Expand Down Expand Up @@ -164,6 +165,18 @@ service Query {
option (google.api.http).get =
"/zeta-chain/observer/getAllTssFundsMigrators";
}

// Queries operational flags
rpc OperationalFlags(QueryOperationalFlagsRequest)
returns (QueryOperationalFlagsResponse) {
option (google.api.http).get = "/zeta-chain/observer/opertaionalFlags";
}
}

message QueryOperationalFlagsRequest {}

message QueryOperationalFlagsResponse {
OperationalFlags operational_flags = 1 [ (gogoproto.nullable) = false ];
}

message QueryTssFundsMigratorInfoAllRequest {}
Expand Down
12 changes: 11 additions & 1 deletion proto/zetachain/zetacore/observer/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "zetachain/zetacore/observer/observer.proto";
import "zetachain/zetacore/observer/params.proto";
import "zetachain/zetacore/observer/pending_nonces.proto";
import "zetachain/zetacore/observer/tss.proto";
import "zetachain/zetacore/observer/operational.proto";
import "zetachain/zetacore/pkg/chains/chains.proto";
import "zetachain/zetacore/pkg/proofs/proofs.proto";

Expand All @@ -31,6 +32,8 @@ service Msg {
rpc DisableCCTX(MsgDisableCCTX) returns (MsgDisableCCTXResponse);
rpc UpdateGasPriceIncreaseFlags(MsgUpdateGasPriceIncreaseFlags)
returns (MsgUpdateGasPriceIncreaseFlagsResponse);
rpc UpdateOperationalFlags(MsgUpdateOperationalFlags)
returns (MsgUpdateOperationalFlagsResponse);
}

message MsgUpdateObserver {
Expand Down Expand Up @@ -136,4 +139,11 @@ message MsgUpdateGasPriceIncreaseFlags {
[ (gogoproto.nullable) = false ];
}

message MsgUpdateGasPriceIncreaseFlagsResponse {}
message MsgUpdateGasPriceIncreaseFlagsResponse {}

message MsgUpdateOperationalFlags {
string creator = 1;
OperationalFlags operationalFlags = 2 [ (gogoproto.nullable) = false ];
}

message MsgUpdateOperationalFlagsResponse {}
1 change: 1 addition & 0 deletions x/authority/types/authorization_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var (
"/zetachain.zetacore.observer.MsgUpdateChainParams",
"/zetachain.zetacore.observer.MsgEnableCCTX",
"/zetachain.zetacore.observer.MsgUpdateGasPriceIncreaseFlags",
"/zetachain.zetacore.observer.MsgUpdateOperationalFlags",
}
// AdminPolicyMessages keeps track of the message URLs that can, by default, only be executed by admin policy address
AdminPolicyMessages = []string{
Expand Down
1 change: 1 addition & 0 deletions x/authority/types/authorization_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ func TestDefaultAuthorizationsList(t *testing.T) {
sdk.MsgTypeURL(&observertypes.MsgUpdateChainParams{}),
sdk.MsgTypeURL(&observertypes.MsgEnableCCTX{}),
sdk.MsgTypeURL(&observertypes.MsgUpdateGasPriceIncreaseFlags{}),
sdk.MsgTypeURL(&observertypes.MsgUpdateOperationalFlags{}),
}

// EmergencyPolicyMessageList is a list of messages that can be authorized by the emergency policy
Expand Down
1 change: 1 addition & 0 deletions x/observer/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func GetTxCmd() *cobra.Command {
CmdEnableCCTX(),
CmdDisableCCTX(),
CmdUpdateGasPriceIncreaseFlags(),
CmdUpdateOperationalFlags(),
)

return cmd
Expand Down
65 changes: 65 additions & 0 deletions x/observer/client/cli/tx_update_operational_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package cli

import (
"encoding/json"
"os"
"path/filepath"

"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/node/x/observer/types"
)

func CmdUpdateOperationalFlags() *cobra.Command {
cmd := &cobra.Command{
Use: "update-operational-flags",
Short: "Broadcast message UpdateOperationalFlags",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) (err error) {

Check failure on line 21 in x/observer/client/cli/tx_update_operational_flags.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'args' seems to be unused, consider removing or renaming it as _ (revive)
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

var operationalFlags types.OperationalFlags

flagSet := cmd.Flags()
file, _ := flagSet.GetString("file")
restartHeight, _ := flagSet.GetInt64("restart-height")

if file != "" {
file, err := filepath.Abs(file)
if err != nil {
return err
}
file = filepath.Clean(file)
input, err := os.ReadFile(file) // #nosec G304
if err != nil {
return err
}
err = json.Unmarshal(input, &operationalFlags)
if err != nil {
return err
}
} else {
operationalFlags.RestartHeight = restartHeight
}

msg := types.NewMsgUpdateOperationalFlags(
clientCtx.GetFromAddress().String(),
operationalFlags,
)

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

cmd.Flags().String("file", "", "Path to a JSON file containing OperationalFlags")
cmd.Flags().Int64("restart-height", 0, "Height for a coordinated zetaclient restart")
flags.AddTxFlagsToCmd(cmd)

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

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/zeta-chain/node/x/observer/types"
)

func (k Keeper) OperationalFlags(
c context.Context,
req *types.QueryOperationalFlagsRequest,
) (*types.QueryOperationalFlagsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
ctx := sdk.UnwrapSDKContext(c)
// ignoring found is intentional
operationalFlags, _ := k.GetOperationalFlags(ctx)
return &types.QueryOperationalFlagsResponse{
OperationalFlags: operationalFlags,
}, nil

Check warning on line 25 in x/observer/keeper/grpc_query_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/keeper/grpc_query_operational_flags.go#L16-L25

Added lines #L16 - L25 were not covered by tests
}
28 changes: 28 additions & 0 deletions x/observer/keeper/msg_server_update_operational_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package keeper

import (
"context"

"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"

authoritytypes "github.com/zeta-chain/node/x/authority/types"
"github.com/zeta-chain/node/x/observer/types"
)

func (k msgServer) UpdateOperationalFlags(
goCtx context.Context,
msg *types.MsgUpdateOperationalFlags,
) (*types.MsgUpdateOperationalFlagsResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// check permission
err := k.GetAuthorityKeeper().CheckAuthorization(ctx, msg)
if err != nil {
return nil, errors.Wrap(authoritytypes.ErrUnauthorized, err.Error())
}

Check warning on line 23 in x/observer/keeper/msg_server_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/keeper/msg_server_update_operational_flags.go#L16-L23

Added lines #L16 - L23 were not covered by tests

k.Keeper.SetOperationalFlags(ctx, msg.OperationalFlags)

return &types.MsgUpdateOperationalFlagsResponse{}, nil

Check warning on line 27 in x/observer/keeper/msg_server_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/keeper/msg_server_update_operational_flags.go#L25-L27

Added lines #L25 - L27 were not covered by tests
}
26 changes: 26 additions & 0 deletions x/observer/keeper/operational_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package keeper

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

"github.com/zeta-chain/node/x/observer/types"
)

func (k Keeper) SetOperationalFlags(ctx sdk.Context, operationalFlags types.OperationalFlags) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshal(&operationalFlags)
key := types.KeyPrefix(types.OperationalFlagsKey)
store.Set(key, b)

Check warning on line 13 in x/observer/keeper/operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/keeper/operational_flags.go#L9-L13

Added lines #L9 - L13 were not covered by tests
}

func (k Keeper) GetOperationalFlags(ctx sdk.Context) (val types.OperationalFlags, found bool) {
found = false
store := ctx.KVStore(k.storeKey)
b := store.Get(types.KeyPrefix(types.OperationalFlagsKey))
if b == nil {
return
}
found = true
k.cdc.MustUnmarshal(b, &val)
return

Check warning on line 25 in x/observer/keeper/operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/keeper/operational_flags.go#L16-L25

Added lines #L16 - L25 were not covered by tests
}
2 changes: 2 additions & 0 deletions x/observer/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func RegisterCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgEnableCCTX{}, "observer/EnableCCTX", nil)
cdc.RegisterConcrete(&MsgDisableCCTX{}, "observer/DisableCCTX", nil)
cdc.RegisterConcrete(&MsgUpdateGasPriceIncreaseFlags{}, "observer/UpdateGasPriceIncreaseFlags", nil)
cdc.RegisterConcrete(&MsgUpdateOperationalFlags{}, "observer/UpdateOperationalFlags", nil)
}

func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
Expand All @@ -36,6 +37,7 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
&MsgEnableCCTX{},
&MsgDisableCCTX{},
&MsgUpdateGasPriceIncreaseFlags{},
&MsgUpdateOperationalFlags{},
)

msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
Expand Down
2 changes: 2 additions & 0 deletions x/observer/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ const (
NonceToCctxKeyPrefix = "NonceToCctx-value-"

ParamsKey = "Params-value-"

OperationalFlagsKey = "OperationalFlags"
)

func GetBlameIndex(chainID int64, nonce uint64, digest string, height uint64) string {
Expand Down
48 changes: 48 additions & 0 deletions x/observer/types/message_update_operational_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package types

import (
cosmoserrors "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

const (
TypeMsgUpdateOperationalFlags = "update_operational_flags"
)

var _ sdk.Msg = &MsgUpdateOperationalFlags{}

func NewMsgUpdateOperationalFlags(creator string, flags OperationalFlags) *MsgUpdateOperationalFlags {
return &MsgUpdateOperationalFlags{
Creator: creator,
OperationalFlags: flags,
}

Check warning on line 19 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L15-L19

Added lines #L15 - L19 were not covered by tests
}

func (msg *MsgUpdateOperationalFlags) Route() string {
return RouterKey

Check warning on line 23 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L22-L23

Added lines #L22 - L23 were not covered by tests
}

func (msg *MsgUpdateOperationalFlags) Type() string {
return TypeMsgUpdateOperationalFlags

Check warning on line 27 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L26-L27

Added lines #L26 - L27 were not covered by tests
}

func (msg *MsgUpdateOperationalFlags) GetSigners() []sdk.AccAddress {
creator, err := sdk.AccAddressFromBech32(msg.Creator)
if err != nil {
panic(err)

Check warning on line 33 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L30-L33

Added lines #L30 - L33 were not covered by tests
}
return []sdk.AccAddress{creator}

Check warning on line 35 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L35

Added line #L35 was not covered by tests
}

func (msg *MsgUpdateOperationalFlags) GetSignBytes() []byte {
bz := ModuleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)

Check warning on line 40 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L38-L40

Added lines #L38 - L40 were not covered by tests
}

func (msg *MsgUpdateOperationalFlags) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(msg.Creator); err != nil {
return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err)
}
return nil

Check warning on line 47 in x/observer/types/message_update_operational_flags.go

View check run for this annotation

Codecov / codecov/patch

x/observer/types/message_update_operational_flags.go#L43-L47

Added lines #L43 - L47 were not covered by tests
}
Loading

0 comments on commit ca2cc9f

Please sign in to comment.