github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/p2p/discover/node_test.go (about)

     1  // Copyright 2015 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 discover
    18  
    19  import (
    20  	"fmt"
    21  	"math/rand"
    22  	"net"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  	"testing/quick"
    27  	"time"
    28  
    29  	"github.com/ethereumproject/go-ethereum/crypto"
    30  )
    31  
    32  func ExampleNewNode() {
    33  	id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439")
    34  
    35  	// Complete nodes contain UDP and TCP endpoints:
    36  	n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 30303)
    37  	fmt.Println("n1:", n1)
    38  	fmt.Println("n1.Incomplete() ->", n1.Incomplete())
    39  
    40  	// An incomplete node can be created by passing zero values
    41  	// for all parameters except id.
    42  	n2 := NewNode(id, nil, 0, 0)
    43  	fmt.Println("n2:", n2)
    44  	fmt.Println("n2.Incomplete() ->", n2.Incomplete())
    45  
    46  	// Output:
    47  	// n1: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:30303?discport=52150
    48  	// n1.Incomplete() -> false
    49  	// n2: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439
    50  	// n2.Incomplete() -> true
    51  }
    52  
    53  var parseNodeTests = []struct {
    54  	rawurl     string
    55  	wantError  string
    56  	wantResult *Node
    57  }{
    58  	{
    59  		rawurl:    "http://foobar",
    60  		wantError: `invalid URL scheme, want "enode"`,
    61  	},
    62  	{
    63  		rawurl:    "enode://01010101@123.124.125.126:3",
    64  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
    65  	},
    66  	// Complete nodes with IP address.
    67  	{
    68  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
    69  		wantError: `invalid IP address`,
    70  	},
    71  	{
    72  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
    73  		wantError: `invalid port`,
    74  	},
    75  	{
    76  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
    77  		wantError: `invalid discport in query`,
    78  	},
    79  	{
    80  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
    81  		wantResult: NewNode(
    82  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    83  			net.IP{0x7f, 0x0, 0x0, 0x1},
    84  			52150,
    85  			52150,
    86  		),
    87  	},
    88  	{
    89  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
    90  		wantResult: NewNode(
    91  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    92  			net.ParseIP("::"),
    93  			52150,
    94  			52150,
    95  		),
    96  	},
    97  	{
    98  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
    99  		wantResult: NewNode(
   100  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   101  			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
   102  			52150,
   103  			52150,
   104  		),
   105  	},
   106  	{
   107  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
   108  		wantResult: NewNode(
   109  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   110  			net.IP{0x7f, 0x0, 0x0, 0x1},
   111  			22334,
   112  			52150,
   113  		),
   114  	},
   115  	// Incomplete nodes with no address.
   116  	{
   117  		rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   118  		wantResult: NewNode(
   119  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   120  			nil, 0, 0,
   121  		),
   122  	},
   123  	{
   124  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   125  		wantResult: NewNode(
   126  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   127  			nil, 0, 0,
   128  		),
   129  	},
   130  	// Invalid URLs
   131  	{
   132  		rawurl:    "01010101",
   133  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   134  	},
   135  	{
   136  		rawurl:    "enode://01010101",
   137  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   138  	},
   139  	{
   140  		// This test checks that errors from url.Parse are handled.
   141  		rawurl:    "://foo",
   142  		wantError: `parse ://foo: missing protocol scheme`,
   143  	},
   144  }
   145  
   146  func TestParseNode(t *testing.T) {
   147  	for _, test := range parseNodeTests {
   148  		n, err := ParseNode(test.rawurl)
   149  		if test.wantError != "" {
   150  			if err == nil {
   151  				t.Errorf("test %q:\n  got nil error, expected %#q", test.rawurl, test.wantError)
   152  				continue
   153  			} else if err.Error() != test.wantError {
   154  				t.Errorf("test %q:\n  got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
   155  				continue
   156  			}
   157  		} else {
   158  			if err != nil {
   159  				t.Errorf("test %q:\n  unexpected error: %v", test.rawurl, err)
   160  				continue
   161  			}
   162  			if !reflect.DeepEqual(n, test.wantResult) {
   163  				t.Errorf("test %q:\n  result mismatch:\ngot:  %#v, want: %#v", test.rawurl, n, test.wantResult)
   164  			}
   165  		}
   166  	}
   167  }
   168  
   169  func TestNodeString(t *testing.T) {
   170  	for i, test := range parseNodeTests {
   171  		if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") {
   172  			str := test.wantResult.String()
   173  			if str != test.rawurl {
   174  				t.Errorf("test %d: Node.String() mismatch:\ngot:  %s\nwant: %s", i, str, test.rawurl)
   175  			}
   176  		}
   177  	}
   178  }
   179  
   180  func TestHexID(t *testing.T) {
   181  	ref := NodeID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188}
   182  	id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   183  	id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   184  
   185  	if id1 != ref {
   186  		t.Errorf("wrong id1\ngot  %v\nwant %v", id1[:], ref[:])
   187  	}
   188  	if id2 != ref {
   189  		t.Errorf("wrong id2\ngot  %v\nwant %v", id2[:], ref[:])
   190  	}
   191  }
   192  
   193  func TestNodeID_recover(t *testing.T) {
   194  	prv := newkey()
   195  	hash := make([]byte, 32)
   196  	sig, err := crypto.Sign(hash, prv)
   197  	if err != nil {
   198  		t.Fatalf("signing error: %v", err)
   199  	}
   200  
   201  	pub := PubkeyID(&prv.PublicKey)
   202  	recpub, err := recoverNodeID(hash, sig)
   203  	if err != nil {
   204  		t.Fatalf("recovery error: %v", err)
   205  	}
   206  	if pub != recpub {
   207  		t.Errorf("recovered wrong pubkey:\ngot:  %v\nwant: %v", recpub, pub)
   208  	}
   209  
   210  	ecdsa, err := pub.Pubkey()
   211  	if err != nil {
   212  		t.Errorf("Pubkey error: %v", err)
   213  	}
   214  	if !reflect.DeepEqual(ecdsa, &prv.PublicKey) {
   215  		t.Errorf("Pubkey mismatch:\n  got:  %#v\n  want: %#v", ecdsa, &prv.PublicKey)
   216  	}
   217  }
   218  
   219  func TestNodeID_pubkeyBad(t *testing.T) {
   220  	ecdsa, err := NodeID{}.Pubkey()
   221  	if err == nil {
   222  		t.Error("expected error for zero ID")
   223  	}
   224  	if ecdsa != nil {
   225  		t.Error("expected nil result")
   226  	}
   227  }
   228  
   229  func quickcfg() *quick.Config {
   230  	return &quick.Config{
   231  		MaxCount: 5000,
   232  		Rand:     rand.New(rand.NewSource(time.Now().Unix())),
   233  	}
   234  }
   235  
   236  // TODO: The Generate method can be dropped when we require Go >= 1.5
   237  // because testing/quick learned to generate arrays in 1.5.
   238  
   239  func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value {
   240  	var id NodeID
   241  	m := rand.Intn(len(id))
   242  	for i := len(id) - 1; i > m; i-- {
   243  		id[i] = byte(rand.Uint32())
   244  	}
   245  	return reflect.ValueOf(id)
   246  }