github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/wire/msginv.go (about)

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