github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/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 "net" 22 "os" 23 "path/filepath" 24 "reflect" 25 "strings" 26 "sync" 27 "syscall" 28 29 "github.com/ethereum/go-ethereum/accounts" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/event" 32 "github.com/ethereum/go-ethereum/internal/debug" 33 "github.com/ethereum/go-ethereum/logger" 34 "github.com/ethereum/go-ethereum/logger/glog" 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 = p2p.Config{ 157 PrivateKey: n.config.NodeKey(), 158 Name: n.config.NodeName(), 159 Discovery: !n.config.NoDiscovery, 160 DiscoveryV5: n.config.DiscoveryV5, 161 DiscoveryV5Addr: n.config.DiscoveryV5Addr, 162 BootstrapNodes: n.config.BootstrapNodes, 163 BootstrapNodesV5: n.config.BootstrapNodesV5, 164 StaticNodes: n.config.StaticNodes(), 165 TrustedNodes: n.config.TrusterNodes(), 166 NodeDatabase: n.config.NodeDB(), 167 ListenAddr: n.config.ListenAddr, 168 NetRestrict: n.config.NetRestrict, 169 NAT: n.config.NAT, 170 Dialer: n.config.Dialer, 171 NoDial: n.config.NoDial, 172 MaxPeers: n.config.MaxPeers, 173 MaxPendingPeers: n.config.MaxPendingPeers, 174 } 175 running := &p2p.Server{Config: n.serverConfig} 176 glog.V(logger.Info).Infoln("instance:", n.serverConfig.Name) 177 178 // Otherwise copy and specialize the P2P configuration 179 services := make(map[reflect.Type]Service) 180 for _, constructor := range n.serviceFuncs { 181 // Create a new context for the particular service 182 ctx := &ServiceContext{ 183 config: n.config, 184 services: make(map[reflect.Type]Service), 185 EventMux: n.eventmux, 186 AccountManager: n.accman, 187 } 188 for kind, s := range services { // copy needed for threaded access 189 ctx.services[kind] = s 190 } 191 // Construct and save the service 192 service, err := constructor(ctx) 193 if err != nil { 194 return err 195 } 196 kind := reflect.TypeOf(service) 197 if _, exists := services[kind]; exists { 198 return &DuplicateServiceError{Kind: kind} 199 } 200 services[kind] = service 201 } 202 // Gather the protocols and start the freshly assembled P2P server 203 for _, service := range services { 204 running.Protocols = append(running.Protocols, service.Protocols()...) 205 } 206 if err := running.Start(); err != nil { 207 if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { 208 return ErrDatadirUsed 209 } 210 return err 211 } 212 // Start each of the services 213 started := []reflect.Type{} 214 for kind, service := range services { 215 // Start the next service, stopping all previous upon failure 216 if err := service.Start(running); err != nil { 217 for _, kind := range started { 218 services[kind].Stop() 219 } 220 running.Stop() 221 222 return err 223 } 224 // Mark the service started for potential cleanup 225 started = append(started, kind) 226 } 227 // Lastly start the configured RPC interfaces 228 if err := n.startRPC(services); err != nil { 229 for _, service := range services { 230 service.Stop() 231 } 232 running.Stop() 233 return err 234 } 235 // Finish initializing the startup 236 n.services = services 237 n.server = running 238 n.stop = make(chan struct{}) 239 240 return nil 241 } 242 243 func (n *Node) openDataDir() error { 244 if n.config.DataDir == "" { 245 return nil // ephemeral 246 } 247 248 instdir := filepath.Join(n.config.DataDir, n.config.name()) 249 if err := os.MkdirAll(instdir, 0700); err != nil { 250 return err 251 } 252 // Try to open the instance directory as LevelDB storage. This creates a lock file 253 // which prevents concurrent use by another instance as well as accidental use of the 254 // instance directory as a database. 255 storage, err := storage.OpenFile(instdir, true) 256 if err != nil { 257 return err 258 } 259 n.instanceDirLock = storage 260 return nil 261 } 262 263 // startRPC is a helper method to start all the various RPC endpoint during node 264 // startup. It's not meant to be called at any time afterwards as it makes certain 265 // assumptions about the state of the node. 266 func (n *Node) startRPC(services map[reflect.Type]Service) error { 267 // Gather all the possible APIs to surface 268 apis := n.apis() 269 for _, service := range services { 270 apis = append(apis, service.APIs()...) 271 } 272 // Start the various API endpoints, terminating all in case of errors 273 if err := n.startInProc(apis); err != nil { 274 return err 275 } 276 if err := n.startIPC(apis); err != nil { 277 n.stopInProc() 278 return err 279 } 280 if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil { 281 n.stopIPC() 282 n.stopInProc() 283 return err 284 } 285 if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins); err != nil { 286 n.stopHTTP() 287 n.stopIPC() 288 n.stopInProc() 289 return err 290 } 291 // All API endpoints started successfully 292 n.rpcAPIs = apis 293 return nil 294 } 295 296 // startInProc initializes an in-process RPC endpoint. 297 func (n *Node) startInProc(apis []rpc.API) error { 298 // Register all the APIs exposed by the services 299 handler := rpc.NewServer() 300 for _, api := range apis { 301 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 302 return err 303 } 304 glog.V(logger.Debug).Infof("InProc registered %T under '%s'", api.Service, api.Namespace) 305 } 306 n.inprocHandler = handler 307 return nil 308 } 309 310 // stopInProc terminates the in-process RPC endpoint. 311 func (n *Node) stopInProc() { 312 if n.inprocHandler != nil { 313 n.inprocHandler.Stop() 314 n.inprocHandler = nil 315 } 316 } 317 318 // startIPC initializes and starts the IPC RPC endpoint. 319 func (n *Node) startIPC(apis []rpc.API) error { 320 // Short circuit if the IPC endpoint isn't being exposed 321 if n.ipcEndpoint == "" { 322 return nil 323 } 324 // Register all the APIs exposed by the services 325 handler := rpc.NewServer() 326 for _, api := range apis { 327 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 328 return err 329 } 330 glog.V(logger.Debug).Infof("IPC registered %T under '%s'", api.Service, api.Namespace) 331 } 332 // All APIs registered, start the IPC listener 333 var ( 334 listener net.Listener 335 err error 336 ) 337 if listener, err = rpc.CreateIPCListener(n.ipcEndpoint); err != nil { 338 return err 339 } 340 go func() { 341 glog.V(logger.Info).Infof("IPC endpoint opened: %s", n.ipcEndpoint) 342 343 for { 344 conn, err := listener.Accept() 345 if err != nil { 346 // Terminate if the listener was closed 347 n.lock.RLock() 348 closed := n.ipcListener == nil 349 n.lock.RUnlock() 350 if closed { 351 return 352 } 353 // Not closed, just some error; report and continue 354 glog.V(logger.Error).Infof("IPC accept failed: %v", err) 355 continue 356 } 357 go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) 358 } 359 }() 360 // All listeners booted successfully 361 n.ipcListener = listener 362 n.ipcHandler = handler 363 364 return nil 365 } 366 367 // stopIPC terminates the IPC RPC endpoint. 368 func (n *Node) stopIPC() { 369 if n.ipcListener != nil { 370 n.ipcListener.Close() 371 n.ipcListener = nil 372 373 glog.V(logger.Info).Infof("IPC endpoint closed: %s", n.ipcEndpoint) 374 } 375 if n.ipcHandler != nil { 376 n.ipcHandler.Stop() 377 n.ipcHandler = nil 378 } 379 } 380 381 // startHTTP initializes and starts the HTTP RPC endpoint. 382 func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors string) error { 383 // Short circuit if the HTTP endpoint isn't being exposed 384 if endpoint == "" { 385 return nil 386 } 387 // Generate the whitelist based on the allowed modules 388 whitelist := make(map[string]bool) 389 for _, module := range modules { 390 whitelist[module] = true 391 } 392 // Register all the APIs exposed by the services 393 handler := rpc.NewServer() 394 for _, api := range apis { 395 if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { 396 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 397 return err 398 } 399 glog.V(logger.Debug).Infof("HTTP registered %T under '%s'", api.Service, api.Namespace) 400 } 401 } 402 // All APIs registered, start the HTTP listener 403 var ( 404 listener net.Listener 405 err error 406 ) 407 if listener, err = net.Listen("tcp", endpoint); err != nil { 408 return err 409 } 410 go rpc.NewHTTPServer(cors, handler).Serve(listener) 411 glog.V(logger.Info).Infof("HTTP endpoint opened: http://%s", endpoint) 412 413 // All listeners booted successfully 414 n.httpEndpoint = endpoint 415 n.httpListener = listener 416 n.httpHandler = handler 417 418 return nil 419 } 420 421 // stopHTTP terminates the HTTP RPC endpoint. 422 func (n *Node) stopHTTP() { 423 if n.httpListener != nil { 424 n.httpListener.Close() 425 n.httpListener = nil 426 427 glog.V(logger.Info).Infof("HTTP endpoint closed: http://%s", n.httpEndpoint) 428 } 429 if n.httpHandler != nil { 430 n.httpHandler.Stop() 431 n.httpHandler = nil 432 } 433 } 434 435 // startWS initializes and starts the websocket RPC endpoint. 436 func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins string) error { 437 // Short circuit if the WS endpoint isn't being exposed 438 if endpoint == "" { 439 return nil 440 } 441 // Generate the whitelist based on the allowed modules 442 whitelist := make(map[string]bool) 443 for _, module := range modules { 444 whitelist[module] = true 445 } 446 // Register all the APIs exposed by the services 447 handler := rpc.NewServer() 448 for _, api := range apis { 449 if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { 450 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 451 return err 452 } 453 glog.V(logger.Debug).Infof("WebSocket registered %T under '%s'", api.Service, api.Namespace) 454 } 455 } 456 // All APIs registered, start the HTTP listener 457 var ( 458 listener net.Listener 459 err error 460 ) 461 if listener, err = net.Listen("tcp", endpoint); err != nil { 462 return err 463 } 464 go rpc.NewWSServer(wsOrigins, handler).Serve(listener) 465 glog.V(logger.Info).Infof("WebSocket endpoint opened: ws://%s", endpoint) 466 467 // All listeners booted successfully 468 n.wsEndpoint = endpoint 469 n.wsListener = listener 470 n.wsHandler = handler 471 472 return nil 473 } 474 475 // stopWS terminates the websocket RPC endpoint. 476 func (n *Node) stopWS() { 477 if n.wsListener != nil { 478 n.wsListener.Close() 479 n.wsListener = nil 480 481 glog.V(logger.Info).Infof("WebSocket endpoint closed: ws://%s", n.wsEndpoint) 482 } 483 if n.wsHandler != nil { 484 n.wsHandler.Stop() 485 n.wsHandler = nil 486 } 487 } 488 489 // Stop terminates a running node along with all it's services. In the node was 490 // not started, an error is returned. 491 func (n *Node) Stop() error { 492 n.lock.Lock() 493 defer n.lock.Unlock() 494 495 // Short circuit if the node's not running 496 if n.server == nil { 497 return ErrNodeStopped 498 } 499 500 // Terminate the API, services and the p2p server. 501 n.stopWS() 502 n.stopHTTP() 503 n.stopIPC() 504 n.rpcAPIs = nil 505 failure := &StopError{ 506 Services: make(map[reflect.Type]error), 507 } 508 for kind, service := range n.services { 509 if err := service.Stop(); err != nil { 510 failure.Services[kind] = err 511 } 512 } 513 n.server.Stop() 514 n.services = nil 515 n.server = nil 516 517 // Release instance directory lock. 518 if n.instanceDirLock != nil { 519 n.instanceDirLock.Close() 520 n.instanceDirLock = nil 521 } 522 523 // unblock n.Wait 524 close(n.stop) 525 526 // Remove the keystore if it was created ephemerally. 527 var keystoreErr error 528 if n.ephemeralKeystore != "" { 529 keystoreErr = os.RemoveAll(n.ephemeralKeystore) 530 } 531 532 if len(failure.Services) > 0 { 533 return failure 534 } 535 if keystoreErr != nil { 536 return keystoreErr 537 } 538 return nil 539 } 540 541 // Wait blocks the thread until the node is stopped. If the node is not running 542 // at the time of invocation, the method immediately returns. 543 func (n *Node) Wait() { 544 n.lock.RLock() 545 if n.server == nil { 546 return 547 } 548 stop := n.stop 549 n.lock.RUnlock() 550 551 <-stop 552 } 553 554 // Restart terminates a running node and boots up a new one in its place. If the 555 // node isn't running, an error is returned. 556 func (n *Node) Restart() error { 557 if err := n.Stop(); err != nil { 558 return err 559 } 560 if err := n.Start(); err != nil { 561 return err 562 } 563 return nil 564 } 565 566 // Attach creates an RPC client attached to an in-process API handler. 567 func (n *Node) Attach() (*rpc.Client, error) { 568 n.lock.RLock() 569 defer n.lock.RUnlock() 570 571 if n.server == nil { 572 return nil, ErrNodeStopped 573 } 574 return rpc.DialInProc(n.inprocHandler), nil 575 } 576 577 // Server retrieves the currently running P2P network layer. This method is meant 578 // only to inspect fields of the currently running server, life cycle management 579 // should be left to this Node entity. 580 func (n *Node) Server() *p2p.Server { 581 n.lock.RLock() 582 defer n.lock.RUnlock() 583 584 return n.server 585 } 586 587 // Service retrieves a currently running service registered of a specific type. 588 func (n *Node) Service(service interface{}) error { 589 n.lock.RLock() 590 defer n.lock.RUnlock() 591 592 // Short circuit if the node's not running 593 if n.server == nil { 594 return ErrNodeStopped 595 } 596 // Otherwise try to find the service to return 597 element := reflect.ValueOf(service).Elem() 598 if running, ok := n.services[element.Type()]; ok { 599 element.Set(reflect.ValueOf(running)) 600 return nil 601 } 602 return ErrServiceUnknown 603 } 604 605 // DataDir retrieves the current datadir used by the protocol stack. 606 // Deprecated: No files should be stored in this directory, use InstanceDir instead. 607 func (n *Node) DataDir() string { 608 return n.config.DataDir 609 } 610 611 // InstanceDir retrieves the instance directory used by the protocol stack. 612 func (n *Node) InstanceDir() string { 613 return n.config.instanceDir() 614 } 615 616 // AccountManager retrieves the account manager used by the protocol stack. 617 func (n *Node) AccountManager() *accounts.Manager { 618 return n.accman 619 } 620 621 // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. 622 func (n *Node) IPCEndpoint() string { 623 return n.ipcEndpoint 624 } 625 626 // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. 627 func (n *Node) HTTPEndpoint() string { 628 return n.httpEndpoint 629 } 630 631 // WSEndpoint retrieves the current WS endpoint used by the protocol stack. 632 func (n *Node) WSEndpoint() string { 633 return n.wsEndpoint 634 } 635 636 // EventMux retrieves the event multiplexer used by all the network services in 637 // the current protocol stack. 638 func (n *Node) EventMux() *event.TypeMux { 639 return n.eventmux 640 } 641 642 // OpenDatabase opens an existing database with the given name (or creates one if no 643 // previous can be found) from within the node's instance directory. If the node is 644 // ephemeral, a memory database is returned. 645 func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { 646 if n.config.DataDir == "" { 647 return ethdb.NewMemDatabase() 648 } 649 return ethdb.NewLDBDatabase(n.config.resolvePath(name), cache, handles) 650 } 651 652 // ResolvePath returns the absolute path of a resource in the instance directory. 653 func (n *Node) ResolvePath(x string) string { 654 return n.config.resolvePath(x) 655 } 656 657 // apis returns the collection of RPC descriptors this node offers. 658 func (n *Node) apis() []rpc.API { 659 return []rpc.API{ 660 { 661 Namespace: "admin", 662 Version: "1.0", 663 Service: NewPrivateAdminAPI(n), 664 }, { 665 Namespace: "admin", 666 Version: "1.0", 667 Service: NewPublicAdminAPI(n), 668 Public: true, 669 }, { 670 Namespace: "debug", 671 Version: "1.0", 672 Service: debug.Handler, 673 }, { 674 Namespace: "debug", 675 Version: "1.0", 676 Service: NewPublicDebugAPI(n), 677 Public: true, 678 }, { 679 Namespace: "web3", 680 Version: "1.0", 681 Service: NewPublicWeb3API(n), 682 Public: true, 683 }, 684 } 685 }