github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/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 "crypto/ecdsa" 21 "errors" 22 "fmt" 23 "net" 24 "os" 25 "path/filepath" 26 "reflect" 27 "strings" 28 "sync" 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/prometheus/prometheus/util/flock" 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 flock.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 // Register injects a new service into the node's stack. The service created by 126 // the passed constructor must be unique in its type with regard to sibling ones. 127 func (n *Node) Register(constructor ServiceConstructor) error { 128 n.lock.Lock() 129 defer n.lock.Unlock() 130 131 if n.server != nil { 132 return ErrNodeRunning 133 } 134 n.serviceFuncs = append(n.serviceFuncs, constructor) 135 return nil 136 } 137 138 // Start create a live P2P node and starts running it. 139 func (n *Node) Start() error { 140 n.lock.Lock() 141 defer n.lock.Unlock() 142 143 // Short circuit if the node's already running 144 if n.server != nil { 145 return ErrNodeRunning 146 } 147 if err := n.openDataDir(); err != nil { 148 return err 149 } 150 151 // Initialize the p2p server. This creates the node key and 152 // discovery databases. 153 n.serverConfig = n.config.P2P 154 n.serverConfig.PrivateKey = n.config.NodeKey() 155 n.serverConfig.Name = n.config.NodeName() 156 n.serverConfig.Logger = n.log 157 if n.serverConfig.StaticNodes == nil { 158 n.serverConfig.StaticNodes = n.config.StaticNodes() 159 } 160 if n.serverConfig.TrustedNodes == nil { 161 n.serverConfig.TrustedNodes = n.config.TrustedNodes() 162 } 163 if n.serverConfig.NodeDatabase == "" { 164 n.serverConfig.NodeDatabase = n.config.NodeDB() 165 } 166 n.serverConfig.EnableNodePermission = n.config.EnableNodePermission 167 n.serverConfig.DataDir = n.config.DataDir 168 running := &p2p.Server{Config: n.serverConfig} 169 n.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 return convertFileLockError(err) 201 } 202 // Start each of the services 203 started := []reflect.Type{} 204 for kind, service := range services { 205 // Start the next service, stopping all previous upon failure 206 if err := service.Start(running); err != nil { 207 for _, kind := range started { 208 services[kind].Stop() 209 } 210 running.Stop() 211 212 return err 213 } 214 // Mark the service started for potential cleanup 215 started = append(started, kind) 216 } 217 // Lastly start the configured RPC interfaces 218 if err := n.startRPC(services); err != nil { 219 for _, service := range services { 220 service.Stop() 221 } 222 running.Stop() 223 return err 224 } 225 // Finish initializing the startup 226 n.services = services 227 n.server = running 228 n.stop = make(chan struct{}) 229 230 return nil 231 } 232 233 func (n *Node) openDataDir() error { 234 if n.config.DataDir == "" { 235 return nil // ephemeral 236 } 237 238 instdir := filepath.Join(n.config.DataDir, n.config.name()) 239 if err := os.MkdirAll(instdir, 0700); err != nil { 240 return err 241 } 242 // Lock the instance directory to prevent concurrent use by another instance as well as 243 // accidental use of the instance directory as a database. 244 release, _, err := flock.New(filepath.Join(instdir, "LOCK")) 245 if err != nil { 246 return convertFileLockError(err) 247 } 248 n.instanceDirLock = release 249 return nil 250 } 251 252 // startRPC is a helper method to start all the various RPC endpoint during node 253 // startup. It's not meant to be called at any time afterwards as it makes certain 254 // assumptions about the state of the node. 255 func (n *Node) startRPC(services map[reflect.Type]Service) error { 256 // Gather all the possible APIs to surface 257 apis := n.apis() 258 for _, service := range services { 259 apis = append(apis, service.APIs()...) 260 } 261 // Start the various API endpoints, terminating all in case of errors 262 if err := n.startInProc(apis); err != nil { 263 return err 264 } 265 if err := n.startIPC(apis); err != nil { 266 n.stopInProc() 267 return err 268 } 269 if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil { 270 n.stopIPC() 271 n.stopInProc() 272 return err 273 } 274 if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil { 275 n.stopHTTP() 276 n.stopIPC() 277 n.stopInProc() 278 return err 279 } 280 // All API endpoints started successfully 281 n.rpcAPIs = apis 282 return nil 283 } 284 285 // startInProc initializes an in-process RPC endpoint. 286 func (n *Node) startInProc(apis []rpc.API) error { 287 // Register all the APIs exposed by the services 288 handler := rpc.NewServer() 289 for _, api := range apis { 290 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 291 return err 292 } 293 n.log.Debug("InProc registered", "service", api.Service, "namespace", api.Namespace) 294 } 295 n.inprocHandler = handler 296 return n.eventmux.Post(rpc.InProcServerReadyEvent{}) 297 } 298 299 // stopInProc terminates the in-process RPC endpoint. 300 func (n *Node) stopInProc() { 301 if n.inprocHandler != nil { 302 n.inprocHandler.Stop() 303 n.inprocHandler = nil 304 } 305 } 306 307 // startIPC initializes and starts the IPC RPC endpoint. 308 func (n *Node) startIPC(apis []rpc.API) error { 309 if n.ipcEndpoint == "" { 310 return nil // IPC disabled. 311 } 312 listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis) 313 if err != nil { 314 return err 315 } 316 n.ipcListener = listener 317 n.ipcHandler = handler 318 n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint) 319 return nil 320 } 321 322 // stopIPC terminates the IPC RPC endpoint. 323 func (n *Node) stopIPC() { 324 if n.ipcListener != nil { 325 n.ipcListener.Close() 326 n.ipcListener = nil 327 328 n.log.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint) 329 } 330 if n.ipcHandler != nil { 331 n.ipcHandler.Stop() 332 n.ipcHandler = nil 333 } 334 } 335 336 // startHTTP initializes and starts the HTTP RPC endpoint. 337 func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error { 338 // Short circuit if the HTTP endpoint isn't being exposed 339 if endpoint == "" { 340 return nil 341 } 342 listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts) 343 if err != nil { 344 return err 345 } 346 n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ",")) 347 // All listeners booted successfully 348 n.httpEndpoint = endpoint 349 n.httpListener = listener 350 n.httpHandler = handler 351 352 return nil 353 } 354 355 // stopHTTP terminates the HTTP RPC endpoint. 356 func (n *Node) stopHTTP() { 357 if n.httpListener != nil { 358 n.httpListener.Close() 359 n.httpListener = nil 360 361 n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint)) 362 } 363 if n.httpHandler != nil { 364 n.httpHandler.Stop() 365 n.httpHandler = nil 366 } 367 } 368 369 // startWS initializes and starts the websocket RPC endpoint. 370 func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error { 371 // Short circuit if the WS endpoint isn't being exposed 372 if endpoint == "" { 373 return nil 374 } 375 listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll) 376 if err != nil { 377 return err 378 } 379 n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr())) 380 // All listeners booted successfully 381 n.wsEndpoint = endpoint 382 n.wsListener = listener 383 n.wsHandler = handler 384 385 return nil 386 } 387 388 // stopWS terminates the websocket RPC endpoint. 389 func (n *Node) stopWS() { 390 if n.wsListener != nil { 391 n.wsListener.Close() 392 n.wsListener = nil 393 394 n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint)) 395 } 396 if n.wsHandler != nil { 397 n.wsHandler.Stop() 398 n.wsHandler = nil 399 } 400 } 401 402 // Stop terminates a running node along with all it's services. In the node was 403 // not started, an error is returned. 404 func (n *Node) Stop() error { 405 n.lock.Lock() 406 defer n.lock.Unlock() 407 408 // Short circuit if the node's not running 409 if n.server == nil { 410 return ErrNodeStopped 411 } 412 413 // Terminate the API, services and the p2p server. 414 n.stopWS() 415 n.stopHTTP() 416 n.stopIPC() 417 n.rpcAPIs = nil 418 failure := &StopError{ 419 Services: make(map[reflect.Type]error), 420 } 421 for kind, service := range n.services { 422 if err := service.Stop(); err != nil { 423 failure.Services[kind] = err 424 } 425 } 426 n.server.Stop() 427 n.services = nil 428 n.server = nil 429 430 // Release instance directory lock. 431 if n.instanceDirLock != nil { 432 if err := n.instanceDirLock.Release(); err != nil { 433 n.log.Error("Can't release datadir lock", "err", err) 434 } 435 n.instanceDirLock = nil 436 } 437 438 // unblock n.Wait 439 close(n.stop) 440 441 // Remove the keystore if it was created ephemerally. 442 var keystoreErr error 443 if n.ephemeralKeystore != "" { 444 keystoreErr = os.RemoveAll(n.ephemeralKeystore) 445 } 446 447 if len(failure.Services) > 0 { 448 return failure 449 } 450 if keystoreErr != nil { 451 return keystoreErr 452 } 453 return nil 454 } 455 456 // Wait blocks the thread until the node is stopped. If the node is not running 457 // at the time of invocation, the method immediately returns. 458 func (n *Node) Wait() { 459 n.lock.RLock() 460 if n.server == nil { 461 n.lock.RUnlock() 462 return 463 } 464 stop := n.stop 465 n.lock.RUnlock() 466 467 <-stop 468 } 469 470 // Restart terminates a running node and boots up a new one in its place. If the 471 // node isn't running, an error is returned. 472 func (n *Node) Restart() error { 473 if err := n.Stop(); err != nil { 474 return err 475 } 476 if err := n.Start(); err != nil { 477 return err 478 } 479 return nil 480 } 481 482 // Attach creates an RPC client attached to an in-process API handler. 483 func (n *Node) Attach() (*rpc.Client, error) { 484 n.lock.RLock() 485 defer n.lock.RUnlock() 486 487 if n.server == nil { 488 return nil, ErrNodeStopped 489 } 490 return rpc.DialInProc(n.inprocHandler), nil 491 } 492 493 // RPCHandler returns the in-process RPC request handler. 494 func (n *Node) RPCHandler() (*rpc.Server, error) { 495 n.lock.RLock() 496 defer n.lock.RUnlock() 497 498 if n.inprocHandler == nil { 499 return nil, ErrNodeStopped 500 } 501 return n.inprocHandler, nil 502 } 503 504 // Server retrieves the currently running P2P network layer. This method is meant 505 // only to inspect fields of the currently running server, life cycle management 506 // should be left to this Node entity. 507 func (n *Node) Server() *p2p.Server { 508 n.lock.RLock() 509 defer n.lock.RUnlock() 510 511 return n.server 512 } 513 514 // Service retrieves a currently running service registered of a specific type. 515 func (n *Node) Service(service interface{}) error { 516 n.lock.RLock() 517 defer n.lock.RUnlock() 518 519 // Short circuit if the node's not running 520 if n.server == nil { 521 return ErrNodeStopped 522 } 523 // Otherwise try to find the service to return 524 element := reflect.ValueOf(service).Elem() 525 if running, ok := n.services[element.Type()]; ok { 526 element.Set(reflect.ValueOf(running)) 527 return nil 528 } 529 return ErrServiceUnknown 530 } 531 532 // Quorum 533 // 534 // delegate call to node.Config 535 func (n *Node) IsPermissionEnabled() bool { 536 return n.config.IsPermissionEnabled() 537 } 538 539 // Quorum 540 // 541 // delegate call to node.Config 542 func (n *Node) GetNodeKey() *ecdsa.PrivateKey { 543 return n.config.NodeKey() 544 } 545 546 // DataDir retrieves the current datadir used by the protocol stack. 547 // Deprecated: No files should be stored in this directory, use InstanceDir instead. 548 func (n *Node) DataDir() string { 549 return n.config.DataDir 550 } 551 552 // InstanceDir retrieves the instance directory used by the protocol stack. 553 func (n *Node) InstanceDir() string { 554 return n.config.instanceDir() 555 } 556 557 // AccountManager retrieves the account manager used by the protocol stack. 558 func (n *Node) AccountManager() *accounts.Manager { 559 return n.accman 560 } 561 562 // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. 563 func (n *Node) IPCEndpoint() string { 564 return n.ipcEndpoint 565 } 566 567 // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. 568 func (n *Node) HTTPEndpoint() string { 569 n.lock.Lock() 570 defer n.lock.Unlock() 571 572 if n.httpListener != nil { 573 return n.httpListener.Addr().String() 574 } 575 return n.httpEndpoint 576 } 577 578 // WSEndpoint retrieves the current WS endpoint used by the protocol stack. 579 func (n *Node) WSEndpoint() string { 580 n.lock.Lock() 581 defer n.lock.Unlock() 582 583 if n.wsListener != nil { 584 return n.wsListener.Addr().String() 585 } 586 return n.wsEndpoint 587 } 588 589 // EventMux retrieves the event multiplexer used by all the network services in 590 // the current protocol stack. 591 func (n *Node) EventMux() *event.TypeMux { 592 return n.eventmux 593 } 594 595 // OpenDatabase opens an existing database with the given name (or creates one if no 596 // previous can be found) from within the node's instance directory. If the node is 597 // ephemeral, a memory database is returned. 598 func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { 599 if n.config.DataDir == "" { 600 return ethdb.NewMemDatabase(), nil 601 } 602 return ethdb.NewLDBDatabase(n.config.ResolvePath(name), cache, handles) 603 } 604 605 // ResolvePath returns the absolute path of a resource in the instance directory. 606 func (n *Node) ResolvePath(x string) string { 607 return n.config.ResolvePath(x) 608 } 609 610 // apis returns the collection of RPC descriptors this node offers. 611 func (n *Node) apis() []rpc.API { 612 return []rpc.API{ 613 { 614 Namespace: "admin", 615 Version: "1.0", 616 Service: NewPrivateAdminAPI(n), 617 }, { 618 Namespace: "admin", 619 Version: "1.0", 620 Service: NewPublicAdminAPI(n), 621 Public: true, 622 }, { 623 Namespace: "debug", 624 Version: "1.0", 625 Service: debug.Handler, 626 }, { 627 Namespace: "debug", 628 Version: "1.0", 629 Service: NewPublicDebugAPI(n), 630 Public: true, 631 }, { 632 Namespace: "web3", 633 Version: "1.0", 634 Service: NewPublicWeb3API(n), 635 Public: true, 636 }, 637 } 638 }