github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/node/node.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:40</date>
    10  //</624450102429224960>
    11  
    12  
    13  package node
    14  
    15  import (
    16  	"errors"
    17  	"fmt"
    18  	"net"
    19  	"os"
    20  	"path/filepath"
    21  	"reflect"
    22  	"strings"
    23  	"sync"
    24  
    25  	"github.com/ethereum/go-ethereum/accounts"
    26  	"github.com/ethereum/go-ethereum/ethdb"
    27  	"github.com/ethereum/go-ethereum/event"
    28  	"github.com/ethereum/go-ethereum/internal/debug"
    29  	"github.com/ethereum/go-ethereum/log"
    30  	"github.com/ethereum/go-ethereum/p2p"
    31  	"github.com/ethereum/go-ethereum/rpc"
    32  	"github.com/prometheus/prometheus/util/flock"
    33  )
    34  
    35  //节点是一个可以在其上注册服务的容器。
    36  type Node struct {
    37  eventmux *event.TypeMux //在堆栈服务之间使用的事件多路复用器
    38  	config   *Config
    39  	accman   *accounts.Manager
    40  
    41  ephemeralKeystore string         //如果非空,则停止将删除的密钥目录
    42  instanceDirLock   flock.Releaser //防止同时使用实例目录
    43  
    44  	serverConfig p2p.Config
    45  server       *p2p.Server //当前运行的P2P网络层
    46  
    47  serviceFuncs []ServiceConstructor     //服务构造函数(按依赖顺序)
    48  services     map[reflect.Type]Service //当前正在运行的服务
    49  
    50  rpcAPIs       []rpc.API   //节点当前提供的API列表
    51  inprocHandler *rpc.Server //处理API请求的进程内RPC请求处理程序
    52  
    53  ipcEndpoint string       //要侦听的IPC终结点(空=禁用IPC)
    54  ipcListener net.Listener //用于服务API请求的IPC RPC侦听器套接字
    55  ipcHandler  *rpc.Server  //用于处理API请求的IPC RPC请求处理程序
    56  
    57  httpEndpoint  string       //要侦听的HTTP端点(接口+端口)(空=禁用HTTP)
    58  httpWhitelist []string     //允许通过此终结点的HTTP RPC模块
    59  httpListener  net.Listener //HTTP RPC侦听器套接字到服务器API请求
    60  httpHandler   *rpc.Server  //处理API请求的HTTP RPC请求处理程序
    61  
    62  wsEndpoint string       //要侦听的WebSocket终结点(接口+端口)(空=禁用WebSocket)
    63  wsListener net.Listener //WebSocket RPC侦听器套接字到服务器API请求
    64  wsHandler  *rpc.Server  //用于处理API请求的WebSocket RPC请求处理程序
    65  
    66  stop chan struct{} //等待终止通知的通道
    67  	lock sync.RWMutex
    68  
    69  	log log.Logger
    70  }
    71  
    72  //new创建一个新的p2p节点,准备好进行协议注册。
    73  func New(conf *Config) (*Node, error) {
    74  //复制config并解析datadir,以便将来对当前
    75  //工作目录不影响节点。
    76  	confCopy := *conf
    77  	conf = &confCopy
    78  	if conf.DataDir != "" {
    79  		absdatadir, err := filepath.Abs(conf.DataDir)
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		conf.DataDir = absdatadir
    84  	}
    85  //确保实例名不会与
    86  //数据目录中的其他文件。
    87  	if strings.ContainsAny(conf.Name, `/\`) {
    88  		return nil, errors.New(`Config.Name must not contain '/' or '\'`)
    89  	}
    90  	if conf.Name == datadirDefaultKeyStore {
    91  		return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`)
    92  	}
    93  	if strings.HasSuffix(conf.Name, ".ipc") {
    94  		return nil, errors.New(`Config.Name cannot end in ".ipc"`)
    95  	}
    96  //确保AccountManager方法在节点启动之前工作。
    97  //我们在命令/geth中依赖这个。
    98  	am, ephemeralKeystore, err := makeAccountManager(conf)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	if conf.Logger == nil {
   103  		conf.Logger = log.New()
   104  	}
   105  //注意:与config的任何交互都会创建/触摸文件
   106  //在数据目录或实例目录中延迟到启动。
   107  	return &Node{
   108  		accman:            am,
   109  		ephemeralKeystore: ephemeralKeystore,
   110  		config:            conf,
   111  		serviceFuncs:      []ServiceConstructor{},
   112  		ipcEndpoint:       conf.IPCEndpoint(),
   113  		httpEndpoint:      conf.HTTPEndpoint(),
   114  		wsEndpoint:        conf.WSEndpoint(),
   115  		eventmux:          new(event.TypeMux),
   116  		log:               conf.Logger,
   117  	}, nil
   118  }
   119  
   120  //寄存器将一个新服务注入到节点的堆栈中。服务创建者
   121  //传递的构造函数在其类型中对于同级构造函数必须是唯一的。
   122  func (n *Node) Register(constructor ServiceConstructor) error {
   123  	n.lock.Lock()
   124  	defer n.lock.Unlock()
   125  
   126  	if n.server != nil {
   127  		return ErrNodeRunning
   128  	}
   129  	n.serviceFuncs = append(n.serviceFuncs, constructor)
   130  	return nil
   131  }
   132  
   133  //开始创建一个活动的P2P节点并开始运行它。
   134  func (n *Node) Start() error {
   135  	n.lock.Lock()
   136  	defer n.lock.Unlock()
   137  
   138  //如果节点已经运行,则短路
   139  	if n.server != nil {
   140  		return ErrNodeRunning
   141  	}
   142  	if err := n.openDataDir(); err != nil {
   143  		return err
   144  	}
   145  
   146  //初始化P2P服务器。这将创建节点键并
   147  //发现数据库。
   148  	n.serverConfig = n.config.P2P
   149  	n.serverConfig.PrivateKey = n.config.NodeKey()
   150  	n.serverConfig.Name = n.config.NodeName()
   151  	n.serverConfig.Logger = n.log
   152  	if n.serverConfig.StaticNodes == nil {
   153  		n.serverConfig.StaticNodes = n.config.StaticNodes()
   154  	}
   155  	if n.serverConfig.TrustedNodes == nil {
   156  		n.serverConfig.TrustedNodes = n.config.TrustedNodes()
   157  	}
   158  	if n.serverConfig.NodeDatabase == "" {
   159  		n.serverConfig.NodeDatabase = n.config.NodeDB()
   160  	}
   161  	running := &p2p.Server{Config: n.serverConfig}
   162  	n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name)
   163  
   164  //否则,复制并专门化p2p配置
   165  	services := make(map[reflect.Type]Service)
   166  	for _, constructor := range n.serviceFuncs {
   167  //为特定服务创建新上下文
   168  		ctx := &ServiceContext{
   169  			config:         n.config,
   170  			services:       make(map[reflect.Type]Service),
   171  			EventMux:       n.eventmux,
   172  			AccountManager: n.accman,
   173  		}
   174  for kind, s := range services { //线程访问所需的副本
   175  			ctx.services[kind] = s
   176  		}
   177  //构建并保存服务
   178  		service, err := constructor(ctx)
   179  		if err != nil {
   180  			return err
   181  		}
   182  		kind := reflect.TypeOf(service)
   183  		if _, exists := services[kind]; exists {
   184  			return &DuplicateServiceError{Kind: kind}
   185  		}
   186  		services[kind] = service
   187  	}
   188  //收集协议并启动新组装的P2P服务器
   189  	for _, service := range services {
   190  		running.Protocols = append(running.Protocols, service.Protocols()...)
   191  	}
   192  	if err := running.Start(); err != nil {
   193  		return convertFileLockError(err)
   194  	}
   195  //启动每个服务
   196  	started := []reflect.Type{}
   197  	for kind, service := range services {
   198  //启动下一个服务,失败时停止所有上一个服务
   199  		if err := service.Start(running); err != nil {
   200  			for _, kind := range started {
   201  				services[kind].Stop()
   202  			}
   203  			running.Stop()
   204  
   205  			return err
   206  		}
   207  //标记服务已启动以进行潜在清理
   208  		started = append(started, kind)
   209  	}
   210  //最后启动配置的RPC接口
   211  	if err := n.startRPC(services); err != nil {
   212  		for _, service := range services {
   213  			service.Stop()
   214  		}
   215  		running.Stop()
   216  		return err
   217  	}
   218  //完成初始化启动
   219  	n.services = services
   220  	n.server = running
   221  	n.stop = make(chan struct{})
   222  
   223  	return nil
   224  }
   225  
   226  func (n *Node) openDataDir() error {
   227  	if n.config.DataDir == "" {
   228  return nil //短暂的
   229  	}
   230  
   231  	instdir := filepath.Join(n.config.DataDir, n.config.name())
   232  	if err := os.MkdirAll(instdir, 0700); err != nil {
   233  		return err
   234  	}
   235  //锁定实例目录以防止另一个实例同时使用
   236  //意外地将实例目录用作数据库。
   237  	release, _, err := flock.New(filepath.Join(instdir, "LOCK"))
   238  	if err != nil {
   239  		return convertFileLockError(err)
   240  	}
   241  	n.instanceDirLock = release
   242  	return nil
   243  }
   244  
   245  //start rpc是一个帮助方法,用于在节点期间启动所有不同的rpc端点。
   246  //启动。以后任何时候都不应该打电话,因为它可以确定
   247  //关于节点状态的假设。
   248  func (n *Node) startRPC(services map[reflect.Type]Service) error {
   249  //收集所有可能的API到表面
   250  	apis := n.apis()
   251  	for _, service := range services {
   252  		apis = append(apis, service.APIs()...)
   253  	}
   254  //启动各种API端点,在出现错误时终止所有端点
   255  	if err := n.startInProc(apis); err != nil {
   256  		return err
   257  	}
   258  	if err := n.startIPC(apis); err != nil {
   259  		n.stopInProc()
   260  		return err
   261  	}
   262  	if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil {
   263  		n.stopIPC()
   264  		n.stopInProc()
   265  		return err
   266  	}
   267  	if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
   268  		n.stopHTTP()
   269  		n.stopIPC()
   270  		n.stopInProc()
   271  		return err
   272  	}
   273  //所有API终结点已成功启动
   274  	n.rpcAPIs = apis
   275  	return nil
   276  }
   277  
   278  //StartInProc初始化进程内RPC终结点。
   279  func (n *Node) startInProc(apis []rpc.API) error {
   280  //注册服务公开的所有API
   281  	handler := rpc.NewServer()
   282  	for _, api := range apis {
   283  		if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
   284  			return err
   285  		}
   286  		n.log.Debug("InProc registered", "namespace", api.Namespace)
   287  	}
   288  	n.inprocHandler = handler
   289  	return nil
   290  }
   291  
   292  //stopinproc终止进程内RPC终结点。
   293  func (n *Node) stopInProc() {
   294  	if n.inprocHandler != nil {
   295  		n.inprocHandler.Stop()
   296  		n.inprocHandler = nil
   297  	}
   298  }
   299  
   300  //StartIPC初始化并启动IPC RPC终结点。
   301  func (n *Node) startIPC(apis []rpc.API) error {
   302  	if n.ipcEndpoint == "" {
   303  return nil //IPC禁用。
   304  	}
   305  	listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis)
   306  	if err != nil {
   307  		return err
   308  	}
   309  	n.ipcListener = listener
   310  	n.ipcHandler = handler
   311  	n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint)
   312  	return nil
   313  }
   314  
   315  //StopIPC终止IPC RPC终结点。
   316  func (n *Node) stopIPC() {
   317  	if n.ipcListener != nil {
   318  		n.ipcListener.Close()
   319  		n.ipcListener = nil
   320  
   321  		n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint)
   322  	}
   323  	if n.ipcHandler != nil {
   324  		n.ipcHandler.Stop()
   325  		n.ipcHandler = nil
   326  	}
   327  }
   328  
   329  //StartHTTP初始化并启动HTTP RPC终结点。
   330  func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error {
   331  //如果HTTP端点未暴露,则短路
   332  	if endpoint == "" {
   333  		return nil
   334  	}
   335  	listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts)
   336  	if err != nil {
   337  		return err
   338  	}
   339  n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s“,终结点),”cors“,strings.join(cors,”,“),”vhosts“,strings.join(vhosts,”,“))
   340  //所有侦听器都已成功启动
   341  	n.httpEndpoint = endpoint
   342  	n.httpListener = listener
   343  	n.httpHandler = handler
   344  
   345  	return nil
   346  }
   347  
   348  //StopHTTP终止HTTP RPC终结点。
   349  func (n *Node) stopHTTP() {
   350  	if n.httpListener != nil {
   351  		n.httpListener.Close()
   352  		n.httpListener = nil
   353  
   354  n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s“,n.httpendpoint)
   355  	}
   356  	if n.httpHandler != nil {
   357  		n.httpHandler.Stop()
   358  		n.httpHandler = nil
   359  	}
   360  }
   361  
   362  //startws初始化并启动WebSocket RPC终结点。
   363  func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
   364  //如果没有暴露WS端点,则短路
   365  	if endpoint == "" {
   366  		return nil
   367  	}
   368  	listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll)
   369  	if err != nil {
   370  		return err
   371  	}
   372  n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s“,listener.addr()))
   373  //所有侦听器都已成功启动
   374  	n.wsEndpoint = endpoint
   375  	n.wsListener = listener
   376  	n.wsHandler = handler
   377  
   378  	return nil
   379  }
   380  
   381  //stopws终止WebSocket RPC终结点。
   382  func (n *Node) stopWS() {
   383  	if n.wsListener != nil {
   384  		n.wsListener.Close()
   385  		n.wsListener = nil
   386  
   387  n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s“,n.wsendpoint)
   388  	}
   389  	if n.wsHandler != nil {
   390  		n.wsHandler.Stop()
   391  		n.wsHandler = nil
   392  	}
   393  }
   394  
   395  //stop终止正在运行的节点及其所有服务。节点中
   396  //未启动,返回错误。
   397  func (n *Node) Stop() error {
   398  	n.lock.Lock()
   399  	defer n.lock.Unlock()
   400  
   401  //节点未运行时短路
   402  	if n.server == nil {
   403  		return ErrNodeStopped
   404  	}
   405  
   406  //终止API、服务和P2P服务器。
   407  	n.stopWS()
   408  	n.stopHTTP()
   409  	n.stopIPC()
   410  	n.rpcAPIs = nil
   411  	failure := &StopError{
   412  		Services: make(map[reflect.Type]error),
   413  	}
   414  	for kind, service := range n.services {
   415  		if err := service.Stop(); err != nil {
   416  			failure.Services[kind] = err
   417  		}
   418  	}
   419  	n.server.Stop()
   420  	n.services = nil
   421  	n.server = nil
   422  
   423  //释放实例目录锁。
   424  	if n.instanceDirLock != nil {
   425  		if err := n.instanceDirLock.Release(); err != nil {
   426  			n.log.Error("Can't release datadir lock", "err", err)
   427  		}
   428  		n.instanceDirLock = nil
   429  	}
   430  
   431  //等待,等待
   432  	close(n.stop)
   433  
   434  //如果密钥库是临时创建的,请将其删除。
   435  	var keystoreErr error
   436  	if n.ephemeralKeystore != "" {
   437  		keystoreErr = os.RemoveAll(n.ephemeralKeystore)
   438  	}
   439  
   440  	if len(failure.Services) > 0 {
   441  		return failure
   442  	}
   443  	if keystoreErr != nil {
   444  		return keystoreErr
   445  	}
   446  	return nil
   447  }
   448  
   449  //等待将阻止线程,直到节点停止。如果节点没有运行
   450  //调用时,该方法立即返回。
   451  func (n *Node) Wait() {
   452  	n.lock.RLock()
   453  	if n.server == nil {
   454  		n.lock.RUnlock()
   455  		return
   456  	}
   457  	stop := n.stop
   458  	n.lock.RUnlock()
   459  
   460  	<-stop
   461  }
   462  
   463  //重新启动终止正在运行的节点,并在其位置启动新节点。如果
   464  //节点未运行,返回错误。
   465  func (n *Node) Restart() error {
   466  	if err := n.Stop(); err != nil {
   467  		return err
   468  	}
   469  	if err := n.Start(); err != nil {
   470  		return err
   471  	}
   472  	return nil
   473  }
   474  
   475  //附加创建一个附加到进程内API处理程序的RPC客户端。
   476  func (n *Node) Attach() (*rpc.Client, error) {
   477  	n.lock.RLock()
   478  	defer n.lock.RUnlock()
   479  
   480  	if n.server == nil {
   481  		return nil, ErrNodeStopped
   482  	}
   483  	return rpc.DialInProc(n.inprocHandler), nil
   484  }
   485  
   486  //rpc handler返回进程内的rpc请求处理程序。
   487  func (n *Node) RPCHandler() (*rpc.Server, error) {
   488  	n.lock.RLock()
   489  	defer n.lock.RUnlock()
   490  
   491  	if n.inprocHandler == nil {
   492  		return nil, ErrNodeStopped
   493  	}
   494  	return n.inprocHandler, nil
   495  }
   496  
   497  //服务器检索当前运行的P2P网络层。这个方法的意思是
   498  //仅检查当前运行的服务器的字段,生命周期管理
   499  //应该留给这个节点实体。
   500  func (n *Node) Server() *p2p.Server {
   501  	n.lock.RLock()
   502  	defer n.lock.RUnlock()
   503  
   504  	return n.server
   505  }
   506  
   507  //服务检索当前正在运行的特定类型的注册服务。
   508  func (n *Node) Service(service interface{}) error {
   509  	n.lock.RLock()
   510  	defer n.lock.RUnlock()
   511  
   512  //节点未运行时短路
   513  	if n.server == nil {
   514  		return ErrNodeStopped
   515  	}
   516  //否则,请尝试查找要返回的服务
   517  	element := reflect.ValueOf(service).Elem()
   518  	if running, ok := n.services[element.Type()]; ok {
   519  		element.Set(reflect.ValueOf(running))
   520  		return nil
   521  	}
   522  	return ErrServiceUnknown
   523  }
   524  
   525  //datadir检索协议堆栈使用的当前datadir。
   526  //已弃用:此目录中不应存储任何文件,请改用instancedir。
   527  func (n *Node) DataDir() string {
   528  	return n.config.DataDir
   529  }
   530  
   531  //instancedir检索协议堆栈使用的实例目录。
   532  func (n *Node) InstanceDir() string {
   533  	return n.config.instanceDir()
   534  }
   535  
   536  //AccountManager检索协议堆栈使用的帐户管理器。
   537  func (n *Node) AccountManager() *accounts.Manager {
   538  	return n.accman
   539  }
   540  
   541  //ipc endpoint检索协议堆栈使用的当前IPC终结点。
   542  func (n *Node) IPCEndpoint() string {
   543  	return n.ipcEndpoint
   544  }
   545  
   546  //http endpoint检索协议堆栈使用的当前HTTP端点。
   547  func (n *Node) HTTPEndpoint() string {
   548  	n.lock.Lock()
   549  	defer n.lock.Unlock()
   550  
   551  	if n.httpListener != nil {
   552  		return n.httpListener.Addr().String()
   553  	}
   554  	return n.httpEndpoint
   555  }
   556  
   557  //ws endpoint检索协议堆栈使用的当前ws endpoint。
   558  func (n *Node) WSEndpoint() string {
   559  	n.lock.Lock()
   560  	defer n.lock.Unlock()
   561  
   562  	if n.wsListener != nil {
   563  		return n.wsListener.Addr().String()
   564  	}
   565  	return n.wsEndpoint
   566  }
   567  
   568  //eventmux检索中所有网络服务使用的事件多路复用器
   569  //当前协议堆栈。
   570  func (n *Node) EventMux() *event.TypeMux {
   571  	return n.eventmux
   572  }
   573  
   574  //opendatabase打开具有给定名称的现有数据库(如果没有,则创建一个)
   575  //可以在节点的实例目录中找到上一个)。如果节点是
   576  //短暂的,返回内存数据库。
   577  func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) {
   578  	if n.config.DataDir == "" {
   579  		return ethdb.NewMemDatabase(), nil
   580  	}
   581  	return ethdb.NewLDBDatabase(n.config.ResolvePath(name), cache, handles)
   582  }
   583  
   584  //resolvepath返回实例目录中资源的绝对路径。
   585  func (n *Node) ResolvePath(x string) string {
   586  	return n.config.ResolvePath(x)
   587  }
   588  
   589  //API返回此节点提供的RPC描述符的集合。
   590  func (n *Node) apis() []rpc.API {
   591  	return []rpc.API{
   592  		{
   593  			Namespace: "admin",
   594  			Version:   "1.0",
   595  			Service:   NewPrivateAdminAPI(n),
   596  		}, {
   597  			Namespace: "admin",
   598  			Version:   "1.0",
   599  			Service:   NewPublicAdminAPI(n),
   600  			Public:    true,
   601  		}, {
   602  			Namespace: "debug",
   603  			Version:   "1.0",
   604  			Service:   debug.Handler,
   605  		}, {
   606  			Namespace: "debug",
   607  			Version:   "1.0",
   608  			Service:   NewPublicDebugAPI(n),
   609  			Public:    true,
   610  		}, {
   611  			Namespace: "web3",
   612  			Version:   "1.0",
   613  			Service:   NewPublicWeb3API(n),
   614  			Public:    true,
   615  		},
   616  	}
   617  }
   618