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