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