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