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