bitbucket.org/number571/tendermint@v0.8.14/test/e2e/app/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "net/http" 9 "os" 10 "path/filepath" 11 "strings" 12 "time" 13 14 "github.com/spf13/viper" 15 "google.golang.org/grpc" 16 17 "bitbucket.org/number571/tendermint/abci/server" 18 "bitbucket.org/number571/tendermint/config" 19 "bitbucket.org/number571/tendermint/crypto/gost512" 20 "bitbucket.org/number571/tendermint/internal/p2p" 21 "bitbucket.org/number571/tendermint/libs/log" 22 tmnet "bitbucket.org/number571/tendermint/libs/net" 23 "bitbucket.org/number571/tendermint/light" 24 lproxy "bitbucket.org/number571/tendermint/light/proxy" 25 lrpc "bitbucket.org/number571/tendermint/light/rpc" 26 dbs "bitbucket.org/number571/tendermint/light/store/db" 27 "bitbucket.org/number571/tendermint/node" 28 "bitbucket.org/number571/tendermint/privval" 29 grpcprivval "bitbucket.org/number571/tendermint/privval/grpc" 30 privvalproto "bitbucket.org/number571/tendermint/proto/tendermint/privval" 31 "bitbucket.org/number571/tendermint/proxy" 32 rpcserver "bitbucket.org/number571/tendermint/rpc/jsonrpc/server" 33 e2e "bitbucket.org/number571/tendermint/test/e2e/pkg" 34 ) 35 36 var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) 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 switch cfg.Mode { 78 case string(e2e.ModeLight): 79 err = startLightNode(cfg) 80 case string(e2e.ModeSeed): 81 err = startSeedNode(cfg) 82 default: 83 err = startNode(cfg) 84 } 85 default: 86 err = fmt.Errorf("invalid protocol %q", cfg.Protocol) 87 } 88 if err != nil { 89 return err 90 } 91 92 // Apparently there's no way to wait for the server, so we just sleep 93 for { 94 time.Sleep(1 * time.Hour) 95 } 96 } 97 98 // startApp starts the application server, listening for connections from Tendermint. 99 func startApp(cfg *Config) error { 100 app, err := NewApplication(cfg) 101 if err != nil { 102 return err 103 } 104 server, err := server.NewServer(cfg.Listen, cfg.Protocol, app) 105 if err != nil { 106 return err 107 } 108 err = server.Start() 109 if err != nil { 110 return err 111 } 112 logger.Info(fmt.Sprintf("Server listening on %v (%v protocol)", cfg.Listen, cfg.Protocol)) 113 return nil 114 } 115 116 // startNode starts a Tendermint node running the application directly. It assumes the Tendermint 117 // configuration is in $TMHOME/config/tendermint.toml. 118 // 119 // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper. 120 func startNode(cfg *Config) error { 121 app, err := NewApplication(cfg) 122 if err != nil { 123 return err 124 } 125 126 tmcfg, nodeLogger, err := setupNode() 127 if err != nil { 128 return fmt.Errorf("failed to setup config: %w", err) 129 } 130 131 n, err := node.New(tmcfg, 132 nodeLogger, 133 proxy.NewLocalClientCreator(app), 134 nil, 135 ) 136 if err != nil { 137 return err 138 } 139 return n.Start() 140 } 141 142 func startSeedNode(cfg *Config) error { 143 tmcfg, nodeLogger, err := setupNode() 144 if err != nil { 145 return fmt.Errorf("failed to setup config: %w", err) 146 } 147 148 tmcfg.Mode = config.ModeSeed 149 150 n, err := node.New(tmcfg, nodeLogger, nil, nil) 151 if err != nil { 152 return err 153 } 154 return n.Start() 155 } 156 157 func startLightNode(cfg *Config) error { 158 tmcfg, nodeLogger, err := setupNode() 159 if err != nil { 160 return err 161 } 162 163 dbContext := &config.DBContext{ID: "light", Config: tmcfg} 164 lightDB, err := config.DefaultDBProvider(dbContext) 165 if err != nil { 166 return err 167 } 168 169 providers := rpcEndpoints(tmcfg.P2P.PersistentPeers) 170 171 c, err := light.NewHTTPClient( 172 context.Background(), 173 cfg.ChainID, 174 light.TrustOptions{ 175 Period: tmcfg.StateSync.TrustPeriod, 176 Height: tmcfg.StateSync.TrustHeight, 177 Hash: tmcfg.StateSync.TrustHashBytes(), 178 }, 179 providers[0], 180 providers[1:], 181 dbs.New(lightDB), 182 light.Logger(nodeLogger), 183 ) 184 if err != nil { 185 return err 186 } 187 188 rpccfg := rpcserver.DefaultConfig() 189 rpccfg.MaxBodyBytes = tmcfg.RPC.MaxBodyBytes 190 rpccfg.MaxHeaderBytes = tmcfg.RPC.MaxHeaderBytes 191 rpccfg.MaxOpenConnections = tmcfg.RPC.MaxOpenConnections 192 // If necessary adjust global WriteTimeout to ensure it's greater than 193 // TimeoutBroadcastTxCommit. 194 // See https://bitbucket.org/number571/tendermint/issues/3435 195 if rpccfg.WriteTimeout <= tmcfg.RPC.TimeoutBroadcastTxCommit { 196 rpccfg.WriteTimeout = tmcfg.RPC.TimeoutBroadcastTxCommit + 1*time.Second 197 } 198 199 p, err := lproxy.NewProxy(c, tmcfg.RPC.ListenAddress, providers[0], rpccfg, nodeLogger, 200 lrpc.KeyPathFn(lrpc.DefaultMerkleKeyPathFn())) 201 if err != nil { 202 return err 203 } 204 205 logger.Info("Starting proxy...", "laddr", tmcfg.RPC.ListenAddress) 206 if err := p.ListenAndServe(); err != http.ErrServerClosed { 207 // Error starting or closing listener: 208 logger.Error("proxy ListenAndServe", "err", err) 209 } 210 211 return nil 212 } 213 214 // startSigner starts a signer server connecting to the given endpoint. 215 func startSigner(cfg *Config) error { 216 filePV, err := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState) 217 if err != nil { 218 return err 219 } 220 221 protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer) 222 var dialFn privval.SocketDialer 223 switch protocol { 224 case "tcp": 225 dialFn = privval.DialTCPFn(address, 3*time.Second, gost512.GenPrivKey()) 226 case "unix": 227 dialFn = privval.DialUnixFn(address) 228 case "grpc": 229 lis, err := net.Listen("tcp", address) 230 if err != nil { 231 return err 232 } 233 ss := grpcprivval.NewSignerServer(cfg.ChainID, filePV, logger) 234 235 s := grpc.NewServer() 236 237 privvalproto.RegisterPrivValidatorAPIServer(s, ss) 238 239 go func() { // no need to clean up since we remove docker containers 240 if err := s.Serve(lis); err != nil { 241 panic(err) 242 } 243 }() 244 245 return nil 246 default: 247 return fmt.Errorf("invalid privval protocol %q", protocol) 248 } 249 250 endpoint := privval.NewSignerDialerEndpoint(logger, dialFn, 251 privval.SignerDialerEndpointRetryWaitInterval(1*time.Second), 252 privval.SignerDialerEndpointConnRetries(100)) 253 err = privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start() 254 if err != nil { 255 return err 256 } 257 258 logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer)) 259 return nil 260 } 261 262 func setupNode() (*config.Config, log.Logger, error) { 263 var tmcfg *config.Config 264 265 home := os.Getenv("TMHOME") 266 if home == "" { 267 return nil, nil, errors.New("TMHOME not set") 268 } 269 270 viper.AddConfigPath(filepath.Join(home, "config")) 271 viper.SetConfigName("config") 272 273 if err := viper.ReadInConfig(); err != nil { 274 return nil, nil, err 275 } 276 277 tmcfg = config.DefaultConfig() 278 279 if err := viper.Unmarshal(tmcfg); err != nil { 280 return nil, nil, err 281 } 282 283 tmcfg.SetRoot(home) 284 285 if err := tmcfg.ValidateBasic(); err != nil { 286 return nil, nil, fmt.Errorf("error in config file: %w", err) 287 } 288 289 nodeLogger, err := log.NewDefaultLogger(tmcfg.LogFormat, tmcfg.LogLevel, false) 290 if err != nil { 291 return nil, nil, err 292 } 293 294 return tmcfg, nodeLogger.With("module", "main"), nil 295 } 296 297 // rpcEndpoints takes a list of persistent peers and splits them into a list of rpc endpoints 298 // using 26657 as the port number 299 func rpcEndpoints(peers string) []string { 300 arr := strings.Split(peers, ",") 301 endpoints := make([]string, len(arr)) 302 for i, v := range arr { 303 addr, err := p2p.ParseNodeAddress(v) 304 if err != nil { 305 panic(err) 306 } 307 // use RPC port instead 308 addr.Port = 26657 309 var rpcEndpoint string 310 // for ipv6 addresses 311 if strings.Contains(addr.Hostname, ":") { 312 rpcEndpoint = "http://[" + addr.Hostname + "]:" + fmt.Sprint(addr.Port) 313 } else { // for ipv4 addresses 314 rpcEndpoint = "http://" + addr.Hostname + ":" + fmt.Sprint(addr.Port) 315 } 316 endpoints[i] = rpcEndpoint 317 } 318 return endpoints 319 }