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