gitee.com/liu-zhao234568/cntest@v1.0.0/node/node.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "errors" 21 "fmt" 22 "net/http" 23 "os" 24 "path/filepath" 25 "reflect" 26 "strings" 27 "sync" 28 29 "gitee.com/liu-zhao234568/cntest/accounts" 30 "gitee.com/liu-zhao234568/cntest/core/rawdb" 31 "gitee.com/liu-zhao234568/cntest/ethdb" 32 "gitee.com/liu-zhao234568/cntest/event" 33 "gitee.com/liu-zhao234568/cntest/log" 34 "gitee.com/liu-zhao234568/cntest/p2p" 35 "gitee.com/liu-zhao234568/cntest/rpc" 36 "github.com/prometheus/tsdb/fileutil" 37 ) 38 39 // Node is a container on which services can be registered. 40 type Node struct { 41 eventmux *event.TypeMux 42 config *Config 43 accman *accounts.Manager 44 log log.Logger 45 ephemKeystore string // if non-empty, the key directory that will be removed by Stop 46 dirLock fileutil.Releaser // prevents concurrent use of instance directory 47 stop chan struct{} // Channel to wait for termination notifications 48 server *p2p.Server // Currently running P2P networking layer 49 startStopLock sync.Mutex // Start/Stop are protected by an additional lock 50 state int // Tracks state of node lifecycle 51 52 lock sync.Mutex 53 lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle 54 rpcAPIs []rpc.API // List of APIs currently provided by the node 55 http *httpServer // 56 ws *httpServer // 57 ipc *ipcServer // Stores information about the ipc http server 58 inprocHandler *rpc.Server // In-process RPC request handler to process the API requests 59 60 databases map[*closeTrackingDB]struct{} // All open databases 61 } 62 63 const ( 64 initializingState = iota 65 runningState 66 closedState 67 ) 68 69 // New creates a new P2P node, ready for protocol registration. 70 func New(conf *Config) (*Node, error) { 71 // Copy config and resolve the datadir so future changes to the current 72 // working directory don't affect the node. 73 confCopy := *conf 74 conf = &confCopy 75 if conf.DataDir != "" { 76 absdatadir, err := filepath.Abs(conf.DataDir) 77 if err != nil { 78 return nil, err 79 } 80 conf.DataDir = absdatadir 81 } 82 if conf.Logger == nil { 83 conf.Logger = log.New() 84 } 85 86 // Ensure that the instance name doesn't cause weird conflicts with 87 // other files in the data directory. 88 if strings.ContainsAny(conf.Name, `/\`) { 89 return nil, errors.New(`Config.Name must not contain '/' or '\'`) 90 } 91 if conf.Name == datadirDefaultKeyStore { 92 return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`) 93 } 94 if strings.HasSuffix(conf.Name, ".ipc") { 95 return nil, errors.New(`Config.Name cannot end in ".ipc"`) 96 } 97 98 node := &Node{ 99 config: conf, 100 inprocHandler: rpc.NewServer(), 101 eventmux: new(event.TypeMux), 102 log: conf.Logger, 103 stop: make(chan struct{}), 104 server: &p2p.Server{Config: conf.P2P}, 105 databases: make(map[*closeTrackingDB]struct{}), 106 } 107 108 // Register built-in APIs. 109 node.rpcAPIs = append(node.rpcAPIs, node.apis()...) 110 111 // Acquire the instance directory lock. 112 if err := node.openDataDir(); err != nil { 113 return nil, err 114 } 115 // Ensure that the AccountManager method works before the node has started. We rely on 116 // this in cmd/geth. 117 am, ephemeralKeystore, err := makeAccountManager(conf) 118 if err != nil { 119 return nil, err 120 } 121 node.accman = am 122 node.ephemKeystore = ephemeralKeystore 123 124 // Initialize the p2p server. This creates the node key and discovery databases. 125 node.server.Config.PrivateKey = node.config.NodeKey() 126 node.server.Config.Name = node.config.NodeName() 127 node.server.Config.Logger = node.log 128 if node.server.Config.StaticNodes == nil { 129 node.server.Config.StaticNodes = node.config.StaticNodes() 130 } 131 if node.server.Config.TrustedNodes == nil { 132 node.server.Config.TrustedNodes = node.config.TrustedNodes() 133 } 134 if node.server.Config.NodeDatabase == "" { 135 node.server.Config.NodeDatabase = node.config.NodeDB() 136 } 137 138 // Check HTTP/WS prefixes are valid. 139 if err := validatePrefix("HTTP", conf.HTTPPathPrefix); err != nil { 140 return nil, err 141 } 142 if err := validatePrefix("WebSocket", conf.WSPathPrefix); err != nil { 143 return nil, err 144 } 145 146 // Configure RPC servers. 147 node.http = newHTTPServer(node.log, conf.HTTPTimeouts) 148 node.ws = newHTTPServer(node.log, rpc.DefaultHTTPTimeouts) 149 node.ipc = newIPCServer(node.log, conf.IPCEndpoint()) 150 151 return node, nil 152 } 153 154 // Start starts all registered lifecycles, RPC services and p2p networking. 155 // Node can only be started once. 156 func (n *Node) Start() error { 157 n.startStopLock.Lock() 158 defer n.startStopLock.Unlock() 159 160 n.lock.Lock() 161 switch n.state { 162 case runningState: 163 n.lock.Unlock() 164 return ErrNodeRunning 165 case closedState: 166 n.lock.Unlock() 167 return ErrNodeStopped 168 } 169 n.state = runningState 170 // open networking and RPC endpoints 171 err := n.openEndpoints() 172 lifecycles := make([]Lifecycle, len(n.lifecycles)) 173 copy(lifecycles, n.lifecycles) 174 n.lock.Unlock() 175 176 // Check if endpoint startup failed. 177 if err != nil { 178 n.doClose(nil) 179 return err 180 } 181 // Start all registered lifecycles. 182 var started []Lifecycle 183 for _, lifecycle := range lifecycles { 184 if err = lifecycle.Start(); err != nil { 185 break 186 } 187 started = append(started, lifecycle) 188 } 189 // Check if any lifecycle failed to start. 190 if err != nil { 191 n.stopServices(started) 192 n.doClose(nil) 193 } 194 return err 195 } 196 197 // Close stops the Node and releases resources acquired in 198 // Node constructor New. 199 func (n *Node) Close() error { 200 n.startStopLock.Lock() 201 defer n.startStopLock.Unlock() 202 203 n.lock.Lock() 204 state := n.state 205 n.lock.Unlock() 206 switch state { 207 case initializingState: 208 // The node was never started. 209 return n.doClose(nil) 210 case runningState: 211 // The node was started, release resources acquired by Start(). 212 var errs []error 213 if err := n.stopServices(n.lifecycles); err != nil { 214 errs = append(errs, err) 215 } 216 return n.doClose(errs) 217 case closedState: 218 return ErrNodeStopped 219 default: 220 panic(fmt.Sprintf("node is in unknown state %d", state)) 221 } 222 } 223 224 // doClose releases resources acquired by New(), collecting errors. 225 func (n *Node) doClose(errs []error) error { 226 // Close databases. This needs the lock because it needs to 227 // synchronize with OpenDatabase*. 228 n.lock.Lock() 229 n.state = closedState 230 errs = append(errs, n.closeDatabases()...) 231 n.lock.Unlock() 232 233 if err := n.accman.Close(); err != nil { 234 errs = append(errs, err) 235 } 236 if n.ephemKeystore != "" { 237 if err := os.RemoveAll(n.ephemKeystore); err != nil { 238 errs = append(errs, err) 239 } 240 } 241 242 // Release instance directory lock. 243 n.closeDataDir() 244 245 // Unblock n.Wait. 246 close(n.stop) 247 248 // Report any errors that might have occurred. 249 switch len(errs) { 250 case 0: 251 return nil 252 case 1: 253 return errs[0] 254 default: 255 return fmt.Errorf("%v", errs) 256 } 257 } 258 259 // openEndpoints starts all network and RPC endpoints. 260 func (n *Node) openEndpoints() error { 261 // start networking endpoints 262 n.log.Info("Starting peer-to-peer node", "instance", n.server.Name) 263 if err := n.server.Start(); err != nil { 264 return convertFileLockError(err) 265 } 266 // start RPC endpoints 267 err := n.startRPC() 268 if err != nil { 269 n.stopRPC() 270 n.server.Stop() 271 } 272 return err 273 } 274 275 // containsLifecycle checks if 'lfs' contains 'l'. 276 func containsLifecycle(lfs []Lifecycle, l Lifecycle) bool { 277 for _, obj := range lfs { 278 if obj == l { 279 return true 280 } 281 } 282 return false 283 } 284 285 // stopServices terminates running services, RPC and p2p networking. 286 // It is the inverse of Start. 287 func (n *Node) stopServices(running []Lifecycle) error { 288 n.stopRPC() 289 290 // Stop running lifecycles in reverse order. 291 failure := &StopError{Services: make(map[reflect.Type]error)} 292 for i := len(running) - 1; i >= 0; i-- { 293 if err := running[i].Stop(); err != nil { 294 failure.Services[reflect.TypeOf(running[i])] = err 295 } 296 } 297 298 // Stop p2p networking. 299 n.server.Stop() 300 301 if len(failure.Services) > 0 { 302 return failure 303 } 304 return nil 305 } 306 307 func (n *Node) openDataDir() error { 308 if n.config.DataDir == "" { 309 return nil // ephemeral 310 } 311 312 instdir := filepath.Join(n.config.DataDir, n.config.name()) 313 if err := os.MkdirAll(instdir, 0700); err != nil { 314 return err 315 } 316 // Lock the instance directory to prevent concurrent use by another instance as well as 317 // accidental use of the instance directory as a database. 318 release, _, err := fileutil.Flock(filepath.Join(instdir, "LOCK")) 319 if err != nil { 320 return convertFileLockError(err) 321 } 322 n.dirLock = release 323 return nil 324 } 325 326 func (n *Node) closeDataDir() { 327 // Release instance directory lock. 328 if n.dirLock != nil { 329 if err := n.dirLock.Release(); err != nil { 330 n.log.Error("Can't release datadir lock", "err", err) 331 } 332 n.dirLock = nil 333 } 334 } 335 336 // configureRPC is a helper method to configure all the various RPC endpoints during node 337 // startup. It's not meant to be called at any time afterwards as it makes certain 338 // assumptions about the state of the node. 339 func (n *Node) startRPC() error { 340 if err := n.startInProc(); err != nil { 341 return err 342 } 343 344 // Configure IPC. 345 if n.ipc.endpoint != "" { 346 if err := n.ipc.start(n.rpcAPIs); err != nil { 347 return err 348 } 349 } 350 351 // Configure HTTP. 352 if n.config.HTTPHost != "" { 353 config := httpConfig{ 354 CorsAllowedOrigins: n.config.HTTPCors, 355 Vhosts: n.config.HTTPVirtualHosts, 356 Modules: n.config.HTTPModules, 357 prefix: n.config.HTTPPathPrefix, 358 } 359 if err := n.http.setListenAddr(n.config.HTTPHost, n.config.HTTPPort); err != nil { 360 return err 361 } 362 if err := n.http.enableRPC(n.rpcAPIs, config); err != nil { 363 return err 364 } 365 } 366 367 // Configure WebSocket. 368 if n.config.WSHost != "" { 369 server := n.wsServerForPort(n.config.WSPort) 370 config := wsConfig{ 371 Modules: n.config.WSModules, 372 Origins: n.config.WSOrigins, 373 prefix: n.config.WSPathPrefix, 374 } 375 if err := server.setListenAddr(n.config.WSHost, n.config.WSPort); err != nil { 376 return err 377 } 378 if err := server.enableWS(n.rpcAPIs, config); err != nil { 379 return err 380 } 381 } 382 383 if err := n.http.start(); err != nil { 384 return err 385 } 386 return n.ws.start() 387 } 388 389 func (n *Node) wsServerForPort(port int) *httpServer { 390 if n.config.HTTPHost == "" || n.http.port == port { 391 return n.http 392 } 393 return n.ws 394 } 395 396 func (n *Node) stopRPC() { 397 n.http.stop() 398 n.ws.stop() 399 n.ipc.stop() 400 n.stopInProc() 401 } 402 403 // startInProc registers all RPC APIs on the inproc server. 404 func (n *Node) startInProc() error { 405 for _, api := range n.rpcAPIs { 406 if err := n.inprocHandler.RegisterName(api.Namespace, api.Service); err != nil { 407 return err 408 } 409 } 410 return nil 411 } 412 413 // stopInProc terminates the in-process RPC endpoint. 414 func (n *Node) stopInProc() { 415 n.inprocHandler.Stop() 416 } 417 418 // Wait blocks until the node is closed. 419 func (n *Node) Wait() { 420 <-n.stop 421 } 422 423 // RegisterLifecycle registers the given Lifecycle on the node. 424 func (n *Node) RegisterLifecycle(lifecycle Lifecycle) { 425 n.lock.Lock() 426 defer n.lock.Unlock() 427 428 if n.state != initializingState { 429 panic("can't register lifecycle on running/stopped node") 430 } 431 if containsLifecycle(n.lifecycles, lifecycle) { 432 panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle)) 433 } 434 n.lifecycles = append(n.lifecycles, lifecycle) 435 } 436 437 // RegisterProtocols adds backend's protocols to the node's p2p server. 438 func (n *Node) RegisterProtocols(protocols []p2p.Protocol) { 439 n.lock.Lock() 440 defer n.lock.Unlock() 441 442 if n.state != initializingState { 443 panic("can't register protocols on running/stopped node") 444 } 445 n.server.Protocols = append(n.server.Protocols, protocols...) 446 } 447 448 // RegisterAPIs registers the APIs a service provides on the node. 449 func (n *Node) RegisterAPIs(apis []rpc.API) { 450 n.lock.Lock() 451 defer n.lock.Unlock() 452 453 if n.state != initializingState { 454 panic("can't register APIs on running/stopped node") 455 } 456 n.rpcAPIs = append(n.rpcAPIs, apis...) 457 } 458 459 // RegisterHandler mounts a handler on the given path on the canonical HTTP server. 460 // 461 // The name of the handler is shown in a log message when the HTTP server starts 462 // and should be a descriptive term for the service provided by the handler. 463 func (n *Node) RegisterHandler(name, path string, handler http.Handler) { 464 n.lock.Lock() 465 defer n.lock.Unlock() 466 467 if n.state != initializingState { 468 panic("can't register HTTP handler on running/stopped node") 469 } 470 471 n.http.mux.Handle(path, handler) 472 n.http.handlerNames[path] = name 473 } 474 475 // Attach creates an RPC client attached to an in-process API handler. 476 func (n *Node) Attach() (*rpc.Client, error) { 477 return rpc.DialInProc(n.inprocHandler), nil 478 } 479 480 // RPCHandler returns the in-process RPC request handler. 481 func (n *Node) RPCHandler() (*rpc.Server, error) { 482 n.lock.Lock() 483 defer n.lock.Unlock() 484 485 if n.state == closedState { 486 return nil, ErrNodeStopped 487 } 488 return n.inprocHandler, nil 489 } 490 491 // Config returns the configuration of node. 492 func (n *Node) Config() *Config { 493 return n.config 494 } 495 496 // Server retrieves the currently running P2P network layer. This method is meant 497 // only to inspect fields of the currently running server. Callers should not 498 // start or stop the returned server. 499 func (n *Node) Server() *p2p.Server { 500 n.lock.Lock() 501 defer n.lock.Unlock() 502 503 return n.server 504 } 505 506 // DataDir retrieves the current datadir used by the protocol stack. 507 // Deprecated: No files should be stored in this directory, use InstanceDir instead. 508 func (n *Node) DataDir() string { 509 return n.config.DataDir 510 } 511 512 // InstanceDir retrieves the instance directory used by the protocol stack. 513 func (n *Node) InstanceDir() string { 514 return n.config.instanceDir() 515 } 516 517 // AccountManager retrieves the account manager used by the protocol stack. 518 func (n *Node) AccountManager() *accounts.Manager { 519 return n.accman 520 } 521 522 // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. 523 func (n *Node) IPCEndpoint() string { 524 return n.ipc.endpoint 525 } 526 527 // HTTPEndpoint returns the URL of the HTTP server. Note that this URL does not 528 // contain the JSON-RPC path prefix set by HTTPPathPrefix. 529 func (n *Node) HTTPEndpoint() string { 530 return "http://" + n.http.listenAddr() 531 } 532 533 // WSEndpoint returns the current JSON-RPC over WebSocket endpoint. 534 func (n *Node) WSEndpoint() string { 535 if n.http.wsAllowed() { 536 return "ws://" + n.http.listenAddr() + n.http.wsConfig.prefix 537 } 538 return "ws://" + n.ws.listenAddr() + n.ws.wsConfig.prefix 539 } 540 541 // EventMux retrieves the event multiplexer used by all the network services in 542 // the current protocol stack. 543 func (n *Node) EventMux() *event.TypeMux { 544 return n.eventmux 545 } 546 547 // OpenDatabase opens an existing database with the given name (or creates one if no 548 // previous can be found) from within the node's instance directory. If the node is 549 // ephemeral, a memory database is returned. 550 func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) { 551 n.lock.Lock() 552 defer n.lock.Unlock() 553 if n.state == closedState { 554 return nil, ErrNodeStopped 555 } 556 557 var db ethdb.Database 558 var err error 559 if n.config.DataDir == "" { 560 db = rawdb.NewMemoryDatabase() 561 } else { 562 db, err = rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace, readonly) 563 } 564 565 if err == nil { 566 db = n.wrapDatabase(db) 567 } 568 return db, err 569 } 570 571 // OpenDatabaseWithFreezer opens an existing database with the given name (or 572 // creates one if no previous can be found) from within the node's data directory, 573 // also attaching a chain freezer to it that moves ancient chain data from the 574 // database to immutable append-only files. If the node is an ephemeral one, a 575 // memory database is returned. 576 func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string, readonly bool) (ethdb.Database, error) { 577 n.lock.Lock() 578 defer n.lock.Unlock() 579 if n.state == closedState { 580 return nil, ErrNodeStopped 581 } 582 583 var db ethdb.Database 584 var err error 585 if n.config.DataDir == "" { 586 db = rawdb.NewMemoryDatabase() 587 } else { 588 root := n.ResolvePath(name) 589 switch { 590 case freezer == "": 591 freezer = filepath.Join(root, "ancient") 592 case !filepath.IsAbs(freezer): 593 freezer = n.ResolvePath(freezer) 594 } 595 db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly) 596 } 597 598 if err == nil { 599 db = n.wrapDatabase(db) 600 } 601 return db, err 602 } 603 604 // ResolvePath returns the absolute path of a resource in the instance directory. 605 func (n *Node) ResolvePath(x string) string { 606 return n.config.ResolvePath(x) 607 } 608 609 // closeTrackingDB wraps the Close method of a database. When the database is closed by the 610 // service, the wrapper removes it from the node's database map. This ensures that Node 611 // won't auto-close the database if it is closed by the service that opened it. 612 type closeTrackingDB struct { 613 ethdb.Database 614 n *Node 615 } 616 617 func (db *closeTrackingDB) Close() error { 618 db.n.lock.Lock() 619 delete(db.n.databases, db) 620 db.n.lock.Unlock() 621 return db.Database.Close() 622 } 623 624 // wrapDatabase ensures the database will be auto-closed when Node is closed. 625 func (n *Node) wrapDatabase(db ethdb.Database) ethdb.Database { 626 wrapper := &closeTrackingDB{db, n} 627 n.databases[wrapper] = struct{}{} 628 return wrapper 629 } 630 631 // closeDatabases closes all open databases. 632 func (n *Node) closeDatabases() (errors []error) { 633 for db := range n.databases { 634 delete(n.databases, db) 635 if err := db.Database.Close(); err != nil { 636 errors = append(errors, err) 637 } 638 } 639 return errors 640 }