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  }