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 }