Sync() downloads the blockchain from peers until 'synced' to the latest 'height' 1) Get the height and begin block params from the state_machine 2) Get peer max_height from P2P 3) Fill a queue of blocks by requesting them from randomly chosen peers 4) When available, process next block from queue 5)
()
| 67 | // 7) Do this until reach the max-peer-height |
| 68 | // 8) Stay on top by listening to incoming cert messages |
| 69 | func (c *Controller) Sync() { |
| 70 | // log the initialization of the syncing process |
| 71 | c.log.Infof("Sync started 🔄 for committee %d", c.Config.ChainId) |
| 72 | // set the Controller as 'syncing' |
| 73 | c.isSyncing.Store(true) |
| 74 | // check if node is alone in the validator set |
| 75 | if c.singleNodeNetwork() && len(c.checkpoints) == 0 { |
| 76 | // complete syncing |
| 77 | c.finishSyncing() |
| 78 | // exit |
| 79 | return |
| 80 | } |
| 81 | // Find the height the FSM is expecting to receive next |
| 82 | fsmHeight := c.FSM.Height() |
| 83 | // queue contains block requests either in-flight or completed |
| 84 | queue := map[uint64]blockSyncRequest{} |
| 85 | // How often to send block requests to maintain the queue |
| 86 | requestTicker := time.NewTicker(blockRequestInterval) |
| 87 | defer requestTicker.Stop() |
| 88 | // Get an initial max height, min vdf iterations and syncing peers |
| 89 | maxHeight, minVDFIterations, _ := c.pollMaxHeight(1) |
| 90 | c.log.Infof("Starting sync 🔄 at height %d", fsmHeight) |
| 91 | // Create a limiter to prevent peers from disconnecting and slashing rep |
| 92 | limiter := lib.NewLimiter(p2p.MaxBlockReqPerWindow*rateScaleFactor, c.P2P.MaxPossiblePeers()*p2p.MaxBlockReqPerWindow, p2p.BlockReqWindowS, "SYNC", c.log) |
| 93 | |
| 94 | // Loop until the sync is complete |
| 95 | // The purpose is to keep the queue full and hand the next block to the FSM |
| 96 | // - List of current peers queried from P2P module |
| 97 | // - Block requests are sent to a peer if there is room available in the queue |
| 98 | // - Peers are chosen randomly from ones which are not rate-limited |
| 99 | // - Block responses are verified and given to the FSM in the expected order |
| 100 | for !c.syncingDone(maxHeight, minVDFIterations) { |
| 101 | select { |
| 102 | case <-limiter.TimeToReset(): |
| 103 | limiter.Reset() |
| 104 | case <-requestTicker.C: |
| 105 | // Get current chain height |
| 106 | fsmHeight := c.FSM.Height() |
| 107 | // Get an updated list of available peers |
| 108 | peers, _, _ := c.P2P.PeerSet.GetAllInfos() |
| 109 | // Update syncing peers list |
| 110 | syncingPeers := make([]string, len(peers)) |
| 111 | for _, peer := range peers { |
| 112 | syncingPeers = append(syncingPeers, lib.BytesToString(peer.Address.PublicKey)) |
| 113 | } |
| 114 | // Calculate the height to stop at when updating queue |
| 115 | stopHeight := min(fsmHeight+blockSyncQueueSize, maxHeight) |
| 116 | // Send block requests for any missing heights in the queue |
| 117 | c.sendBlockRequests(fsmHeight, stopHeight, queue, limiter, syncingPeers) |
| 118 | case msg := <-c.P2P.Inbox(Block): |
| 119 | // verify the response |
| 120 | blockMsg, height := c.verifyResponse(msg, queue) |
| 121 | // Update queued request with this response |
| 122 | if blockMsg != nil { |
| 123 | c.log.Debugf("Received height %d from %s", height, lib.BytesToTruncatedString(msg.Sender.Address.PublicKey)) |
| 124 | // find the queued request for this height |
| 125 | // verifyResponse() confirms this height is present in the queue |
| 126 | req := queue[height] |
no test coverage detected