server.go 2.69 KB
Newer Older
1 2 3 4
package node

import (
	"context"
5
	"fmt"
6 7
	"net"
	"net/http"
8
	"strconv"
9

10
	ophttp "github.com/ethereum-optimism/optimism/op-service/httputil"
11 12 13 14
	"github.com/ethereum/go-ethereum/log"
	"github.com/ethereum/go-ethereum/node"
	"github.com/ethereum/go-ethereum/rpc"

15
	"github.com/ethereum-optimism/optimism/op-node/metrics"
16 17
	"github.com/ethereum-optimism/optimism/op-node/p2p"
	"github.com/ethereum-optimism/optimism/op-node/rollup"
Sabnock01's avatar
Sabnock01 committed
18
	"github.com/ethereum-optimism/optimism/op-service/sources"
19 20 21 22 23
)

type rpcServer struct {
	endpoint   string
	apis       []rpc.API
24
	httpServer *ophttp.HTTPServer
25 26
	appVersion string
	log        log.Logger
27
	sources.L2Client
28 29
}

30
func newRPCServer(ctx context.Context, rpcCfg *RPCConfig, rollupCfg *rollup.Config, l2Client l2EthClient, dr driverClient, log log.Logger, appVersion string, m metrics.Metricer) (*rpcServer, error) {
31
	api := NewNodeAPI(rollupCfg, l2Client, dr, log.New("rpc", "node"), m)
32
	// TODO: extend RPC config with options for WS, IPC and HTTP RPC connections
33
	endpoint := net.JoinHostPort(rpcCfg.ListenAddr, strconv.Itoa(rpcCfg.ListenPort))
34 35 36 37 38 39 40 41 42 43 44 45 46
	r := &rpcServer{
		endpoint: endpoint,
		apis: []rpc.API{{
			Namespace:     "optimism",
			Service:       api,
			Authenticated: false,
		}},
		appVersion: appVersion,
		log:        log,
	}
	return r, nil
}

47 48 49 50 51 52 53 54 55
func (s *rpcServer) EnableAdminAPI(api *adminAPI) {
	s.apis = append(s.apis, rpc.API{
		Namespace:     "admin",
		Version:       "",
		Service:       api,
		Authenticated: false,
	})
}

56 57 58 59 60 61 62 63 64 65 66
func (s *rpcServer) EnableP2P(backend *p2p.APIBackend) {
	s.apis = append(s.apis, rpc.API{
		Namespace:     p2p.NamespaceRPC,
		Version:       "",
		Service:       backend,
		Authenticated: false,
	})
}

func (s *rpcServer) Start() error {
	srv := rpc.NewServer()
67
	if err := node.RegisterApis(s.apis, nil, srv); err != nil {
68 69 70 71 72 73 74 75 76 77 78 79 80
		return err
	}

	// The CORS and VHosts arguments below must be set in order for
	// other services to connect to the opnode. VHosts in particular
	// defaults to localhost, which will prevent containers from
	// calling into the opnode without an "invalid host" error.
	nodeHandler := node.NewHTTPHandlerStack(srv, []string{"*"}, []string{"*"}, nil)

	mux := http.NewServeMux()
	mux.Handle("/", nodeHandler)
	mux.HandleFunc("/healthz", healthzHandler(s.appVersion))

81
	hs, err := ophttp.StartHTTPServer(s.endpoint, mux)
82
	if err != nil {
83
		return fmt.Errorf("failed to start HTTP RPC server: %w", err)
84
	}
85
	s.httpServer = hs
86 87 88
	return nil
}

89 90
func (r *rpcServer) Stop(ctx context.Context) error {
	return r.httpServer.Stop(ctx)
91 92 93
}

func (r *rpcServer) Addr() net.Addr {
94
	return r.httpServer.Addr()
95 96 97 98 99 100 101
}

func healthzHandler(appVersion string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(appVersion))
	}
}