pollMaxHeight() polls all peers for their local MaxHeight and totalVDFIterations for a specific chainId NOTE: unlike other P2P transmissions - RequestBlock enforces a minimum reputation on `mustConnects` to ensure a byzantine validator cannot cause syncing issues above max_height
(backoff int)
| 624 | // NOTE: unlike other P2P transmissions - RequestBlock enforces a minimum reputation on `mustConnects` |
| 625 | // to ensure a byzantine validator cannot cause syncing issues above max_height |
| 626 | func (c *Controller) pollMaxHeight(backoff int) (max, minVDF uint64, syncingPeerList []string) { |
| 627 | // initialize max height and minimumVDFIterations to -1 |
| 628 | maxHeight, minimumVDFIterations := -1, -1 |
| 629 | // empty inbox to start fresh |
| 630 | c.emptyInbox(Block) |
| 631 | // log the initialization |
| 632 | c.log.Infof("Polling chain peers for max height") |
| 633 | // initialize the syncing peers list |
| 634 | syncingPeerList = make([]string, 0) |
| 635 | // ask only for 'max height' from all peers |
| 636 | go c.RequestBlock(true) |
| 637 | // debug log the current status |
| 638 | c.log.Debug("Waiting for peer max heights") |
| 639 | // loop until timeout case |
| 640 | for { |
| 641 | // block until one of the cases is satisfied |
| 642 | select { |
| 643 | // handle the inbound message |
| 644 | case m := <-c.P2P.Inbox(Block): |
| 645 | // unmarshal the inbound message payload as a block message |
| 646 | blockMessage := new(lib.BlockMessage) |
| 647 | if err := lib.Unmarshal(m.Message, blockMessage); err != nil { |
| 648 | // log the unexpected behavior |
| 649 | c.log.Warnf("Invalid block message response from %s", lib.BytesToTruncatedString(m.Sender.Address.PublicKey)) |
| 650 | // slash the peer reputation |
| 651 | c.P2P.ChangeReputation(m.Sender.Address.PublicKey, p2p.InvalidMsgRep) |
| 652 | // reset loop |
| 653 | continue |
| 654 | } |
| 655 | // log the receipt of the block message |
| 656 | c.log.Debugf("Received a block response from peer %s with max height at %d", lib.BytesToTruncatedString(m.Sender.Address.PublicKey), maxHeight) |
| 657 | // don't listen to any peers below the minimumVDFIterations |
| 658 | if int(blockMessage.TotalVdfIterations) < minimumVDFIterations { |
| 659 | // log the status |
| 660 | c.log.Warnf("Ignoring below the minimum vdf iterations") |
| 661 | // reset loop |
| 662 | continue |
| 663 | } |
| 664 | // update the minimum vdf iterations |
| 665 | minimumVDFIterations = int(blockMessage.TotalVdfIterations) |
| 666 | // add to syncing peer list |
| 667 | syncingPeerList = append(syncingPeerList, lib.BytesToString(m.Sender.Address.PublicKey)) |
| 668 | // if the maximum height is exceeded, update the max height |
| 669 | if int(blockMessage.MaxHeight) > maxHeight { |
| 670 | // reset syncing variables if peer exceeds the previous minimum vdf iterations |
| 671 | maxHeight = int(blockMessage.MaxHeight) |
| 672 | } |
| 673 | // if a timeout occurred |
| 674 | case <-time.After(p2p.PollMaxHeightTimeoutS * time.Second * time.Duration(backoff)): |
| 675 | // if the maximum height or vdf iterations remains unset |
| 676 | if maxHeight == -1 || minimumVDFIterations == -1 { |
| 677 | // log the status of no heights received |
| 678 | c.log.Warn("No heights received from peers. Trying again") |
| 679 | // try again with greater backoff |
| 680 | return c.pollMaxHeight(backoff + 1) |
| 681 | } |
| 682 | // log the max height among the peers |
| 683 | c.log.Debugf("Peer max height is %d 🔝", maxHeight) |
no test coverage detected