// Copyright 2021 Evmos Foundation // This file is part of Evmos' Ethermint library. // // The Ethermint library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The Ethermint library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE package main import ( "errors" "io" "os" "path/filepath" "github.com/spf13/cast" "github.com/spf13/cobra" tmcfg "github.com/tendermint/tendermint/config" tmcli "github.com/tendermint/tendermint/libs/cli" tmlog "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/rpc" sdkserver "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/snapshots" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/cerc-io/laconicd/app" ethermintclient "github.com/cerc-io/laconicd/client" "github.com/cerc-io/laconicd/client/debug" "github.com/cerc-io/laconicd/crypto/hd" "github.com/cerc-io/laconicd/encoding" "github.com/cerc-io/laconicd/ethereum/eip712" "github.com/cerc-io/laconicd/server" servercfg "github.com/cerc-io/laconicd/server/config" srvflags "github.com/cerc-io/laconicd/server/flags" ethermint "github.com/cerc-io/laconicd/types" ) const EnvPrefix = "LACONIC" // NewRootCmd creates a new root command for simd. It is called once in the // main function. func NewRootCmd() (*cobra.Command, params.EncodingConfig) { encodingConfig := encoding.MakeConfig(app.ModuleBasics) initClientCtx := client.Context{}. WithCodec(encodingConfig.Codec). WithInterfaceRegistry(encodingConfig.InterfaceRegistry). WithTxConfig(encodingConfig.TxConfig). WithLegacyAmino(encodingConfig.Amino). WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). WithBroadcastMode(flags.BroadcastBlock). WithHomeDir(app.DefaultNodeHome). WithKeyringOptions(hd.EthSecp256k1Option()). WithViper(EnvPrefix) eip712.SetEncodingConfig(encodingConfig) rootCmd := &cobra.Command{ Use: "laconicd", Short: "Laconic Daemon", PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { // set the default command outputs cmd.SetOut(cmd.OutOrStdout()) cmd.SetErr(cmd.ErrOrStderr()) initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) if err != nil { return err } initClientCtx, err = config.ReadFromClientConfig(initClientCtx) if err != nil { return err } if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { return err } // FIXME: replace AttoPhoton with bond denom customAppTemplate, customAppConfig := servercfg.AppConfig(ethermint.AttoPhoton) return sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, tmcfg.DefaultConfig()) }, } // TODO: double-check // authclient.Codec = encodingConfig.Codec cfg := sdk.GetConfig() cfg.Seal() rootCmd.AddCommand( ethermintclient.ValidateChainID( genutilcli.InitCmd(app.ModuleBasics, app.DefaultNodeHome), ), genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome), genutilcli.MigrateGenesisCmd(), // TODO: shouldn't this include the local app version instead of the SDK? genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome), genutilcli.ValidateGenesisCmd(app.ModuleBasics), AddGenesisAccountCmd(app.DefaultNodeHome), tmcli.NewCompletionCmd(rootCmd, true), ethermintclient.NewTestnetCmd(app.ModuleBasics, banktypes.GenesisBalancesIterator{}), debug.Cmd(), config.Cmd(), ) a := appCreator{encodingConfig} server.AddCommands(rootCmd, server.NewDefaultStartOptions(a.newApp, app.DefaultNodeHome), a.appExport, addModuleInitFlags) // add keybase, auxiliary RPC, query, and tx child commands rootCmd.AddCommand( rpc.StatusCommand(), queryCommand(), txCommand(), ethermintclient.KeyCommands(app.DefaultNodeHome), ) rootCmd, err := srvflags.AddTxFlags(rootCmd) if err != nil { panic(err) } // add rosetta rootCmd.AddCommand(sdkserver.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec)) // Add flags for GQL server. rootCmd = srvflags.AddGQLFlags(rootCmd) return rootCmd, encodingConfig } func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) } func queryCommand() *cobra.Command { cmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, Short: "Querying subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } cmd.AddCommand( authcmd.GetAccountCmd(), rpc.ValidatorCommand(), rpc.BlockCommand(), authcmd.QueryTxsByEventsCmd(), authcmd.QueryTxCmd(), ) app.ModuleBasics.AddQueryCommands(cmd) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") return cmd } func txCommand() *cobra.Command { cmd := &cobra.Command{ Use: "tx", Short: "Transactions subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } cmd.AddCommand( authcmd.GetSignCommand(), authcmd.GetSignBatchCommand(), authcmd.GetMultiSignCommand(), authcmd.GetMultiSignBatchCmd(), authcmd.GetValidateSignaturesCommand(), authcmd.GetBroadcastCommand(), authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), authcmd.GetAuxToFeeCommand(), ) app.ModuleBasics.AddTxCommands(cmd) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") return cmd } type appCreator struct { encCfg params.EncodingConfig } // newApp is an appCreator func (a appCreator) newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { var cache sdk.MultiStorePersistentCache if cast.ToBool(appOpts.Get(sdkserver.FlagInterBlockCache)) { cache = store.NewCommitKVStoreCacheManager() } skipUpgradeHeights := make(map[int64]bool) for _, h := range cast.ToIntSlice(appOpts.Get(sdkserver.FlagUnsafeSkipUpgrades)) { skipUpgradeHeights[int64(h)] = true } pruningOpts, err := sdkserver.GetPruningOptionsFromFlags(appOpts) if err != nil { panic(err) } snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") if err = os.MkdirAll(snapshotDir, os.ModePerm); err != nil { panic(err) } snapshotDB, err := dbm.NewDB("metadata", sdkserver.GetAppDBBackend(appOpts), snapshotDir) if err != nil { panic(err) } snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) if err != nil { panic(err) } snapshotOptions := snapshottypes.NewSnapshotOptions( cast.ToUint64(appOpts.Get(sdkserver.FlagStateSyncSnapshotInterval)), cast.ToUint32(appOpts.Get(sdkserver.FlagStateSyncSnapshotKeepRecent)), ) ethermintApp := app.NewEthermintApp( logger, db, traceStore, true, skipUpgradeHeights, cast.ToString(appOpts.Get(flags.FlagHome)), cast.ToUint(appOpts.Get(sdkserver.FlagInvCheckPeriod)), a.encCfg, appOpts, baseapp.SetPruning(pruningOpts), baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(sdkserver.FlagMinGasPrices))), baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(sdkserver.FlagHaltHeight))), baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(sdkserver.FlagHaltTime))), baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(sdkserver.FlagMinRetainBlocks))), baseapp.SetInterBlockCache(cache), baseapp.SetTrace(cast.ToBool(appOpts.Get(sdkserver.FlagTrace))), baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(sdkserver.FlagIndexEvents))), baseapp.SetSnapshot(snapshotStore, snapshotOptions), baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(sdkserver.FlagIAVLCacheSize))), baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(sdkserver.FlagDisableIAVLFastNode))), ) return ethermintApp } // appExport creates a new simapp (optionally at a given height) // and exports state. func (a appCreator) appExport( logger tmlog.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOpts servertypes.AppOptions, ) (servertypes.ExportedApp, error) { var ethermintApp *app.EthermintApp homePath, ok := appOpts.Get(flags.FlagHome).(string) if !ok || homePath == "" { return servertypes.ExportedApp{}, errors.New("application home not set") } if height != -1 { ethermintApp = app.NewEthermintApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), a.encCfg, appOpts) if err := ethermintApp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { ethermintApp = app.NewEthermintApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), a.encCfg, appOpts) } return ethermintApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) }