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