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