gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/node/node.go (about) 1 // Copyright 2018 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain 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 aquachain 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 aquachain 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 "gitlab.com/aquachain/aquachain/aqua/accounts" 30 "gitlab.com/aquachain/aquachain/aqua/event" 31 "gitlab.com/aquachain/aquachain/aquadb" 32 "gitlab.com/aquachain/aquachain/common/log" 33 "gitlab.com/aquachain/aquachain/internal/debug" 34 "gitlab.com/aquachain/aquachain/internal/flock" 35 "gitlab.com/aquachain/aquachain/p2p" 36 "gitlab.com/aquachain/aquachain/rpc" 37 rpcclient "gitlab.com/aquachain/aquachain/rpc/rpcclient" 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/aquachain. 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 if n.config.P2P.ChainId == 0 { 144 return fmt.Errorf("no chain id") 145 } 146 // Short circuit if the node's already running 147 if n.server != nil { 148 return ErrNodeRunning 149 } 150 if err := n.openDataDir(); err != nil { 151 return err 152 } 153 154 // Initialize the p2p server. This creates the node key and 155 // discovery databases. 156 n.serverConfig = n.config.P2P 157 n.serverConfig.PrivateKey = n.config.NodeKey() 158 n.serverConfig.Name = n.config.NodeName() 159 n.serverConfig.Logger = n.log 160 if n.serverConfig.StaticNodes == nil { 161 n.serverConfig.StaticNodes = n.config.StaticNodes() 162 } 163 if n.serverConfig.TrustedNodes == nil { 164 n.serverConfig.TrustedNodes = n.config.TrustedNodes() 165 } 166 if n.serverConfig.NodeDatabase == "" { 167 n.serverConfig.NodeDatabase = n.config.NodeDB() 168 } 169 running := &p2p.Server{Config: n.serverConfig} 170 n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name, "listening", n.serverConfig.ListenAddr) 171 172 // Otherwise copy and specialize the P2P configuration 173 services := make(map[reflect.Type]Service) 174 for _, constructor := range n.serviceFuncs { 175 // Create a new context for the particular service 176 ctx := &ServiceContext{ 177 config: n.config, 178 services: make(map[reflect.Type]Service), 179 EventMux: n.eventmux, 180 AccountManager: n.accman, 181 } 182 for kind, s := range services { // copy needed for threaded access 183 ctx.services[kind] = s 184 } 185 // Construct and save the service 186 service, err := constructor(ctx) 187 if err != nil { 188 return err 189 } 190 kind := reflect.TypeOf(service) 191 if _, exists := services[kind]; exists { 192 return &DuplicateServiceError{Kind: kind} 193 } 194 services[kind] = service 195 } 196 // Gather the protocols and start the freshly assembled P2P server 197 for _, service := range services { 198 running.Protocols = append(running.Protocols, service.Protocols()...) 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 service == nil { 208 log.Warn("skipping service:", "kind", kind) 209 continue 210 } 211 if err := service.Start(running); err != nil { 212 for _, kind := range started { 213 services[kind].Stop() 214 } 215 running.Stop() 216 217 return err 218 } 219 // Mark the service started for potential cleanup 220 started = append(started, kind) 221 } 222 // Lastly start the configured RPC interfaces 223 if err := n.startRPC(services); err != nil { 224 for _, service := range services { 225 service.Stop() 226 } 227 running.Stop() 228 return err 229 } 230 // Finish initializing the startup 231 n.services = services 232 n.server = running 233 n.stop = make(chan struct{}) 234 235 return nil 236 } 237 238 func (n *Node) openDataDir() error { 239 if n.config.DataDir == "" { 240 return nil // ephemeral 241 } 242 243 instdir := filepath.Join(n.config.DataDir, n.config.name()) 244 if err := os.MkdirAll(instdir, 0700); err != nil { 245 return err 246 } 247 // Lock the instance directory to prevent concurrent use by another instance as well as 248 // accidental use of the instance directory as a database. 249 release, _, err := flock.New(filepath.Join(instdir, "LOCK")) 250 if err != nil { 251 return convertFileLockError(err) 252 } 253 n.instanceDirLock = release 254 return nil 255 } 256 257 // startRPC is a helper method to start all the various RPC endpoint during node 258 // startup. It's not meant to be called at any time afterwards as it makes certain 259 // assumptions about the state of the node. 260 func (n *Node) startRPC(services map[reflect.Type]Service) error { 261 // Gather all the possible APIs to surface 262 apis := n.apis() 263 for _, service := range services { 264 apis = append(apis, service.APIs()...) 265 } 266 // Start the various API endpoints, terminating all in case of errors 267 if err := n.startInProc(apis); err != nil { 268 return err 269 } 270 if err := n.startIPC(apis); err != nil { 271 n.stopInProc() 272 return err 273 } 274 if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.RPCAllowIP, n.config.RPCBehindProxy); err != nil { 275 n.stopIPC() 276 n.stopInProc() 277 return err 278 } 279 if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll, n.config.RPCAllowIP, n.config.RPCBehindProxy); err != nil { 280 n.stopHTTP() 281 n.stopIPC() 282 n.stopInProc() 283 return err 284 } 285 // All API endpoints started successfully 286 n.rpcAPIs = apis 287 return nil 288 } 289 290 // startInProc initializes an in-process RPC endpoint. 291 func (n *Node) startInProc(apis []rpc.API) error { 292 // Register all the APIs exposed by the services 293 handler := rpc.NewServer() 294 for _, api := range apis { 295 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 296 return err 297 } 298 n.log.Debug("InProc registered", "service", fmt.Sprintf("%T ( %s_ )", api.Service, api.Namespace)) 299 } 300 n.inprocHandler = handler 301 return nil 302 } 303 304 // stopInProc terminates the in-process RPC endpoint. 305 func (n *Node) stopInProc() { 306 if n.inprocHandler != nil { 307 n.inprocHandler.Stop() 308 n.inprocHandler = nil 309 } 310 } 311 312 // startIPC initializes and starts the IPC RPC endpoint. 313 func (n *Node) startIPC(apis []rpc.API) error { 314 // Short circuit if the IPC endpoint isn't being exposed 315 if n.ipcEndpoint == "" { 316 return nil 317 } 318 // Register all the APIs exposed by the services 319 handler := rpc.NewServer() 320 for _, api := range apis { 321 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 322 return err 323 } 324 n.log.Debug("IPC registered", "service", fmt.Sprintf("%T ( %s_ )", api.Service, api.Namespace)) 325 } 326 // All APIs registered, start the IPC listener 327 var ( 328 listener net.Listener 329 err error 330 ) 331 if listener, err = rpc.CreateIPCListener(n.ipcEndpoint); err != nil { 332 return err 333 } 334 go func() { 335 n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint) 336 337 for { 338 conn, err := listener.Accept() 339 if err != nil { 340 // Terminate if the listener was closed 341 n.lock.RLock() 342 closed := n.ipcListener == nil 343 n.lock.RUnlock() 344 if closed { 345 return 346 } 347 // Not closed, just some error; report and continue 348 n.log.Error("IPC accept failed", "err", err) 349 continue 350 } 351 go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) 352 } 353 }() 354 // All listeners booted successfully 355 n.ipcListener = listener 356 n.ipcHandler = handler 357 358 return nil 359 } 360 361 // stopIPC terminates the IPC RPC endpoint. 362 func (n *Node) stopIPC() { 363 if n.ipcListener != nil { 364 n.ipcListener.Close() 365 n.ipcListener = nil 366 367 n.log.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint) 368 } 369 if n.ipcHandler != nil { 370 n.ipcHandler.Stop() 371 n.ipcHandler = nil 372 } 373 } 374 375 // startHTTP initializes and starts the HTTP RPC endpoint. 376 func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, allowip []string, behindreverseproxy bool) error { 377 // Short circuit if the HTTP endpoint isn't being exposed 378 if endpoint == "" { 379 return nil 380 } 381 // Generate the whitelist based on the allowed modules 382 whitelist := make(map[string]bool) 383 for _, module := range modules { 384 whitelist[module] = true 385 } 386 // Register all the APIs exposed by the services 387 handler := rpc.NewServer() 388 for _, api := range apis { 389 if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { 390 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 391 return err 392 } 393 n.log.Debug("HTTP registered", "service", fmt.Sprintf("%T ( %s_ )", api.Service, api.Namespace)) 394 } 395 } 396 // All APIs registered, start the HTTP listener 397 var ( 398 listener net.Listener 399 err error 400 ) 401 if listener, err = net.Listen("tcp", endpoint); err != nil { 402 return err 403 } 404 if len(allowip) == 0 || allowip[0] == "none" { 405 n.log.Warn("The '-allowip' flag has not been set. Please consider using it to restrict RPC access. HTTP server disabled. To allow any IP, use -allowip='*'") 406 } else { 407 go rpc.NewHTTPServer(cors, vhosts, allowip, behindreverseproxy, handler).Serve(listener) 408 n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ","), "allowip", strings.Join(allowip, ",")) 409 } 410 // All listeners booted successfully 411 n.httpEndpoint = endpoint 412 n.httpListener = listener 413 n.httpHandler = handler 414 415 return nil 416 } 417 418 // stopHTTP terminates the HTTP RPC endpoint. 419 func (n *Node) stopHTTP() { 420 if n.httpListener != nil { 421 n.httpListener.Close() 422 n.httpListener = nil 423 424 n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint)) 425 } 426 if n.httpHandler != nil { 427 n.httpHandler.Stop() 428 n.httpHandler = nil 429 } 430 } 431 432 // startWS initializes and starts the websocket RPC endpoint. 433 func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool, allowedip []string, behindproxy bool) error { 434 // Short circuit if the WS endpoint isn't being exposed 435 if endpoint == "" { 436 return nil 437 } 438 // Generate the whitelist based on the allowed modules 439 whitelist := make(map[string]bool) 440 for _, module := range modules { 441 whitelist[module] = true 442 } 443 // Register all the APIs exposed by the services 444 handler := rpc.NewServer() 445 for _, api := range apis { 446 if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { 447 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 448 return err 449 } 450 n.log.Debug("WebSocket registered", "service", fmt.Sprintf("%T ( %s_ )", api.Service, api.Namespace)) 451 } 452 } 453 // All APIs registered, start the HTTP listener 454 var ( 455 listener net.Listener 456 err error 457 ) 458 if listener, err = net.Listen("tcp", endpoint); err != nil { 459 return err 460 } 461 go rpc.NewWSServer(wsOrigins, allowedip, behindproxy, handler).Serve(listener) 462 n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr())) 463 464 // All listeners booted successfully 465 n.wsEndpoint = endpoint 466 n.wsListener = listener 467 n.wsHandler = handler 468 469 return nil 470 } 471 472 // stopWS terminates the websocket RPC endpoint. 473 func (n *Node) stopWS() { 474 if n.wsListener != nil { 475 n.wsListener.Close() 476 n.wsListener = nil 477 478 n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint)) 479 } 480 if n.wsHandler != nil { 481 n.wsHandler.Stop() 482 n.wsHandler = nil 483 } 484 } 485 486 // Stop terminates a running node along with all it's services. In the node was 487 // not started, an error is returned. 488 func (n *Node) Stop() error { 489 n.lock.Lock() 490 defer n.lock.Unlock() 491 492 // Short circuit if the node's not running 493 if n.server == nil { 494 return ErrNodeStopped 495 } 496 497 // Terminate the API, services and the p2p server. 498 n.stopWS() 499 n.stopHTTP() 500 n.stopIPC() 501 n.rpcAPIs = nil 502 failure := &StopError{ 503 Services: make(map[reflect.Type]error), 504 } 505 for kind, service := range n.services { 506 if err := service.Stop(); err != nil { 507 failure.Services[kind] = err 508 } 509 } 510 n.server.Stop() 511 n.services = nil 512 n.server = nil 513 514 // Release instance directory lock. 515 if n.instanceDirLock != nil { 516 if err := n.instanceDirLock.Release(); err != nil { 517 n.log.Error("Can't release datadir lock", "err", err) 518 } 519 n.instanceDirLock = nil 520 } 521 522 // unblock n.Wait 523 close(n.stop) 524 525 // Remove the keystore if it was created ephemerally. 526 var keystoreErr error 527 if n.ephemeralKeystore != "" { 528 keystoreErr = os.RemoveAll(n.ephemeralKeystore) 529 } 530 531 if len(failure.Services) > 0 { 532 return failure 533 } 534 if keystoreErr != nil { 535 return keystoreErr 536 } 537 return nil 538 } 539 540 // Wait blocks the thread until the node is stopped. If the node is not running 541 // at the time of invocation, the method immediately returns. 542 func (n *Node) Wait() { 543 n.lock.RLock() 544 if n.server == nil { 545 n.lock.RUnlock() 546 return 547 } 548 stop := n.stop 549 n.lock.RUnlock() 550 551 <-stop 552 } 553 554 // Restart terminates a running node and boots up a new one in its place. If the 555 // node isn't running, an error is returned. 556 func (n *Node) Restart() error { 557 n.log.Info("Restarting P2P node") 558 if err := n.Stop(); err != nil { 559 return err 560 } 561 if err := n.Start(); err != nil { 562 return err 563 } 564 return nil 565 } 566 567 // Attach creates an RPC client attached to an in-process API handler. 568 func (n *Node) Attach() (*rpcclient.Client, error) { 569 n.log.Trace("Attaching new client") 570 n.lock.RLock() 571 defer n.lock.RUnlock() 572 573 if n.server == nil { 574 return nil, ErrNodeStopped 575 } 576 return rpcclient.DialInProc(n.inprocHandler), nil 577 } 578 579 // RPCHandler returns the in-process RPC request handler. 580 func (n *Node) RPCHandler() (*rpc.Server, error) { 581 n.lock.RLock() 582 defer n.lock.RUnlock() 583 584 if n.inprocHandler == nil { 585 return nil, ErrNodeStopped 586 } 587 return n.inprocHandler, nil 588 } 589 590 // Server retrieves the currently running P2P network layer. This method is meant 591 // only to inspect fields of the currently running server, life cycle management 592 // should be left to this Node entity. 593 func (n *Node) Server() *p2p.Server { 594 n.lock.RLock() 595 defer n.lock.RUnlock() 596 597 return n.server 598 } 599 600 // Service retrieves a currently running service registered of a specific type. 601 func (n *Node) Service(service interface{}) error { 602 n.lock.RLock() 603 defer n.lock.RUnlock() 604 605 // Short circuit if the node's not running 606 if n.server == nil { 607 return ErrNodeStopped 608 } 609 // Otherwise try to find the service to return 610 element := reflect.ValueOf(service).Elem() 611 if running, ok := n.services[element.Type()]; ok { 612 element.Set(reflect.ValueOf(running)) 613 return nil 614 } 615 return ErrServiceUnknown 616 } 617 618 // DataDir retrieves the current datadir used by the protocol stack. 619 // Deprecated: No files should be stored in this directory, use InstanceDir instead. 620 func (n *Node) DataDir() string { 621 return n.config.DataDir 622 } 623 624 func (n *Node) Config() Config { 625 return *n.config 626 } 627 628 // InstanceDir retrieves the instance directory used by the protocol stack. 629 func (n *Node) InstanceDir() string { 630 return n.config.instanceDir() 631 } 632 633 // AccountManager retrieves the account manager used by the protocol stack. 634 func (n *Node) AccountManager() *accounts.Manager { 635 return n.accman 636 } 637 638 // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. 639 func (n *Node) IPCEndpoint() string { 640 return n.ipcEndpoint 641 } 642 643 // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. 644 func (n *Node) HTTPEndpoint() string { 645 return n.httpEndpoint 646 } 647 648 // WSEndpoint retrieves the current WS endpoint used by the protocol stack. 649 func (n *Node) WSEndpoint() string { 650 return n.wsEndpoint 651 } 652 653 // EventMux retrieves the event multiplexer used by all the network services in 654 // the current protocol stack. 655 func (n *Node) EventMux() *event.TypeMux { 656 return n.eventmux 657 } 658 659 // OpenDatabase opens an existing database with the given name (or creates one if no 660 // previous can be found) from within the node's instance directory. If the node is 661 // ephemeral, a memory database is returned. 662 func (n *Node) OpenDatabase(name string, cache, handles int) (aquadb.Database, error) { 663 if n.config.DataDir == "" { 664 return aquadb.NewMemDatabase(), nil 665 } 666 return aquadb.NewLDBDatabase(n.config.resolvePath(name), cache, handles) 667 } 668 669 // ResolvePath returns the absolute path of a resource in the instance directory. 670 func (n *Node) ResolvePath(x string) string { 671 return n.config.resolvePath(x) 672 } 673 674 // apis returns the collection of RPC descriptors this node offers. 675 func (n *Node) apis() []rpc.API { 676 return []rpc.API{ 677 { 678 Namespace: "admin", 679 Version: "1.0", 680 Service: NewPrivateAdminAPI(n), 681 }, { 682 Namespace: "admin", 683 Version: "1.0", 684 Service: NewPublicAdminAPI(n), 685 Public: true, 686 }, { 687 Namespace: "debug", 688 Version: "1.0", 689 Service: debug.Handler, 690 }, { 691 Namespace: "debug", 692 Version: "1.0", 693 Service: NewPublicDebugAPI(n), 694 Public: true, 695 }, { 696 Namespace: "web3", 697 Version: "1.0", 698 Service: NewPublicWeb3API(n), 699 Public: true, 700 }, 701 } 702 }