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 ChainInfo singleton state variable in authority #2275

Merged
merged 10 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* [2113](https://github.com/zeta-chain/node/pull/2113) - add zetaclientd-supervisor process
* [2154](https://github.com/zeta-chain/node/pull/2154) - add `ibccrosschain` module
* [2258](https://github.com/zeta-chain/node/pull/2258) - add Optimism and Base in static chain information
* [2275](https://github.com/zeta-chain/node/pull/2275) - add ChainInfo singleton state variable in authority

### Refactor

Expand Down
35 changes: 34 additions & 1 deletion pkg/chains/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,47 @@ type SigninAlgo string
// Chains represent a slice of Chain
type Chains []Chain

// Validate checks whether the chain is valid
// The function check the chain ID is positive and all enum fields have a defined value
func (chain Chain) Validate() error {
if chain.ChainId <= 0 {
return fmt.Errorf("chain ID must be positive")
}

if _, ok := ChainName_name[int32(chain.ChainName)]; !ok {
return fmt.Errorf("invalid chain name %d", int32(chain.ChainName))
}

if _, ok := Network_name[int32(chain.Network)]; !ok {
return fmt.Errorf("invalid network %d", int32(chain.Network))
}

if _, ok := NetworkType_name[int32(chain.NetworkType)]; !ok {
return fmt.Errorf("invalid network type %d", int32(chain.NetworkType))
}

if _, ok := Vm_name[int32(chain.Vm)]; !ok {
return fmt.Errorf("invalid vm %d", int32(chain.Vm))
}

if _, ok := Consensus_name[int32(chain.Consensus)]; !ok {
return fmt.Errorf("invalid consensus %d", int32(chain.Consensus))
}

return nil
}

// IsEqual compare two chain to see whether they represent the same chain
func (chain Chain) IsEqual(c Chain) bool {
return chain.ChainId == c.ChainId
}

// IsZetaChain returns true if the chain is a ZetaChain chain
func (chain Chain) IsZetaChain() bool {
return chain.Network == Network_zeta
return !chain.IsExternal
kingpinXD marked this conversation as resolved.
Show resolved Hide resolved
}

// IsExternalChain returns true if the chain is an ExternalChain chain, not ZetaChain
func (chain Chain) IsExternalChain() bool {
return chain.IsExternal
}
Expand Down
127 changes: 127 additions & 0 deletions pkg/chains/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,133 @@ import (
"github.com/stretchr/testify/require"
)

func TestChain_Validate(t *testing.T) {
tests := []struct {
name string
chain Chain
errStr string
}{
{
name: "should pass if chain is valid",
chain: Chain{
ChainId: 42,
ChainName: ChainName_empty,
Network: Network_optimism,
NetworkType: NetworkType_testnet,
Vm: Vm_evm,
Consensus: Consensus_op_stack,
IsExternal: true,
},
},
{
name: "should error if chain ID is zero",
chain: Chain{
ChainId: 0,
ChainName: ChainName_empty,
Network: Network_optimism,
NetworkType: NetworkType_testnet,
Vm: Vm_evm,
Consensus: Consensus_op_stack,
IsExternal: true,
},
errStr: "chain ID must be positive",
},
{
name: "should error if chain ID is negative",
chain: Chain{
ChainId: 0,
ChainName: ChainName_empty,
Network: Network_optimism,
NetworkType: NetworkType_testnet,
Vm: Vm_evm,
Consensus: Consensus_op_stack,
IsExternal: true,
},
errStr: "chain ID must be positive",
},
{
name: "should error if chain name invalid",
chain: Chain{
ChainId: 42,
ChainName: ChainName_base_sepolia + 1,
Network: Network_optimism,
NetworkType: NetworkType_testnet,
Vm: Vm_evm,
Consensus: Consensus_op_stack,
IsExternal: true,
},
errStr: "invalid chain name",
},
{
name: "should error if network invalid",
chain: Chain{
ChainId: 42,
ChainName: ChainName_empty,
Network: Network_base + 1,
NetworkType: NetworkType_testnet,
Vm: Vm_evm,
Consensus: Consensus_op_stack,
IsExternal: true,
},
errStr: "invalid network",
},
{
name: "should error if network type invalid",
chain: Chain{
ChainId: 42,
ChainName: ChainName_empty,
Network: Network_base,
NetworkType: NetworkType_devnet + 1,
Vm: Vm_evm,
Consensus: Consensus_op_stack,
IsExternal: true,
},
errStr: "invalid network type",
},
{
name: "should error if vm invalid",
chain: Chain{
ChainId: 42,
ChainName: ChainName_empty,
Network: Network_base,
NetworkType: NetworkType_devnet,
Vm: Vm_evm + 1,
Consensus: Consensus_op_stack,
IsExternal: true,
},
errStr: "invalid vm",
},
{
name: "should error if consensus invalid",
chain: Chain{
ChainId: 42,
ChainName: ChainName_empty,
Network: Network_base,
NetworkType: NetworkType_devnet,
Vm: Vm_evm,
Consensus: Consensus_op_stack + 1,
IsExternal: true,
},
errStr: "invalid consensus",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.errStr != "" {
require.ErrorContains(t, tt.chain.Validate(), tt.errStr)
} else {
require.NoError(t, tt.chain.Validate())
}
})
kingpinXD marked this conversation as resolved.
Show resolved Hide resolved
}

t.Run("all default chains are valid", func(t *testing.T) {
for _, chain := range DefaultChainsList() {
require.NoError(t, chain.Validate())
}
})
}

func TestChain_EncodeAddress(t *testing.T) {
tests := []struct {
name string
Expand Down
14 changes: 14 additions & 0 deletions proto/zetachain/zetacore/authority/chain_info.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
syntax = "proto3";
package zetachain.zetacore.authority;

import "zetachain/zetacore/pkg/chains/chains.proto";
import "gogoproto/gogo.proto";

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

// ChainInfo contains static information about the chains
lumtis marked this conversation as resolved.
Show resolved Hide resolved
// This structure is used to dynamically update these info on a live network
// before hardcoding the values in a upgrade
message ChainInfo {
repeated pkg.chains.Chain chains = 1 [ (gogoproto.nullable) = false ];
}
6 changes: 5 additions & 1 deletion proto/zetachain/zetacore/authority/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ syntax = "proto3";
package zetachain.zetacore.authority;

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

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 ]; }
message GenesisState {
Policies policies = 1 [ (gogoproto.nullable) = false ];
ChainInfo chain_info = 2 [ (gogoproto.nullable) = false ];
}
19 changes: 18 additions & 1 deletion testutil/sample/authority.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package sample

import authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
import (
"github.com/zeta-chain/zetacore/pkg/chains"
authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
)

func Policies() authoritytypes.Policies {
return authoritytypes.Policies{
Expand All @@ -20,3 +23,17 @@ func Policies() authoritytypes.Policies {
},
}
}

func ChainInfo(startChainID int64) authoritytypes.ChainInfo {
chain1 := Chain(startChainID)
chain2 := Chain(startChainID + 1)
chain3 := Chain(startChainID + 2)

return authoritytypes.ChainInfo{
Chains: []chains.Chain{
*chain1,
*chain2,
*chain3,
},
}
}
15 changes: 13 additions & 2 deletions testutil/sample/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,20 @@ func GenDoc(t *testing.T) *types.GenesisDoc {
func Chain(chainID int64) *chains.Chain {
r := newRandFromSeed(chainID)

chainNameLen := len(chains.ChainName_name)
networkLen := len(chains.Network_name)
networkTypeLen := len(chains.NetworkType_name)
vmLen := len(chains.Vm_name)
consensusLen := len(chains.Consensus_name)

return &chains.Chain{
ChainName: chains.ChainName(r.Intn(4)),
ChainId: chainID,
ChainId: chainID,
ChainName: chains.ChainName(r.Intn(chainNameLen)),
Network: chains.Network(r.Intn(networkLen)),
NetworkType: chains.NetworkType(r.Intn(networkTypeLen)),
Vm: chains.Vm(r.Intn(vmLen)),
Consensus: chains.Consensus(r.Intn(consensusLen)),
IsExternal: true,
}
}

Expand Down
37 changes: 37 additions & 0 deletions typescript/zetachain/zetacore/authority/chain_info_pb.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// @generated by protoc-gen-es v1.3.0 with parameter "target=dts"
// @generated from file zetachain/zetacore/authority/chain_info.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 { Chain } from "../pkg/chains/chains_pb.js";

/**
* ChainInfo contains static information about the chains
* This structure is used to dynamically update these info on a live network
* before hardcoding the values in a upgrade
*
* @generated from message zetachain.zetacore.authority.ChainInfo
*/
export declare class ChainInfo extends Message<ChainInfo> {
/**
* @generated from field: repeated zetachain.zetacore.pkg.chains.Chain chains = 1;
*/
chains: Chain[];

constructor(data?: PartialMessage<ChainInfo>);

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

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

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

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

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

6 changes: 6 additions & 0 deletions 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 { ChainInfo } from "./chain_info_pb.js";

/**
* GenesisState defines the authority module's genesis state.
Expand All @@ -18,6 +19,11 @@ export declare class GenesisState extends Message<GenesisState> {
*/
policies?: Policies;

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

constructor(data?: PartialMessage<GenesisState>);

static readonly runtime: typeof proto3;
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 "./chain_info_pb";
export * from "./genesis_pb";
export * from "./policies_pb";
export * from "./query_pb";
Expand Down
6 changes: 6 additions & 0 deletions x/authority/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
// InitGenesis initializes the authority module's state from a provided genesis state
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
k.SetPolicies(ctx, genState.Policies)
k.SetChainInfo(ctx, genState.ChainInfo)
}

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

chainInfo, found := k.GetChainInfo(ctx)
if found {
genesis.ChainInfo = chainInfo
}

return &genesis
}
8 changes: 7 additions & 1 deletion x/authority/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (

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

// Init
Expand All @@ -26,6 +27,11 @@ func TestGenesis(t *testing.T) {
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)
Expand Down
Loading
Loading