msginv.go raw

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