github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/node/node.go (about)

     1  package node
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/neatlab/neatio/chain/core/rawdb"
    14  
    15  	"github.com/neatlab/neatio/chain/accounts"
    16  	"github.com/neatlab/neatio/chain/log"
    17  	"github.com/neatlab/neatio/internal/debug"
    18  	"github.com/neatlab/neatio/neatdb"
    19  	"github.com/neatlab/neatio/network/p2p"
    20  	"github.com/neatlab/neatio/network/rpc"
    21  	"github.com/neatlab/neatio/utilities/event"
    22  	flock "github.com/neatlib/flock-go"
    23  )
    24  
    25  type Node struct {
    26  	eventmux *event.TypeMux
    27  	config   *Config
    28  	accman   *accounts.Manager
    29  
    30  	ephemeralKeystore string
    31  	instanceDirLock   flock.Releaser
    32  
    33  	serverConfig p2p.Config
    34  	server       *p2p.Server
    35  
    36  	serviceFuncs []ServiceConstructor
    37  	services     map[reflect.Type]Service
    38  
    39  	rpcAPIs       []rpc.API
    40  	inprocHandler *rpc.Server
    41  
    42  	ipcEndpoint string
    43  	ipcListener net.Listener
    44  	ipcHandler  *rpc.Server
    45  
    46  	httpEndpoint  string
    47  	httpWhitelist []string
    48  	httpListener  net.Listener
    49  	httpHandler   *rpc.Server
    50  
    51  	wsEndpoint string
    52  	wsListener net.Listener
    53  	wsHandler  *rpc.Server
    54  
    55  	stop chan struct{}
    56  	lock sync.RWMutex
    57  
    58  	log log.Logger
    59  }
    60  
    61  func New(conf *Config) (*Node, error) {
    62  	confCopy := *conf
    63  	conf = &confCopy
    64  	if conf.DataDir != "" {
    65  		absdatadir, err := filepath.Abs(conf.DataDir)
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  		conf.DataDir = absdatadir
    70  	}
    71  	if strings.ContainsAny(conf.Name, `/\`) {
    72  		return nil, errors.New(`Config.Name must not contain '/' or '\'`)
    73  	}
    74  	if conf.Name == datadirDefaultKeyStore {
    75  		return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`)
    76  	}
    77  	if strings.HasSuffix(conf.Name, ".ipc") {
    78  		return nil, errors.New(`Config.Name cannot end in ".ipc"`)
    79  	}
    80  	am, ephemeralKeystore, err := makeAccountManager(conf)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	if conf.Logger == nil {
    85  		conf.Logger = log.New()
    86  	}
    87  	return &Node{
    88  		accman:            am,
    89  		ephemeralKeystore: ephemeralKeystore,
    90  		config:            conf,
    91  		serviceFuncs:      []ServiceConstructor{},
    92  		ipcEndpoint:       conf.IPCEndpoint(),
    93  		httpEndpoint:      conf.HTTPEndpoint(),
    94  		wsEndpoint:        conf.WSEndpoint(),
    95  		eventmux:          new(event.TypeMux),
    96  		log:               conf.Logger,
    97  	}, nil
    98  }
    99  
   100  func (n *Node) Close() error {
   101  	var errs []error
   102  
   103  	if err := n.Stop(); err != nil && err != ErrNodeStopped {
   104  		errs = append(errs, err)
   105  	}
   106  	if err := n.accman.Close(); err != nil {
   107  		errs = append(errs, err)
   108  	}
   109  	switch len(errs) {
   110  	case 0:
   111  		return nil
   112  	case 1:
   113  		return errs[0]
   114  	default:
   115  		return fmt.Errorf("%v", errs)
   116  	}
   117  }
   118  
   119  func (n *Node) Register(constructor ServiceConstructor) error {
   120  	n.lock.Lock()
   121  	defer n.lock.Unlock()
   122  
   123  	if n.server != nil {
   124  		return ErrNodeRunning
   125  	}
   126  	n.serviceFuncs = append(n.serviceFuncs, constructor)
   127  	return nil
   128  }
   129  
   130  func (n *Node) Start() error {
   131  	n.lock.Lock()
   132  	defer n.lock.Unlock()
   133  
   134  	if n.server != nil {
   135  		return ErrNodeRunning
   136  	}
   137  	if err := n.openDataDir(); err != nil {
   138  		return err
   139  	}
   140  
   141  	n.serverConfig = n.config.P2P
   142  	n.serverConfig.PrivateKey = n.config.NodeKey()
   143  	n.serverConfig.Name = n.config.NodeName()
   144  	n.serverConfig.Logger = n.log
   145  	if n.serverConfig.StaticNodes == nil {
   146  		n.serverConfig.StaticNodes = n.config.StaticNodes()
   147  	}
   148  	if n.serverConfig.TrustedNodes == nil {
   149  		n.serverConfig.TrustedNodes = n.config.TrustedNodes()
   150  	}
   151  	if n.serverConfig.NodeDatabase == "" {
   152  		n.serverConfig.NodeDatabase = n.config.NodeDB()
   153  	}
   154  	running := &p2p.Server{Config: n.serverConfig}
   155  	n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name)
   156  
   157  	services := make(map[reflect.Type]Service)
   158  	for _, constructor := range n.serviceFuncs {
   159  		ctx := &ServiceContext{
   160  			config:         n.config,
   161  			services:       make(map[reflect.Type]Service),
   162  			EventMux:       n.eventmux,
   163  			AccountManager: n.accman,
   164  		}
   165  		for kind, s := range services {
   166  			ctx.services[kind] = s
   167  		}
   168  		service, err := constructor(ctx)
   169  		if err != nil {
   170  			return err
   171  		}
   172  		kind := reflect.TypeOf(service)
   173  		if _, exists := services[kind]; exists {
   174  			return &DuplicateServiceError{Kind: kind}
   175  		}
   176  		services[kind] = service
   177  	}
   178  	for _, service := range services {
   179  		running.Protocols = append(running.Protocols, service.Protocols()...)
   180  	}
   181  	if err := running.Start(); err != nil {
   182  		return convertFileLockError(err)
   183  	}
   184  	started := []reflect.Type{}
   185  	for kind, service := range services {
   186  		if err := service.Start(running); err != nil {
   187  			for _, kind := range started {
   188  				services[kind].Stop()
   189  			}
   190  			running.Stop()
   191  
   192  			return err
   193  		}
   194  		started = append(started, kind)
   195  	}
   196  	if err := n.startRPC(services); err != nil {
   197  		for _, service := range services {
   198  			service.Stop()
   199  		}
   200  		running.Stop()
   201  		return err
   202  	}
   203  	n.services = services
   204  	n.server = running
   205  	n.stop = make(chan struct{})
   206  
   207  	return nil
   208  }
   209  
   210  func (n *Node) openDataDir() error {
   211  	if n.config.DataDir == "" {
   212  		return nil
   213  	}
   214  
   215  	instdir := filepath.Join(n.config.DataDir, n.config.name())
   216  	if err := os.MkdirAll(instdir, 0700); err != nil {
   217  		return err
   218  	}
   219  	release, _, err := flock.New(filepath.Join(instdir, "LOCK"))
   220  	if err != nil {
   221  		return convertFileLockError(err)
   222  	}
   223  	n.instanceDirLock = release
   224  	return nil
   225  }
   226  
   227  func (n *Node) startRPC(services map[reflect.Type]Service) error {
   228  	apis := n.apis()
   229  	for _, service := range services {
   230  		apis = append(apis, service.APIs()...)
   231  	}
   232  	if err := n.startInProc(apis); err != nil {
   233  		return err
   234  	}
   235  	if err := n.startIPC(apis); err != nil {
   236  		n.stopInProc()
   237  		return err
   238  	}
   239  	if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil {
   240  		n.stopIPC()
   241  		n.stopInProc()
   242  		return err
   243  	}
   244  	if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
   245  		n.stopHTTP()
   246  		n.stopIPC()
   247  		n.stopInProc()
   248  		return err
   249  	}
   250  	n.rpcAPIs = apis
   251  	return nil
   252  }
   253  
   254  func (n *Node) startInProc(apis []rpc.API) error {
   255  	handler := rpc.NewServer()
   256  	for _, api := range apis {
   257  		if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
   258  			return err
   259  		}
   260  		n.log.Debug("InProc registered", "service", api.Service, "namespace", api.Namespace)
   261  	}
   262  	n.inprocHandler = handler
   263  	return nil
   264  }
   265  
   266  func (n *Node) stopInProc() {
   267  	if n.inprocHandler != nil {
   268  		n.inprocHandler.Stop()
   269  		n.inprocHandler = nil
   270  	}
   271  }
   272  
   273  func (n *Node) startIPC(apis []rpc.API) error {
   274  	if n.ipcEndpoint == "" {
   275  		return nil
   276  	}
   277  	listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis)
   278  	if err != nil {
   279  		return err
   280  	}
   281  	n.ipcListener = listener
   282  	n.ipcHandler = handler
   283  	return nil
   284  }
   285  
   286  func (n *Node) stopIPC() {
   287  	if n.ipcListener != nil {
   288  		n.ipcListener.Close()
   289  		n.ipcListener = nil
   290  
   291  		n.log.Info("IPC endpoint closed", "endpoint", n.ipcEndpoint)
   292  	}
   293  	if n.ipcHandler != nil {
   294  		n.ipcHandler.Stop()
   295  		n.ipcHandler = nil
   296  	}
   297  }
   298  
   299  func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error {
   300  	if endpoint == "" {
   301  		return nil
   302  	}
   303  	listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts)
   304  	if err != nil {
   305  		return err
   306  	}
   307  	n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ","))
   308  	n.httpEndpoint = endpoint
   309  	n.httpListener = listener
   310  	n.httpHandler = handler
   311  
   312  	return nil
   313  }
   314  
   315  func (n *Node) stopHTTP() {
   316  	if n.httpListener != nil {
   317  		n.httpListener.Close()
   318  		n.httpListener = nil
   319  
   320  		n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint))
   321  	}
   322  	if n.httpHandler != nil {
   323  		n.httpHandler.Stop()
   324  		n.httpHandler = nil
   325  	}
   326  }
   327  
   328  func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
   329  	if endpoint == "" {
   330  		return nil
   331  	}
   332  	listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll)
   333  	if err != nil {
   334  		return err
   335  	}
   336  	n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
   337  	n.wsEndpoint = endpoint
   338  	n.wsListener = listener
   339  	n.wsHandler = handler
   340  
   341  	return nil
   342  }
   343  
   344  func (n *Node) stopWS() {
   345  	if n.wsListener != nil {
   346  		n.wsListener.Close()
   347  		n.wsListener = nil
   348  
   349  		n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint))
   350  	}
   351  	if n.wsHandler != nil {
   352  		n.wsHandler.Stop()
   353  		n.wsHandler = nil
   354  	}
   355  }
   356  
   357  func (n *Node) Stop() error {
   358  	n.lock.Lock()
   359  	defer n.lock.Unlock()
   360  
   361  	if n.server == nil {
   362  		return ErrNodeStopped
   363  	}
   364  
   365  	n.stopWS()
   366  	n.stopHTTP()
   367  	n.stopIPC()
   368  	n.rpcAPIs = nil
   369  	failure := &StopError{
   370  		Services: make(map[reflect.Type]error),
   371  	}
   372  	for kind, service := range n.services {
   373  		if err := service.Stop(); err != nil {
   374  			failure.Services[kind] = err
   375  		}
   376  	}
   377  	n.server.Stop()
   378  	n.services = nil
   379  	n.server = nil
   380  
   381  	if n.instanceDirLock != nil {
   382  		if err := n.instanceDirLock.Release(); err != nil {
   383  			n.log.Error("Can't release datadir lock", "err", err)
   384  		}
   385  		n.instanceDirLock = nil
   386  	}
   387  
   388  	close(n.stop)
   389  
   390  	var keystoreErr error
   391  	if n.ephemeralKeystore != "" {
   392  		keystoreErr = os.RemoveAll(n.ephemeralKeystore)
   393  	}
   394  
   395  	if len(failure.Services) > 0 {
   396  		return failure
   397  	}
   398  	if keystoreErr != nil {
   399  		return keystoreErr
   400  	}
   401  	return nil
   402  }
   403  
   404  func (n *Node) Wait() {
   405  	n.lock.RLock()
   406  	if n.server == nil {
   407  		n.lock.RUnlock()
   408  		return
   409  	}
   410  	stop := n.stop
   411  	n.lock.RUnlock()
   412  
   413  	<-stop
   414  }
   415  
   416  func (n *Node) Restart() error {
   417  	if err := n.Stop(); err != nil {
   418  		return err
   419  	}
   420  	if err := n.Start(); err != nil {
   421  		return err
   422  	}
   423  	return nil
   424  }
   425  
   426  func (n *Node) Attach() (*rpc.Client, error) {
   427  	n.lock.RLock()
   428  	defer n.lock.RUnlock()
   429  
   430  	if n.server == nil {
   431  		return nil, ErrNodeStopped
   432  	}
   433  	return rpc.DialInProc(n.inprocHandler), nil
   434  }
   435  
   436  func (n *Node) RPCHandler() (*rpc.Server, error) {
   437  	n.lock.RLock()
   438  	defer n.lock.RUnlock()
   439  
   440  	if n.inprocHandler == nil {
   441  		return nil, ErrNodeStopped
   442  	}
   443  	return n.inprocHandler, nil
   444  }
   445  
   446  func (n *Node) Server() *p2p.Server {
   447  	n.lock.RLock()
   448  	defer n.lock.RUnlock()
   449  
   450  	return n.server
   451  }
   452  
   453  func (n *Node) Service(service interface{}) error {
   454  	n.lock.RLock()
   455  	defer n.lock.RUnlock()
   456  
   457  	if n.server == nil {
   458  		return ErrNodeStopped
   459  	}
   460  	element := reflect.ValueOf(service).Elem()
   461  	if running, ok := n.services[element.Type()]; ok {
   462  		element.Set(reflect.ValueOf(running))
   463  		return nil
   464  	}
   465  	return ErrServiceUnknown
   466  }
   467  
   468  func (n *Node) DataDir() string {
   469  	return n.config.DataDir
   470  }
   471  
   472  func (n *Node) InstanceDir() string {
   473  	return n.config.instanceDir()
   474  }
   475  
   476  func (n *Node) AccountManager() *accounts.Manager {
   477  	return n.accman
   478  }
   479  
   480  func (n *Node) IPCEndpoint() string {
   481  	return n.ipcEndpoint
   482  }
   483  
   484  func (n *Node) HTTPEndpoint() string {
   485  	return n.httpEndpoint
   486  }
   487  
   488  func (n *Node) WSEndpoint() string {
   489  	return n.wsEndpoint
   490  }
   491  
   492  func (n *Node) EventMux() *event.TypeMux {
   493  	return n.eventmux
   494  }
   495  
   496  func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (neatdb.Database, error) {
   497  	if n.config.DataDir == "" {
   498  		return rawdb.NewMemoryDatabase(), nil
   499  	}
   500  	return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace)
   501  }
   502  
   503  func (n *Node) ResolvePath(x string) string {
   504  	return n.config.ResolvePath(x)
   505  }
   506  
   507  func (n *Node) SetP2PServer(p2pServer *p2p.Server) {
   508  	n.server = p2pServer
   509  }
   510  
   511  func (n *Node) StopChan() <-chan struct{} {
   512  	return n.stop
   513  }
   514  
   515  func (n *Node) apis() []rpc.API {
   516  	return []rpc.API{
   517  		{
   518  			Namespace: "admin",
   519  			Version:   "1.0",
   520  			Service:   NewPrivateAdminAPI(n),
   521  		}, {
   522  			Namespace: "admin",
   523  			Version:   "1.0",
   524  			Service:   NewPublicAdminAPI(n),
   525  			Public:    true,
   526  		}, {
   527  			Namespace: "debug",
   528  			Version:   "1.0",
   529  			Service:   debug.Handler,
   530  		}, {
   531  			Namespace: "debug",
   532  			Version:   "1.0",
   533  			Service:   NewPublicDebugAPI(n),
   534  			Public:    true,
   535  		}, {
   536  			Namespace: "web3",
   537  			Version:   "1.0",
   538  			Service:   NewPublicWeb3API(n),
   539  			Public:    true,
   540  		},
   541  	}
   542  }