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