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