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