github.com/bloxroute-labs/bor@v0.1.4/node/node.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "errors" 21 "fmt" 22 "net" 23 "os" 24 "path/filepath" 25 "reflect" 26 "strings" 27 "sync" 28 29 "github.com/maticnetwork/bor/accounts" 30 "github.com/maticnetwork/bor/core/rawdb" 31 "github.com/maticnetwork/bor/ethdb" 32 "github.com/maticnetwork/bor/event" 33 "github.com/maticnetwork/bor/internal/debug" 34 "github.com/maticnetwork/bor/log" 35 "github.com/maticnetwork/bor/p2p" 36 "github.com/maticnetwork/bor/rpc" 37 "github.com/prometheus/tsdb/fileutil" 38 ) 39 40 // Node is a container on which services can be registered. 41 type Node struct { 42 eventmux *event.TypeMux // Event multiplexer used between the services of a stack 43 config *Config 44 accman *accounts.Manager 45 46 ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop 47 instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory 48 49 serverConfig p2p.Config 50 server *p2p.Server // Currently running P2P networking layer 51 52 serviceFuncs []ServiceConstructor // Service constructors (in dependency order) 53 services map[reflect.Type]Service // Currently running services 54 55 rpcAPIs []rpc.API // List of APIs currently provided by the node 56 inprocHandler *rpc.Server // In-process RPC request handler to process the API requests 57 58 ipcEndpoint string // IPC endpoint to listen at (empty = IPC disabled) 59 ipcListener net.Listener // IPC RPC listener socket to serve API requests 60 ipcHandler *rpc.Server // IPC RPC request handler to process the API requests 61 62 httpEndpoint string // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled) 63 httpWhitelist []string // HTTP RPC modules to allow through this endpoint 64 httpListener net.Listener // HTTP RPC listener socket to server API requests 65 httpHandler *rpc.Server // HTTP RPC request handler to process the API requests 66 67 wsEndpoint string // Websocket endpoint (interface + port) to listen at (empty = websocket disabled) 68 wsListener net.Listener // Websocket RPC listener socket to server API requests 69 wsHandler *rpc.Server // Websocket RPC request handler to process the API requests 70 71 stop chan struct{} // Channel to wait for termination notifications 72 lock sync.RWMutex 73 74 log log.Logger 75 } 76 77 // New creates a new P2P node, ready for protocol registration. 78 func New(conf *Config) (*Node, error) { 79 // Copy config and resolve the datadir so future changes to the current 80 // working directory don't affect the node. 81 confCopy := *conf 82 conf = &confCopy 83 if conf.DataDir != "" { 84 absdatadir, err := filepath.Abs(conf.DataDir) 85 if err != nil { 86 return nil, err 87 } 88 conf.DataDir = absdatadir 89 } 90 // Ensure that the instance name doesn't cause weird conflicts with 91 // other files in the data directory. 92 if strings.ContainsAny(conf.Name, `/\`) { 93 return nil, errors.New(`Config.Name must not contain '/' or '\'`) 94 } 95 if conf.Name == datadirDefaultKeyStore { 96 return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`) 97 } 98 if strings.HasSuffix(conf.Name, ".ipc") { 99 return nil, errors.New(`Config.Name cannot end in ".ipc"`) 100 } 101 // Ensure that the AccountManager method works before the node has started. 102 // We rely on this in cmd/geth. 103 am, ephemeralKeystore, err := makeAccountManager(conf) 104 if err != nil { 105 return nil, err 106 } 107 if conf.Logger == nil { 108 conf.Logger = log.New() 109 } 110 // Note: any interaction with Config that would create/touch files 111 // in the data directory or instance directory is delayed until Start. 112 return &Node{ 113 accman: am, 114 ephemeralKeystore: ephemeralKeystore, 115 config: conf, 116 serviceFuncs: []ServiceConstructor{}, 117 ipcEndpoint: conf.IPCEndpoint(), 118 httpEndpoint: conf.HTTPEndpoint(), 119 wsEndpoint: conf.WSEndpoint(), 120 eventmux: new(event.TypeMux), 121 log: conf.Logger, 122 }, nil 123 } 124 125 // Close stops the Node and releases resources acquired in 126 // Node constructor New. 127 func (n *Node) Close() error { 128 var errs []error 129 130 // Terminate all subsystems and collect any errors 131 if err := n.Stop(); err != nil && err != ErrNodeStopped { 132 errs = append(errs, err) 133 } 134 if err := n.accman.Close(); err != nil { 135 errs = append(errs, err) 136 } 137 // Report any errors that might have occurred 138 switch len(errs) { 139 case 0: 140 return nil 141 case 1: 142 return errs[0] 143 default: 144 return fmt.Errorf("%v", errs) 145 } 146 } 147 148 // Register injects a new service into the node's stack. The service created by 149 // the passed constructor must be unique in its type with regard to sibling ones. 150 func (n *Node) Register(constructor ServiceConstructor) error { 151 n.lock.Lock() 152 defer n.lock.Unlock() 153 154 if n.server != nil { 155 return ErrNodeRunning 156 } 157 n.serviceFuncs = append(n.serviceFuncs, constructor) 158 return nil 159 } 160 161 // Start create a live P2P node and starts running it. 162 func (n *Node) Start() error { 163 n.lock.Lock() 164 defer n.lock.Unlock() 165 166 // Short circuit if the node's already running 167 if n.server != nil { 168 return ErrNodeRunning 169 } 170 if err := n.openDataDir(); err != nil { 171 return err 172 } 173 174 // Initialize the p2p server. This creates the node key and 175 // discovery databases. 176 n.serverConfig = n.config.P2P 177 n.serverConfig.PrivateKey = n.config.NodeKey() 178 n.serverConfig.Name = n.config.NodeName() 179 n.serverConfig.Logger = n.log 180 if n.serverConfig.StaticNodes == nil { 181 n.serverConfig.StaticNodes = n.config.StaticNodes() 182 } 183 if n.serverConfig.TrustedNodes == nil { 184 n.serverConfig.TrustedNodes = n.config.TrustedNodes() 185 } 186 if n.serverConfig.NodeDatabase == "" { 187 n.serverConfig.NodeDatabase = n.config.NodeDB() 188 } 189 running := &p2p.Server{Config: n.serverConfig} 190 n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name) 191 192 // Otherwise copy and specialize the P2P configuration 193 services := make(map[reflect.Type]Service) 194 for _, constructor := range n.serviceFuncs { 195 // Create a new context for the particular service 196 ctx := &ServiceContext{ 197 config: n.config, 198 services: make(map[reflect.Type]Service), 199 EventMux: n.eventmux, 200 AccountManager: n.accman, 201 } 202 for kind, s := range services { // copy needed for threaded access 203 ctx.services[kind] = s 204 } 205 // Construct and save the service 206 service, err := constructor(ctx) 207 if err != nil { 208 return err 209 } 210 kind := reflect.TypeOf(service) 211 if _, exists := services[kind]; exists { 212 return &DuplicateServiceError{Kind: kind} 213 } 214 services[kind] = service 215 } 216 // Gather the protocols and start the freshly assembled P2P server 217 for _, service := range services { 218 running.Protocols = append(running.Protocols, service.Protocols()...) 219 } 220 if err := running.Start(); err != nil { 221 return convertFileLockError(err) 222 } 223 // Start each of the services 224 var started []reflect.Type 225 for kind, service := range services { 226 // Start the next service, stopping all previous upon failure 227 if err := service.Start(running); err != nil { 228 for _, kind := range started { 229 services[kind].Stop() 230 } 231 running.Stop() 232 233 return err 234 } 235 // Mark the service started for potential cleanup 236 started = append(started, kind) 237 } 238 // Lastly start the configured RPC interfaces 239 if err := n.startRPC(services); err != nil { 240 for _, service := range services { 241 service.Stop() 242 } 243 running.Stop() 244 return err 245 } 246 // Finish initializing the startup 247 n.services = services 248 n.server = running 249 n.stop = make(chan struct{}) 250 return nil 251 } 252 253 // Config returns the configuration of node. 254 func (n *Node) Config() *Config { 255 return n.config 256 } 257 258 func (n *Node) openDataDir() error { 259 if n.config.DataDir == "" { 260 return nil // ephemeral 261 } 262 263 instdir := filepath.Join(n.config.DataDir, n.config.name()) 264 if err := os.MkdirAll(instdir, 0700); err != nil { 265 return err 266 } 267 // Lock the instance directory to prevent concurrent use by another instance as well as 268 // accidental use of the instance directory as a database. 269 release, _, err := fileutil.Flock(filepath.Join(instdir, "LOCK")) 270 if err != nil { 271 return convertFileLockError(err) 272 } 273 n.instanceDirLock = release 274 return nil 275 } 276 277 // startRPC is a helper method to start all the various RPC endpoint during node 278 // startup. It's not meant to be called at any time afterwards as it makes certain 279 // assumptions about the state of the node. 280 func (n *Node) startRPC(services map[reflect.Type]Service) error { 281 // Gather all the possible APIs to surface 282 apis := n.apis() 283 for _, service := range services { 284 apis = append(apis, service.APIs()...) 285 } 286 // Start the various API endpoints, terminating all in case of errors 287 if err := n.startInProc(apis); err != nil { 288 return err 289 } 290 if err := n.startIPC(apis); err != nil { 291 n.stopInProc() 292 return err 293 } 294 if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil { 295 n.stopIPC() 296 n.stopInProc() 297 return err 298 } 299 if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil { 300 n.stopHTTP() 301 n.stopIPC() 302 n.stopInProc() 303 return err 304 } 305 // All API endpoints started successfully 306 n.rpcAPIs = apis 307 return nil 308 } 309 310 // startInProc initializes an in-process RPC endpoint. 311 func (n *Node) startInProc(apis []rpc.API) error { 312 // Register all the APIs exposed by the services 313 handler := rpc.NewServer() 314 for _, api := range apis { 315 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 316 return err 317 } 318 n.log.Debug("InProc registered", "namespace", api.Namespace) 319 } 320 n.inprocHandler = handler 321 return nil 322 } 323 324 // stopInProc terminates the in-process RPC endpoint. 325 func (n *Node) stopInProc() { 326 if n.inprocHandler != nil { 327 n.inprocHandler.Stop() 328 n.inprocHandler = nil 329 } 330 } 331 332 // startIPC initializes and starts the IPC RPC endpoint. 333 func (n *Node) startIPC(apis []rpc.API) error { 334 if n.ipcEndpoint == "" { 335 return nil // IPC disabled. 336 } 337 listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis) 338 if err != nil { 339 return err 340 } 341 n.ipcListener = listener 342 n.ipcHandler = handler 343 n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint) 344 return nil 345 } 346 347 // stopIPC terminates the IPC RPC endpoint. 348 func (n *Node) stopIPC() { 349 if n.ipcListener != nil { 350 n.ipcListener.Close() 351 n.ipcListener = nil 352 353 n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint) 354 } 355 if n.ipcHandler != nil { 356 n.ipcHandler.Stop() 357 n.ipcHandler = nil 358 } 359 } 360 361 // startHTTP initializes and starts the HTTP RPC endpoint. 362 func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error { 363 // Short circuit if the HTTP endpoint isn't being exposed 364 if endpoint == "" { 365 return nil 366 } 367 listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts) 368 if err != nil { 369 return err 370 } 371 n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ",")) 372 // All listeners booted successfully 373 n.httpEndpoint = endpoint 374 n.httpListener = listener 375 n.httpHandler = handler 376 377 return nil 378 } 379 380 // stopHTTP terminates the HTTP RPC endpoint. 381 func (n *Node) stopHTTP() { 382 if n.httpListener != nil { 383 n.httpListener.Close() 384 n.httpListener = nil 385 386 n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint)) 387 } 388 if n.httpHandler != nil { 389 n.httpHandler.Stop() 390 n.httpHandler = nil 391 } 392 } 393 394 // startWS initializes and starts the websocket RPC endpoint. 395 func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error { 396 // Short circuit if the WS endpoint isn't being exposed 397 if endpoint == "" { 398 return nil 399 } 400 listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll) 401 if err != nil { 402 return err 403 } 404 n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr())) 405 // All listeners booted successfully 406 n.wsEndpoint = endpoint 407 n.wsListener = listener 408 n.wsHandler = handler 409 410 return nil 411 } 412 413 // stopWS terminates the websocket RPC endpoint. 414 func (n *Node) stopWS() { 415 if n.wsListener != nil { 416 n.wsListener.Close() 417 n.wsListener = nil 418 419 n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint)) 420 } 421 if n.wsHandler != nil { 422 n.wsHandler.Stop() 423 n.wsHandler = nil 424 } 425 } 426 427 // Stop terminates a running node along with all it's services. In the node was 428 // not started, an error is returned. 429 func (n *Node) Stop() error { 430 n.lock.Lock() 431 defer n.lock.Unlock() 432 433 // Short circuit if the node's not running 434 if n.server == nil { 435 return ErrNodeStopped 436 } 437 438 // Terminate the API, services and the p2p server. 439 n.stopWS() 440 n.stopHTTP() 441 n.stopIPC() 442 n.rpcAPIs = nil 443 failure := &StopError{ 444 Services: make(map[reflect.Type]error), 445 } 446 for kind, service := range n.services { 447 if err := service.Stop(); err != nil { 448 failure.Services[kind] = err 449 } 450 } 451 n.server.Stop() 452 n.services = nil 453 n.server = nil 454 455 // Release instance directory lock. 456 if n.instanceDirLock != nil { 457 if err := n.instanceDirLock.Release(); err != nil { 458 n.log.Error("Can't release datadir lock", "err", err) 459 } 460 n.instanceDirLock = nil 461 } 462 463 // unblock n.Wait 464 close(n.stop) 465 466 // Remove the keystore if it was created ephemerally. 467 var keystoreErr error 468 if n.ephemeralKeystore != "" { 469 keystoreErr = os.RemoveAll(n.ephemeralKeystore) 470 } 471 472 if len(failure.Services) > 0 { 473 return failure 474 } 475 if keystoreErr != nil { 476 return keystoreErr 477 } 478 return nil 479 } 480 481 // Wait blocks the thread until the node is stopped. If the node is not running 482 // at the time of invocation, the method immediately returns. 483 func (n *Node) Wait() { 484 n.lock.RLock() 485 if n.server == nil { 486 n.lock.RUnlock() 487 return 488 } 489 stop := n.stop 490 n.lock.RUnlock() 491 492 <-stop 493 } 494 495 // Restart terminates a running node and boots up a new one in its place. If the 496 // node isn't running, an error is returned. 497 func (n *Node) Restart() error { 498 if err := n.Stop(); err != nil { 499 return err 500 } 501 if err := n.Start(); err != nil { 502 return err 503 } 504 return nil 505 } 506 507 // Attach creates an RPC client attached to an in-process API handler. 508 func (n *Node) Attach() (*rpc.Client, error) { 509 n.lock.RLock() 510 defer n.lock.RUnlock() 511 512 if n.server == nil { 513 return nil, ErrNodeStopped 514 } 515 return rpc.DialInProc(n.inprocHandler), nil 516 } 517 518 // RPCHandler returns the in-process RPC request handler. 519 func (n *Node) RPCHandler() (*rpc.Server, error) { 520 n.lock.RLock() 521 defer n.lock.RUnlock() 522 523 if n.inprocHandler == nil { 524 return nil, ErrNodeStopped 525 } 526 return n.inprocHandler, nil 527 } 528 529 // Server retrieves the currently running P2P network layer. This method is meant 530 // only to inspect fields of the currently running server, life cycle management 531 // should be left to this Node entity. 532 func (n *Node) Server() *p2p.Server { 533 n.lock.RLock() 534 defer n.lock.RUnlock() 535 536 return n.server 537 } 538 539 // Service retrieves a currently running service registered of a specific type. 540 func (n *Node) Service(service interface{}) error { 541 n.lock.RLock() 542 defer n.lock.RUnlock() 543 544 // Short circuit if the node's not running 545 if n.server == nil { 546 return ErrNodeStopped 547 } 548 // Otherwise try to find the service to return 549 element := reflect.ValueOf(service).Elem() 550 if running, ok := n.services[element.Type()]; ok { 551 element.Set(reflect.ValueOf(running)) 552 return nil 553 } 554 return ErrServiceUnknown 555 } 556 557 // DataDir retrieves the current datadir used by the protocol stack. 558 // Deprecated: No files should be stored in this directory, use InstanceDir instead. 559 func (n *Node) DataDir() string { 560 return n.config.DataDir 561 } 562 563 // InstanceDir retrieves the instance directory used by the protocol stack. 564 func (n *Node) InstanceDir() string { 565 return n.config.instanceDir() 566 } 567 568 // AccountManager retrieves the account manager used by the protocol stack. 569 func (n *Node) AccountManager() *accounts.Manager { 570 return n.accman 571 } 572 573 // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. 574 func (n *Node) IPCEndpoint() string { 575 return n.ipcEndpoint 576 } 577 578 // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. 579 func (n *Node) HTTPEndpoint() string { 580 n.lock.Lock() 581 defer n.lock.Unlock() 582 583 if n.httpListener != nil { 584 return n.httpListener.Addr().String() 585 } 586 return n.httpEndpoint 587 } 588 589 // WSEndpoint retrieves the current WS endpoint used by the protocol stack. 590 func (n *Node) WSEndpoint() string { 591 n.lock.Lock() 592 defer n.lock.Unlock() 593 594 if n.wsListener != nil { 595 return n.wsListener.Addr().String() 596 } 597 return n.wsEndpoint 598 } 599 600 // EventMux retrieves the event multiplexer used by all the network services in 601 // the current protocol stack. 602 func (n *Node) EventMux() *event.TypeMux { 603 return n.eventmux 604 } 605 606 // OpenDatabase opens an existing database with the given name (or creates one if no 607 // previous can be found) from within the node's instance directory. If the node is 608 // ephemeral, a memory database is returned. 609 func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) { 610 if n.config.DataDir == "" { 611 return rawdb.NewMemoryDatabase(), nil 612 } 613 return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace) 614 } 615 616 // OpenDatabaseWithFreezer opens an existing database with the given name (or 617 // creates one if no previous can be found) from within the node's data directory, 618 // also attaching a chain freezer to it that moves ancient chain data from the 619 // database to immutable append-only files. If the node is an ephemeral one, a 620 // memory database is returned. 621 func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) { 622 if n.config.DataDir == "" { 623 return rawdb.NewMemoryDatabase(), nil 624 } 625 root := n.config.ResolvePath(name) 626 627 switch { 628 case freezer == "": 629 freezer = filepath.Join(root, "ancient") 630 case !filepath.IsAbs(freezer): 631 freezer = n.config.ResolvePath(freezer) 632 } 633 return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace) 634 } 635 636 // ResolvePath returns the absolute path of a resource in the instance directory. 637 func (n *Node) ResolvePath(x string) string { 638 return n.config.ResolvePath(x) 639 } 640 641 // apis returns the collection of RPC descriptors this node offers. 642 func (n *Node) apis() []rpc.API { 643 return []rpc.API{ 644 { 645 Namespace: "admin", 646 Version: "1.0", 647 Service: NewPrivateAdminAPI(n), 648 }, { 649 Namespace: "admin", 650 Version: "1.0", 651 Service: NewPublicAdminAPI(n), 652 Public: true, 653 }, { 654 Namespace: "debug", 655 Version: "1.0", 656 Service: debug.Handler, 657 }, { 658 Namespace: "web3", 659 Version: "1.0", 660 Service: NewPublicWeb3API(n), 661 Public: true, 662 }, 663 } 664 }