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