node.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  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. "errors"
  19. "fmt"
  20. "net"
  21. "os"
  22. "path/filepath"
  23. "reflect"
  24. "strings"
  25. "sync"
  26. "github.com/ethereum/go-ethereum/accounts"
  27. "github.com/ethereum/go-ethereum/ethdb"
  28. "github.com/ethereum/go-ethereum/event"
  29. "github.com/ethereum/go-ethereum/internal/debug"
  30. "github.com/ethereum/go-ethereum/log"
  31. "github.com/ethereum/go-ethereum/p2p"
  32. "github.com/ethereum/go-ethereum/rpc"
  33. "github.com/prometheus/prometheus/util/flock"
  34. )
  35. // Node is a container on which services can be registered.
  36. type Node struct {
  37. eventmux *event.TypeMux // Event multiplexer used between the services of a stack
  38. config *Config
  39. accman *accounts.Manager
  40. ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
  41. instanceDirLock flock.Releaser // prevents concurrent use of instance directory
  42. serverConfig p2p.Config
  43. server *p2p.Server // Currently running P2P networking layer
  44. serviceFuncs []ServiceConstructor // Service constructors (in dependency order)
  45. services map[reflect.Type]Service // Currently running services
  46. rpcAPIs []rpc.API // List of APIs currently provided by the node
  47. inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
  48. ipcEndpoint string // IPC endpoint to listen at (empty = IPC disabled)
  49. ipcListener net.Listener // IPC RPC listener socket to serve API requests
  50. ipcHandler *rpc.Server // IPC RPC request handler to process the API requests
  51. httpEndpoint string // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled)
  52. httpWhitelist []string // HTTP RPC modules to allow through this endpoint
  53. httpListener net.Listener // HTTP RPC listener socket to server API requests
  54. httpHandler *rpc.Server // HTTP RPC request handler to process the API requests
  55. wsEndpoint string // Websocket endpoint (interface + port) to listen at (empty = websocket disabled)
  56. wsListener net.Listener // Websocket RPC listener socket to server API requests
  57. wsHandler *rpc.Server // Websocket RPC request handler to process the API requests
  58. stop chan struct{} // Channel to wait for termination notifications
  59. lock sync.RWMutex
  60. }
  61. // New creates a new P2P node, ready for protocol registration.
  62. func New(conf *Config) (*Node, error) {
  63. // Copy config and resolve the datadir so future changes to the current
  64. // working directory don't affect the node.
  65. confCopy := *conf
  66. conf = &confCopy
  67. if conf.DataDir != "" {
  68. absdatadir, err := filepath.Abs(conf.DataDir)
  69. if err != nil {
  70. return nil, err
  71. }
  72. conf.DataDir = absdatadir
  73. }
  74. // Ensure that the instance name doesn't cause weird conflicts with
  75. // other files in the data directory.
  76. if strings.ContainsAny(conf.Name, `/\`) {
  77. return nil, errors.New(`Config.Name must not contain '/' or '\'`)
  78. }
  79. if conf.Name == datadirDefaultKeyStore {
  80. return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`)
  81. }
  82. if strings.HasSuffix(conf.Name, ".ipc") {
  83. return nil, errors.New(`Config.Name cannot end in ".ipc"`)
  84. }
  85. // Ensure that the AccountManager method works before the node has started.
  86. // We rely on this in cmd/geth.
  87. am, ephemeralKeystore, err := makeAccountManager(conf)
  88. if err != nil {
  89. return nil, err
  90. }
  91. // Note: any interaction with Config that would create/touch files
  92. // in the data directory or instance directory is delayed until Start.
  93. return &Node{
  94. accman: am,
  95. ephemeralKeystore: ephemeralKeystore,
  96. config: conf,
  97. serviceFuncs: []ServiceConstructor{},
  98. ipcEndpoint: conf.IPCEndpoint(),
  99. httpEndpoint: conf.HTTPEndpoint(),
  100. wsEndpoint: conf.WSEndpoint(),
  101. eventmux: new(event.TypeMux),
  102. }, nil
  103. }
  104. // Register injects a new service into the node's stack. The service created by
  105. // the passed constructor must be unique in its type with regard to sibling ones.
  106. func (n *Node) Register(constructor ServiceConstructor) error {
  107. n.lock.Lock()
  108. defer n.lock.Unlock()
  109. if n.server != nil {
  110. return ErrNodeRunning
  111. }
  112. n.serviceFuncs = append(n.serviceFuncs, constructor)
  113. return nil
  114. }
  115. // Start create a live P2P node and starts running it.
  116. func (n *Node) Start() error {
  117. n.lock.Lock()
  118. defer n.lock.Unlock()
  119. // Short circuit if the node's already running
  120. if n.server != nil {
  121. return ErrNodeRunning
  122. }
  123. if err := n.openDataDir(); err != nil {
  124. return err
  125. }
  126. // Initialize the p2p server. This creates the node key and
  127. // discovery databases.
  128. n.serverConfig = n.config.P2P
  129. n.serverConfig.PrivateKey = n.config.NodeKey()
  130. n.serverConfig.Name = n.config.NodeName()
  131. if n.serverConfig.StaticNodes == nil {
  132. n.serverConfig.StaticNodes = n.config.StaticNodes()
  133. }
  134. if n.serverConfig.TrustedNodes == nil {
  135. n.serverConfig.TrustedNodes = n.config.TrustedNodes()
  136. }
  137. if n.serverConfig.NodeDatabase == "" {
  138. n.serverConfig.NodeDatabase = n.config.NodeDB()
  139. }
  140. running := &p2p.Server{Config: n.serverConfig}
  141. log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name)
  142. // Otherwise copy and specialize the P2P configuration
  143. services := make(map[reflect.Type]Service)
  144. for _, constructor := range n.serviceFuncs {
  145. // Create a new context for the particular service
  146. ctx := &ServiceContext{
  147. config: n.config,
  148. services: make(map[reflect.Type]Service),
  149. EventMux: n.eventmux,
  150. AccountManager: n.accman,
  151. }
  152. for kind, s := range services { // copy needed for threaded access
  153. ctx.services[kind] = s
  154. }
  155. // Construct and save the service
  156. service, err := constructor(ctx)
  157. if err != nil {
  158. return err
  159. }
  160. kind := reflect.TypeOf(service)
  161. if _, exists := services[kind]; exists {
  162. return &DuplicateServiceError{Kind: kind}
  163. }
  164. services[kind] = service
  165. }
  166. // Gather the protocols and start the freshly assembled P2P server
  167. for _, service := range services {
  168. running.Protocols = append(running.Protocols, service.Protocols()...)
  169. }
  170. if err := running.Start(); err != nil {
  171. return convertFileLockError(err)
  172. }
  173. // Start each of the services
  174. started := []reflect.Type{}
  175. for kind, service := range services {
  176. // Start the next service, stopping all previous upon failure
  177. if err := service.Start(running); err != nil {
  178. for _, kind := range started {
  179. services[kind].Stop()
  180. }
  181. running.Stop()
  182. return err
  183. }
  184. // Mark the service started for potential cleanup
  185. started = append(started, kind)
  186. }
  187. // Lastly start the configured RPC interfaces
  188. if err := n.startRPC(services); err != nil {
  189. for _, service := range services {
  190. service.Stop()
  191. }
  192. running.Stop()
  193. return err
  194. }
  195. // Finish initializing the startup
  196. n.services = services
  197. n.server = running
  198. n.stop = make(chan struct{})
  199. return nil
  200. }
  201. func (n *Node) openDataDir() error {
  202. if n.config.DataDir == "" {
  203. return nil // ephemeral
  204. }
  205. instdir := filepath.Join(n.config.DataDir, n.config.name())
  206. if err := os.MkdirAll(instdir, 0700); err != nil {
  207. return err
  208. }
  209. // Lock the instance directory to prevent concurrent use by another instance as well as
  210. // accidental use of the instance directory as a database.
  211. release, _, err := flock.New(filepath.Join(instdir, "LOCK"))
  212. if err != nil {
  213. return convertFileLockError(err)
  214. }
  215. n.instanceDirLock = release
  216. return nil
  217. }
  218. // startRPC is a helper method to start all the various RPC endpoint during node
  219. // startup. It's not meant to be called at any time afterwards as it makes certain
  220. // assumptions about the state of the node.
  221. func (n *Node) startRPC(services map[reflect.Type]Service) error {
  222. // Gather all the possible APIs to surface
  223. apis := n.apis()
  224. for _, service := range services {
  225. apis = append(apis, service.APIs()...)
  226. }
  227. // Start the various API endpoints, terminating all in case of errors
  228. if err := n.startInProc(apis); err != nil {
  229. return err
  230. }
  231. if err := n.startIPC(apis); err != nil {
  232. n.stopInProc()
  233. return err
  234. }
  235. if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors); err != nil {
  236. n.stopIPC()
  237. n.stopInProc()
  238. return err
  239. }
  240. if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins); err != nil {
  241. n.stopHTTP()
  242. n.stopIPC()
  243. n.stopInProc()
  244. return err
  245. }
  246. // All API endpoints started successfully
  247. n.rpcAPIs = apis
  248. return nil
  249. }
  250. // startInProc initializes an in-process RPC endpoint.
  251. func (n *Node) startInProc(apis []rpc.API) error {
  252. // Register all the APIs exposed by the services
  253. handler := rpc.NewServer()
  254. for _, api := range apis {
  255. if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
  256. return err
  257. }
  258. log.Debug(fmt.Sprintf("InProc registered %T under '%s'", api.Service, api.Namespace))
  259. }
  260. n.inprocHandler = handler
  261. return nil
  262. }
  263. // stopInProc terminates the in-process RPC endpoint.
  264. func (n *Node) stopInProc() {
  265. if n.inprocHandler != nil {
  266. n.inprocHandler.Stop()
  267. n.inprocHandler = nil
  268. }
  269. }
  270. // startIPC initializes and starts the IPC RPC endpoint.
  271. func (n *Node) startIPC(apis []rpc.API) error {
  272. // Short circuit if the IPC endpoint isn't being exposed
  273. if n.ipcEndpoint == "" {
  274. return nil
  275. }
  276. // Register all the APIs exposed by the services
  277. handler := rpc.NewServer()
  278. for _, api := range apis {
  279. if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
  280. return err
  281. }
  282. log.Debug(fmt.Sprintf("IPC registered %T under '%s'", api.Service, api.Namespace))
  283. }
  284. // All APIs registered, start the IPC listener
  285. var (
  286. listener net.Listener
  287. err error
  288. )
  289. if listener, err = rpc.CreateIPCListener(n.ipcEndpoint); err != nil {
  290. return err
  291. }
  292. go func() {
  293. log.Info(fmt.Sprintf("IPC endpoint opened: %s", n.ipcEndpoint))
  294. for {
  295. conn, err := listener.Accept()
  296. if err != nil {
  297. // Terminate if the listener was closed
  298. n.lock.RLock()
  299. closed := n.ipcListener == nil
  300. n.lock.RUnlock()
  301. if closed {
  302. return
  303. }
  304. // Not closed, just some error; report and continue
  305. log.Error(fmt.Sprintf("IPC accept failed: %v", err))
  306. continue
  307. }
  308. go handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions)
  309. }
  310. }()
  311. // All listeners booted successfully
  312. n.ipcListener = listener
  313. n.ipcHandler = handler
  314. return nil
  315. }
  316. // stopIPC terminates the IPC RPC endpoint.
  317. func (n *Node) stopIPC() {
  318. if n.ipcListener != nil {
  319. n.ipcListener.Close()
  320. n.ipcListener = nil
  321. log.Info(fmt.Sprintf("IPC endpoint closed: %s", n.ipcEndpoint))
  322. }
  323. if n.ipcHandler != nil {
  324. n.ipcHandler.Stop()
  325. n.ipcHandler = nil
  326. }
  327. }
  328. // startHTTP initializes and starts the HTTP RPC endpoint.
  329. func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string) error {
  330. // Short circuit if the HTTP endpoint isn't being exposed
  331. if endpoint == "" {
  332. return nil
  333. }
  334. // Generate the whitelist based on the allowed modules
  335. whitelist := make(map[string]bool)
  336. for _, module := range modules {
  337. whitelist[module] = true
  338. }
  339. // Register all the APIs exposed by the services
  340. handler := rpc.NewServer()
  341. for _, api := range apis {
  342. if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
  343. if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
  344. return err
  345. }
  346. log.Debug(fmt.Sprintf("HTTP registered %T under '%s'", api.Service, api.Namespace))
  347. }
  348. }
  349. // All APIs registered, start the HTTP listener
  350. var (
  351. listener net.Listener
  352. err error
  353. )
  354. if listener, err = net.Listen("tcp", endpoint); err != nil {
  355. return err
  356. }
  357. go rpc.NewHTTPServer(cors, handler).Serve(listener)
  358. log.Info(fmt.Sprintf("HTTP endpoint opened: http://%s", endpoint))
  359. // All listeners booted successfully
  360. n.httpEndpoint = endpoint
  361. n.httpListener = listener
  362. n.httpHandler = handler
  363. return nil
  364. }
  365. // stopHTTP terminates the HTTP RPC endpoint.
  366. func (n *Node) stopHTTP() {
  367. if n.httpListener != nil {
  368. n.httpListener.Close()
  369. n.httpListener = nil
  370. log.Info(fmt.Sprintf("HTTP endpoint closed: http://%s", n.httpEndpoint))
  371. }
  372. if n.httpHandler != nil {
  373. n.httpHandler.Stop()
  374. n.httpHandler = nil
  375. }
  376. }
  377. // startWS initializes and starts the websocket RPC endpoint.
  378. func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string) error {
  379. // Short circuit if the WS endpoint isn't being exposed
  380. if endpoint == "" {
  381. return nil
  382. }
  383. // Generate the whitelist based on the allowed modules
  384. whitelist := make(map[string]bool)
  385. for _, module := range modules {
  386. whitelist[module] = true
  387. }
  388. // Register all the APIs exposed by the services
  389. handler := rpc.NewServer()
  390. for _, api := range apis {
  391. if whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
  392. if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
  393. return err
  394. }
  395. log.Debug(fmt.Sprintf("WebSocket registered %T under '%s'", api.Service, api.Namespace))
  396. }
  397. }
  398. // All APIs registered, start the HTTP listener
  399. var (
  400. listener net.Listener
  401. err error
  402. )
  403. if listener, err = net.Listen("tcp", endpoint); err != nil {
  404. return err
  405. }
  406. go rpc.NewWSServer(wsOrigins, handler).Serve(listener)
  407. log.Info(fmt.Sprintf("WebSocket endpoint opened: ws://%s", endpoint))
  408. // All listeners booted successfully
  409. n.wsEndpoint = endpoint
  410. n.wsListener = listener
  411. n.wsHandler = handler
  412. return nil
  413. }
  414. // stopWS terminates the websocket RPC endpoint.
  415. func (n *Node) stopWS() {
  416. if n.wsListener != nil {
  417. n.wsListener.Close()
  418. n.wsListener = nil
  419. log.Info(fmt.Sprintf("WebSocket endpoint closed: ws://%s", n.wsEndpoint))
  420. }
  421. if n.wsHandler != nil {
  422. n.wsHandler.Stop()
  423. n.wsHandler = nil
  424. }
  425. }
  426. // Stop terminates a running node along with all it's services. In the node was
  427. // not started, an error is returned.
  428. func (n *Node) Stop() error {
  429. n.lock.Lock()
  430. defer n.lock.Unlock()
  431. // Short circuit if the node's not running
  432. if n.server == nil {
  433. return ErrNodeStopped
  434. }
  435. // Terminate the API, services and the p2p server.
  436. n.stopWS()
  437. n.stopHTTP()
  438. n.stopIPC()
  439. n.rpcAPIs = nil
  440. failure := &StopError{
  441. Services: make(map[reflect.Type]error),
  442. }
  443. for kind, service := range n.services {
  444. if err := service.Stop(); err != nil {
  445. failure.Services[kind] = err
  446. }
  447. }
  448. n.server.Stop()
  449. n.services = nil
  450. n.server = nil
  451. // Release instance directory lock.
  452. if n.instanceDirLock != nil {
  453. if err := n.instanceDirLock.Release(); err != nil {
  454. log.Error("Can't release datadir lock", "err", err)
  455. }
  456. n.instanceDirLock = nil
  457. }
  458. // unblock n.Wait
  459. close(n.stop)
  460. // Remove the keystore if it was created ephemerally.
  461. var keystoreErr error
  462. if n.ephemeralKeystore != "" {
  463. keystoreErr = os.RemoveAll(n.ephemeralKeystore)
  464. }
  465. if len(failure.Services) > 0 {
  466. return failure
  467. }
  468. if keystoreErr != nil {
  469. return keystoreErr
  470. }
  471. return nil
  472. }
  473. // Wait blocks the thread until the node is stopped. If the node is not running
  474. // at the time of invocation, the method immediately returns.
  475. func (n *Node) Wait() {
  476. n.lock.RLock()
  477. if n.server == nil {
  478. n.lock.RUnlock()
  479. return
  480. }
  481. stop := n.stop
  482. n.lock.RUnlock()
  483. <-stop
  484. }
  485. // Restart terminates a running node and boots up a new one in its place. If the
  486. // node isn't running, an error is returned.
  487. func (n *Node) Restart() error {
  488. if err := n.Stop(); err != nil {
  489. return err
  490. }
  491. if err := n.Start(); err != nil {
  492. return err
  493. }
  494. return nil
  495. }
  496. // Attach creates an RPC client attached to an in-process API handler.
  497. func (n *Node) Attach() (*rpc.Client, error) {
  498. n.lock.RLock()
  499. defer n.lock.RUnlock()
  500. if n.server == nil {
  501. return nil, ErrNodeStopped
  502. }
  503. return rpc.DialInProc(n.inprocHandler), nil
  504. }
  505. // Server retrieves the currently running P2P network layer. This method is meant
  506. // only to inspect fields of the currently running server, life cycle management
  507. // should be left to this Node entity.
  508. func (n *Node) Server() *p2p.Server {
  509. n.lock.RLock()
  510. defer n.lock.RUnlock()
  511. return n.server
  512. }
  513. // Service retrieves a currently running service registered of a specific type.
  514. func (n *Node) Service(service interface{}) error {
  515. n.lock.RLock()
  516. defer n.lock.RUnlock()
  517. // Short circuit if the node's not running
  518. if n.server == nil {
  519. return ErrNodeStopped
  520. }
  521. // Otherwise try to find the service to return
  522. element := reflect.ValueOf(service).Elem()
  523. if running, ok := n.services[element.Type()]; ok {
  524. element.Set(reflect.ValueOf(running))
  525. return nil
  526. }
  527. return ErrServiceUnknown
  528. }
  529. // DataDir retrieves the current datadir used by the protocol stack.
  530. // Deprecated: No files should be stored in this directory, use InstanceDir instead.
  531. func (n *Node) DataDir() string {
  532. return n.config.DataDir
  533. }
  534. // InstanceDir retrieves the instance directory used by the protocol stack.
  535. func (n *Node) InstanceDir() string {
  536. return n.config.instanceDir()
  537. }
  538. // AccountManager retrieves the account manager used by the protocol stack.
  539. func (n *Node) AccountManager() *accounts.Manager {
  540. return n.accman
  541. }
  542. // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
  543. func (n *Node) IPCEndpoint() string {
  544. return n.ipcEndpoint
  545. }
  546. // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
  547. func (n *Node) HTTPEndpoint() string {
  548. return n.httpEndpoint
  549. }
  550. // WSEndpoint retrieves the current WS endpoint used by the protocol stack.
  551. func (n *Node) WSEndpoint() string {
  552. return n.wsEndpoint
  553. }
  554. // EventMux retrieves the event multiplexer used by all the network services in
  555. // the current protocol stack.
  556. func (n *Node) EventMux() *event.TypeMux {
  557. return n.eventmux
  558. }
  559. // OpenDatabase opens an existing database with the given name (or creates one if no
  560. // previous can be found) from within the node's instance directory. If the node is
  561. // ephemeral, a memory database is returned.
  562. func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) {
  563. if n.config.DataDir == "" {
  564. return ethdb.NewMemDatabase()
  565. }
  566. return ethdb.NewLDBDatabase(n.config.resolvePath(name), cache, handles)
  567. }
  568. // ResolvePath returns the absolute path of a resource in the instance directory.
  569. func (n *Node) ResolvePath(x string) string {
  570. return n.config.resolvePath(x)
  571. }
  572. // apis returns the collection of RPC descriptors this node offers.
  573. func (n *Node) apis() []rpc.API {
  574. return []rpc.API{
  575. {
  576. Namespace: "admin",
  577. Version: "1.0",
  578. Service: NewPrivateAdminAPI(n),
  579. }, {
  580. Namespace: "admin",
  581. Version: "1.0",
  582. Service: NewPublicAdminAPI(n),
  583. Public: true,
  584. }, {
  585. Namespace: "debug",
  586. Version: "1.0",
  587. Service: debug.Handler,
  588. }, {
  589. Namespace: "debug",
  590. Version: "1.0",
  591. Service: NewPublicDebugAPI(n),
  592. Public: true,
  593. }, {
  594. Namespace: "web3",
  595. Version: "1.0",
  596. Service: NewPublicWeb3API(n),
  597. Public: true,
  598. },
  599. }
  600. }