github.com/soomindae/tendermint@v0.0.5-0.20210528140126-84a0c70c8162/test/e2e/app/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/http" 8 "os" 9 "path/filepath" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/spf13/viper" 15 16 "github.com/soomindae/tendermint/abci/server" 17 "github.com/soomindae/tendermint/config" 18 "github.com/soomindae/tendermint/crypto/ed25519" 19 tmflags "github.com/soomindae/tendermint/libs/cli/flags" 20 "github.com/soomindae/tendermint/libs/log" 21 tmnet "github.com/soomindae/tendermint/libs/net" 22 "github.com/soomindae/tendermint/light" 23 lproxy "github.com/soomindae/tendermint/light/proxy" 24 lrpc "github.com/soomindae/tendermint/light/rpc" 25 dbs "github.com/soomindae/tendermint/light/store/db" 26 "github.com/soomindae/tendermint/node" 27 "github.com/soomindae/tendermint/p2p" 28 "github.com/soomindae/tendermint/privval" 29 "github.com/soomindae/tendermint/proxy" 30 rpcserver "github.com/soomindae/tendermint/rpc/jsonrpc/server" 31 e2e "github.com/soomindae/tendermint/test/e2e/pkg" 32 mcs "github.com/soomindae/tendermint/test/maverick/consensus" 33 maverick "github.com/soomindae/tendermint/test/maverick/node" 34 ) 35 36 var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) 37 38 // main is the binary entrypoint. 39 func main() { 40 if len(os.Args) != 2 { 41 fmt.Printf("Usage: %v <configfile>", os.Args[0]) 42 return 43 } 44 configFile := "" 45 if len(os.Args) == 2 { 46 configFile = os.Args[1] 47 } 48 49 if err := run(configFile); err != nil { 50 logger.Error(err.Error()) 51 os.Exit(1) 52 } 53 } 54 55 // run runs the application - basically like main() with error handling. 56 func run(configFile string) error { 57 cfg, err := LoadConfig(configFile) 58 if err != nil { 59 return err 60 } 61 62 // Start remote signer (must start before node if running builtin). 63 if cfg.PrivValServer != "" { 64 if err = startSigner(cfg); err != nil { 65 return err 66 } 67 if cfg.Protocol == "builtin" { 68 time.Sleep(1 * time.Second) 69 } 70 } 71 72 // Start app server. 73 switch cfg.Protocol { 74 case "socket", "grpc": 75 err = startApp(cfg) 76 case "builtin": 77 if len(cfg.Misbehaviors) == 0 { 78 if cfg.Mode == string(e2e.ModeLight) { 79 err = startLightClient(cfg) 80 } else { 81 err = startNode(cfg) 82 } 83 } else { 84 err = startMaverick(cfg) 85 } 86 default: 87 err = fmt.Errorf("invalid protocol %q", cfg.Protocol) 88 } 89 if err != nil { 90 return err 91 } 92 93 // Apparently there's no way to wait for the server, so we just sleep 94 for { 95 time.Sleep(1 * time.Hour) 96 } 97 } 98 99 // startApp starts the application server, listening for connections from Tendermint. 100 func startApp(cfg *Config) error { 101 app, err := NewApplication(cfg) 102 if err != nil { 103 return err 104 } 105 server, err := server.NewServer(cfg.Listen, cfg.Protocol, app) 106 if err != nil { 107 return err 108 } 109 err = server.Start() 110 if err != nil { 111 return err 112 } 113 logger.Info(fmt.Sprintf("Server listening on %v (%v protocol)", cfg.Listen, cfg.Protocol)) 114 return nil 115 } 116 117 // startNode starts a Tendermint node running the application directly. It assumes the Tendermint 118 // configuration is in $TMHOME/config/tendermint.toml. 119 // 120 // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper. 121 func startNode(cfg *Config) error { 122 app, err := NewApplication(cfg) 123 if err != nil { 124 return err 125 } 126 127 tmcfg, nodeLogger, nodeKey, err := setupNode() 128 if err != nil { 129 return fmt.Errorf("failed to setup config: %w", err) 130 } 131 132 n, err := node.NewNode(tmcfg, 133 privval.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile()), 134 nodeKey, 135 proxy.NewLocalClientCreator(app), 136 node.DefaultGenesisDocProviderFunc(tmcfg), 137 node.DefaultDBProvider, 138 node.DefaultMetricsProvider(tmcfg.Instrumentation), 139 nodeLogger, 140 ) 141 if err != nil { 142 return err 143 } 144 return n.Start() 145 } 146 147 func startLightClient(cfg *Config) error { 148 tmcfg, nodeLogger, _, err := setupNode() 149 if err != nil { 150 return err 151 } 152 153 dbContext := &node.DBContext{ID: "light", Config: tmcfg} 154 lightDB, err := node.DefaultDBProvider(dbContext) 155 if err != nil { 156 return err 157 } 158 159 providers := rpcEndpoints(tmcfg.P2P.PersistentPeers) 160 161 c, err := light.NewHTTPClient( 162 context.Background(), 163 cfg.ChainID, 164 light.TrustOptions{ 165 Period: tmcfg.StateSync.TrustPeriod, 166 Height: tmcfg.StateSync.TrustHeight, 167 Hash: tmcfg.StateSync.TrustHashBytes(), 168 }, 169 providers[0], 170 providers[1:], 171 dbs.New(lightDB, "light"), 172 light.Logger(nodeLogger), 173 ) 174 if err != nil { 175 return err 176 } 177 178 rpccfg := rpcserver.DefaultConfig() 179 rpccfg.MaxBodyBytes = tmcfg.RPC.MaxBodyBytes 180 rpccfg.MaxHeaderBytes = tmcfg.RPC.MaxHeaderBytes 181 rpccfg.MaxOpenConnections = tmcfg.RPC.MaxOpenConnections 182 // If necessary adjust global WriteTimeout to ensure it's greater than 183 // TimeoutBroadcastTxCommit. 184 // See https://github.com/soomindae/tendermint/issues/3435 185 if rpccfg.WriteTimeout <= tmcfg.RPC.TimeoutBroadcastTxCommit { 186 rpccfg.WriteTimeout = tmcfg.RPC.TimeoutBroadcastTxCommit + 1*time.Second 187 } 188 189 p, err := lproxy.NewProxy(c, tmcfg.RPC.ListenAddress, providers[0], rpccfg, nodeLogger, 190 lrpc.KeyPathFn(lrpc.DefaultMerkleKeyPathFn())) 191 if err != nil { 192 return err 193 } 194 195 logger.Info("Starting proxy...", "laddr", tmcfg.RPC.ListenAddress) 196 if err := p.ListenAndServe(); err != http.ErrServerClosed { 197 // Error starting or closing listener: 198 logger.Error("proxy ListenAndServe", "err", err) 199 } 200 201 return nil 202 } 203 204 // FIXME: Temporarily disconnected maverick until it is redesigned 205 // startMaverick starts a Maverick node that runs the application directly. It assumes the Tendermint 206 // configuration is in $TMHOME/config/tendermint.toml. 207 func startMaverick(cfg *Config) error { 208 app, err := NewApplication(cfg) 209 if err != nil { 210 return err 211 } 212 213 tmcfg, logger, nodeKey, err := setupNode() 214 if err != nil { 215 return fmt.Errorf("failed to setup config: %w", err) 216 } 217 218 misbehaviors := make(map[int64]mcs.Misbehavior, len(cfg.Misbehaviors)) 219 for heightString, misbehaviorString := range cfg.Misbehaviors { 220 height, _ := strconv.ParseInt(heightString, 10, 64) 221 misbehaviors[height] = mcs.MisbehaviorList[misbehaviorString] 222 } 223 224 n, err := maverick.NewNode(tmcfg, 225 maverick.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile()), 226 nodeKey, 227 proxy.NewLocalClientCreator(app), 228 maverick.DefaultGenesisDocProviderFunc(tmcfg), 229 maverick.DefaultDBProvider, 230 maverick.DefaultMetricsProvider(tmcfg.Instrumentation), 231 logger, 232 misbehaviors, 233 ) 234 if err != nil { 235 return err 236 } 237 238 return n.Start() 239 } 240 241 // startSigner starts a signer server connecting to the given endpoint. 242 func startSigner(cfg *Config) error { 243 filePV := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState) 244 245 protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer) 246 var dialFn privval.SocketDialer 247 switch protocol { 248 case "tcp": 249 dialFn = privval.DialTCPFn(address, 3*time.Second, ed25519.GenPrivKey()) 250 case "unix": 251 dialFn = privval.DialUnixFn(address) 252 default: 253 return fmt.Errorf("invalid privval protocol %q", protocol) 254 } 255 256 endpoint := privval.NewSignerDialerEndpoint(logger, dialFn, 257 privval.SignerDialerEndpointRetryWaitInterval(1*time.Second), 258 privval.SignerDialerEndpointConnRetries(100)) 259 err := privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start() 260 if err != nil { 261 return err 262 } 263 logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer)) 264 return nil 265 } 266 267 func setupNode() (*config.Config, log.Logger, *p2p.NodeKey, error) { 268 var tmcfg *config.Config 269 270 home := os.Getenv("TMHOME") 271 if home == "" { 272 return nil, nil, nil, errors.New("TMHOME not set") 273 } 274 275 viper.AddConfigPath(filepath.Join(home, "config")) 276 viper.SetConfigName("config") 277 278 if err := viper.ReadInConfig(); err != nil { 279 return nil, nil, nil, err 280 } 281 282 tmcfg = config.DefaultConfig() 283 284 if err := viper.Unmarshal(tmcfg); err != nil { 285 return nil, nil, nil, err 286 } 287 288 tmcfg.SetRoot(home) 289 290 if err := tmcfg.ValidateBasic(); err != nil { 291 return nil, nil, nil, fmt.Errorf("error in config file: %w", err) 292 } 293 294 if tmcfg.LogFormat == config.LogFormatJSON { 295 logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout)) 296 } 297 298 nodeLogger, err := tmflags.ParseLogLevel(tmcfg.LogLevel, logger, config.DefaultLogLevel) 299 if err != nil { 300 return nil, nil, nil, err 301 } 302 303 nodeLogger = nodeLogger.With("module", "main") 304 305 nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile()) 306 if err != nil { 307 return nil, nil, nil, fmt.Errorf("failed to load or gen node key %s: %w", tmcfg.NodeKeyFile(), err) 308 } 309 310 return tmcfg, nodeLogger, nodeKey, nil 311 } 312 313 // rpcEndpoints takes a list of persistent peers and splits them into a list of rpc endpoints 314 // using 26657 as the port number 315 func rpcEndpoints(peers string) []string { 316 arr := strings.Split(peers, ",") 317 endpoints := make([]string, len(arr)) 318 for i, v := range arr { 319 urlString := strings.SplitAfter(v, "@")[1] 320 hostName := strings.Split(urlString, ":26656")[0] 321 // use RPC port instead 322 port := 26657 323 rpcEndpoint := "http://" + hostName + ":" + fmt.Sprint(port) 324 endpoints[i] = rpcEndpoint 325 } 326 return endpoints 327 }