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  }