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