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