Start Server

Start Server

The Start function initializes and starts the server, setting up the necessary components for peer-to-peer communication.
Steps:
  1. Locking and Checking Running State:
    1. starts by acquiring a lock to ensure thread safety. It then checks if the server is already running, returning an error if it is.
  1. Setting Up Logging and Clock:
    1. The logging mechanism and clock are initialized. If NoDial is set to true and ListenAddr is not specified, a warning is logged indicating the server won't be able to dial or listen.
  1. Warn if the server is neither to dial or listen:
  1. Static Fields Initialization:
    1. Several channels and function hooks are initialized. A private key is mandatory, and if not set, an error is returned.
  1. Setup Local Node:
    1. setupLocalNode initializes the local node, setting its attributes and preparing it for operation.
  1. Setup Port Mapping:
    1. setupPortMapping configures the port mapping for NAT. Port mapping helps local node to predict its external IP, which helps other remote nodes to send message to it successfully.
  1. Setup Listening:
    1. If a listening address is provided, setupListening starts the TCP listener. Listening process listens dial message from remote nodes, performs RLPx and Protocol handshake with remote nodes. RLPx handshake help two nodes exchange shared secret to exchange message with security. Protocol handshake let two nodes know their matched sub protocols which is to be performed between. After those handshakes have suceeded, two nodes become peers of each other and begin performing sub protocols.
  1. Setup Discovery:
    1. setupDiscovery initializes the discovery mechanisms for finding peers. This help nodes find enough nodes in the network, maintain a connected and resilient distributed network.
  1. Setup Dial Scheduler:
    1. This sets up the scheduler responsible for managing outbound connections. It dials nodes found in discovery process, try to establish protocol-level connection with them.
  1. Run Main Loop:
    1. The main server loop (run) is started in a new goroutine. loopWG is used to track the goroutine's lifecycle. Main loop is responsible for managing peer connections and orchestrating the server's lifecycle. For example, when local node has finished handshakes with remote node, listening process sends the corresponding connection to the remote node to the main loop, which performs several checks and adds the remote node to the peer list, then starts perform sub protocols with the peer.
/// ---p2p/server.go--- // Start starts running the server. // Servers can not be re-used after stopping. func (srv *Server) Start() (err error) { // Locking and State Check: srv.lock.Lock() defer srv.lock.Unlock() if srv.running { return errors.New("server already running") } srv.running = true // Setting Up Logging and Clock: srv.log = srv.Logger if srv.log == nil { srv.log = log.Root() } if srv.clock == nil { srv.clock = mclock.System{} } // Warn if the server is neither to dial or listen: if srv.NoDial && srv.ListenAddr == "" { srv.log.Warn("P2P server will be useless, neither dialing nor listening") } // Static Fields Initialization: // static fields if srv.PrivateKey == nil { return errors.New("Server.PrivateKey must be set to a non-nil key") } if srv.newTransport == nil { srv.newTransport = newRLPX } if srv.listenFunc == nil { srv.listenFunc = net.Listen } srv.quit = make(chan struct{}) srv.delpeer = make(chan peerDrop) srv.checkpointPostHandshake = make(chan *conn) srv.checkpointAddPeer = make(chan *conn) srv.addtrusted = make(chan *enode.Node) srv.removetrusted = make(chan *enode.Node) srv.peerOp = make(chan peerOpFunc) srv.peerOpDone = make(chan struct{}) // Setup Local Node: if err := srv.setupLocalNode(); err != nil { return err } // Setup Port Mapping: srv.setupPortMapping() // Setup Listening: if srv.ListenAddr != "" { if err := srv.setupListening(); err != nil { return err } } // Setup Discovery: if err := srv.setupDiscovery(); err != nil { return err } // Setup Dial Scheduler: srv.setupDialScheduler() // Run Main Loop: srv.loopWG.Add(1) go srv.run() return nil }