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