github.com/core-coin/go-core/v2@v2.1.9/p2p/discover/v5wire/encoding_test.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package v5wire 18 19 import ( 20 "bytes" 21 "encoding/hex" 22 "flag" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "net" 27 "os" 28 "path/filepath" 29 "reflect" 30 "strings" 31 "testing" 32 33 "github.com/davecgh/go-spew/spew" 34 35 "github.com/core-coin/go-core/v2/common/hexutil" 36 "github.com/core-coin/go-core/v2/common/mclock" 37 "github.com/core-coin/go-core/v2/crypto" 38 "github.com/core-coin/go-core/v2/p2p/enode" 39 ) 40 41 // To regenerate discv5 test vectors, run 42 // 43 // go test -run TestVectors -write-test-vectors 44 var writeTestVectorsFlag = flag.Bool("write-test-vectors", false, "Overwrite discv5 test vectors in testdata/") 45 46 var ( 47 testKeyA, _ = crypto.UnmarshalPrivateKeyHex("1033b1bac4c731e800b6399a357e51cf1b20eec942aac608c90b89553003e2ed3f94bd80613ee9006b1e62b6bb45109d0db9a4833e78363992") 48 testKeyB, _ = crypto.UnmarshalPrivateKeyHex("1033b1bac4c731e800b6399a357e51cf1b20eec942aac608c90b89553003e2ed3f94bd80613ee9006b1e62b6bb45109d0db9a4833e78363991") 49 testEphKey, _ = crypto.UnmarshalPrivateKeyHex("1033b1bac4c731e800b6399a357e51cf1b20eec942aac608c90b89553003e2ed3f94bd80613ee9006b1e62b6bb45109d0db9a4833e78363993") 50 testIDnonce = [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} 51 ) 52 53 // This test checks that the minPacketSize and randomPacketMsgSize constants are well-defined. 54 func TestMinSizes(t *testing.T) { 55 var ( 56 gcmTagSize = 16 57 emptyMsg = sizeofMessageAuthData + gcmTagSize 58 ) 59 t.Log("static header size", sizeofStaticPacketData) 60 t.Log("whoareyou size", sizeofStaticPacketData+sizeofWhoareyouAuthData) 61 t.Log("empty msg size", sizeofStaticPacketData+emptyMsg) 62 if want := emptyMsg; minMessageSize != want { 63 t.Fatalf("wrong minMessageSize %d, want %d", minMessageSize, want) 64 } 65 if sizeofMessageAuthData+randomPacketMsgSize < minMessageSize { 66 t.Fatalf("randomPacketMsgSize %d too small", randomPacketMsgSize) 67 } 68 } 69 70 // This test checks the basic handshake flow where A talks to B and A has no secrets. 71 func TestHandshake(t *testing.T) { 72 t.Parallel() 73 net := newHandshakeTest() 74 defer net.close() 75 76 // A -> B RANDOM PACKET 77 packet, _ := net.nodeA.encode(t, net.nodeB, &Findnode{}) 78 resp := net.nodeB.expectDecode(t, UnknownPacket, packet) 79 80 // A <- B WHOAREYOU 81 challenge := &Whoareyou{ 82 Nonce: resp.(*Unknown).Nonce, 83 IDNonce: testIDnonce, 84 RecordSeq: 0, 85 } 86 whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge) 87 net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) 88 89 // A -> B FINDNODE (handshake packet) 90 findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) 91 net.nodeB.expectDecode(t, FindnodeMsg, findnode) 92 if len(net.nodeB.c.sc.handshakes) > 0 { 93 t.Fatalf("node B didn't remove handshake from challenge map") 94 } 95 96 // A <- B NODES 97 nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) 98 net.nodeA.expectDecode(t, NodesMsg, nodes) 99 } 100 101 // This test checks that handshake attempts are removed within the timeout. 102 func TestHandshake_timeout(t *testing.T) { 103 t.Parallel() 104 net := newHandshakeTest() 105 defer net.close() 106 107 // A -> B RANDOM PACKET 108 packet, _ := net.nodeA.encode(t, net.nodeB, &Findnode{}) 109 resp := net.nodeB.expectDecode(t, UnknownPacket, packet) 110 111 // A <- B WHOAREYOU 112 challenge := &Whoareyou{ 113 Nonce: resp.(*Unknown).Nonce, 114 IDNonce: testIDnonce, 115 RecordSeq: 0, 116 } 117 whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge) 118 net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) 119 120 // A -> B FINDNODE (handshake packet) after timeout 121 net.clock.Run(handshakeTimeout + 1) 122 findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) 123 net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, findnode) 124 } 125 126 // This test checks handshake behavior when no record is sent in the auth response. 127 func TestHandshake_norecord(t *testing.T) { 128 t.Parallel() 129 net := newHandshakeTest() 130 defer net.close() 131 132 // A -> B RANDOM PACKET 133 packet, _ := net.nodeA.encode(t, net.nodeB, &Findnode{}) 134 resp := net.nodeB.expectDecode(t, UnknownPacket, packet) 135 136 // A <- B WHOAREYOU 137 nodeA := net.nodeA.n() 138 if nodeA.Seq() == 0 { 139 t.Fatal("need non-zero sequence number") 140 } 141 challenge := &Whoareyou{ 142 Nonce: resp.(*Unknown).Nonce, 143 IDNonce: testIDnonce, 144 RecordSeq: nodeA.Seq(), 145 Node: nodeA, 146 } 147 whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge) 148 net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) 149 150 // A -> B FINDNODE 151 findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) 152 net.nodeB.expectDecode(t, FindnodeMsg, findnode) 153 154 // A <- B NODES 155 nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) 156 net.nodeA.expectDecode(t, NodesMsg, nodes) 157 } 158 159 // In this test, A tries to send FINDNODE with existing secrets but B doesn't know 160 // anything about A. 161 func TestHandshake_rekey(t *testing.T) { 162 t.Parallel() 163 net := newHandshakeTest() 164 defer net.close() 165 166 session := &session{ 167 readKey: []byte("BBBBBBBBBBBBBBBB"), 168 writeKey: []byte("AAAAAAAAAAAAAAAA"), 169 } 170 net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), session) 171 172 // A -> B FINDNODE (encrypted with zero keys) 173 findnode, authTag := net.nodeA.encode(t, net.nodeB, &Findnode{}) 174 net.nodeB.expectDecode(t, UnknownPacket, findnode) 175 176 // A <- B WHOAREYOU 177 challenge := &Whoareyou{Nonce: authTag, IDNonce: testIDnonce} 178 whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge) 179 net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) 180 181 // Check that new keys haven't been stored yet. 182 sa := net.nodeA.c.sc.session(net.nodeB.id(), net.nodeB.addr()) 183 if !bytes.Equal(sa.writeKey, session.writeKey) || !bytes.Equal(sa.readKey, session.readKey) { 184 t.Fatal("node A stored keys too early") 185 } 186 if s := net.nodeB.c.sc.session(net.nodeA.id(), net.nodeA.addr()); s != nil { 187 t.Fatal("node B stored keys too early") 188 } 189 190 // A -> B FINDNODE encrypted with new keys 191 findnode, _ = net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) 192 net.nodeB.expectDecode(t, FindnodeMsg, findnode) 193 194 // A <- B NODES 195 nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) 196 net.nodeA.expectDecode(t, NodesMsg, nodes) 197 } 198 199 // In this test A and B have different keys before the handshake. 200 func TestHandshake_rekey2(t *testing.T) { 201 t.Parallel() 202 net := newHandshakeTest() 203 defer net.close() 204 205 initKeysA := &session{ 206 readKey: []byte("BBBBBBBBBBBBBBBB"), 207 writeKey: []byte("AAAAAAAAAAAAAAAA"), 208 } 209 initKeysB := &session{ 210 readKey: []byte("CCCCCCCCCCCCCCCC"), 211 writeKey: []byte("DDDDDDDDDDDDDDDD"), 212 } 213 net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), initKeysA) 214 net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), initKeysB) 215 216 // A -> B FINDNODE encrypted with initKeysA 217 findnode, authTag := net.nodeA.encode(t, net.nodeB, &Findnode{Distances: []uint{3}}) 218 net.nodeB.expectDecode(t, UnknownPacket, findnode) 219 220 // A <- B WHOAREYOU 221 challenge := &Whoareyou{Nonce: authTag, IDNonce: testIDnonce} 222 whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge) 223 net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) 224 225 // A -> B FINDNODE (handshake packet) 226 findnode, _ = net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) 227 net.nodeB.expectDecode(t, FindnodeMsg, findnode) 228 229 // A <- B NODES 230 nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) 231 net.nodeA.expectDecode(t, NodesMsg, nodes) 232 } 233 234 func TestHandshake_BadHandshakeAttack(t *testing.T) { 235 t.Parallel() 236 net := newHandshakeTest() 237 defer net.close() 238 239 // A -> B RANDOM PACKET 240 packet, _ := net.nodeA.encode(t, net.nodeB, &Findnode{}) 241 resp := net.nodeB.expectDecode(t, UnknownPacket, packet) 242 243 // A <- B WHOAREYOU 244 challenge := &Whoareyou{ 245 Nonce: resp.(*Unknown).Nonce, 246 IDNonce: testIDnonce, 247 RecordSeq: 0, 248 } 249 whoareyou, _ := net.nodeB.encode(t, net.nodeA, challenge) 250 net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) 251 252 // A -> B FINDNODE 253 incorrect_challenge := &Whoareyou{ 254 IDNonce: [16]byte{5, 6, 7, 8, 9, 6, 11, 12}, 255 RecordSeq: challenge.RecordSeq, 256 Node: challenge.Node, 257 sent: challenge.sent, 258 } 259 incorrect_findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, incorrect_challenge, &Findnode{}) 260 incorrect_findnode2 := make([]byte, len(incorrect_findnode)) 261 copy(incorrect_findnode2, incorrect_findnode) 262 263 net.nodeB.expectDecodeErr(t, errInvalidNonceSig, incorrect_findnode) 264 265 // Reject new findnode as previous handshake is now deleted. 266 net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, incorrect_findnode2) 267 268 // The findnode packet is again rejected even with a valid challenge this time. 269 findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) 270 net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, findnode) 271 } 272 273 // This test checks some malformed packets. 274 func TestDecodeErrorsV5(t *testing.T) { 275 t.Parallel() 276 net := newHandshakeTest() 277 defer net.close() 278 279 net.nodeA.expectDecodeErr(t, errTooShort, []byte{}) 280 // TODO some more tests would be nice :) 281 // - check invalid authdata sizes 282 // - check invalid handshake data sizes 283 } 284 285 // This test checks that all test vectors can be decoded. 286 func TestTestVectorsV5(t *testing.T) { 287 var ( 288 idA = enode.PubkeyToIDV4(testKeyA.PublicKey()) 289 idB = enode.PubkeyToIDV4(testKeyB.PublicKey()) 290 addr = "127.0.0.1" 291 session = &session{ 292 writeKey: hexutil.MustDecode("0x00000000000000000000000000000000"), 293 readKey: hexutil.MustDecode("0x01010101010101010101010101010101"), 294 } 295 challenge0A, challenge1A, challenge0B Whoareyou 296 ) 297 298 // Create challenge packets. 299 c := Whoareyou{ 300 Nonce: Nonce{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, 301 IDNonce: testIDnonce, 302 } 303 challenge0A, challenge1A, challenge0B = c, c, c 304 challenge1A.RecordSeq = 1 305 net := newHandshakeTest() 306 challenge0A.Node = net.nodeA.n() 307 challenge0B.Node = net.nodeB.n() 308 challenge1A.Node = net.nodeA.n() 309 net.close() 310 311 type testVectorTest struct { 312 name string // test vector name 313 packet Packet // the packet to be encoded 314 challenge *Whoareyou // handshake challenge passed to encoder 315 prep func(*handshakeTest) // called before encode/decode 316 } 317 tests := []testVectorTest{ 318 { 319 name: "v5.1-whoareyou", 320 packet: &challenge0B, 321 }, 322 { 323 name: "v5.1-ping-message", 324 packet: &Ping{ 325 ReqID: []byte{0, 0, 0, 1}, 326 ENRSeq: 2, 327 }, 328 prep: func(net *handshakeTest) { 329 net.nodeA.c.sc.storeNewSession(idB, addr, session) 330 net.nodeB.c.sc.storeNewSession(idA, addr, session.keysFlipped()) 331 }, 332 }, 333 { 334 name: "v5.1-ping-handshake-enr", 335 packet: &Ping{ 336 ReqID: []byte{0, 0, 0, 1}, 337 ENRSeq: 1, 338 }, 339 challenge: &challenge0A, 340 prep: func(net *handshakeTest) { 341 // Update challenge.Header.AuthData. 342 net.nodeA.c.Encode(idB, "", &challenge0A, nil) 343 net.nodeB.c.sc.storeSentHandshake(idA, addr, &challenge0A) 344 }, 345 }, 346 { 347 name: "v5.1-ping-handshake", 348 packet: &Ping{ 349 ReqID: []byte{0, 0, 0, 1}, 350 ENRSeq: 1, 351 }, 352 challenge: &challenge1A, 353 prep: func(net *handshakeTest) { 354 // Update challenge data. 355 net.nodeA.c.Encode(idB, "", &challenge1A, nil) 356 net.nodeB.c.sc.storeSentHandshake(idA, addr, &challenge1A) 357 }, 358 }, 359 } 360 361 for _, test := range tests { 362 test := test 363 t.Run(test.name, func(t *testing.T) { 364 net := newHandshakeTest() 365 defer net.close() 366 367 // Override all random inputs. 368 net.nodeA.c.sc.nonceGen = func(counter uint32) (Nonce, error) { 369 return Nonce{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, nil 370 } 371 net.nodeA.c.sc.maskingIVGen = func(buf []byte) error { 372 return nil // all zero 373 } 374 net.nodeA.c.sc.ephemeralKeyGen = func(read io.Reader) (*crypto.PrivateKey, error) { 375 return testEphKey, nil 376 } 377 378 // Prime the codec for encoding/decoding. 379 if test.prep != nil { 380 test.prep(net) 381 } 382 383 file := filepath.Join("testdata", test.name+".txt") 384 if *writeTestVectorsFlag { 385 // Encode the packet. 386 d, nonce := net.nodeA.encodeWithChallenge(t, net.nodeB, test.challenge, test.packet) 387 comment := testVectorComment(net, test.packet, test.challenge, nonce) 388 writeTestVector(file, comment, d) 389 } 390 enc := hexFile(file) 391 net.nodeB.expectDecode(t, test.packet.Kind(), enc) 392 }) 393 } 394 } 395 396 // testVectorComment creates the commentary for discv5 test vector files. 397 func testVectorComment(net *handshakeTest, p Packet, challenge *Whoareyou, nonce Nonce) string { 398 o := new(strings.Builder) 399 printWhoareyou := func(p *Whoareyou) { 400 fmt.Fprintf(o, "whoareyou.challenge-data = %#x\n", p.ChallengeData) 401 fmt.Fprintf(o, "whoareyou.request-nonce = %#x\n", p.Nonce[:]) 402 fmt.Fprintf(o, "whoareyou.id-nonce = %#x\n", p.IDNonce[:]) 403 fmt.Fprintf(o, "whoareyou.enr-seq = %d\n", p.RecordSeq) 404 } 405 406 fmt.Fprintf(o, "src-node-id = %#x\n", net.nodeA.id().Bytes()) 407 fmt.Fprintf(o, "dest-node-id = %#x\n", net.nodeB.id().Bytes()) 408 switch p := p.(type) { 409 case *Whoareyou: 410 // WHOAREYOU packet. 411 printWhoareyou(p) 412 case *Ping: 413 fmt.Fprintf(o, "nonce = %#x\n", nonce[:]) 414 fmt.Fprintf(o, "read-key = %#x\n", net.nodeA.c.sc.session(net.nodeB.id(), net.nodeB.addr()).writeKey) 415 fmt.Fprintf(o, "ping.req-id = %#x\n", p.ReqID) 416 fmt.Fprintf(o, "ping.enr-seq = %d\n", p.ENRSeq) 417 if challenge != nil { 418 // Handshake message packet. 419 fmt.Fprint(o, "\nhandshake inputs:\n\n") 420 printWhoareyou(challenge) 421 fmt.Fprintf(o, "ephemeral-key = %#x\n", testEphKey.PrivateKey()) 422 fmt.Fprintf(o, "ephemeral-pubkey = %#x\n", testEphKey.PublicKey()) 423 } 424 default: 425 panic(fmt.Errorf("unhandled packet type %T", p)) 426 } 427 return o.String() 428 } 429 430 // This benchmark checks performance of handshake packet decoding. 431 func BenchmarkV5_DecodeHandshakePingSecp256k1(b *testing.B) { 432 net := newHandshakeTest() 433 defer net.close() 434 435 var ( 436 idA = net.nodeA.id() 437 challenge = &Whoareyou{Node: net.nodeB.n()} 438 message = &Ping{ReqID: []byte("reqid")} 439 ) 440 enc, _, err := net.nodeA.c.Encode(net.nodeB.id(), "", message, challenge) 441 if err != nil { 442 b.Fatal("can't encode handshake packet") 443 } 444 challenge.Node = nil // force ENR signature verification in decoder 445 b.ResetTimer() 446 447 input := make([]byte, len(enc)) 448 for i := 0; i < b.N; i++ { 449 copy(input, enc) 450 net.nodeB.c.sc.storeSentHandshake(idA, "", challenge) 451 _, _, _, err := net.nodeB.c.Decode(input, "") 452 if err != nil { 453 b.Fatal(err) 454 } 455 } 456 } 457 458 // This benchmark checks how long it takes to decode an encrypted ping packet. 459 func BenchmarkV5_DecodePing(b *testing.B) { 460 net := newHandshakeTest() 461 defer net.close() 462 463 session := &session{ 464 readKey: []byte{233, 203, 93, 195, 86, 47, 177, 186, 227, 43, 2, 141, 244, 230, 120, 17}, 465 writeKey: []byte{79, 145, 252, 171, 167, 216, 252, 161, 208, 190, 176, 106, 214, 39, 178, 134}, 466 } 467 net.nodeA.c.sc.storeNewSession(net.nodeB.id(), net.nodeB.addr(), session) 468 net.nodeB.c.sc.storeNewSession(net.nodeA.id(), net.nodeA.addr(), session.keysFlipped()) 469 addrB := net.nodeA.addr() 470 ping := &Ping{ReqID: []byte("reqid"), ENRSeq: 5} 471 enc, _, err := net.nodeA.c.Encode(net.nodeB.id(), addrB, ping, nil) 472 if err != nil { 473 b.Fatalf("can't encode: %v", err) 474 } 475 b.ResetTimer() 476 477 input := make([]byte, len(enc)) 478 for i := 0; i < b.N; i++ { 479 copy(input, enc) 480 _, _, packet, _ := net.nodeB.c.Decode(input, addrB) 481 if _, ok := packet.(*Ping); !ok { 482 b.Fatalf("wrong packet type %T", packet) 483 } 484 } 485 } 486 487 var pp = spew.NewDefaultConfig() 488 489 type handshakeTest struct { 490 nodeA, nodeB handshakeTestNode 491 clock mclock.Simulated 492 } 493 494 type handshakeTestNode struct { 495 ln *enode.LocalNode 496 c *Codec 497 } 498 499 func newHandshakeTest() *handshakeTest { 500 t := new(handshakeTest) 501 t.nodeA.init(testKeyA, net.IP{127, 0, 0, 1}, &t.clock) 502 t.nodeB.init(testKeyB, net.IP{127, 0, 0, 1}, &t.clock) 503 return t 504 } 505 506 func (t *handshakeTest) close() { 507 t.nodeA.ln.Database().Close() 508 t.nodeB.ln.Database().Close() 509 } 510 511 func (n *handshakeTestNode) init(key *crypto.PrivateKey, ip net.IP, clock mclock.Clock) { 512 db, _ := enode.OpenDB("") 513 n.ln = enode.NewLocalNode(db, key) 514 n.ln.SetStaticIP(ip) 515 if n.ln.Node().Seq() != 1 { 516 panic(fmt.Errorf("unexpected seq %d", n.ln.Node().Seq())) 517 } 518 n.c = NewCodec(n.ln, key, clock) 519 } 520 521 func (n *handshakeTestNode) encode(t testing.TB, to handshakeTestNode, p Packet) ([]byte, Nonce) { 522 t.Helper() 523 return n.encodeWithChallenge(t, to, nil, p) 524 } 525 526 func (n *handshakeTestNode) encodeWithChallenge(t testing.TB, to handshakeTestNode, c *Whoareyou, p Packet) ([]byte, Nonce) { 527 t.Helper() 528 529 // Copy challenge and add destination node. This avoids sharing 'c' among the two codecs. 530 var challenge *Whoareyou 531 if c != nil { 532 challengeCopy := *c 533 challenge = &challengeCopy 534 challenge.Node = to.n() 535 } 536 // Encode to destination. 537 enc, nonce, err := n.c.Encode(to.id(), to.addr(), p, challenge) 538 if err != nil { 539 t.Fatal(fmt.Errorf("(%s) %v", n.ln.ID().TerminalString(), err)) 540 } 541 t.Logf("(%s) -> (%s) %s\n%s", n.ln.ID().TerminalString(), to.id().TerminalString(), p.Name(), hex.Dump(enc)) 542 return enc, nonce 543 } 544 545 func (n *handshakeTestNode) expectDecode(t *testing.T, ptype byte, p []byte) Packet { 546 t.Helper() 547 548 dec, err := n.decode(p) 549 if err != nil { 550 t.Fatal(fmt.Errorf("(%s) %v", n.ln.ID().TerminalString(), err)) 551 } 552 t.Logf("(%s) %#v", n.ln.ID().TerminalString(), pp.NewFormatter(dec)) 553 if dec.Kind() != ptype { 554 t.Fatalf("expected packet type %d, got %d", ptype, dec.Kind()) 555 } 556 return dec 557 } 558 559 func (n *handshakeTestNode) expectDecodeErr(t *testing.T, wantErr error, p []byte) { 560 t.Helper() 561 if _, err := n.decode(p); !reflect.DeepEqual(err, wantErr) { 562 t.Fatal(fmt.Errorf("(%s) got err %q, want %q", n.ln.ID().TerminalString(), err, wantErr)) 563 } 564 } 565 566 func (n *handshakeTestNode) decode(input []byte) (Packet, error) { 567 _, _, p, err := n.c.Decode(input, "127.0.0.1") 568 return p, err 569 } 570 571 func (n *handshakeTestNode) n() *enode.Node { 572 return n.ln.Node() 573 } 574 575 func (n *handshakeTestNode) addr() string { 576 return n.ln.Node().IP().String() 577 } 578 579 func (n *handshakeTestNode) id() enode.ID { 580 return n.ln.ID() 581 } 582 583 // hexFile reads the given file and decodes the hex data contained in it. 584 // Whitespace and any lines beginning with the # character are ignored. 585 func hexFile(file string) []byte { 586 fileContent, err := ioutil.ReadFile(file) 587 if err != nil { 588 panic(err) 589 } 590 591 // Gather hex data, ignore comments. 592 var text []byte 593 for _, line := range bytes.Split(fileContent, []byte("\n")) { 594 line = bytes.TrimSpace(line) 595 if len(line) > 0 && line[0] == '#' { 596 continue 597 } 598 text = append(text, line...) 599 } 600 601 // Parse the hex. 602 if bytes.HasPrefix(text, []byte("0x")) { 603 text = text[2:] 604 } 605 data := make([]byte, hex.DecodedLen(len(text))) 606 if _, err := hex.Decode(data, text); err != nil { 607 panic("invalid hex in " + file) 608 } 609 return data 610 } 611 612 // writeTestVector writes a test vector file with the given commentary and binary data. 613 func writeTestVector(file, comment string, data []byte) { 614 fd, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 615 if err != nil { 616 panic(err) 617 } 618 defer fd.Close() 619 620 if len(comment) > 0 { 621 for _, line := range strings.Split(strings.TrimSpace(comment), "\n") { 622 fmt.Fprintf(fd, "# %s\n", line) 623 } 624 fmt.Fprintln(fd) 625 } 626 for len(data) > 0 { 627 var chunk []byte 628 if len(data) < 32 { 629 chunk = data 630 } else { 631 chunk = data[:32] 632 } 633 data = data[len(chunk):] 634 fmt.Fprintf(fd, "%x\n", chunk) 635 } 636 }