github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/server/util.go (about) 1 package server 2 3 import ( 4 "encoding/json" 5 "errors" 6 "net" 7 "os" 8 "os/signal" 9 "path/filepath" 10 "syscall" 11 "time" 12 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags" 14 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/lcd" 15 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 16 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/server/config" 17 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/version" 18 tcmd "github.com/fibonacci-chain/fbc/libs/tendermint/cmd/tendermint/commands" 19 cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config" 20 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/cli" 21 tmflags "github.com/fibonacci-chain/fbc/libs/tendermint/libs/cli/flags" 22 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 23 "github.com/fibonacci-chain/fbc/libs/tendermint/state" 24 "github.com/gogo/protobuf/jsonpb" 25 "github.com/google/gops/agent" 26 "github.com/spf13/cobra" 27 "github.com/spf13/viper" 28 ) 29 30 const FlagGops = "gops" 31 32 // server context 33 type Context struct { 34 Config *cfg.Config 35 Logger log.Logger 36 } 37 38 func NewDefaultContext() *Context { 39 return NewContext( 40 cfg.DefaultConfig(), 41 log.NewTMLogger(log.NewSyncWriter(os.Stdout)), 42 ) 43 } 44 45 func NewContext(config *cfg.Config, logger log.Logger) *Context { 46 return &Context{config, logger} 47 } 48 49 //___________________________________________________________________________________ 50 51 // PersistentPreRunEFn returns a PersistentPreRunE function for cobra 52 // that initailizes the passed in context with a properly configured 53 // logger and config object. 54 func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error { 55 return func(cmd *cobra.Command, args []string) error { 56 if cmd.Name() == version.Cmd.Name() { 57 return nil 58 } 59 config, err := interceptLoadConfig() 60 if err != nil { 61 return err 62 } 63 if !viper.IsSet(state.FlagDeliverTxsExecMode) { 64 if viper.GetBool(state.FlagEnableConcurrency) { 65 viper.Set(state.FlagDeliverTxsExecMode, state.DeliverTxsExecModeParallel) 66 } 67 } 68 // okchain 69 output := os.Stdout 70 if !config.LogStdout { 71 output, err = os.OpenFile(config.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) 72 if err != nil { 73 return err 74 } 75 } 76 77 logger := log.NewTMLogger(log.NewSyncWriter(output)) 78 logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel()) 79 if err != nil { 80 return err 81 } 82 if viper.GetBool(cli.TraceFlag) { 83 logger = log.NewTracingLogger(logger) 84 } 85 logger = logger.With("module", "main") 86 context.Config = config 87 context.Logger = logger 88 89 if viper.GetBool(FlagGops) { 90 err = agent.Listen(agent.Options{ShutdownCleanup: true}) 91 if err != nil { 92 logger.Error("gops agent error", "err", err) 93 } 94 } 95 96 return nil 97 } 98 } 99 100 // If a new config is created, change some of the default tendermint settings 101 func interceptLoadConfig() (conf *cfg.Config, err error) { 102 tmpConf := cfg.DefaultConfig() 103 err = viper.Unmarshal(tmpConf) 104 if err != nil { 105 // TODO: Handle with #870 106 panic(err) 107 } 108 rootDir := tmpConf.RootDir 109 configFilePath := filepath.Join(rootDir, "config/config.toml") 110 // Intercept only if the file doesn't already exist 111 112 if _, err := os.Stat(configFilePath); os.IsNotExist(err) { 113 // the following parse config is needed to create directories 114 conf, _ = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary. 115 conf.ProfListenAddress = "localhost:6060" 116 conf.P2P.RecvRate = 5120000 117 conf.P2P.SendRate = 5120000 118 conf.TxIndex.IndexAllKeys = true 119 conf.Consensus.TimeoutCommit = 3 * time.Second 120 conf.Consensus.TimeoutConsensus = 1 * time.Second 121 cfg.WriteConfigFile(configFilePath, conf) 122 // Fall through, just so that its parsed into memory. 123 } 124 125 if conf == nil { 126 conf, err = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary. 127 if err != nil { 128 panic(err) 129 } 130 } 131 132 appConfigFilePath := filepath.Join(rootDir, "config/fbchaind.toml") 133 if _, err := os.Stat(appConfigFilePath); os.IsNotExist(err) { 134 appConf, _ := config.ParseConfig() 135 config.WriteConfigFile(appConfigFilePath, appConf) 136 } 137 138 viper.SetConfigName("fbchaind") 139 err = viper.MergeInConfig() 140 141 return conf, err 142 } 143 144 // add server commands 145 func AddCommands( 146 ctx *Context, cdc *codec.CodecProxy, 147 registry jsonpb.AnyResolver, 148 rootCmd *cobra.Command, 149 appCreator AppCreator, appStop AppStop, appExport AppExporter, 150 registerRouters func(rs *lcd.RestServer), 151 registerAppFlagFn func(cmd *cobra.Command), 152 appPreRun func(ctx *Context, cmd *cobra.Command) error, 153 subFunc func(logger log.Logger) log.Subscriber) { 154 155 rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") 156 rootCmd.PersistentFlags().String("log_file", ctx.Config.LogFile, "Log file") 157 rootCmd.PersistentFlags().Bool("log_stdout", ctx.Config.LogStdout, "Print log to stdout, rather than a file") 158 159 tendermintCmd := &cobra.Command{ 160 Use: "tendermint", 161 Short: "Tendermint subcommands", 162 } 163 164 tendermintCmd.AddCommand( 165 ShowNodeIDCmd(ctx), 166 ShowValidatorCmd(ctx), 167 ShowAddressCmd(ctx), 168 VersionCmd(ctx), 169 ) 170 171 rootCmd.AddCommand( 172 StartCmd(ctx, cdc, registry, appCreator, appStop, registerRouters, registerAppFlagFn, appPreRun, subFunc), 173 StopCmd(ctx), 174 UnsafeResetAllCmd(ctx), 175 flags.LineBreak, 176 tendermintCmd, 177 ExportCmd(ctx, cdc.GetCdc(), appExport), 178 flags.LineBreak, 179 version.Cmd, 180 ) 181 } 182 183 //___________________________________________________________________________________ 184 185 // InsertKeyJSON inserts a new JSON field/key with a given value to an existing 186 // JSON message. An error is returned if any serialization operation fails. 187 // 188 // NOTE: The ordering of the keys returned as the resulting JSON message is 189 // non-deterministic, so the client should not rely on key ordering. 190 func InsertKeyJSON(cdc *codec.Codec, baseJSON []byte, key string, value json.RawMessage) ([]byte, error) { 191 var jsonMap map[string]json.RawMessage 192 193 if err := cdc.UnmarshalJSON(baseJSON, &jsonMap); err != nil { 194 return nil, err 195 } 196 197 jsonMap[key] = value 198 bz, err := codec.MarshalJSONIndent(cdc, jsonMap) 199 200 return json.RawMessage(bz), err 201 } 202 203 // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go 204 // TODO there must be a better way to get external IP 205 func ExternalIP() (string, error) { 206 ifaces, err := net.Interfaces() 207 if err != nil { 208 return "", err 209 } 210 for _, iface := range ifaces { 211 if skipInterface(iface) { 212 continue 213 } 214 addrs, err := iface.Addrs() 215 if err != nil { 216 return "", err 217 } 218 for _, addr := range addrs { 219 ip := addrToIP(addr) 220 if ip == nil || ip.IsLoopback() { 221 continue 222 } 223 ip = ip.To4() 224 if ip == nil { 225 continue // not an ipv4 address 226 } 227 return ip.String(), nil 228 } 229 } 230 return "", errors.New("are you connected to the network?") 231 } 232 233 // TrapSignal traps SIGINT and SIGTERM and terminates the server correctly. 234 func TrapSignal(cleanupFunc func()) { 235 sigs := make(chan os.Signal, 1) 236 signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 237 go func() { 238 sig := <-sigs 239 if cleanupFunc != nil { 240 cleanupFunc() 241 } 242 exitCode := 128 243 switch sig { 244 case syscall.SIGINT: 245 exitCode += int(syscall.SIGINT) 246 case syscall.SIGTERM: 247 exitCode += int(syscall.SIGTERM) 248 } 249 os.Exit(exitCode) 250 }() 251 } 252 253 func skipInterface(iface net.Interface) bool { 254 if iface.Flags&net.FlagUp == 0 { 255 return true // interface down 256 } 257 if iface.Flags&net.FlagLoopback != 0 { 258 return true // loopback interface 259 } 260 return false 261 } 262 263 func addrToIP(addr net.Addr) net.IP { 264 var ip net.IP 265 switch v := addr.(type) { 266 case *net.IPNet: 267 ip = v.IP 268 case *net.IPAddr: 269 ip = v.IP 270 } 271 return ip 272 } 273 274 // DONTCOVER