美文网首页区块链研习社区块链研究
btcd 源码分析系列 - 1 - 启动分析

btcd 源码分析系列 - 1 - 启动分析

作者: tpkeeper | 来源:发表于2019-09-28 08:43 被阅读0次

参考:btcd

主启动顺序

main函数位于btcd.go,此处省略了辅助功能的服务(profile等)

  1. loadconfig() 加载配置
  2. doUpgrades() 升级操作
  3. loadBlockDB() 加载数据库
  4. server.start() 启动server
func btcdMain(serverChan chan<- *server) error {
    // Load configuration and parse command line.  This function also
    // initializes logging and configures it accordingly.
    tcfg, _, err := loadConfig()
    if err != nil {
        return err
    }
    cfg = tcfg
    defer func() {
        if logRotator != nil {
            logRotator.Close()
        }
    }()


    // Load the block database.
    db, err := loadBlockDB()
    if err != nil {
        btcdLog.Errorf("%v", err)
        return err
    }
    defer func() {
        // Ensure the database is sync'd and closed on shutdown.
        btcdLog.Infof("Gracefully shutting down the database...")
        db.Close()
    }()

    
    // Create server and start it.
    server, err := newServer(cfg.Listeners, db, activeNetParams.Params,
        interrupt)
    if err != nil {
        // TODO: this logging could do with some beautifying.
        btcdLog.Errorf("Unable to start server on %v: %v",
            cfg.Listeners, err)
        return err
    }
    defer func() {
        btcdLog.Infof("Gracefully shutting down the server...")
        server.Stop()
        server.WaitForShutdown()
        srvrLog.Infof("Server shutdown complete")
    }()
    server.Start()
    if serverChan != nil {
        serverChan <- server
    }

    // Wait until the interrupt signal is received from an OS signal or
    // shutdown is requested through one of the subsystems such as the RPC
    // server.
    <-interrupt
    return nil
}

server启动顺序

start()函数实现位于server.go

  1. peerHandler() p2p服务,用于处理节点间的同步信息 端口 :12008
  2. rpcServer.Start() rpcServer,用于处理客户端的rpc请求 端口:12009
  3. cpuMiner.Start() 用于挖矿服务
// Start begins accepting connections from peers.
func (s *server) Start() {
    // Already started?
    if atomic.AddInt32(&s.started, 1) != 1 {
        return
    }

    srvrLog.Trace("Starting server")

    // Server startup time. Used for the uptime command for uptime calculation.
    s.startupTime = time.Now().Unix()

    // Start the peer handler which in turn starts the address and block
    // managers.
    s.wg.Add(1)
    go s.peerHandler()

    if s.nat != nil {
        s.wg.Add(1)
        go s.upnpUpdateThread()
    }

    if !cfg.DisableRPC {
        s.wg.Add(1)

        // Start the rebroadcastHandler, which ensures user tx received by
        // the RPC server are rebroadcast until being included in a block.
        go s.rebroadcastHandler()

        s.rpcServer.Start()
    }

    // Start the CPU miner if generation is enabled.
    if cfg.Generate {
        s.cpuMiner.Start()
    }
}

peerHander启动顺序

peerHandler()函数实现位于server.go

  1. addrManager.Start() 处理节点信息地址
  2. syncManager.Start() 处理节点同步
  3. connManager.Start() 处理节点之间连接 (支持tcp/onion)
// peerHandler is used to handle peer operations such as adding and removing
// peers to and from the server, banning peers, and broadcasting messages to
// peers.  It must be run in a goroutine.

func (s *server) peerHandler() {
    // Start the address manager and sync manager, both of which are needed
    // by peers.  This is done here since their lifecycle is closely tied
    // to this handler and rather than adding more channels to sychronize
    // things, it's easier and slightly faster to simply start and stop them
    // in this handler.
    
    s.addrManager.Start()
    s.syncManager.Start()

    srvrLog.Tracef("Starting peer handler")

    state := &peerState{
        inboundPeers:    make(map[int32]*serverPeer),
        persistentPeers: make(map[int32]*serverPeer),
        outboundPeers:   make(map[int32]*serverPeer),
        banned:          make(map[string]time.Time),
        outboundGroups:  make(map[string]int),
    }

    if !cfg.DisableDNSSeed {
        // Add peers discovered through DNS to the address manager.
        connmgr.SeedFromDNS(activeNetParams.Params, defaultRequiredServices,
            btcdLookup, func(addrs []*wire.NetAddress) {
                // Bitcoind uses a lookup of the dns seeder here. This
                // is rather strange since the values looked up by the
                // DNS seed lookups will vary quite a lot.
                // to replicate this behaviour we put all addresses as
                // having come from the first one.
                s.addrManager.AddAddresses(addrs, addrs[0])
            })
    }
    go s.connManager.Start()
}

rpcServer启动顺序

rpcServer.Start()函数实现位于rpcserver.go

  1. httpServer.serve() 监听rpc请求(支持http/websocket)
// Start is used by server.go to start the rpc listener.
func (s *rpcServer) Start() {
    if atomic.AddInt32(&s.started, 1) != 1 {
        return
    }

    rpcsLog.Trace("Starting RPC server")
    rpcServeMux := http.NewServeMux()
    httpServer := &http.Server{
        Handler: rpcServeMux,

        // Timeout connections which don't complete the initial
        // handshake within the allowed timeframe.
        ReadTimeout: time.Second * rpcAuthTimeoutSeconds,
    }
    rpcServeMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Connection", "close")
        w.Header().Set("Content-Type", "application/json")
        r.Close = true

        // Limit the number of connections to max allowed.
        if s.limitConnections(w, r.RemoteAddr) {
            return
        }

        // Keep track of the number of connected clients.
        s.incrementClients()
        defer s.decrementClients()
        _, isAdmin, err := s.checkAuth(r, true)
        if err != nil {
            jsonAuthFail(w)
            return
        }

        // Read and respond to the request.
        s.jsonRPCRead(w, r, isAdmin)
    })

    // Websocket endpoint.
    rpcServeMux.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        authenticated, isAdmin, err := s.checkAuth(r, false)
        if err != nil {
            jsonAuthFail(w)
            return
        }

        // Attempt to upgrade the connection to a websocket connection
        // using the default size for read/write buffers.
        ws, err := websocket.Upgrade(w, r, nil, 0, 0)
        if err != nil {
            if _, ok := err.(websocket.HandshakeError); !ok {
                rpcsLog.Errorf("Unexpected websocket error: %v",
                    err)
            }
            http.Error(w, "400 Bad Request.", http.StatusBadRequest)
            return
        }
        s.WebsocketHandler(ws, r.RemoteAddr, authenticated, isAdmin)
    })

    for _, listener := range s.cfg.Listeners {
        s.wg.Add(1)
        go func(listener net.Listener) {
            rpcsLog.Infof("RPC server listening on %s", listener.Addr())
            httpServer.Serve(listener)
            rpcsLog.Tracef("RPC listener done for %s", listener.Addr())
            s.wg.Done()
        }(listener)
    }

    s.ntfnMgr.Start()
}

相关文章

网友评论

    本文标题:btcd 源码分析系列 - 1 - 启动分析

    本文链接:https://www.haomeiwen.com/subject/azyhyctx.html