Skip to content

node-info, WebSocket-start, and WebSocket-stop endpoints diverge from the documented example output, parameter typing, and success semantics #35547

Description

@BenWhite713

1. admin_nodeInfo: admin_nodeInfo no longer populates protocols.eth.difficulty, leaving the documented fixed difficulty example unproducible

  • Statement: admin_nodeInfo no longer populates protocols.eth.difficulty, leaving the documented fixed difficulty example unproducible.
  • URL: https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-admin
  • Code location:
    • node/api.go:312-318

      go-ethereum/node/api.go

      Lines 312 to 318 in 81ab8b5

      func (api *adminAPI) NodeInfo() (*p2p.NodeInfo, error) {
      server := api.node.Server()
      if server == nil {
      return nil, ErrNodeStopped
      }
      return server.NodeInfo(), nil
      }
    • p2p/server.go:1046-1063

      go-ethereum/p2p/server.go

      Lines 1046 to 1063 in 81ab8b5

      Protocols: make(map[string]interface{}),
      }
      info.Ports.Discovery = node.UDP()
      info.Ports.Listener = node.TCP()
      info.ENR = node.String()
      // Gather all the running protocol infos (only once per protocol type)
      for _, proto := range srv.Protocols {
      if _, ok := info.Protocols[proto.Name]; !ok {
      nodeInfo := interface{}("unknown")
      if query := proto.NodeInfo; query != nil {
      nodeInfo = proto.NodeInfo()
      }
      info.Protocols[proto.Name] = nodeInfo
      }
      }
      return info
      }
  • Description: Root cause — adminAPI.NodeInfo simply forwards to Server.NodeInfo(), which builds info.Protocols generically by calling each registered protocol's NodeInfo() callback (proto.NodeInfo()) and storing whatever value that callback returns, or the literal string "unknown" if the protocol registered no callback. Whether an eth protocol handler still reports a difficulty field is entirely up to that handler's own NodeInfo implementation; post-merge chains have no meaningful proof-of-work difficulty to report, so the field is no longer populated, making the documentation's fixed example value (17179869184) unreproducible on current networks.
  • Method: admin_nodeInfo

2. admin_startWS: admin_startWS uses a *int port decoded from a JSON number, not the documented *rpc.HexNumber quantity

  • Statement: admin_startWS uses a *int port decoded from a JSON number, not the documented *rpc.HexNumber quantity.
  • URL: https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-admin
  • Code location:
    • node/api.go:238-255

      go-ethereum/node/api.go

      Lines 238 to 255 in 81ab8b5

      func (api *adminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
      api.node.lock.Lock()
      defer api.node.lock.Unlock()
      // Determine host and port.
      if host == nil {
      h := DefaultWSHost
      if api.node.config.WSHost != "" {
      h = api.node.config.WSHost
      }
      host = &h
      }
      if port == nil {
      port = &api.node.config.WSPort
      }
      // Determine config.
      config := wsConfig{
    • node/node.go:507-516

      go-ethereum/node/node.go

      Lines 507 to 516 in 81ab8b5

      func (n *Node) wsServerForPort(port int, authenticated bool) *httpServer {
      httpServer, wsServer := n.http, n.ws
      if authenticated {
      httpServer, wsServer = n.httpAuth, n.wsAuth
      }
      if n.config.HTTPHost == "" || httpServer.port == port {
      return httpServer
      }
      return wsServer
      }
  • Description: Root cause — adminAPI.StartWS(host *string, port *int, allowedOrigins *string, apis *string) declares port as a plain *int, which the standard JSON-RPC codec decodes from an ordinary JSON number (and defaults to api.node.config.WSPort when omitted); no *rpc.HexNumber type — a hex-string-decoding wrapper used elsewhere in the legacy RPC layer — appears anywhere in this handler's signature or in the wsServerForPort lookup that consumes the resolved port. The documented hex-quantity type therefore describes a decoding rule this parameter does not follow.
  • Method: admin_startWS

3. admin_stopWS: admin_stopWS returns true after invoking stop routines even when no WebSocket endpoint was actually closed

  • Statement: admin_stopWS returns true after invoking stop routines even when no WebSocket endpoint was actually closed.
  • URL: https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-admin
  • Code location:
    • node/api.go:294-298

      go-ethereum/node/api.go

      Lines 294 to 298 in 81ab8b5

      func (api *adminAPI) StopWS() (bool, error) {
      api.node.http.stopWS()
      api.node.ws.stop()
      return true, nil
      }
    • node/rpcstack.go:633-645
      func (is *ipcServer) stop() error {
      is.mu.Lock()
      defer is.mu.Unlock()
      if is.listener == nil {
      return nil // not running
      }
      err := is.listener.Close()
      is.srv.Stop()
      is.listener, is.srv = nil, nil
      is.log.Info("IPC endpoint closed", "url", is.endpoint)
      return err
      }
  • Description: Root cause — adminAPI.StopWS unconditionally calls api.node.http.stopWS() and api.node.ws.stop() and then return true, nil, without inspecting either call's return value or otherwise checking whether a WebSocket listener was actually running and got closed; the underlying stop() implementations themselves treat "not running" as a no-op success (if is.listener == nil { return nil }), so there is no signal anywhere in the chain that would make StopWS report anything other than unconditional success, even when there was nothing to stop.
  • Method: admin_stopWS

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions