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