| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"syscall" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts" | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							| 
									
										
										
										
											2016-01-26 14:39:21 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/internal/debug" | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/logger/glog" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	"github.com/syndtr/goleveldb/leveldb/storage" | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	ErrDatadirUsed    = errors.New("datadir already used") | 
					
						
							|  |  |  | 	ErrNodeStopped    = errors.New("node not started") | 
					
						
							|  |  |  | 	ErrNodeRunning    = errors.New("node already running") | 
					
						
							|  |  |  | 	ErrServiceUnknown = errors.New("unknown service") | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | // Node is a container on which services can be registered. | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | type Node struct { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	eventmux *event.TypeMux // Event multiplexer used between the services of a stack | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	config   *Config | 
					
						
							|  |  |  | 	accman   *accounts.Manager | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	ephemeralKeystore string          // if non-empty, the key directory that will be removed by Stop | 
					
						
							|  |  |  | 	instanceDirLock   storage.Storage // prevents concurrent use of instance directory | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-18 11:31:00 +02:00
										 |  |  | 	serverConfig p2p.Config | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	server       *p2p.Server // Currently running P2P networking layer | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	serviceFuncs []ServiceConstructor     // Service constructors (in dependency order) | 
					
						
							|  |  |  | 	services     map[reflect.Type]Service // Currently running services | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 	rpcAPIs       []rpc.API   // List of APIs currently provided by the node | 
					
						
							|  |  |  | 	inprocHandler *rpc.Server // In-process RPC request handler to process the API requests | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	ipcEndpoint string       // IPC endpoint to listen at (empty = IPC disabled) | 
					
						
							|  |  |  | 	ipcListener net.Listener // IPC RPC listener socket to serve API requests | 
					
						
							|  |  |  | 	ipcHandler  *rpc.Server  // IPC RPC request handler to process the API requests | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	httpEndpoint  string       // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled) | 
					
						
							|  |  |  | 	httpWhitelist []string     // HTTP RPC modules to allow through this endpoint | 
					
						
							|  |  |  | 	httpListener  net.Listener // HTTP RPC listener socket to server API requests | 
					
						
							|  |  |  | 	httpHandler   *rpc.Server  // HTTP RPC request handler to process the API requests | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	wsEndpoint string       // Websocket endpoint (interface + port) to listen at (empty = websocket disabled) | 
					
						
							|  |  |  | 	wsListener net.Listener // Websocket RPC listener socket to server API requests | 
					
						
							|  |  |  | 	wsHandler  *rpc.Server  // Websocket RPC request handler to process the API requests | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	stop chan struct{} // Channel to wait for termination notifications | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	lock sync.RWMutex | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New creates a new P2P node, ready for protocol registration. | 
					
						
							|  |  |  | func New(conf *Config) (*Node, error) { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// Copy config and resolve the datadir so future changes to the current | 
					
						
							|  |  |  | 	// working directory don't affect the node. | 
					
						
							|  |  |  | 	confCopy := *conf | 
					
						
							|  |  |  | 	conf = &confCopy | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if conf.DataDir != "" { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 		absdatadir, err := filepath.Abs(conf.DataDir) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 		conf.DataDir = absdatadir | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that the instance name doesn't cause weird conflicts with | 
					
						
							|  |  |  | 	// other files in the data directory. | 
					
						
							|  |  |  | 	if strings.ContainsAny(conf.Name, `/\`) { | 
					
						
							|  |  |  | 		return nil, errors.New(`Config.Name must not contain '/' or '\'`) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if conf.Name == datadirDefaultKeyStore { | 
					
						
							|  |  |  | 		return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	if strings.HasSuffix(conf.Name, ".ipc") { | 
					
						
							|  |  |  | 		return nil, errors.New(`Config.Name cannot end in ".ipc"`) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Ensure that the AccountManager method works before the node has started. | 
					
						
							|  |  |  | 	// We rely on this in cmd/geth. | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	am, ephemeralKeystore, err := makeAccountManager(conf) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	// Note: any interaction with Config that would create/touch files | 
					
						
							|  |  |  | 	// in the data directory or instance directory is delayed until Start. | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	return &Node{ | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 		accman:            am, | 
					
						
							|  |  |  | 		ephemeralKeystore: ephemeralKeystore, | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 		config:            conf, | 
					
						
							|  |  |  | 		serviceFuncs:      []ServiceConstructor{}, | 
					
						
							|  |  |  | 		ipcEndpoint:       conf.IPCEndpoint(), | 
					
						
							|  |  |  | 		httpEndpoint:      conf.HTTPEndpoint(), | 
					
						
							|  |  |  | 		wsEndpoint:        conf.WSEndpoint(), | 
					
						
							|  |  |  | 		eventmux:          new(event.TypeMux), | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | // Register injects a new service into the node's stack. The service created by | 
					
						
							|  |  |  | // the passed constructor must be unique in its type with regard to sibling ones. | 
					
						
							|  |  |  | func (n *Node) Register(constructor ServiceConstructor) error { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	n.lock.Lock() | 
					
						
							|  |  |  | 	defer n.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	if n.server != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		return ErrNodeRunning | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	n.serviceFuncs = append(n.serviceFuncs, constructor) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Start create a live P2P node and starts running it. | 
					
						
							|  |  |  | func (n *Node) Start() error { | 
					
						
							|  |  |  | 	n.lock.Lock() | 
					
						
							|  |  |  | 	defer n.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Short circuit if the node's already running | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	if n.server != nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		return ErrNodeRunning | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	if err := n.openDataDir(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize the p2p server. This creates the node key and | 
					
						
							|  |  |  | 	// discovery databases. | 
					
						
							|  |  |  | 	n.serverConfig = p2p.Config{ | 
					
						
							| 
									
										
										
										
											2016-11-09 16:35:04 +02:00
										 |  |  | 		PrivateKey:       n.config.NodeKey(), | 
					
						
							|  |  |  | 		Name:             n.config.NodeName(), | 
					
						
							|  |  |  | 		Discovery:        !n.config.NoDiscovery, | 
					
						
							|  |  |  | 		DiscoveryV5:      n.config.DiscoveryV5, | 
					
						
							|  |  |  | 		DiscoveryV5Addr:  n.config.DiscoveryV5Addr, | 
					
						
							|  |  |  | 		BootstrapNodes:   n.config.BootstrapNodes, | 
					
						
							|  |  |  | 		BootstrapNodesV5: n.config.BootstrapNodesV5, | 
					
						
							|  |  |  | 		StaticNodes:      n.config.StaticNodes(), | 
					
						
							|  |  |  | 		TrustedNodes:     n.config.TrusterNodes(), | 
					
						
							|  |  |  | 		NodeDatabase:     n.config.NodeDB(), | 
					
						
							|  |  |  | 		ListenAddr:       n.config.ListenAddr, | 
					
						
							| 
									
										
										
										
											2016-11-22 20:52:31 +01:00
										 |  |  | 		NetRestrict:      n.config.NetRestrict, | 
					
						
							| 
									
										
										
										
											2016-11-09 16:35:04 +02:00
										 |  |  | 		NAT:              n.config.NAT, | 
					
						
							|  |  |  | 		Dialer:           n.config.Dialer, | 
					
						
							|  |  |  | 		NoDial:           n.config.NoDial, | 
					
						
							|  |  |  | 		MaxPeers:         n.config.MaxPeers, | 
					
						
							|  |  |  | 		MaxPendingPeers:  n.config.MaxPendingPeers, | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-18 11:31:00 +02:00
										 |  |  | 	running := &p2p.Server{Config: n.serverConfig} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	glog.V(logger.Info).Infoln("instance:", n.serverConfig.Name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Otherwise copy and specialize the P2P configuration | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	services := make(map[reflect.Type]Service) | 
					
						
							|  |  |  | 	for _, constructor := range n.serviceFuncs { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 		// Create a new context for the particular service | 
					
						
							|  |  |  | 		ctx := &ServiceContext{ | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 			config:         n.config, | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 			services:       make(map[reflect.Type]Service), | 
					
						
							|  |  |  | 			EventMux:       n.eventmux, | 
					
						
							|  |  |  | 			AccountManager: n.accman, | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		for kind, s := range services { // copy needed for threaded access | 
					
						
							|  |  |  | 			ctx.services[kind] = s | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// Construct and save the service | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		service, err := constructor(ctx) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		kind := reflect.TypeOf(service) | 
					
						
							|  |  |  | 		if _, exists := services[kind]; exists { | 
					
						
							|  |  |  | 			return &DuplicateServiceError{Kind: kind} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		services[kind] = service | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Gather the protocols and start the freshly assembled P2P server | 
					
						
							|  |  |  | 	for _, service := range services { | 
					
						
							|  |  |  | 		running.Protocols = append(running.Protocols, service.Protocols()...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := running.Start(); err != nil { | 
					
						
							|  |  |  | 		if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { | 
					
						
							|  |  |  | 			return ErrDatadirUsed | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start each of the services | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	started := []reflect.Type{} | 
					
						
							|  |  |  | 	for kind, service := range services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		// Start the next service, stopping all previous upon failure | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 		if err := service.Start(running); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 			for _, kind := range started { | 
					
						
							|  |  |  | 				services[kind].Stop() | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 			running.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Mark the service started for potential cleanup | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		started = append(started, kind) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	// Lastly start the configured RPC interfaces | 
					
						
							|  |  |  | 	if err := n.startRPC(services); err != nil { | 
					
						
							|  |  |  | 		for _, service := range services { | 
					
						
							|  |  |  | 			service.Stop() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		running.Stop() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	// Finish initializing the startup | 
					
						
							|  |  |  | 	n.services = services | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	n.server = running | 
					
						
							|  |  |  | 	n.stop = make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | func (n *Node) openDataDir() error { | 
					
						
							|  |  |  | 	if n.config.DataDir == "" { | 
					
						
							|  |  |  | 		return nil // ephemeral | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	instdir := filepath.Join(n.config.DataDir, n.config.name()) | 
					
						
							|  |  |  | 	if err := os.MkdirAll(instdir, 0700); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Try to open the instance directory as LevelDB storage. This creates a lock file | 
					
						
							|  |  |  | 	// which prevents concurrent use by another instance as well as accidental use of the | 
					
						
							|  |  |  | 	// instance directory as a database. | 
					
						
							|  |  |  | 	storage, err := storage.OpenFile(instdir, true) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	n.instanceDirLock = storage | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | // startRPC is a helper method to start all the various RPC endpoint during node | 
					
						
							|  |  |  | // startup. It's not meant to be called at any time afterwards as it makes certain | 
					
						
							|  |  |  | // assumptions about the state of the node. | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | func (n *Node) startRPC(services map[reflect.Type]Service) error { | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// Gather all the possible APIs to surface | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	apis := n.apis() | 
					
						
							|  |  |  | 	for _, service := range services { | 
					
						
							|  |  |  | 		apis = append(apis, service.APIs()...) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// Start the various API endpoints, terminating all in case of errors | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 	if err := n.startInProc(apis); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	if err := n.startIPC(apis); err != nil { | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 		n.stopInProc() | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil { | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		n.stopIPC() | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 		n.stopInProc() | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins); err != nil { | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 		n.stopHTTP() | 
					
						
							|  |  |  | 		n.stopIPC() | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 		n.stopInProc() | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// All API endpoints started successfully | 
					
						
							|  |  |  | 	n.rpcAPIs = apis | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | // startInProc initializes an in-process RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) startInProc(apis []rpc.API) error { | 
					
						
							|  |  |  | 	// Register all the APIs exposed by the services | 
					
						
							|  |  |  | 	handler := rpc.NewServer() | 
					
						
							|  |  |  | 	for _, api := range apis { | 
					
						
							|  |  |  | 		if err := handler.RegisterName(api.Namespace, api.Service); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		glog.V(logger.Debug).Infof("InProc registered %T under '%s'", api.Service, api.Namespace) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	n.inprocHandler = handler | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // stopInProc terminates the in-process RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) stopInProc() { | 
					
						
							|  |  |  | 	if n.inprocHandler != nil { | 
					
						
							|  |  |  | 		n.inprocHandler.Stop() | 
					
						
							|  |  |  | 		n.inprocHandler = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | // startIPC initializes and starts the IPC RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) startIPC(apis []rpc.API) error { | 
					
						
							|  |  |  | 	// Short circuit if the IPC endpoint isn't being exposed | 
					
						
							|  |  |  | 	if n.ipcEndpoint == "" { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register all the APIs exposed by the services | 
					
						
							|  |  |  | 	handler := rpc.NewServer() | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	for _, api := range apis { | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		if err := handler.RegisterName(api.Namespace, api.Service); err != nil { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		glog.V(logger.Debug).Infof("IPC registered %T under '%s'", api.Service, api.Namespace) | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	// All APIs registered, start the IPC listener | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		listener net.Listener | 
					
						
							|  |  |  | 		err      error | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	if listener, err = rpc.CreateIPCListener(n.ipcEndpoint); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		glog.V(logger.Info).Infof("IPC endpoint opened: %s", n.ipcEndpoint) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			conn, err := listener.Accept() | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				// Terminate if the listener was closed | 
					
						
							|  |  |  | 				n.lock.RLock() | 
					
						
							|  |  |  | 				closed := n.ipcListener == nil | 
					
						
							|  |  |  | 				n.lock.RUnlock() | 
					
						
							|  |  |  | 				if closed { | 
					
						
							|  |  |  | 					return | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 				// Not closed, just some error; report and continue | 
					
						
							|  |  |  | 				glog.V(logger.Error).Infof("IPC accept failed: %v", err) | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-04-28 12:00:11 +03:00
										 |  |  | 			go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions) | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	// All listeners booted successfully | 
					
						
							|  |  |  | 	n.ipcListener = listener | 
					
						
							|  |  |  | 	n.ipcHandler = handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // stopIPC terminates the IPC RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) stopIPC() { | 
					
						
							|  |  |  | 	if n.ipcListener != nil { | 
					
						
							|  |  |  | 		n.ipcListener.Close() | 
					
						
							|  |  |  | 		n.ipcListener = nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		glog.V(logger.Info).Infof("IPC endpoint closed: %s", n.ipcEndpoint) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.ipcHandler != nil { | 
					
						
							|  |  |  | 		n.ipcHandler.Stop() | 
					
						
							|  |  |  | 		n.ipcHandler = nil | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // startHTTP initializes and starts the HTTP RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors string) error { | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	// Short circuit if the HTTP endpoint isn't being exposed | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	if endpoint == "" { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Generate the whitelist based on the allowed modules | 
					
						
							|  |  |  | 	whitelist := make(map[string]bool) | 
					
						
							|  |  |  | 	for _, module := range modules { | 
					
						
							|  |  |  | 		whitelist[module] = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register all the APIs exposed by the services | 
					
						
							|  |  |  | 	handler := rpc.NewServer() | 
					
						
							|  |  |  | 	for _, api := range apis { | 
					
						
							|  |  |  | 		if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { | 
					
						
							|  |  |  | 			if err := handler.RegisterName(api.Namespace, api.Service); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			glog.V(logger.Debug).Infof("HTTP registered %T under '%s'", api.Service, api.Namespace) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// All APIs registered, start the HTTP listener | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		listener net.Listener | 
					
						
							|  |  |  | 		err      error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if listener, err = net.Listen("tcp", endpoint); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	go rpc.NewHTTPServer(cors, handler).Serve(listener) | 
					
						
							|  |  |  | 	glog.V(logger.Info).Infof("HTTP endpoint opened: http://%s", endpoint) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	// All listeners booted successfully | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	n.httpEndpoint = endpoint | 
					
						
							|  |  |  | 	n.httpListener = listener | 
					
						
							|  |  |  | 	n.httpHandler = handler | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | // stopHTTP terminates the HTTP RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) stopHTTP() { | 
					
						
							|  |  |  | 	if n.httpListener != nil { | 
					
						
							|  |  |  | 		n.httpListener.Close() | 
					
						
							|  |  |  | 		n.httpListener = nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		glog.V(logger.Info).Infof("HTTP endpoint closed: http://%s", n.httpEndpoint) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.httpHandler != nil { | 
					
						
							|  |  |  | 		n.httpHandler.Stop() | 
					
						
							|  |  |  | 		n.httpHandler = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | // startWS initializes and starts the websocket RPC endpoint. | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins string) error { | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	// Short circuit if the WS endpoint isn't being exposed | 
					
						
							|  |  |  | 	if endpoint == "" { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Generate the whitelist based on the allowed modules | 
					
						
							|  |  |  | 	whitelist := make(map[string]bool) | 
					
						
							|  |  |  | 	for _, module := range modules { | 
					
						
							|  |  |  | 		whitelist[module] = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Register all the APIs exposed by the services | 
					
						
							|  |  |  | 	handler := rpc.NewServer() | 
					
						
							|  |  |  | 	for _, api := range apis { | 
					
						
							|  |  |  | 		if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) { | 
					
						
							|  |  |  | 			if err := handler.RegisterName(api.Namespace, api.Service); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			glog.V(logger.Debug).Infof("WebSocket registered %T under '%s'", api.Service, api.Namespace) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// All APIs registered, start the HTTP listener | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		listener net.Listener | 
					
						
							|  |  |  | 		err      error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if listener, err = net.Listen("tcp", endpoint); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-14 09:38:54 +01:00
										 |  |  | 	go rpc.NewWSServer(wsOrigins, handler).Serve(listener) | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	glog.V(logger.Info).Infof("WebSocket endpoint opened: ws://%s", endpoint) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// All listeners booted successfully | 
					
						
							|  |  |  | 	n.wsEndpoint = endpoint | 
					
						
							|  |  |  | 	n.wsListener = listener | 
					
						
							|  |  |  | 	n.wsHandler = handler | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // stopWS terminates the websocket RPC endpoint. | 
					
						
							|  |  |  | func (n *Node) stopWS() { | 
					
						
							|  |  |  | 	if n.wsListener != nil { | 
					
						
							|  |  |  | 		n.wsListener.Close() | 
					
						
							|  |  |  | 		n.wsListener = nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		glog.V(logger.Info).Infof("WebSocket endpoint closed: ws://%s", n.wsEndpoint) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.wsHandler != nil { | 
					
						
							|  |  |  | 		n.wsHandler.Stop() | 
					
						
							|  |  |  | 		n.wsHandler = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Stop terminates a running node along with all it's services. In the node was | 
					
						
							|  |  |  | // not started, an error is returned. | 
					
						
							|  |  |  | func (n *Node) Stop() error { | 
					
						
							|  |  |  | 	n.lock.Lock() | 
					
						
							|  |  |  | 	defer n.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Short circuit if the node's not running | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	if n.server == nil { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		return ErrNodeStopped | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Terminate the API, services and the p2p server. | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	n.stopWS() | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	n.stopHTTP() | 
					
						
							| 
									
										
										
										
											2016-02-05 15:08:48 +02:00
										 |  |  | 	n.stopIPC() | 
					
						
							| 
									
										
										
										
											2016-02-05 13:45:36 +02:00
										 |  |  | 	n.rpcAPIs = nil | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	failure := &StopError{ | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		Services: make(map[reflect.Type]error), | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	for kind, service := range n.services { | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		if err := service.Stop(); err != nil { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 			failure.Services[kind] = err | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	n.server.Stop() | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	n.services = nil | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	n.server = nil | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Release instance directory lock. | 
					
						
							|  |  |  | 	if n.instanceDirLock != nil { | 
					
						
							|  |  |  | 		n.instanceDirLock.Close() | 
					
						
							|  |  |  | 		n.instanceDirLock = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// unblock n.Wait | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	close(n.stop) | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	// Remove the keystore if it was created ephemerally. | 
					
						
							|  |  |  | 	var keystoreErr error | 
					
						
							|  |  |  | 	if n.ephemeralKeystore != "" { | 
					
						
							|  |  |  | 		keystoreErr = os.RemoveAll(n.ephemeralKeystore) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	if len(failure.Services) > 0 { | 
					
						
							|  |  |  | 		return failure | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | 	if keystoreErr != nil { | 
					
						
							|  |  |  | 		return keystoreErr | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | // Wait blocks the thread until the node is stopped. If the node is not running | 
					
						
							|  |  |  | // at the time of invocation, the method immediately returns. | 
					
						
							|  |  |  | func (n *Node) Wait() { | 
					
						
							|  |  |  | 	n.lock.RLock() | 
					
						
							|  |  |  | 	if n.server == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stop := n.stop | 
					
						
							|  |  |  | 	n.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	<-stop | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Restart terminates a running node and boots up a new one in its place. If the | 
					
						
							|  |  |  | // node isn't running, an error is returned. | 
					
						
							|  |  |  | func (n *Node) Restart() error { | 
					
						
							|  |  |  | 	if err := n.Stop(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := n.Start(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | // Attach creates an RPC client attached to an in-process API handler. | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | func (n *Node) Attach() (*rpc.Client, error) { | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | 	n.lock.RLock() | 
					
						
							|  |  |  | 	defer n.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if n.server == nil { | 
					
						
							|  |  |  | 		return nil, ErrNodeStopped | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-12 17:47:15 +02:00
										 |  |  | 	return rpc.DialInProc(n.inprocHandler), nil | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // Server retrieves the currently running P2P network layer. This method is meant | 
					
						
							|  |  |  | // only to inspect fields of the currently running server, life cycle management | 
					
						
							|  |  |  | // should be left to this Node entity. | 
					
						
							|  |  |  | func (n *Node) Server() *p2p.Server { | 
					
						
							|  |  |  | 	n.lock.RLock() | 
					
						
							|  |  |  | 	defer n.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	return n.server | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | // Service retrieves a currently running service registered of a specific type. | 
					
						
							|  |  |  | func (n *Node) Service(service interface{}) error { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	n.lock.RLock() | 
					
						
							|  |  |  | 	defer n.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Short circuit if the node's not running | 
					
						
							|  |  |  | 	if n.server == nil { | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 		return ErrNodeStopped | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Otherwise try to find the service to return | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	element := reflect.ValueOf(service).Elem() | 
					
						
							|  |  |  | 	if running, ok := n.services[element.Type()]; ok { | 
					
						
							|  |  |  | 		element.Set(reflect.ValueOf(running)) | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-26 18:35:44 +02:00
										 |  |  | 	return ErrServiceUnknown | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // DataDir retrieves the current datadir used by the protocol stack. | 
					
						
							| 
									
										
										
										
											2016-11-10 17:03:24 +01:00
										 |  |  | // Deprecated: No files should be stored in this directory, use InstanceDir instead. | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | func (n *Node) DataDir() string { | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | 	return n.config.DataDir | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-10 17:03:24 +01:00
										 |  |  | // InstanceDir retrieves the instance directory used by the protocol stack. | 
					
						
							|  |  |  | func (n *Node) InstanceDir() string { | 
					
						
							|  |  |  | 	return n.config.instanceDir() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 18:38:32 +02:00
										 |  |  | // AccountManager retrieves the account manager used by the protocol stack. | 
					
						
							|  |  |  | func (n *Node) AccountManager() *accounts.Manager { | 
					
						
							|  |  |  | 	return n.accman | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 13:24:42 +02:00
										 |  |  | // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. | 
					
						
							|  |  |  | func (n *Node) IPCEndpoint() string { | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | 	return n.ipcEndpoint | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-09 14:10:40 +02:00
										 |  |  | // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. | 
					
						
							|  |  |  | func (n *Node) HTTPEndpoint() string { | 
					
						
							|  |  |  | 	return n.httpEndpoint | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WSEndpoint retrieves the current WS endpoint used by the protocol stack. | 
					
						
							|  |  |  | func (n *Node) WSEndpoint() string { | 
					
						
							|  |  |  | 	return n.wsEndpoint | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | // EventMux retrieves the event multiplexer used by all the network services in | 
					
						
							|  |  |  | // the current protocol stack. | 
					
						
							|  |  |  | func (n *Node) EventMux() *event.TypeMux { | 
					
						
							| 
									
										
										
										
											2015-11-17 18:33:25 +02:00
										 |  |  | 	return n.eventmux | 
					
						
							| 
									
										
										
										
											2015-11-05 23:57:57 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 13:28:17 +02:00
										 |  |  | // OpenDatabase opens an existing database with the given name (or creates one if no | 
					
						
							|  |  |  | // previous can be found) from within the node's instance directory. If the node is | 
					
						
							|  |  |  | // ephemeral, a memory database is returned. | 
					
						
							|  |  |  | func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { | 
					
						
							|  |  |  | 	if n.config.DataDir == "" { | 
					
						
							|  |  |  | 		return ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ethdb.NewLDBDatabase(n.config.resolvePath(name), cache, handles) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ResolvePath returns the absolute path of a resource in the instance directory. | 
					
						
							|  |  |  | func (n *Node) ResolvePath(x string) string { | 
					
						
							|  |  |  | 	return n.config.resolvePath(x) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | // apis returns the collection of RPC descriptors this node offers. | 
					
						
							|  |  |  | func (n *Node) apis() []rpc.API { | 
					
						
							|  |  |  | 	return []rpc.API{ | 
					
						
							| 
									
										
										
										
											2015-12-04 20:56:11 +02:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Namespace: "admin", | 
					
						
							|  |  |  | 			Version:   "1.0", | 
					
						
							|  |  |  | 			Service:   NewPrivateAdminAPI(n), | 
					
						
							|  |  |  | 		}, { | 
					
						
							|  |  |  | 			Namespace: "admin", | 
					
						
							|  |  |  | 			Version:   "1.0", | 
					
						
							|  |  |  | 			Service:   NewPublicAdminAPI(n), | 
					
						
							|  |  |  | 			Public:    true, | 
					
						
							|  |  |  | 		}, { | 
					
						
							|  |  |  | 			Namespace: "debug", | 
					
						
							|  |  |  | 			Version:   "1.0", | 
					
						
							| 
									
										
										
										
											2016-01-26 14:39:21 +01:00
										 |  |  | 			Service:   debug.Handler, | 
					
						
							| 
									
										
										
										
											2015-12-04 20:56:11 +02:00
										 |  |  | 		}, { | 
					
						
							|  |  |  | 			Namespace: "debug", | 
					
						
							|  |  |  | 			Version:   "1.0", | 
					
						
							|  |  |  | 			Service:   NewPublicDebugAPI(n), | 
					
						
							|  |  |  | 			Public:    true, | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | 		}, { | 
					
						
							|  |  |  | 			Namespace: "web3", | 
					
						
							|  |  |  | 			Version:   "1.0", | 
					
						
							|  |  |  | 			Service:   NewPublicWeb3API(n), | 
					
						
							|  |  |  | 			Public:    true, | 
					
						
							| 
									
										
										
										
											2015-12-04 20:56:11 +02:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-02 19:06:43 +02:00
										 |  |  | } |