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