msggetdata_test.go raw
1 package wire
2
3 import (
4 "bytes"
5 "io"
6 "reflect"
7 "testing"
8
9 "github.com/davecgh/go-spew/spew"
10
11 "github.com/p9c/p9/pkg/chainhash"
12 )
13
14 // TestGetData tests the MsgGetData API.
15 func TestGetData(t *testing.T) {
16 pver := ProtocolVersion
17 // Ensure the command is expected value.
18 wantCmd := "getdata"
19 msg := NewMsgGetData()
20 if cmd := msg.Command(); cmd != wantCmd {
21 t.Errorf("NewMsgGetData: wrong command - got %v want %v",
22 cmd, wantCmd,
23 )
24 }
25 // Ensure max payload is expected value for latest protocol version. Num inventory vectors (varInt) + max allowed
26 // inventory vectors.
27 wantPayload := uint32(1800009)
28 maxPayload := msg.MaxPayloadLength(pver)
29 if maxPayload != wantPayload {
30 t.Errorf("MaxPayloadLength: wrong max payload length for "+
31 "protocol version %d - got %v, want %v", pver,
32 maxPayload, wantPayload,
33 )
34 }
35 // Ensure inventory vectors are added properly.
36 hash := chainhash.Hash{}
37 iv := NewInvVect(InvTypeBlock, &hash)
38 e := msg.AddInvVect(iv)
39 if e != nil {
40 t.Errorf("AddInvVect: %v", e)
41 }
42 if msg.InvList[0] != iv {
43 t.Errorf("AddInvVect: wrong invvect added - got %v, want %v",
44 spew.Sprint(msg.InvList[0]), spew.Sprint(iv),
45 )
46 }
47 // Ensure adding more than the max allowed inventory vectors per message returns an error.
48 for i := 0; i < MaxInvPerMsg; i++ {
49 e = msg.AddInvVect(iv)
50 }
51 if e == nil {
52 t.Errorf("AddInvVect: expected error on too many inventory " +
53 "vectors not received",
54 )
55 }
56 // Ensure creating the message with a size hint larger than the max works as expected.
57 msg = NewMsgGetDataSizeHint(MaxInvPerMsg + 1)
58 wantCap := MaxInvPerMsg
59 if cap(msg.InvList) != wantCap {
60 t.Errorf("NewMsgGetDataSizeHint: wrong cap for size hint - "+
61 "got %v, want %v", cap(msg.InvList), wantCap,
62 )
63 }
64 }
65
66 // TestGetDataWire tests the MsgGetData wire encode and decode for various numbers of inventory vectors and protocol
67 // versions.
68 func TestGetDataWire(t *testing.T) {
69 // Block 203707 hash.
70 hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc"
71 blockHash, e := chainhash.NewHashFromStr(hashStr)
72 if e != nil {
73 t.Errorf("NewHashFromStr: %v", e)
74 }
75 // Transaction 1 of Block 203707 hash.
76 hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0"
77 txHash, e := chainhash.NewHashFromStr(hashStr)
78 if e != nil {
79 t.Errorf("NewHashFromStr: %v", e)
80 }
81 iv := NewInvVect(InvTypeBlock, blockHash)
82 iv2 := NewInvVect(InvTypeTx, txHash)
83 // Empty MsgGetData message.
84 NoInv := NewMsgGetData()
85 NoInvEncoded := []byte{
86 0x00, // Varint for number of inventory vectors
87 }
88 // MsgGetData message with multiple inventory vectors.
89 MultiInv := NewMsgGetData()
90 e = MultiInv.AddInvVect(iv)
91 if e != nil {
92 t.Log(e)
93 }
94 e = MultiInv.AddInvVect(iv2)
95 if e != nil {
96 t.Log(e)
97 }
98 MultiInvEncoded := []byte{
99 0x02, // Varint for number of inv vectors
100 0x02, 0x00, 0x00, 0x00, // InvTypeBlock
101 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
102 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
103 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
104 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash
105 0x01, 0x00, 0x00, 0x00, // InvTypeTx
106 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf,
107 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8,
108 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98,
109 0x0a, 0xf0, 0x2b, 0x39, 0xc7, 0x3d, 0x8a, 0xd2, // Tx 1 of block 203707 hash
110 }
111 tests := []struct {
112 in *MsgGetData // Message to encode
113 out *MsgGetData // Expected decoded message
114 buf []byte // Wire encoding
115 pver uint32 // Protocol version for wire encoding
116 enc MessageEncoding // Message encoding format
117 }{
118 // Latest protocol version with no inv vectors.
119 {
120 NoInv,
121 NoInv,
122 NoInvEncoded,
123 ProtocolVersion,
124 BaseEncoding,
125 },
126 // Latest protocol version with multiple inv vectors.
127 {
128 MultiInv,
129 MultiInv,
130 MultiInvEncoded,
131 ProtocolVersion,
132 BaseEncoding,
133 },
134 // Protocol version BIP0035Version no inv vectors.
135 {
136 NoInv,
137 NoInv,
138 NoInvEncoded,
139 BIP0035Version,
140 BaseEncoding,
141 },
142 // Protocol version BIP0035Version with multiple inv vectors.
143 {
144 MultiInv,
145 MultiInv,
146 MultiInvEncoded,
147 BIP0035Version,
148 BaseEncoding,
149 },
150 // Protocol version BIP0031Version no inv vectors.
151 {
152 NoInv,
153 NoInv,
154 NoInvEncoded,
155 BIP0031Version,
156 BaseEncoding,
157 },
158 // Protocol version BIP0031Version with multiple inv vectors.
159 {
160 MultiInv,
161 MultiInv,
162 MultiInvEncoded,
163 BIP0031Version,
164 BaseEncoding,
165 },
166 // Protocol version NetAddressTimeVersion no inv vectors.
167 {
168 NoInv,
169 NoInv,
170 NoInvEncoded,
171 NetAddressTimeVersion,
172 BaseEncoding,
173 },
174 // Protocol version NetAddressTimeVersion with multiple inv vectors.
175 {
176 MultiInv,
177 MultiInv,
178 MultiInvEncoded,
179 NetAddressTimeVersion,
180 BaseEncoding,
181 },
182 // Protocol version MultipleAddressVersion no inv vectors.
183 {
184 NoInv,
185 NoInv,
186 NoInvEncoded,
187 MultipleAddressVersion,
188 BaseEncoding,
189 },
190 // Protocol version MultipleAddressVersion with multiple inv vectors.
191 {
192 MultiInv,
193 MultiInv,
194 MultiInvEncoded,
195 MultipleAddressVersion,
196 BaseEncoding,
197 },
198 }
199 t.Logf("Running %d tests", len(tests))
200 for i, test := range tests {
201 // Encode the message to wire format.
202 var buf bytes.Buffer
203 e := test.in.BtcEncode(&buf, test.pver, test.enc)
204 if e != nil {
205 t.Errorf("BtcEncode #%d error %v", i, e)
206 continue
207 }
208 if !bytes.Equal(buf.Bytes(), test.buf) {
209 t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
210 spew.Sdump(buf.Bytes()), spew.Sdump(test.buf),
211 )
212 continue
213 }
214 // Decode the message from wire format.
215 var msg MsgGetData
216 rbuf := bytes.NewReader(test.buf)
217 e = msg.BtcDecode(rbuf, test.pver, test.enc)
218 if e != nil {
219 t.Errorf("BtcDecode #%d error %v", i, e)
220 continue
221 }
222 if !reflect.DeepEqual(&msg, test.out) {
223 t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
224 spew.Sdump(msg), spew.Sdump(test.out),
225 )
226 continue
227 }
228 }
229 }
230
231 // TestGetDataWireErrors performs negative tests against wire encode and decode of MsgGetData to confirm error paths
232 // work correctly.
233 func TestGetDataWireErrors(t *testing.T) {
234 pver := ProtocolVersion
235 wireErr := &MessageError{}
236 // Block 203707 hash.
237 hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc"
238 blockHash, e := chainhash.NewHashFromStr(hashStr)
239 if e != nil {
240 t.Errorf("NewHashFromStr: %v", e)
241 }
242 iv := NewInvVect(InvTypeBlock, blockHash)
243 // Base message used to induce errors.
244 baseGetData := NewMsgGetData()
245 e = baseGetData.AddInvVect(iv)
246 if e != nil {
247 t.Log(e)
248 }
249 baseGetDataEncoded := []byte{
250 0x02, // Varint for number of inv vectors
251 0x02, 0x00, 0x00, 0x00, // InvTypeBlock
252 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
253 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
254 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
255 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash
256 }
257 // Message that forces an error by having more than the max allowed inv
258 // vectors.
259 maxGetData := NewMsgGetData()
260 for i := 0; i < MaxInvPerMsg; i++ {
261 e = maxGetData.AddInvVect(iv)
262 if e != nil {
263 t.Log(e)
264 }
265 }
266 maxGetData.InvList = append(maxGetData.InvList, iv)
267 maxGetDataEncoded := []byte{
268 0xfd, 0x51, 0xc3, // Varint for number of inv vectors (50001)
269 }
270 tests := []struct {
271 in *MsgGetData // value to encode
272 buf []byte // Wire encoding
273 pver uint32 // Protocol version for wire encoding
274 enc MessageEncoding // Message encoding format
275 max int // Max size of fixed buffer to induce errors
276 writeErr error // Expected write error
277 readErr error // Expected read error
278 }{
279 // Latest protocol version with intentional read/write errors. Force error in inventory vector count
280 {baseGetData, baseGetDataEncoded, pver, BaseEncoding, 0, io.ErrShortWrite, io.EOF},
281 // Force error in inventory list.
282 {baseGetData, baseGetDataEncoded, pver, BaseEncoding, 1, io.ErrShortWrite, io.EOF},
283 // Force error with greater than max inventory vectors.
284 {maxGetData, maxGetDataEncoded, pver, BaseEncoding, 3, wireErr, wireErr},
285 }
286 t.Logf("Running %d tests", len(tests))
287 for i, test := range tests {
288 // Encode to wire format.
289 w := newFixedWriter(test.max)
290 e := test.in.BtcEncode(w, test.pver, test.enc)
291 if reflect.TypeOf(e) != reflect.TypeOf(test.writeErr) {
292 t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
293 i, e, test.writeErr,
294 )
295 continue
296 }
297 // For errors which are not of type MessageError, check them for equality.
298 if _, ok := e.(*MessageError); !ok {
299 if e != test.writeErr {
300 t.Errorf("BtcEncode #%d wrong error got: %v, "+
301 "want: %v", i, e, test.writeErr,
302 )
303 continue
304 }
305 }
306 // Decode from wire format.
307 var msg MsgGetData
308 r := newFixedReader(test.max, test.buf)
309 e = msg.BtcDecode(r, test.pver, test.enc)
310 if reflect.TypeOf(e) != reflect.TypeOf(test.readErr) {
311 t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
312 i, e, test.readErr,
313 )
314 continue
315 }
316 // For errors which are not of type MessageError, check them for equality.
317 if _, ok := e.(*MessageError); !ok {
318 if e != test.readErr {
319 t.Errorf("BtcDecode #%d wrong error got: %v, "+
320 "want: %v", i, e, test.readErr,
321 )
322 continue
323 }
324 }
325 }
326 }
327