Skip to content

Commit

Permalink
feat: add ChainInfo singleton state variable in authority (#2275)
Browse files Browse the repository at this point in the history
* add chain validate method

* add chain info type

* add chain info type proto

* add chain info in genesis

* generate

* changelog

* Update x/authority/types/chain_info.go

Co-authored-by: Tanmay <[email protected]>

* revert is ZetaChain logic

* fix name

---------

Co-authored-by: Tanmay <[email protected]>
  • Loading branch information
lumtis and kingpinXD authored May 29, 2024
1 parent 89ca461 commit 42fe69c
Show file tree
Hide file tree
Showing 21 changed files with 872 additions and 19 deletions.
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
33 changes: 33 additions & 0 deletions 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
}

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

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

0 comments on commit 42fe69c

Please sign in to comment.