code: func (p *Peer) PushGetBlocksMsg(locator blockchain.BlockLocator, stopHash *chainhash.Hash) error {
  	// Extract the begin hash from the block locator, if one was specified,
  	// to use for filtering duplicate getblocks requests.
  	var beginHash *chainhash.Hash
  	if len(locator) > 0 {
  		beginHash = locator[0]
  	}
  
  	// Filter duplicate getblocks requests.
  	p.prevGetBlocksMtx.Lock()
  	isDuplicate := p.prevGetBlocksStop != nil && p.prevGetBlocksBegin != nil &&
  		beginHash != nil && stopHash.IsEqual(p.prevGetBlocksStop) &&
  		beginHash.IsEqual(p.prevGetBlocksBegin)
  	p.prevGetBlocksMtx.Unlock()
  
  	if isDuplicate {
  		log.Tracef("Filtering duplicate [getblocks] with begin "+
  			"hash %v, stop hash %v", beginHash, stopHash)
  		return nil
  	}
  
  	// Construct the getblocks request and queue it to be sent.
  	msg := wire.NewMsgGetBlocks(stopHash)
  	for _, hash := range locator {
  		err := msg.AddBlockLocatorHash(hash)
  		if err != nil {
  			return err
  		}
  	}
  	p.QueueMessage(msg, nil)
  
  	// Update the previous getblocks request information for filtering
  	// duplicates.
  	p.prevGetBlocksMtx.Lock()
  	p.prevGetBlocksBegin = beginHash
  	p.prevGetBlocksStop = stopHash
  	p.prevGetBlocksMtx.Unlock()
  	return nil
  }
docs: // PushGetBlocksMsg 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.