github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/cmd/tendermint/commands/lite.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"os"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/spf13/cobra"
    11  
    12  	dbm "github.com/tendermint/tm-db"
    13  
    14  	"github.com/tendermint/tendermint/libs/log"
    15  	tmos "github.com/tendermint/tendermint/libs/os"
    16  	"github.com/tendermint/tendermint/light"
    17  	lproxy "github.com/tendermint/tendermint/light/proxy"
    18  	lrpc "github.com/tendermint/tendermint/light/rpc"
    19  	dbs "github.com/tendermint/tendermint/light/store/db"
    20  	rpchttp "github.com/tendermint/tendermint/rpc/client/http"
    21  	rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
    22  )
    23  
    24  // LightCmd represents the base command when called without any subcommands
    25  var LightCmd = &cobra.Command{
    26  	Use:   "light [chainID]",
    27  	Short: "Run a light client proxy server, verifying Tendermint rpc",
    28  	Long: `Run a light client proxy server, verifying Tendermint rpc.
    29  
    30  All calls that can be tracked back to a block header by a proof
    31  will be verified before passing them back to the caller. Other than
    32  that, it will present the same interface as a full Tendermint node.
    33  
    34  Example:
    35  
    36  start a fresh instance:
    37  
    38  light cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657
    39  	--height 962118 --hash 28B97BE9F6DE51AC69F70E0B7BFD7E5C9CD1A595B7DC31AFF27C50D4948020CD
    40  
    41  continue from latest state:
    42  
    43  light cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657
    44  `,
    45  	RunE: runProxy,
    46  	Args: cobra.ExactArgs(1),
    47  	Example: `light cosmoshub-3 -p http://52.57.29.196:26657 -w http://public-seed-node.cosmoshub.certus.one:26657
    48  	--height 962118 --hash 28B97BE9F6DE51AC69F70E0B7BFD7E5C9CD1A595B7DC31AFF27C50D4948020CD`,
    49  }
    50  
    51  var (
    52  	listenAddr         string
    53  	primaryAddr        string
    54  	witnessAddrsJoined string
    55  	chainID            string
    56  	home               string
    57  	maxOpenConnections int
    58  
    59  	trustingPeriod time.Duration
    60  	trustedHeight  int64
    61  	trustedHash    []byte
    62  
    63  	verbose bool
    64  )
    65  
    66  func init() {
    67  	LightCmd.Flags().StringVar(&listenAddr, "laddr", "tcp://localhost:8888",
    68  		"Serve the proxy on the given address")
    69  	LightCmd.Flags().StringVarP(&primaryAddr, "primary", "p", "",
    70  		"Connect to a Tendermint node at this address")
    71  	LightCmd.Flags().StringVarP(&witnessAddrsJoined, "witnesses", "w", "",
    72  		"Tendermint nodes to cross-check the primary node, comma-separated")
    73  	LightCmd.Flags().StringVar(&home, "home-dir", ".tendermint-light", "Specify the home directory")
    74  	LightCmd.Flags().IntVar(
    75  		&maxOpenConnections,
    76  		"max-open-connections",
    77  		900,
    78  		"Maximum number of simultaneous connections (including WebSocket).")
    79  	LightCmd.Flags().DurationVar(&trustingPeriod, "trusting-period", 168*time.Hour,
    80  		"Trusting period. Should be significantly less than the unbonding period")
    81  	LightCmd.Flags().Int64Var(&trustedHeight, "height", 1, "Trusted header's height")
    82  	LightCmd.Flags().BytesHexVar(&trustedHash, "hash", []byte{}, "Trusted header's hash")
    83  	LightCmd.Flags().BoolVar(&verbose, "verbose", false, "Verbose output")
    84  }
    85  
    86  func runProxy(cmd *cobra.Command, args []string) error {
    87  	// Initialise logger.
    88  	logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
    89  	var option log.Option
    90  	if verbose {
    91  		option, _ = log.AllowLevel("debug")
    92  	} else {
    93  		option, _ = log.AllowLevel("info")
    94  	}
    95  	logger = log.NewFilter(logger, option)
    96  
    97  	chainID = args[0]
    98  	logger.Info("Creating client...", "chainID", chainID)
    99  
   100  	witnessesAddrs := strings.Split(witnessAddrsJoined, ",")
   101  
   102  	db, err := dbm.NewGoLevelDB("light-client-db", home)
   103  	if err != nil {
   104  		return fmt.Errorf("can't create a db: %w", err)
   105  	}
   106  
   107  	var c *light.Client
   108  	if trustedHeight > 0 && len(trustedHash) > 0 { // fresh installation
   109  		c, err = light.NewHTTPClient(
   110  			chainID,
   111  			light.TrustOptions{
   112  				Period: trustingPeriod,
   113  				Height: trustedHeight,
   114  				Hash:   trustedHash,
   115  			},
   116  			primaryAddr,
   117  			witnessesAddrs,
   118  			dbs.New(db, chainID),
   119  			light.Logger(logger),
   120  		)
   121  	} else { // continue from latest state
   122  		c, err = light.NewHTTPClientFromTrustedStore(
   123  			chainID,
   124  			trustingPeriod,
   125  			primaryAddr,
   126  			witnessesAddrs,
   127  			dbs.New(db, chainID),
   128  			light.Logger(logger),
   129  		)
   130  	}
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	rpcClient, err := rpchttp.New(primaryAddr, "/websocket")
   136  	if err != nil {
   137  		return fmt.Errorf("http client for %s: %w", primaryAddr, err)
   138  	}
   139  
   140  	cfg := rpcserver.DefaultConfig()
   141  	cfg.MaxBodyBytes = config.RPC.MaxBodyBytes
   142  	cfg.MaxHeaderBytes = config.RPC.MaxHeaderBytes
   143  	cfg.MaxOpenConnections = maxOpenConnections
   144  	// If necessary adjust global WriteTimeout to ensure it's greater than
   145  	// TimeoutBroadcastTxCommit.
   146  	// See https://github.com/tendermint/tendermint/issues/3435
   147  	if cfg.WriteTimeout <= config.RPC.TimeoutBroadcastTxCommit {
   148  		cfg.WriteTimeout = config.RPC.TimeoutBroadcastTxCommit + 1*time.Second
   149  	}
   150  
   151  	p := lproxy.Proxy{
   152  		Addr:   listenAddr,
   153  		Config: cfg,
   154  		Client: lrpc.NewClient(rpcClient, c),
   155  		Logger: logger,
   156  	}
   157  	// Stop upon receiving SIGTERM or CTRL-C.
   158  	tmos.TrapSignal(logger, func() {
   159  		p.Listener.Close()
   160  	})
   161  
   162  	logger.Info("Starting proxy...", "laddr", listenAddr)
   163  	if err := p.ListenAndServe(); err != http.ErrServerClosed {
   164  		// Error starting or closing listener:
   165  		logger.Error("proxy ListenAndServe", "err", err)
   166  	}
   167  
   168  	return nil
   169  }