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