msggetheaders_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 // TestGetHeaders tests the MsgGetHeader API.
15 func TestGetHeaders(t *testing.T) {
16 pver := ProtocolVersion
17 // Block 99500 hash.
18 hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0"
19 locatorHash, e := chainhash.NewHashFromStr(hashStr)
20 if e != nil {
21 t.Errorf("NewHashFromStr: %v", e)
22 }
23 // Ensure the command is expected value.
24 wantCmd := "getheaders"
25 msg := NewMsgGetHeaders()
26 if cmd := msg.Command(); cmd != wantCmd {
27 t.Errorf("NewMsgGetHeaders: wrong command - got %v want %v",
28 cmd, wantCmd,
29 )
30 }
31 // Ensure max payload is expected value for latest protocol version. Protocol version 4 bytes + num hashes (varInt)
32 // + max block locator hashes + hash stop.
33 wantPayload := uint32(16045)
34 maxPayload := msg.MaxPayloadLength(pver)
35 if maxPayload != wantPayload {
36 t.Errorf("MaxPayloadLength: wrong max payload length for "+
37 "protocol version %d - got %v, want %v", pver,
38 maxPayload, wantPayload,
39 )
40 }
41 // Ensure block locator hashes are added properly.
42 e = msg.AddBlockLocatorHash(locatorHash)
43 if e != nil {
44 t.Errorf("AddBlockLocatorHash: %v", e)
45 }
46 if msg.BlockLocatorHashes[0] != locatorHash {
47 t.Errorf("AddBlockLocatorHash: wrong block locator added - "+
48 "got %v, want %v",
49 spew.Sprint(msg.BlockLocatorHashes[0]),
50 spew.Sprint(locatorHash),
51 )
52 }
53 // Ensure adding more than the max allowed block locator hashes per message returns an error.
54 for i := 0; i < MaxBlockLocatorsPerMsg; i++ {
55 e = msg.AddBlockLocatorHash(locatorHash)
56 }
57 if e == nil {
58 t.Errorf("AddBlockLocatorHash: expected error on too many " +
59 "block locator hashes not received",
60 )
61 }
62 }
63
64 // TestGetHeadersWire tests the MsgGetHeaders wire encode and decode for various numbers of block locator hashes and
65 // protocol versions.
66 func TestGetHeadersWire(t *testing.T) {
67 // Set protocol inside getheaders message. Use protocol version 60002 specifically here instead of the latest
68 // because the test data is using bytes encoded with that protocol version.
69 pver := uint32(60002)
70 // Block 99499 hash.
71 hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535"
72 hashLocator, e := chainhash.NewHashFromStr(hashStr)
73 if e != nil {
74 t.Errorf("NewHashFromStr: %v", e)
75 }
76 // Block 99500 hash.
77 hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0"
78 hashLocator2, e := chainhash.NewHashFromStr(hashStr)
79 if e != nil {
80 t.Errorf("NewHashFromStr: %v", e)
81 }
82 // Block 100000 hash.
83 hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
84 hashStop, e := chainhash.NewHashFromStr(hashStr)
85 if e != nil {
86 t.Errorf("NewHashFromStr: %v", e)
87 }
88 // MsgGetHeaders message with no block locators or stop hash.
89 noLocators := NewMsgGetHeaders()
90 noLocators.ProtocolVersion = pver
91 noLocatorsEncoded := []byte{
92 0x62, 0xea, 0x00, 0x00, // Protocol version 60002
93 0x00, // Varint for number of block locator hashes
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop
98 }
99 // MsgGetHeaders message with multiple block locators and a stop hash.
100 multiLocators := NewMsgGetHeaders()
101 multiLocators.ProtocolVersion = pver
102 multiLocators.HashStop = *hashStop
103 e = multiLocators.AddBlockLocatorHash(hashLocator2)
104 if e != nil {
105 t.Log(e)
106 }
107 e = multiLocators.AddBlockLocatorHash(hashLocator)
108 if e != nil {
109 t.Log(e)
110 }
111 multiLocatorsEncoded := []byte{
112 0x62, 0xea, 0x00, 0x00, // Protocol version 60002
113 0x02, // Varint for number of block locator hashes
114 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63,
115 0xd2, 0x20, 0xcc, 0x69, 0x12, 0x83, 0xcb, 0x65,
116 0xbc, 0xaa, 0xe4, 0x79, 0x94, 0xef, 0x9e, 0x7b,
117 0xad, 0xe7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99500 hash
118 0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60,
119 0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9,
120 0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40,
121 0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99499 hash
122 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39,
123 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2,
124 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa,
125 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop
126 }
127 tests := []struct {
128 in *MsgGetHeaders // Message to encode
129 out *MsgGetHeaders // Expected decoded message
130 buf []byte // Wire encoding
131 pver uint32 // Protocol version for wire encoding
132 enc MessageEncoding // Message encoding format
133 }{
134 // Latest protocol version with no block locators.
135 {
136 noLocators,
137 noLocators,
138 noLocatorsEncoded,
139 ProtocolVersion,
140 BaseEncoding,
141 },
142 // Latest protocol version with multiple block locators.
143 {
144 multiLocators,
145 multiLocators,
146 multiLocatorsEncoded,
147 ProtocolVersion,
148 BaseEncoding,
149 },
150 // Protocol version BIP0035Version with no block locators.
151 {
152 noLocators,
153 noLocators,
154 noLocatorsEncoded,
155 BIP0035Version,
156 BaseEncoding,
157 },
158 // Protocol version BIP0035Version with multiple block locators.
159 {
160 multiLocators,
161 multiLocators,
162 multiLocatorsEncoded,
163 BIP0035Version,
164 BaseEncoding,
165 },
166 // Protocol version BIP0031Version with no block locators.
167 {
168 noLocators,
169 noLocators,
170 noLocatorsEncoded,
171 BIP0031Version,
172 BaseEncoding,
173 },
174 // Protocol version BIP0031Versionwith multiple block locators.
175 {
176 multiLocators,
177 multiLocators,
178 multiLocatorsEncoded,
179 BIP0031Version,
180 BaseEncoding,
181 },
182 // Protocol version NetAddressTimeVersion with no block locators.
183 {
184 noLocators,
185 noLocators,
186 noLocatorsEncoded,
187 NetAddressTimeVersion,
188 BaseEncoding,
189 },
190 // Protocol version NetAddressTimeVersion multiple block locators.
191 {
192 multiLocators,
193 multiLocators,
194 multiLocatorsEncoded,
195 NetAddressTimeVersion,
196 BaseEncoding,
197 },
198 // Protocol version MultipleAddressVersion with no block locators.
199 {
200 noLocators,
201 noLocators,
202 noLocatorsEncoded,
203 MultipleAddressVersion,
204 BaseEncoding,
205 },
206 // Protocol version MultipleAddressVersion multiple block locators.
207 {
208 multiLocators,
209 multiLocators,
210 multiLocatorsEncoded,
211 MultipleAddressVersion,
212 BaseEncoding,
213 },
214 }
215 t.Logf("Running %d tests", len(tests))
216 for i, test := range tests {
217 // Encode the message to wire format.
218 var buf bytes.Buffer
219 e := test.in.BtcEncode(&buf, test.pver, test.enc)
220 if e != nil {
221 t.Errorf("BtcEncode #%d error %v", i, e)
222 continue
223 }
224 if !bytes.Equal(buf.Bytes(), test.buf) {
225 t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
226 spew.Sdump(buf.Bytes()), spew.Sdump(test.buf),
227 )
228 continue
229 }
230 // Decode the message from wire format.
231 var msg MsgGetHeaders
232 rbuf := bytes.NewReader(test.buf)
233 e = msg.BtcDecode(rbuf, test.pver, test.enc)
234 if e != nil {
235 t.Errorf("BtcDecode #%d error %v", i, e)
236 continue
237 }
238 if !reflect.DeepEqual(&msg, test.out) {
239 t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
240 spew.Sdump(&msg), spew.Sdump(test.out),
241 )
242 continue
243 }
244 }
245 }
246
247 // TestGetHeadersWireErrors performs negative tests against wire encode and decode of MsgGetHeaders to confirm error
248 // paths work correctly.
249 func TestGetHeadersWireErrors(t *testing.T) {
250 // Set protocol inside getheaders message. Use protocol version 60002 specifically here instead of the latest
251 // because the test data is using bytes encoded with that protocol version.
252 pver := uint32(60002)
253 wireErr := &MessageError{}
254 // Block 99499 hash.
255 hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535"
256 hashLocator, e := chainhash.NewHashFromStr(hashStr)
257 if e != nil {
258 t.Errorf("NewHashFromStr: %v", e)
259 }
260 // Block 99500 hash.
261 hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0"
262 hashLocator2, e := chainhash.NewHashFromStr(hashStr)
263 if e != nil {
264 t.Errorf("NewHashFromStr: %v", e)
265 }
266 // Block 100000 hash.
267 hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
268 hashStop, e := chainhash.NewHashFromStr(hashStr)
269 if e != nil {
270 t.Errorf("NewHashFromStr: %v", e)
271 }
272 // MsgGetHeaders message with multiple block locators and a stop hash.
273 baseGetHeaders := NewMsgGetHeaders()
274 baseGetHeaders.ProtocolVersion = pver
275 baseGetHeaders.HashStop = *hashStop
276 e = baseGetHeaders.AddBlockLocatorHash(hashLocator2)
277 if e != nil {
278 t.Log(e)
279 }
280 e = baseGetHeaders.AddBlockLocatorHash(hashLocator)
281 if e != nil {
282 t.Log(e)
283 }
284 baseGetHeadersEncoded := []byte{
285 0x62, 0xea, 0x00, 0x00, // Protocol version 60002
286 0x02, // Varint for number of block locator hashes
287 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63,
288 0xd2, 0x20, 0xcc, 0x69, 0x12, 0x83, 0xcb, 0x65,
289 0xbc, 0xaa, 0xe4, 0x79, 0x94, 0xef, 0x9e, 0x7b,
290 0xad, 0xe7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99500 hash
291 0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60,
292 0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9,
293 0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40,
294 0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99499 hash
295 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39,
296 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2,
297 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa,
298 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop
299 }
300 // Message that forces an error by having more than the max allowed
301 // block locator hashes.
302 maxGetHeaders := NewMsgGetHeaders()
303 for i := 0; i < MaxBlockLocatorsPerMsg; i++ {
304 e = maxGetHeaders.AddBlockLocatorHash(&mainNetGenesisHash)
305 if e != nil {
306 t.Log(e)
307 }
308 }
309 maxGetHeaders.BlockLocatorHashes = append(maxGetHeaders.BlockLocatorHashes,
310 &mainNetGenesisHash,
311 )
312 maxGetHeadersEncoded := []byte{
313 0x62, 0xea, 0x00, 0x00, // Protocol version 60002
314 0xfd, 0xf5, 0x01, // Varint for number of block loc hashes (501)
315 }
316 tests := []struct {
317 in *MsgGetHeaders // value to encode
318 buf []byte // Wire encoding
319 pver uint32 // Protocol version for wire encoding
320 enc MessageEncoding // Message encoding format
321 max int // Max size of fixed buffer to induce errors
322 writeErr error // Expected write error
323 readErr error // Expected read error
324 }{
325 // Force error in protocol version.
326 {baseGetHeaders, baseGetHeadersEncoded, pver, BaseEncoding, 0, io.ErrShortWrite, io.EOF},
327 // Force error in block locator hash count.
328 {baseGetHeaders, baseGetHeadersEncoded, pver, BaseEncoding, 4, io.ErrShortWrite, io.EOF},
329 // Force error in block locator hashes.
330 {baseGetHeaders, baseGetHeadersEncoded, pver, BaseEncoding, 5, io.ErrShortWrite, io.EOF},
331 // Force error in stop hash.
332 {baseGetHeaders, baseGetHeadersEncoded, pver, BaseEncoding, 69, io.ErrShortWrite, io.EOF},
333 // Force error with greater than max block locator hashes.
334 {maxGetHeaders, maxGetHeadersEncoded, pver, BaseEncoding, 7, wireErr, wireErr},
335 }
336 t.Logf("Running %d tests", len(tests))
337 for i, test := range tests {
338 // Encode to wire format.
339 w := newFixedWriter(test.max)
340 e := test.in.BtcEncode(w, test.pver, test.enc)
341 if reflect.TypeOf(e) != reflect.TypeOf(test.writeErr) {
342 t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
343 i, e, test.writeErr,
344 )
345 continue
346 }
347 // For errors which are not of type MessageError, check them for equality.
348 if _, ok := e.(*MessageError); !ok {
349 if e != test.writeErr {
350 t.Errorf("BtcEncode #%d wrong error got: %v, "+
351 "want: %v", i, e, test.writeErr,
352 )
353 continue
354 }
355 }
356 // Decode from wire format.
357 var msg MsgGetHeaders
358 r := newFixedReader(test.max, test.buf)
359 e = msg.BtcDecode(r, test.pver, test.enc)
360 if reflect.TypeOf(e) != reflect.TypeOf(test.readErr) {
361 t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
362 i, e, test.readErr,
363 )
364 continue
365 }
366 // For errors which are not of type MessageError, check them for equality.
367 if _, ok := e.(*MessageError); !ok {
368 if e != test.readErr {
369 t.Errorf("BtcDecode #%d wrong error got: %v, "+
370 "want: %v", i, e, test.readErr,
371 )
372 continue
373 }
374 }
375 }
376 }
377