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