Files
tendermint/light/proxy/proxy.go
William Banfield bc2b529b95 inspect: add inspect mode for debugging crashed tendermint node (#6785)
EDIT: Updated, see [comment below]( https://github.com/tendermint/tendermint/pull/6785#issuecomment-897793175)

This change adds a sketch of the `Debug` mode. 

This change adds a `Debug` struct to the node package. This `Debug` struct is intended to be created and started by a command in the `cmd` directory. The `Debug` struct runs the RPC server on the data directories: both the state store and the block store.

This change required a good deal of refactoring. Namely, a new `rpc.go` file was added to the `node` package. This file encapsulates functions for starting RPC servers used by nodes. A potential additional change is to further factor this code into shared code _in_ the `rpc` package. 

Minor API tweaks were also made that seemed appropriate such as the mechanism for fetching routes from the `rpc/core` package.

Additional work is required to register the `Debug` service as a command in the `cmd` directory but I am looking for feedback on if this direction seems appropriate before diving much further.

closes: #5908
2021-08-24 18:12:06 +00:00

123 lines
3.1 KiB
Go

package proxy
import (
"context"
"fmt"
"net"
"net/http"
"github.com/tendermint/tendermint/libs/log"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
"github.com/tendermint/tendermint/light"
lrpc "github.com/tendermint/tendermint/light/rpc"
rpchttp "github.com/tendermint/tendermint/rpc/client/http"
rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
)
// A Proxy defines parameters for running an HTTP server proxy.
type Proxy struct {
Addr string // TCP address to listen on, ":http" if empty
Config *rpcserver.Config
Client *lrpc.Client
Logger log.Logger
Listener net.Listener
}
// NewProxy creates the struct used to run an HTTP server for serving light
// client rpc requests.
func NewProxy(
lightClient *light.Client,
listenAddr, providerAddr string,
config *rpcserver.Config,
logger log.Logger,
opts ...lrpc.Option,
) (*Proxy, error) {
rpcClient, err := rpchttp.NewWithTimeout(providerAddr, config.WriteTimeout)
if err != nil {
return nil, fmt.Errorf("failed to create http client for %s: %w", providerAddr, err)
}
return &Proxy{
Addr: listenAddr,
Config: config,
Client: lrpc.NewClient(rpcClient, lightClient, opts...),
Logger: logger,
}, nil
}
// ListenAndServe configures the rpcserver.WebsocketManager, sets up the RPC
// routes to proxy via Client, and starts up an HTTP server on the TCP network
// address p.Addr.
// See http#Server#ListenAndServe.
func (p *Proxy) ListenAndServe() error {
listener, mux, err := p.listen()
if err != nil {
return err
}
p.Listener = listener
return rpcserver.Serve(
listener,
mux,
p.Logger,
p.Config,
)
}
// ListenAndServeTLS acts identically to ListenAndServe, except that it expects
// HTTPS connections.
// See http#Server#ListenAndServeTLS.
func (p *Proxy) ListenAndServeTLS(certFile, keyFile string) error {
listener, mux, err := p.listen()
if err != nil {
return err
}
p.Listener = listener
return rpcserver.ServeTLS(
listener,
mux,
certFile,
keyFile,
p.Logger,
p.Config,
)
}
func (p *Proxy) listen() (net.Listener, *http.ServeMux, error) {
mux := http.NewServeMux()
// 1) Register regular routes.
r := RPCRoutes(p.Client)
rpcserver.RegisterRPCFuncs(mux, r, p.Logger)
// 2) Allow websocket connections.
wmLogger := p.Logger.With("protocol", "websocket")
wm := rpcserver.NewWebsocketManager(r,
rpcserver.OnDisconnect(func(remoteAddr string) {
err := p.Client.UnsubscribeAll(context.Background(), remoteAddr)
if err != nil && err != tmpubsub.ErrSubscriptionNotFound {
wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err)
}
}),
rpcserver.ReadLimit(p.Config.MaxBodyBytes),
)
wm.SetLogger(wmLogger)
mux.HandleFunc("/websocket", wm.WebsocketHandler)
// 3) Start a client.
if !p.Client.IsRunning() {
if err := p.Client.Start(); err != nil {
return nil, mux, fmt.Errorf("can't start client: %w", err)
}
}
// 4) Start listening for new connections.
listener, err := rpcserver.Listen(p.Addr, p.Config.MaxOpenConnections)
if err != nil {
return nil, mux, err
}
return listener, mux, nil
}