node.go 22 KB

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