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