github.com/klaytn/klaytn@v1.10.2/cmd/kbn/node.go (about)

     1  // Modifications Copyright 2019 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of go-ethereum.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from node/node.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package main
    22  
    23  import (
    24  	"fmt"
    25  	"net"
    26  	"strings"
    27  	"sync"
    28  
    29  	"github.com/klaytn/klaytn/log"
    30  	"github.com/klaytn/klaytn/networks/grpc"
    31  	"github.com/klaytn/klaytn/networks/rpc"
    32  	"github.com/klaytn/klaytn/node"
    33  )
    34  
    35  // Node is a container on which services can be registered.
    36  type Node struct {
    37  	config *bootnodeConfig
    38  
    39  	rpcAPIs       []rpc.API
    40  	inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
    41  
    42  	ipcEndpoint string       // IPC endpoint to listen at (empty = IPC disabled)
    43  	ipcListener net.Listener // IPC RPC listener socket to serve API requests
    44  	ipcHandler  *rpc.Server  // IPC RPC request handler to process the API requests
    45  
    46  	httpEndpoint  string       // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled)
    47  	httpWhitelist []string     // HTTP RPC modules to allow through this endpoint
    48  	httpListener  net.Listener // HTTP RPC listener socket to server API requests
    49  	httpHandler   *rpc.Server  // HTTP RPC request handler to process the API requests
    50  
    51  	wsEndpoint string       // Websocket endpoint (interface + port) to listen at (empty = websocket disabled)
    52  	wsListener net.Listener // Websocket RPC listener socket to server API requests
    53  	wsHandler  *rpc.Server  // Websocket RPC request handler to process the API requests
    54  
    55  	grpcEndpoint string         // gRPC endpoint (interface + port) to listen at (empty = gRPC disabled)
    56  	grpcListener *grpc.Listener // gRPC listener socket to server API requests
    57  	grpcHandler  *rpc.Server    // gRPC request handler to process the API requests
    58  
    59  	stop chan struct{} // Channel to wait for termination notifications
    60  	lock sync.RWMutex
    61  
    62  	logger log.Logger
    63  }
    64  
    65  // New creates a new P2P node, ready for protocol registration.
    66  func New(conf *bootnodeConfig) (*Node, error) {
    67  	// Copy config and resolve the datadir so future changes to the current
    68  	// working directory don't affect the node.
    69  	confCopy := *conf
    70  	conf = &confCopy
    71  
    72  	// Note: any interaction with Config that would create/touch files
    73  	// in the data directory or instance directory is delayed until Start.
    74  	return &Node{
    75  		config:       conf,
    76  		ipcEndpoint:  conf.IPCEndpoint(),
    77  		httpEndpoint: conf.HTTPEndpoint(),
    78  		wsEndpoint:   conf.WSEndpoint(),
    79  		grpcEndpoint: conf.GRPCEndpoint(),
    80  		logger:       conf.Logger,
    81  	}, nil
    82  }
    83  
    84  func (n *Node) Start() error {
    85  	n.lock.Lock()
    86  	defer n.lock.Unlock()
    87  
    88  	// Lastly start the configured RPC interfaces
    89  	if err := n.startRPC(); err != nil {
    90  		return err
    91  	}
    92  
    93  	// Finish initializing the startup
    94  	n.stop = make(chan struct{})
    95  
    96  	return nil
    97  }
    98  
    99  // startRPC is a helper method to start all the various RPC endpoint during node
   100  // startup. It's not meant to be called at any time afterwards as it makes certain
   101  // assumptions about the state of the node.
   102  func (n *Node) startRPC() error {
   103  	apis := n.apis()
   104  	// Start the various API endpoints, terminating all in case of errors
   105  	if err := n.startInProc(apis); err != nil {
   106  		return err
   107  	}
   108  	if err := n.startIPC(apis); err != nil {
   109  		n.stopInProc()
   110  		return err
   111  	}
   112  
   113  	if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts); err != nil {
   114  		n.stopIPC()
   115  		n.stopInProc()
   116  		return err
   117  	}
   118  	if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
   119  		n.stopHTTP()
   120  		n.stopIPC()
   121  		n.stopInProc()
   122  		return err
   123  	}
   124  
   125  	// start gRPC server
   126  	if err := n.startgRPC(apis); err != nil {
   127  		n.stopHTTP()
   128  		n.stopIPC()
   129  		n.stopInProc()
   130  		return err
   131  	}
   132  	// All API endpoints started successfully
   133  	n.rpcAPIs = apis
   134  
   135  	return nil
   136  }
   137  
   138  // startInProc initializes an in-process RPC endpoint.
   139  func (n *Node) startInProc(apis []rpc.API) error {
   140  	// Register all the APIs exposed by the services
   141  	handler := rpc.NewServer()
   142  	for _, api := range apis {
   143  		if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
   144  			return err
   145  		}
   146  		n.logger.Debug("InProc registered", "service", api.Service, "namespace", api.Namespace)
   147  	}
   148  	n.inprocHandler = handler
   149  	return nil
   150  }
   151  
   152  // stopInProc terminates the in-process RPC endpoint.
   153  func (n *Node) stopInProc() {
   154  	if n.inprocHandler != nil {
   155  		n.inprocHandler.Stop()
   156  		n.inprocHandler = nil
   157  	}
   158  }
   159  
   160  // startIPC initializes and starts the IPC RPC endpoint.
   161  func (n *Node) startIPC(apis []rpc.API) error {
   162  	if n.ipcEndpoint == "" {
   163  		return nil // IPC disabled.
   164  	}
   165  	listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis)
   166  	if err != nil {
   167  		return err
   168  	}
   169  	n.ipcListener = listener
   170  	n.ipcHandler = handler
   171  	n.logger.Info("IPC endpoint opened", "url", n.ipcEndpoint)
   172  	return nil
   173  }
   174  
   175  // stopIPC terminates the IPC RPC endpoint.
   176  func (n *Node) stopIPC() {
   177  	if n.ipcListener != nil {
   178  		n.ipcListener.Close()
   179  		n.ipcListener = nil
   180  
   181  		n.logger.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint)
   182  	}
   183  	if n.ipcHandler != nil {
   184  		n.ipcHandler.Stop()
   185  		n.ipcHandler = nil
   186  	}
   187  }
   188  
   189  // startgRPC initializes and starts the gRPC endpoint.
   190  func (n *Node) startgRPC(apis []rpc.API) error {
   191  	if n.grpcEndpoint == "" {
   192  		return nil
   193  	}
   194  
   195  	handler := rpc.NewServer()
   196  	for _, api := range apis {
   197  		if api.Public {
   198  			if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
   199  				return err
   200  			}
   201  			n.logger.Debug("gRPC registered", "namespace", api.Namespace)
   202  		}
   203  	}
   204  
   205  	listener := &grpc.Listener{Addr: n.grpcEndpoint}
   206  	n.grpcHandler = handler
   207  	n.grpcListener = listener
   208  	listener.SetRPCServer(handler)
   209  
   210  	go listener.Start()
   211  	n.logger.Info("gRPC endpoint opened", "url", n.grpcEndpoint)
   212  	return nil
   213  }
   214  
   215  // startHTTP initializes and starts the HTTP RPC endpoint.
   216  func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string) error {
   217  	// Short circuit if the HTTP endpoint isn't being exposed
   218  	if endpoint == "" {
   219  		return nil
   220  	}
   221  	listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, n.config.HTTPTimeouts)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	n.logger.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ","))
   226  	// All listeners booted successfully
   227  	n.httpEndpoint = endpoint
   228  	n.httpListener = listener
   229  	n.httpHandler = handler
   230  
   231  	return nil
   232  }
   233  
   234  // startFastHTTP initializes and starts the HTTP RPC endpoint.
   235  func (n *Node) startFastHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string) error {
   236  	// Short circuit if the HTTP endpoint isn't being exposed
   237  	if endpoint == "" {
   238  		return nil
   239  	}
   240  	listener, handler, err := rpc.StartFastHTTPEndpoint(endpoint, apis, modules, cors, vhosts, n.config.HTTPTimeouts)
   241  	if err != nil {
   242  		return err
   243  	}
   244  	n.logger.Info("FastHTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ","))
   245  	// All listeners booted successfully
   246  	n.httpEndpoint = endpoint
   247  	n.httpListener = listener
   248  	n.httpHandler = handler
   249  
   250  	return nil
   251  }
   252  
   253  // stopHTTP terminates the HTTP RPC endpoint.
   254  func (n *Node) stopHTTP() {
   255  	if n.httpListener != nil {
   256  		n.httpListener.Close()
   257  		n.httpListener = nil
   258  
   259  		n.logger.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint))
   260  	}
   261  	if n.httpHandler != nil {
   262  		n.httpHandler.Stop()
   263  		n.httpHandler = nil
   264  	}
   265  }
   266  
   267  // startWS initializes and starts the websocket RPC endpoint.
   268  func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
   269  	// Short circuit if the WS endpoint isn't being exposed
   270  	if endpoint == "" {
   271  		return nil
   272  	}
   273  	listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll)
   274  	if err != nil {
   275  		return err
   276  	}
   277  	n.logger.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
   278  	// All listeners booted successfully
   279  	n.wsEndpoint = endpoint
   280  	n.wsListener = listener
   281  	n.wsHandler = handler
   282  
   283  	return nil
   284  }
   285  
   286  // startFastWS initializes and starts the websocket RPC endpoint.
   287  func (n *Node) startFastWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
   288  	// Short circuit if the WS endpoint isn't being exposed
   289  	if endpoint == "" {
   290  		return nil
   291  	}
   292  	listener, handler, err := rpc.StartFastWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll)
   293  	if err != nil {
   294  		return err
   295  	}
   296  	n.logger.Info("FastWebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
   297  	// All listeners booted successfully
   298  	n.wsEndpoint = endpoint
   299  	n.wsListener = listener
   300  	n.wsHandler = handler
   301  
   302  	return nil
   303  }
   304  
   305  // stopWS terminates the websocket RPC endpoint.
   306  func (n *Node) stopWS() {
   307  	if n.wsListener != nil {
   308  		n.wsListener.Close()
   309  		n.wsListener = nil
   310  
   311  		n.logger.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint))
   312  	}
   313  	if n.wsHandler != nil {
   314  		n.wsHandler.Stop()
   315  		n.wsHandler = nil
   316  	}
   317  }
   318  
   319  func (n *Node) stopgRPC() {
   320  	if n.grpcListener != nil {
   321  		n.grpcListener.Stop()
   322  		n.grpcListener = nil
   323  
   324  		n.logger.Info("gRPC endpoint closed", "url", fmt.Sprintf("grpc://%s", n.grpcEndpoint))
   325  	}
   326  
   327  	if n.grpcHandler != nil {
   328  		n.grpcHandler.Stop()
   329  		n.grpcHandler = nil
   330  	}
   331  }
   332  
   333  // Stop terminates a running node along with all it's services. In the node was
   334  // not started, an error is returned.
   335  func (n *Node) Stop() error {
   336  	n.lock.Lock()
   337  	defer n.lock.Unlock()
   338  
   339  	// Terminate the API, services and the p2p server.
   340  	n.stopWS()
   341  	n.stopHTTP()
   342  	n.stopIPC()
   343  	n.stopgRPC()
   344  	n.rpcAPIs = nil
   345  
   346  	// unblock n.Wait
   347  	close(n.stop)
   348  
   349  	return nil
   350  }
   351  
   352  // Wait blocks the thread until the node is stopped. If the node is not running
   353  // at the time of invocation, the method immediately returns.
   354  func (n *Node) Wait() {
   355  	n.lock.RLock()
   356  	stop := n.stop
   357  	n.lock.RUnlock()
   358  
   359  	<-stop
   360  }
   361  
   362  // Restart terminates a running node and boots up a new one in its place. If the
   363  // node isn't running, an error is returned.
   364  func (n *Node) Restart() error {
   365  	if err := n.Stop(); err != nil {
   366  		return err
   367  	}
   368  	if err := n.Start(); err != nil {
   369  		return err
   370  	}
   371  	return nil
   372  }
   373  
   374  // Attach creates an RPC client attached to an in-process API handler.
   375  func (n *Node) Attach() (*rpc.Client, error) {
   376  	n.lock.RLock()
   377  	defer n.lock.RUnlock()
   378  
   379  	return rpc.DialInProc(n.inprocHandler), nil
   380  }
   381  
   382  // RPCHandler returns the in-process RPC request handler.
   383  func (n *Node) RPCHandler() (*rpc.Server, error) {
   384  	n.lock.RLock()
   385  	defer n.lock.RUnlock()
   386  
   387  	if n.inprocHandler == nil {
   388  		return nil, node.ErrNodeStopped
   389  	}
   390  	return n.inprocHandler, nil
   391  }
   392  
   393  // DataDir retrieves the current datadir used by the protocol stack.
   394  // Deprecated: No files should be stored in this directory, use InstanceDir instead.
   395  func (n *Node) DataDir() string {
   396  	return n.config.DataDir
   397  }
   398  
   399  // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
   400  func (n *Node) IPCEndpoint() string {
   401  	return n.ipcEndpoint
   402  }
   403  
   404  // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
   405  func (n *Node) HTTPEndpoint() string {
   406  	return n.httpEndpoint
   407  }
   408  
   409  // WSEndpoint retrieves the current WS endpoint used by the protocol stack.
   410  func (n *Node) WSEndpoint() string {
   411  	return n.wsEndpoint
   412  }
   413  
   414  func (n *Node) appendAPIs(apis []rpc.API) {
   415  	n.rpcAPIs = append(n.rpcAPIs, apis...)
   416  }
   417  
   418  func (n *Node) apis() []rpc.API {
   419  	return n.rpcAPIs
   420  }