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