diff --git a/app/app.go b/app/app.go index 0625df5f08..b30335c128 100644 --- a/app/app.go +++ b/app/app.go @@ -574,29 +574,7 @@ func New( // so that other modules that want to create or claim capabilities afterwards in InitChain // can do so safely. // NOTE: Cross-chain module must be initialized after observer module, as pending nonces in crosschain needs the tss pubkey from observer module - app.mm.SetOrderInitGenesis( - authtypes.ModuleName, - banktypes.ModuleName, - distrtypes.ModuleName, - stakingtypes.ModuleName, - slashingtypes.ModuleName, - govtypes.ModuleName, - crisistypes.ModuleName, - evmtypes.ModuleName, - feemarkettypes.ModuleName, - paramstypes.ModuleName, - group.ModuleName, - genutiltypes.ModuleName, - upgradetypes.ModuleName, - evidencetypes.ModuleName, - vestingtypes.ModuleName, - observertypes.ModuleName, - crosschaintypes.ModuleName, - fungibletypes.ModuleName, - emissionstypes.ModuleName, - authz.ModuleName, - authoritytypes.ModuleName, - ) + app.mm.SetOrderInitGenesis(InitGenesisModuleList()...) app.mm.RegisterInvariants(&app.CrisisKeeper) app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) diff --git a/app/init_genesis.go b/app/init_genesis.go new file mode 100644 index 0000000000..4156424e97 --- /dev/null +++ b/app/init_genesis.go @@ -0,0 +1,49 @@ +package app + +import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/group" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + emissionsModuleTypes "github.com/zeta-chain/zetacore/x/emissions/types" + fungibleModuleTypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func InitGenesisModuleList() []string { + return []string{ + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + stakingtypes.ModuleName, + slashingtypes.ModuleName, + govtypes.ModuleName, + crisistypes.ModuleName, + evmtypes.ModuleName, + feemarkettypes.ModuleName, + paramstypes.ModuleName, + group.ModuleName, + genutiltypes.ModuleName, + upgradetypes.ModuleName, + evidencetypes.ModuleName, + vestingtypes.ModuleName, + observertypes.ModuleName, + crosschaintypes.ModuleName, + fungibleModuleTypes.ModuleName, + emissionsModuleTypes.ModuleName, + authz.ModuleName, + } +} diff --git a/cmd/zetacored/parse_genesis.go b/cmd/zetacored/parse_genesis.go new file mode 100644 index 0000000000..c15a3f0fe7 --- /dev/null +++ b/cmd/zetacored/parse_genesis.go @@ -0,0 +1,182 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/group" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" + "github.com/spf13/cobra" + "github.com/tendermint/tendermint/types" + "github.com/zeta-chain/zetacore/app" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + emissionsModuleTypes "github.com/zeta-chain/zetacore/x/emissions/types" + fungibleModuleTypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +var Copy = map[string]bool{ + slashingtypes.ModuleName: true, + govtypes.ModuleName: true, + crisistypes.ModuleName: true, + feemarkettypes.ModuleName: true, + paramstypes.ModuleName: true, + group.ModuleName: true, + upgradetypes.ModuleName: true, + evidencetypes.ModuleName: true, + vestingtypes.ModuleName: true, + fungibleModuleTypes.ModuleName: true, + emissionsModuleTypes.ModuleName: true, + authz.ModuleName: true, +} +var Skip = map[string]bool{ + evmtypes.ModuleName: true, + stakingtypes.ModuleName: true, + genutiltypes.ModuleName: true, + authtypes.ModuleName: true, + banktypes.ModuleName: true, + distributiontypes.ModuleName: true, +} + +var Modify = map[string]bool{ + crosschaintypes.ModuleName: true, + observertypes.ModuleName: true, +} + +func CmdParseGenesisFile() *cobra.Command { + cmd := &cobra.Command{ + Use: "parse-genesis-file [import-genesis-file] [optional-genesis-file]", + Short: "Parse the genesis file", + Args: cobra.MaximumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + cdc := clientCtx.Codec + genesisFilePath := filepath.Join(app.DefaultNodeHome, "config", "genesis.json") + if len(args) == 2 { + genesisFilePath = args[1] + } + genDoc, err := GetGenDoc(genesisFilePath) + importData, err := GetGenDoc(args[0]) + + err = ImportDataIntoFile(genDoc, importData, cdc) + if err != nil { + return err + } + + err = genutil.ExportGenesisFile(genDoc, genesisFilePath) + if err != nil { + return err + } + + return nil + }, + } + return cmd +} + +func ImportDataIntoFile(genDoc *types.GenesisDoc, importFile *types.GenesisDoc, cdc codec.Codec) error { + + appState, err := genutiltypes.GenesisStateFromGenDoc(*genDoc) + if err != nil { + return err + } + importAppState, err := genutiltypes.GenesisStateFromGenDoc(*importFile) + if err != nil { + return err + } + moduleList := app.InitGenesisModuleList() + for _, m := range moduleList { + if Skip[m] { + continue + } + if Copy[m] { + appState[m] = importAppState[m] + } + if Modify[m] { + switch m { + case crosschaintypes.ModuleName: + err := ModifyCrossChainState(appState, importAppState, cdc) + if err != nil { + return err + } + case observertypes.ModuleName: + err := ModifyObserverState(appState, importAppState, cdc) + if err != nil { + return err + } + default: + return fmt.Errorf("modify function for %s not found", m) + } + } + } + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + genDoc.AppState = appStateJSON + + return nil +} + +func ModifyCrossChainState(appState map[string]json.RawMessage, importAppState map[string]json.RawMessage, cdc codec.Codec) error { + importedCrossChainGenState := crosschaintypes.GetGenesisStateFromAppState(cdc, importAppState) + importedCrossChainGenState.CrossChainTxs = importedCrossChainGenState.CrossChainTxs[:math.Min(10, len(importedCrossChainGenState.CrossChainTxs))] + importedCrossChainGenState.InTxHashToCctxList = importedCrossChainGenState.InTxHashToCctxList[:math.Min(10, len(importedCrossChainGenState.InTxHashToCctxList))] + importedCrossChainGenState.FinalizedInbounds = importedCrossChainGenState.FinalizedInbounds[:math.Min(10, len(importedCrossChainGenState.FinalizedInbounds))] + importedCrossChainStateBz, err := json.Marshal(importedCrossChainGenState) + if err != nil { + return fmt.Errorf("failed to marshal zetacrosschain genesis state: %w", err) + } + appState[crosschaintypes.ModuleName] = importedCrossChainStateBz + return nil +} + +func ModifyObserverState(appState map[string]json.RawMessage, importAppState map[string]json.RawMessage, cdc codec.Codec) error { + importedObserverGenState := observertypes.GetGenesisStateFromAppState(cdc, importAppState) + importedObserverGenState.Ballots = importedObserverGenState.Ballots[:math.Min(10, len(importedObserverGenState.Ballots))] + importedObserverGenState.NonceToCctx = importedObserverGenState.NonceToCctx[:math.Min(10, len(importedObserverGenState.NonceToCctx))] + importedObserverStateBz, err := cdc.MarshalJSON(&importedObserverGenState) + if err != nil { + return fmt.Errorf("failed to marshal observer genesis state: %w", err) + } + + appState[observertypes.ModuleName] = importedObserverStateBz + return nil +} + +func GetGenDoc(fp string) (*types.GenesisDoc, error) { + path, err := filepath.Abs(fp) + if err != nil { + return nil, err + } + jsonBlob, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return nil, err + } + genData, err := types.GenesisDocFromJSON(jsonBlob) + if err != nil { + return nil, err + } + return genData, nil +} diff --git a/cmd/zetacored/parse_genesis_test.go b/cmd/zetacored/parse_genesis_test.go new file mode 100644 index 0000000000..eb96955c1d --- /dev/null +++ b/cmd/zetacored/parse_genesis_test.go @@ -0,0 +1,225 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/types" + "github.com/zeta-chain/zetacore/app" + zetacored "github.com/zeta-chain/zetacore/cmd/zetacored" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + emissionstypes "github.com/zeta-chain/zetacore/x/emissions/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func setCosmosConfig() { + cosmosConf := sdk.GetConfig() + cosmosConf.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub) + cosmosConf.Seal() +} +func Test_ModifyCrossChainState(t *testing.T) { + setCosmosConfig() + t.Run("successfully modify cross chain state to reduce data", func(t *testing.T) { + cdc := keepertest.NewCodec() + appState := sample.AppState(t) + importData := GetImportData(t, cdc, 100) + err := zetacored.ModifyCrossChainState(appState, importData, cdc) + require.NoError(t, err) + + modifiedCrosschainAppState := crosschaintypes.GetGenesisStateFromAppState(cdc, appState) + require.Len(t, modifiedCrosschainAppState.CrossChainTxs, 10) + require.Len(t, modifiedCrosschainAppState.InTxHashToCctxList, 10) + require.Len(t, modifiedCrosschainAppState.FinalizedInbounds, 10) + }) + + t.Run("successfully modify cross chain state without changing data when not needed", func(t *testing.T) { + cdc := keepertest.NewCodec() + appState := sample.AppState(t) + importData := GetImportData(t, cdc, 8) + err := zetacored.ModifyCrossChainState(appState, importData, cdc) + require.NoError(t, err) + + modifiedCrosschainAppState := crosschaintypes.GetGenesisStateFromAppState(cdc, appState) + require.Len(t, modifiedCrosschainAppState.CrossChainTxs, 8) + require.Len(t, modifiedCrosschainAppState.InTxHashToCctxList, 8) + require.Len(t, modifiedCrosschainAppState.FinalizedInbounds, 8) + }) +} + +func Test_ModifyObserverState(t *testing.T) { + setCosmosConfig() + t.Run("successfully modify observer state to reduce data", func(t *testing.T) { + cdc := keepertest.NewCodec() + appState := sample.AppState(t) + importData := GetImportData(t, cdc, 100) + err := zetacored.ModifyObserverState(appState, importData, cdc) + require.NoError(t, err) + + modifiedObserverAppState := observertypes.GetGenesisStateFromAppState(cdc, appState) + require.Len(t, modifiedObserverAppState.Ballots, 10) + require.Len(t, modifiedObserverAppState.NonceToCctx, 10) + }) + + t.Run("successfully modify observer state without changing data when not needed", func(t *testing.T) { + cdc := keepertest.NewCodec() + appState := sample.AppState(t) + importData := GetImportData(t, cdc, 8) + err := zetacored.ModifyObserverState(appState, importData, cdc) + require.NoError(t, err) + + modifiedObserverAppState := observertypes.GetGenesisStateFromAppState(cdc, appState) + require.Len(t, modifiedObserverAppState.Ballots, 8) + require.Len(t, modifiedObserverAppState.NonceToCctx, 8) + }) + +} + +func Test_ImportDataIntoFile(t *testing.T) { + setCosmosConfig() + cdc := keepertest.NewCodec() + genDoc := sample.GenDoc(t) + importGenDoc := ImportGenDoc(t, cdc, 100) + + err := zetacored.ImportDataIntoFile(genDoc, importGenDoc, cdc) + require.NoError(t, err) + + appState, err := genutiltypes.GenesisStateFromGenDoc(*genDoc) + require.NoError(t, err) + + // Crosschain module is in Modify list + crosschainStateAfterImport := crosschaintypes.GetGenesisStateFromAppState(cdc, appState) + require.Len(t, crosschainStateAfterImport.CrossChainTxs, 10) + require.Len(t, crosschainStateAfterImport.InTxHashToCctxList, 10) + require.Len(t, crosschainStateAfterImport.FinalizedInbounds, 10) + + // Bank module is in Skip list + var bankStateAfterImport banktypes.GenesisState + if appState[banktypes.ModuleName] != nil { + err := cdc.UnmarshalJSON(appState[banktypes.ModuleName], &bankStateAfterImport) + if err != nil { + panic(fmt.Sprintf("Failed to get genesis state from app state: %s", err.Error())) + } + } + // 4 balances were present in the original genesis state + require.Len(t, bankStateAfterImport.Balances, 4) + + // Emissions module is in Copy list + var emissionStateAfterImport emissionstypes.GenesisState + if appState[emissionstypes.ModuleName] != nil { + err := cdc.UnmarshalJSON(appState[emissionstypes.ModuleName], &emissionStateAfterImport) + if err != nil { + panic(fmt.Sprintf("Failed to get genesis state from app state: %s", err.Error())) + } + } + require.Len(t, emissionStateAfterImport.WithdrawableEmissions, 100) +} + +func Test_GetGenDoc(t *testing.T) { + t.Run("successfully get genesis doc from file", func(t *testing.T) { + fp := filepath.Join(os.TempDir(), "genesis.json") + err := genutil.ExportGenesisFile(sample.GenDoc(t), fp) + require.NoError(t, err) + _, err = zetacored.GetGenDoc(fp) + require.NoError(t, err) + }) + t.Run("fail to get genesis doc from file", func(t *testing.T) { + _, err := zetacored.GetGenDoc("test") + require.ErrorContains(t, err, "no such file or directory") + }) +} + +func ImportGenDoc(t *testing.T, cdc *codec.ProtoCodec, n int) *types.GenesisDoc { + importGenDoc := sample.GenDoc(t) + importStateJson, err := json.Marshal(GetImportData(t, cdc, n)) + require.NoError(t, err) + importGenDoc.AppState = importStateJson + return importGenDoc +} + +func GetImportData(t *testing.T, cdc *codec.ProtoCodec, n int) map[string]json.RawMessage { + importData := sample.AppState(t) + + // Add crosschain data to genesis state + importedCrossChainGenState := crosschaintypes.GetGenesisStateFromAppState(cdc, importData) + cctxList := make([]*crosschaintypes.CrossChainTx, n) + intxHashToCctxList := make([]crosschaintypes.InTxHashToCctx, n) + finalLizedInbounds := make([]string, n) + for i := 0; i < n; i++ { + cctxList[i] = sample.CrossChainTx(t, fmt.Sprintf("crosschain-%d", i)) + intxHashToCctxList[i] = sample.InTxHashToCctx(t, fmt.Sprintf("intxHashToCctxList-%d", i)) + finalLizedInbounds[i] = fmt.Sprintf("finalLizedInbounds-%d", i) + } + importedCrossChainGenState.CrossChainTxs = cctxList + importedCrossChainGenState.InTxHashToCctxList = intxHashToCctxList + importedCrossChainGenState.FinalizedInbounds = finalLizedInbounds + importedCrossChainStateBz, err := json.Marshal(importedCrossChainGenState) + require.NoError(t, err) + importData[crosschaintypes.ModuleName] = importedCrossChainStateBz + + // Add observer data to genesis state + importedObserverGenState := observertypes.GetGenesisStateFromAppState(cdc, importData) + ballots := make([]*observertypes.Ballot, n) + nonceToCctx := make([]observertypes.NonceToCctx, n) + for i := 0; i < n; i++ { + ballots[i] = sample.Ballot(t, fmt.Sprintf("ballots-%d", i)) + nonceToCctx[i] = sample.NonceToCCTX(t, fmt.Sprintf("nonceToCctx-%d", i)) + } + importedObserverGenState.Ballots = ballots + importedObserverGenState.NonceToCctx = nonceToCctx + importedObserverStateBz, err := cdc.MarshalJSON(&importedObserverGenState) + require.NoError(t, err) + importData[observertypes.ModuleName] = importedObserverStateBz + + // Add emission data to genesis state + var importedEmissionGenesis emissionstypes.GenesisState + if importData[emissionstypes.ModuleName] != nil { + err := cdc.UnmarshalJSON(importData[emissionstypes.ModuleName], &importedEmissionGenesis) + if err != nil { + panic(fmt.Sprintf("Failed to get genesis state from app state: %s", err.Error())) + } + } + withdrawableEmissions := make([]emissionstypes.WithdrawableEmissions, n) + for i := 0; i < n; i++ { + withdrawableEmissions[i] = sample.WithdrawableEmissions(t) + } + importedEmissionGenesis.WithdrawableEmissions = withdrawableEmissions + importedEmissionGenesisBz, err := cdc.MarshalJSON(&importedEmissionGenesis) + require.NoError(t, err) + importData[emissionstypes.ModuleName] = importedEmissionGenesisBz + + // Add bank data to genesis state + var importedBankGenesis banktypes.GenesisState + if importData[banktypes.ModuleName] != nil { + err := cdc.UnmarshalJSON(importData[banktypes.ModuleName], &importedBankGenesis) + if err != nil { + panic(fmt.Sprintf("Failed to get genesis state from app state: %s", err.Error())) + } + } + balances := make([]banktypes.Balance, n) + supply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt())) + for i := 0; i < n; i++ { + balances[i] = banktypes.Balance{ + Address: sample.AccAddress(), + Coins: sample.Coins(), + } + supply = supply.Add(balances[i].Coins...) + } + importedBankGenesis.Balances = balances + importedBankGenesis.Supply = supply + importedBankGenesisBz, err := cdc.MarshalJSON(&importedBankGenesis) + require.NoError(t, err) + importData[banktypes.ModuleName] = importedBankGenesisBz + + return importData +} diff --git a/cmd/zetacored/root.go b/cmd/zetacored/root.go index 9f1835c9bb..7c14d1bfcb 100644 --- a/cmd/zetacored/root.go +++ b/cmd/zetacored/root.go @@ -134,6 +134,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig appparams.EncodingConfig genutilcli.ValidateGenesisCmd(app.ModuleBasics), AddGenesisAccountCmd(app.DefaultNodeHome), AddObserverAccountsCmd(), + CmdParseGenesisFile(), GetPubKeyCmd(), CollectObserverInfoCmd(), AddrConversionCmd(), diff --git a/testutil/sample/observer.go b/testutil/sample/observer.go index c90036ff07..011495a8b2 100644 --- a/testutil/sample/observer.go +++ b/testutil/sample/observer.go @@ -266,3 +266,13 @@ func VotesSuccessOnly(voteCount int) []types.VoteType { } return votes } + +func NonceToCCTX(t *testing.T, seed string) types.NonceToCctx { + r := newRandFromStringSeed(t, seed) + return types.NonceToCctx{ + ChainId: r.Int63(), + Nonce: r.Int63(), + CctxIndex: StringRandom(r, 64), + Tss: Tss().TssPubkey, + } +} diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index 71b9eac564..97183a7276 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -1,6 +1,7 @@ package sample import ( + "encoding/json" "errors" "hash/fnv" "math/rand" @@ -8,7 +9,9 @@ import ( "testing" sdkmath "cosmossdk.io/math" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ethcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/tendermint/tendermint/types" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -164,3 +167,16 @@ func IntInRange(low, high int64) sdkmath.Int { i := Int64InRange(low, high) return sdkmath.NewInt(i) } +func AppState(t *testing.T) map[string]json.RawMessage { + + appState, err := genutiltypes.GenesisStateFromGenDoc(*GenDoc(t)) + require.NoError(t, err) + return appState +} + +func GenDoc(t *testing.T) *types.GenesisDoc { + jsonBlob := []byte("{\n \"genesis_time\": \"2024-04-02T04:39:30.314827Z\",\n \"chain_id\": \"localnet_101-1\",\n \"initial_height\": \"1\",\n \"consensus_params\": {\n \"block\": {\n \"max_bytes\": \"22020096\",\n \"max_gas\": \"10000000\",\n \"time_iota_ms\": \"1000\"\n },\n \"evidence\": {\n \"max_age_num_blocks\": \"100000\",\n \"max_age_duration\": \"172800000000000\",\n \"max_bytes\": \"1048576\"\n },\n \"validator\": {\n \"pub_key_types\": [\n \"ed25519\"\n ]\n },\n \"version\": {}\n },\n \"app_hash\": \"\",\n \"app_state\": {\n \"auth\": {\n \"params\": {\n \"max_memo_characters\": \"256\",\n \"tx_sig_limit\": \"7\",\n \"tx_size_cost_per_byte\": \"10\",\n \"sig_verify_cost_ed25519\": \"590\",\n \"sig_verify_cost_secp256k1\": \"1000\"\n },\n \"accounts\": [\n {\n \"@type\": \"/ethermint.types.v1.EthAccount\",\n \"base_account\": {\n \"address\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"pub_key\": null,\n \"account_number\": \"0\",\n \"sequence\": \"0\"\n },\n \"code_hash\": \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"\n },\n {\n \"@type\": \"/ethermint.types.v1.EthAccount\",\n \"base_account\": {\n \"address\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"pub_key\": null,\n \"account_number\": \"0\",\n \"sequence\": \"0\"\n },\n \"code_hash\": \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"\n },\n {\n \"@type\": \"/ethermint.types.v1.EthAccount\",\n \"base_account\": {\n \"address\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"pub_key\": null,\n \"account_number\": \"0\",\n \"sequence\": \"0\"\n },\n \"code_hash\": \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"\n },\n {\n \"@type\": \"/ethermint.types.v1.EthAccount\",\n \"base_account\": {\n \"address\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"pub_key\": null,\n \"account_number\": \"0\",\n \"sequence\": \"0\"\n },\n \"code_hash\": \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"\n }\n ]\n },\n \"authz\": {\n \"authorization\": [\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgGasPriceVoter\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTx\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgVoteOnObservedOutboundTx\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgCreateTSSVoter\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgAddToOutTxTracker\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.observer.MsgAddBlameVote\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"grantee\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.observer.MsgAddBlockHeader\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgGasPriceVoter\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTx\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgVoteOnObservedOutboundTx\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgCreateTSSVoter\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.crosschain.MsgAddToOutTxTracker\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.observer.MsgAddBlameVote\"\n },\n \"expiration\": null\n },\n {\n \"granter\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"grantee\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"authorization\": {\n \"@type\": \"/cosmos.authz.v1beta1.GenericAuthorization\",\n \"msg\": \"/zetachain.zetacore.observer.MsgAddBlockHeader\"\n },\n \"expiration\": null\n }\n ]\n },\n \"bank\": {\n \"params\": {\n \"send_enabled\": [],\n \"default_send_enabled\": true\n },\n \"balances\": [\n {\n \"address\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"coins\": [\n {\n \"denom\": \"azeta\",\n \"amount\": \"4200000000000000000000000\"\n }\n ]\n },\n {\n \"address\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"coins\": [\n {\n \"denom\": \"azeta\",\n \"amount\": \"1000000000000000000000\"\n }\n ]\n },\n {\n \"address\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"coins\": [\n {\n \"denom\": \"azeta\",\n \"amount\": \"4200000000000000000000000\"\n }\n ]\n },\n {\n \"address\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"coins\": [\n {\n \"denom\": \"azeta\",\n \"amount\": \"1000000000000000000000\"\n }\n ]\n }\n ],\n \"supply\": [\n {\n \"denom\": \"azeta\",\n \"amount\": \"8402000000000000000000000\"\n }\n ],\n \"denom_metadata\": []\n },\n \"crisis\": {\n \"constant_fee\": {\n \"denom\": \"azeta\",\n \"amount\": \"1000\"\n }\n },\n \"crosschain\": {\n \"params\": {},\n \"outTxTrackerList\": [],\n \"inTxHashToCctxList\": [],\n \"in_tx_tracker_list\": [],\n \"zeta_accounting\": {\n \"aborted_zeta_amount\": \"0\"\n }\n },\n \"distribution\": {\n \"params\": {\n \"community_tax\": \"0.020000000000000000\",\n \"base_proposer_reward\": \"0.010000000000000000\",\n \"bonus_proposer_reward\": \"0.040000000000000000\",\n \"withdraw_addr_enabled\": true\n },\n \"fee_pool\": {\n \"community_pool\": []\n },\n \"delegator_withdraw_infos\": [],\n \"previous_proposer\": \"\",\n \"outstanding_rewards\": [],\n \"validator_accumulated_commissions\": [],\n \"validator_historical_rewards\": [],\n \"validator_current_rewards\": [],\n \"delegator_starting_infos\": [],\n \"validator_slash_events\": []\n },\n \"emissions\": {\n \"params\": {\n \"max_bond_factor\": \"1.25\",\n \"min_bond_factor\": \"0.75\",\n \"avg_block_time\": \"6.00\",\n \"target_bond_ratio\": \"00.67\",\n \"validator_emission_percentage\": \"00.50\",\n \"observer_emission_percentage\": \"00.25\",\n \"tss_signer_emission_percentage\": \"00.25\",\n \"duration_factor_constant\": \"0.001877876953694702\",\n \"observer_slash_amount\": \"100000000000000000\"\n },\n \"withdrawableEmissions\": []\n },\n \"evidence\": {\n \"evidence\": []\n },\n \"evm\": {\n \"accounts\": [],\n \"params\": {\n \"evm_denom\": \"azeta\",\n \"enable_create\": true,\n \"enable_call\": true,\n \"extra_eips\": [],\n \"chain_config\": {\n \"homestead_block\": \"0\",\n \"dao_fork_block\": \"0\",\n \"dao_fork_support\": true,\n \"eip150_block\": \"0\",\n \"eip150_hash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"eip155_block\": \"0\",\n \"eip158_block\": \"0\",\n \"byzantium_block\": \"0\",\n \"constantinople_block\": \"0\",\n \"petersburg_block\": \"0\",\n \"istanbul_block\": \"0\",\n \"muir_glacier_block\": \"0\",\n \"berlin_block\": \"0\",\n \"london_block\": \"0\",\n \"arrow_glacier_block\": \"0\",\n \"gray_glacier_block\": \"0\",\n \"merge_netsplit_block\": \"0\",\n \"shanghai_block\": \"0\",\n \"cancun_block\": \"0\"\n },\n \"allow_unprotected_txs\": false\n }\n },\n \"feemarket\": {\n \"params\": {\n \"no_base_fee\": false,\n \"base_fee_change_denominator\": 8,\n \"elasticity_multiplier\": 2,\n \"enable_height\": \"0\",\n \"base_fee\": \"1000000000\",\n \"min_gas_price\": \"0.000000000000000000\",\n \"min_gas_multiplier\": \"0.500000000000000000\"\n },\n \"block_gas\": \"0\"\n },\n \"fungible\": {\n \"params\": {},\n \"foreignCoinsList\": [],\n \"systemContract\": null\n },\n \"genutil\": {\n \"gen_txs\": [\n {\n \"body\": {\n \"messages\": [\n {\n \"@type\": \"/cosmos.staking.v1beta1.MsgCreateValidator\",\n \"description\": {\n \"moniker\": \"Zetanode-Localnet\",\n \"identity\": \"\",\n \"website\": \"\",\n \"security_contact\": \"\",\n \"details\": \"\"\n },\n \"commission\": {\n \"rate\": \"0.100000000000000000\",\n \"max_rate\": \"0.200000000000000000\",\n \"max_change_rate\": \"0.010000000000000000\"\n },\n \"min_self_delegation\": \"1\",\n \"delegator_address\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"validator_address\": \"zetavaloper13c7p3xrhd6q2rx3h235jpt8pjdwvacyw7tkass\",\n \"pubkey\": {\n \"@type\": \"/cosmos.crypto.ed25519.PubKey\",\n \"key\": \"ByI4L3eyFD5JbtlCr6HEASaUUMf8PWjLMBYjKd4Zqq8=\"\n },\n \"value\": {\n \"denom\": \"azeta\",\n \"amount\": \"1000000000000000000000\"\n }\n }\n ],\n \"memo\": \"9bb63c4104c15f332d0b25d6e982f2dcf389f24f@192.168.2.12:26656\",\n \"timeout_height\": \"0\",\n \"extension_options\": [],\n \"non_critical_extension_options\": []\n },\n \"auth_info\": {\n \"signer_infos\": [\n {\n \"public_key\": {\n \"@type\": \"/cosmos.crypto.secp256k1.PubKey\",\n \"key\": \"A05F6QuFVpb/5KrIPvlHr209ZsD22gW0omhLSXWAtQrh\"\n },\n \"mode_info\": {\n \"single\": {\n \"mode\": \"SIGN_MODE_DIRECT\"\n }\n },\n \"sequence\": \"0\"\n }\n ],\n \"fee\": {\n \"amount\": [],\n \"gas_limit\": \"200000\",\n \"payer\": \"\",\n \"granter\": \"\"\n },\n \"tip\": null\n },\n \"signatures\": [\n \"H0MPTY7zgX9+fscgDgtszGDbjG3llzlGOLb6lrTwfUxm/EO6Wz1eGmc51stq4D0gAGd8u8hSNCQKf5uU8V/Jdw==\"\n ]\n }\n ]\n },\n \"gov\": {\n \"starting_proposal_id\": \"1\",\n \"deposits\": [],\n \"votes\": [],\n \"proposals\": [],\n \"deposit_params\": {\n \"min_deposit\": [\n {\n \"denom\": \"azeta\",\n \"amount\": \"10000000\"\n }\n ],\n \"max_deposit_period\": \"172800s\"\n },\n \"voting_params\": {\n \"voting_period\": \"10s\"\n },\n \"tally_params\": {\n \"quorum\": \"0.334000000000000000\",\n \"threshold\": \"0.500000000000000000\",\n \"veto_threshold\": \"0.334000000000000000\"\n }\n },\n \"group\": {\n \"group_seq\": \"0\",\n \"groups\": [],\n \"group_members\": [],\n \"group_policy_seq\": \"0\",\n \"group_policies\": [],\n \"proposal_seq\": \"0\",\n \"proposals\": [],\n \"votes\": []\n },\n \"mint\": {\n \"params\": {\n \"mint_denom\": \"azeta\"\n }\n },\n \"observer\": {\n \"observers\": {\n \"observer_list\": [\n \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\"\n ]\n },\n \"nodeAccountList\": [\n {\n \"operator\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\",\n \"granteeAddress\": \"zeta10up34mvwjhjd9xkq56fwsf0k75vtg287uav69n\",\n \"granteePubkey\": {\n \"secp256k1\": \"zetapub1addwnpepqtlu7fykuh875xjckz4mn4x0mzc25rrqk5qne7mrwxqmatgllv3nx6lrkdp\"\n },\n \"nodeStatus\": 4\n },\n {\n \"operator\": \"zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2\",\n \"granteeAddress\": \"zeta1unzpyll3tmutf0r8sqpxpnj46vtdr59mw8qepx\",\n \"granteePubkey\": {\n \"secp256k1\": \"zetapub1addwnpepqwy5pmg39regpq0gkggxehmfm8hwmxxw94sch7qzh4smava0szs07kk5045\"\n },\n \"nodeStatus\": 4\n }\n ],\n \"crosschain_flags\": {\n \"isInboundEnabled\": true,\n \"isOutboundEnabled\": true\n },\n \"params\": {\n \"observer_params\": [\n {\n \"chain\": {\n \"chain_name\": 2,\n \"chain_id\": 101\n },\n \"ballot_threshold\": \"0.660000000000000000\",\n \"min_observer_delegation\": \"1000000000000000000000.000000000000000000\",\n \"is_supported\": true\n },\n {\n \"chain\": {\n \"chain_name\": 15,\n \"chain_id\": 18444\n },\n \"ballot_threshold\": \"0.660000000000000000\",\n \"min_observer_delegation\": \"1000000000000000000000.000000000000000000\",\n \"is_supported\": true\n },\n {\n \"chain\": {\n \"chain_name\": 14,\n \"chain_id\": 1337\n },\n \"ballot_threshold\": \"0.660000000000000000\",\n \"min_observer_delegation\": \"1000000000000000000000.000000000000000000\",\n \"is_supported\": true\n }\n ],\n \"admin_policy\": [\n {\n \"address\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\"\n },\n {\n \"policy_type\": 1,\n \"address\": \"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax\"\n }\n ],\n \"ballot_maturity_blocks\": 100\n },\n \"keygen\": {\n \"granteePubkeys\": [\n \"zetapub1addwnpepqtlu7fykuh875xjckz4mn4x0mzc25rrqk5qne7mrwxqmatgllv3nx6lrkdp\",\n \"zetapub1addwnpepqwy5pmg39regpq0gkggxehmfm8hwmxxw94sch7qzh4smava0szs07kk5045\"\n ],\n \"blockNumber\": 5\n },\n \"chain_params_list\": {},\n \"tss\": {},\n \"tss_history\": [],\n \"tss_fund_migrators\": [],\n \"blame_list\": [],\n \"pending_nonces\": [],\n \"chain_nonces\": [],\n \"nonce_to_cctx\": []\n },\n \"params\": null,\n \"slashing\": {\n \"params\": {\n \"signed_blocks_window\": \"100\",\n \"min_signed_per_window\": \"0.500000000000000000\",\n \"downtime_jail_duration\": \"600s\",\n \"slash_fraction_double_sign\": \"0.050000000000000000\",\n \"slash_fraction_downtime\": \"0.010000000000000000\"\n },\n \"signing_infos\": [],\n \"missed_blocks\": []\n },\n \"staking\": {\n \"params\": {\n \"unbonding_time\": \"1814400s\",\n \"max_validators\": 100,\n \"max_entries\": 7,\n \"historical_entries\": 10000,\n \"bond_denom\": \"azeta\",\n \"min_commission_rate\": \"0.000000000000000000\"\n },\n \"last_total_power\": \"0\",\n \"last_validator_powers\": [],\n \"validators\": [],\n \"delegations\": [],\n \"unbonding_delegations\": [],\n \"redelegations\": [],\n \"exported\": false\n },\n \"upgrade\": {},\n \"vesting\": {}\n }\n}") + genDoc, err := types.GenesisDocFromJSON(jsonBlob) + require.NoError(t, err) + return genDoc +}