msggetdata.go raw

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