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  }