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