code: func (p *Peer) PushGetHeadersMsg(locator blockchain.BlockLocator, stopHash *chainhash.Hash) error {
  	// Extract the begin hash from the block locator, if one was specified,
  	// to use for filtering duplicate getheaders requests.
  	var beginHash *chainhash.Hash
  	if len(locator) > 0 {
  		beginHash = locator[0]
  	}
  
  	// Filter duplicate getheaders requests.
  	p.prevGetHdrsMtx.Lock()
  	isDuplicate := p.prevGetHdrsStop != nil && p.prevGetHdrsBegin != nil &&
  		beginHash != nil && stopHash.IsEqual(p.prevGetHdrsStop) &&
  		beginHash.IsEqual(p.prevGetHdrsBegin)
  	p.prevGetHdrsMtx.Unlock()
  
  	if isDuplicate {
  		log.Tracef("Filtering duplicate [getheaders] with begin hash %v",
  			beginHash)
  		return nil
  	}
  
  	// Construct the getheaders request and queue it to be sent.
  	msg := wire.NewMsgGetHeaders()
  	msg.HashStop = *stopHash
  	for _, hash := range locator {
  		err := msg.AddBlockLocatorHash(hash)
  		if err != nil {
  			return err
  		}
  	}
  	p.QueueMessage(msg, nil)
  
  	// Update the previous getheaders request information for filtering
  	// duplicates.
  	p.prevGetHdrsMtx.Lock()
  	p.prevGetHdrsBegin = beginHash
  	p.prevGetHdrsStop = stopHash
  	p.prevGetHdrsMtx.Unlock()
  	return nil
  }
docs: // PushGetHeadersMsg sends a getblocks message for the provided block locator
  // and stop hash.  It will ignore back-to-back duplicate requests.
  //
  // This function is safe for concurrent access.