github.com/btcsuite/btcd@v0.24.0/wire/msggetdata.go (about)

     1  // Copyright (c) 2013-2015 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  )
    11  
    12  // MsgGetData implements the Message interface and represents a bitcoin
    13  // getdata message.  It is used to request data such as blocks and transactions
    14  // from another peer.  It should be used in response to the inv (MsgInv) message
    15  // to request the actual data referenced by each inventory vector the receiving
    16  // peer doesn't already have.  Each message is limited to a maximum number of
    17  // inventory vectors, which is currently 50,000.  As a result, multiple messages
    18  // must be used to request larger amounts of data.
    19  //
    20  // Use the AddInvVect function to build up the list of inventory vectors when
    21  // sending a getdata message to another peer.
    22  type MsgGetData struct {
    23  	InvList []*InvVect
    24  }
    25  
    26  // AddInvVect adds an inventory vector to the message.
    27  func (msg *MsgGetData) AddInvVect(iv *InvVect) error {
    28  	if len(msg.InvList)+1 > MaxInvPerMsg {
    29  		str := fmt.Sprintf("too many invvect in message [max %v]",
    30  			MaxInvPerMsg)
    31  		return messageError("MsgGetData.AddInvVect", str)
    32  	}
    33  
    34  	msg.InvList = append(msg.InvList, iv)
    35  	return nil
    36  }
    37  
    38  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
    39  // This is part of the Message interface implementation.
    40  func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
    41  	buf := binarySerializer.Borrow()
    42  	defer binarySerializer.Return(buf)
    43  
    44  	count, err := ReadVarIntBuf(r, pver, buf)
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	// Limit to max inventory vectors per message.
    50  	if count > MaxInvPerMsg {
    51  		str := fmt.Sprintf("too many invvect in message [%v]", count)
    52  		return messageError("MsgGetData.BtcDecode", str)
    53  	}
    54  
    55  	// Create a contiguous slice of inventory vectors to deserialize into in
    56  	// order to reduce the number of allocations.
    57  	invList := make([]InvVect, count)
    58  	msg.InvList = make([]*InvVect, 0, count)
    59  	for i := uint64(0); i < count; i++ {
    60  		iv := &invList[i]
    61  		err := readInvVectBuf(r, pver, iv, buf)
    62  		if err != nil {
    63  			return err
    64  		}
    65  		msg.AddInvVect(iv)
    66  	}
    67  
    68  	return nil
    69  }
    70  
    71  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
    72  // This is part of the Message interface implementation.
    73  func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
    74  	// Limit to max inventory vectors per message.
    75  	count := len(msg.InvList)
    76  	if count > MaxInvPerMsg {
    77  		str := fmt.Sprintf("too many invvect in message [%v]", count)
    78  		return messageError("MsgGetData.BtcEncode", str)
    79  	}
    80  
    81  	buf := binarySerializer.Borrow()
    82  	defer binarySerializer.Return(buf)
    83  
    84  	err := WriteVarIntBuf(w, pver, uint64(count), buf)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	for _, iv := range msg.InvList {
    90  		err := writeInvVectBuf(w, pver, iv, buf)
    91  		if err != nil {
    92  			return err
    93  		}
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  // Command returns the protocol command string for the message.  This is part
   100  // of the Message interface implementation.
   101  func (msg *MsgGetData) Command() string {
   102  	return CmdGetData
   103  }
   104  
   105  // MaxPayloadLength returns the maximum length the payload can be for the
   106  // receiver.  This is part of the Message interface implementation.
   107  func (msg *MsgGetData) MaxPayloadLength(pver uint32) uint32 {
   108  	// Num inventory vectors (varInt) + max allowed inventory vectors.
   109  	return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload)
   110  }
   111  
   112  // NewMsgGetData returns a new bitcoin getdata message that conforms to the
   113  // Message interface.  See MsgGetData for details.
   114  func NewMsgGetData() *MsgGetData {
   115  	return &MsgGetData{
   116  		InvList: make([]*InvVect, 0, defaultInvListAlloc),
   117  	}
   118  }
   119  
   120  // NewMsgGetDataSizeHint returns a new bitcoin getdata message that conforms to
   121  // the Message interface.  See MsgGetData for details.  This function differs
   122  // from NewMsgGetData in that it allows a default allocation size for the
   123  // backing array which houses the inventory vector list.  This allows callers
   124  // who know in advance how large the inventory list will grow to avoid the
   125  // overhead of growing the internal backing array several times when appending
   126  // large amounts of inventory vectors with AddInvVect.  Note that the specified
   127  // hint is just that - a hint that is used for the default allocation size.
   128  // Adding more (or less) inventory vectors will still work properly.  The size
   129  // hint is limited to MaxInvPerMsg.
   130  func NewMsgGetDataSizeHint(sizeHint uint) *MsgGetData {
   131  	// Limit the specified hint to the maximum allow per message.
   132  	if sizeHint > MaxInvPerMsg {
   133  		sizeHint = MaxInvPerMsg
   134  	}
   135  
   136  	return &MsgGetData{
   137  		InvList: make([]*InvVect, 0, sizeHint),
   138  	}
   139  }