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