github.com/palcoin-project/palcd@v1.0.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  	count, err := ReadVarInt(r, pver)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	// Limit to max inventory vectors per message.
    55  	if count > MaxInvPerMsg {
    56  		str := fmt.Sprintf("too many invvect in message [%v]", count)
    57  		return messageError("MsgInv.BtcDecode", str)
    58  	}
    59  
    60  	// Create a contiguous slice of inventory vectors to deserialize into in
    61  	// order to reduce the number of allocations.
    62  	invList := make([]InvVect, count)
    63  	msg.InvList = make([]*InvVect, 0, count)
    64  	for i := uint64(0); i < count; i++ {
    65  		iv := &invList[i]
    66  		err := readInvVect(r, pver, iv)
    67  		if err != nil {
    68  			return err
    69  		}
    70  		msg.AddInvVect(iv)
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
    77  // This is part of the Message interface implementation.
    78  func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
    79  	// Limit to max inventory vectors per message.
    80  	count := len(msg.InvList)
    81  	if count > MaxInvPerMsg {
    82  		str := fmt.Sprintf("too many invvect in message [%v]", count)
    83  		return messageError("MsgInv.BtcEncode", str)
    84  	}
    85  
    86  	err := WriteVarInt(w, pver, uint64(count))
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	for _, iv := range msg.InvList {
    92  		err := writeInvVect(w, pver, iv)
    93  		if err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  // Command returns the protocol command string for the message.  This is part
   102  // of the Message interface implementation.
   103  func (msg *MsgInv) Command() string {
   104  	return CmdInv
   105  }
   106  
   107  // MaxPayloadLength returns the maximum length the payload can be for the
   108  // receiver.  This is part of the Message interface implementation.
   109  func (msg *MsgInv) MaxPayloadLength(pver uint32) uint32 {
   110  	// Num inventory vectors (varInt) + max allowed inventory vectors.
   111  	return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload)
   112  }
   113  
   114  // NewMsgInv returns a new bitcoin inv message that conforms to the Message
   115  // interface.  See MsgInv for details.
   116  func NewMsgInv() *MsgInv {
   117  	return &MsgInv{
   118  		InvList: make([]*InvVect, 0, defaultInvListAlloc),
   119  	}
   120  }
   121  
   122  // NewMsgInvSizeHint returns a new bitcoin inv message that conforms to the
   123  // Message interface.  See MsgInv for details.  This function differs from
   124  // NewMsgInv in that it allows a default allocation size for the backing array
   125  // which houses the inventory vector list.  This allows callers who know in
   126  // advance how large the inventory list will grow to avoid the overhead of
   127  // growing the internal backing array several times when appending large amounts
   128  // of inventory vectors with AddInvVect.  Note that the specified hint is just
   129  // that - a hint that is used for the default allocation size.  Adding more
   130  // (or less) inventory vectors will still work properly.  The size hint is
   131  // limited to MaxInvPerMsg.
   132  func NewMsgInvSizeHint(sizeHint uint) *MsgInv {
   133  	// Limit the specified hint to the maximum allow per message.
   134  	if sizeHint > MaxInvPerMsg {
   135  		sizeHint = MaxInvPerMsg
   136  	}
   137  
   138  	return &MsgInv{
   139  		InvList: make([]*InvVect, 0, sizeHint),
   140  	}
   141  }