github.com/klaytn/klaytn@v1.12.1/networks/p2p/dial_test.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from p2p/dial_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package p2p
    22  
    23  import (
    24  	"encoding/binary"
    25  	"net"
    26  	"reflect"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/davecgh/go-spew/spew"
    31  	"github.com/klaytn/klaytn/common"
    32  	"github.com/klaytn/klaytn/common/math"
    33  	"github.com/klaytn/klaytn/networks/p2p/discover"
    34  	"github.com/klaytn/klaytn/networks/p2p/netutil"
    35  )
    36  
    37  func init() {
    38  	spew.Config.Indent = "\t"
    39  }
    40  
    41  type dialtest struct {
    42  	init   *dialstate // state before and after the test.
    43  	rounds []round
    44  }
    45  
    46  type failedInfo struct {
    47  	id        discover.NodeID
    48  	failedTry int
    49  }
    50  
    51  type round struct {
    52  	peers   []*Peer      // current peer set
    53  	done    []task       // tasks that got done this round
    54  	new     []task       // the result must match this one
    55  	expired []failedInfo // task
    56  }
    57  
    58  func runDialTest(t *testing.T, test dialtest) {
    59  	var (
    60  		vTime   time.Time
    61  		running int
    62  	)
    63  	pm := func(ps []*Peer) map[discover.NodeID]*Peer {
    64  		m := make(map[discover.NodeID]*Peer)
    65  		for _, p := range ps {
    66  			m[p.ID()] = p
    67  		}
    68  		return m
    69  	}
    70  	for i, round := range test.rounds {
    71  		for _, task := range round.done {
    72  			running--
    73  			if running < 0 {
    74  				panic("running task counter underflow")
    75  			}
    76  			test.init.taskDone(task, vTime)
    77  		}
    78  
    79  		for _, info := range round.expired {
    80  			if dt, ok := test.init.static[info.id]; ok {
    81  				dt.failedTry = info.failedTry
    82  			}
    83  		}
    84  
    85  		new := test.init.newTasks(running, pm(round.peers), vTime)
    86  		if !sametasks(new, round.new) {
    87  			t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n",
    88  				i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running))
    89  		}
    90  
    91  		// Time advances by 16 seconds on every round.
    92  		vTime = vTime.Add(16 * time.Second)
    93  		running += len(new)
    94  	}
    95  }
    96  
    97  type fakeTable []*discover.Node
    98  
    99  func (t fakeTable) Name() string                                                    { return "fakeTable" }
   100  func (t fakeTable) Self() *discover.Node                                            { return new(discover.Node) }
   101  func (t fakeTable) Close()                                                          {}
   102  func (t fakeTable) Lookup(discover.NodeID, discover.NodeType) []*discover.Node      { return nil }
   103  func (t fakeTable) Resolve(discover.NodeID, discover.NodeType) *discover.Node       { return nil }
   104  func (t fakeTable) GetNodes(targetType discover.NodeType, max int) []*discover.Node { return nil }
   105  func (t fakeTable) ReadRandomNodes(buf []*discover.Node, nType discover.NodeType) int {
   106  	return copy(buf, t)
   107  }
   108  
   109  func (t fakeTable) RetrieveNodes(target common.Hash, nType discover.NodeType, nresults int) []*discover.Node {
   110  	return nil
   111  }
   112  func (t fakeTable) CreateUpdateNodeOnDB(n *discover.Node) error              { return nil }
   113  func (t fakeTable) CreateUpdateNodeOnTable(n *discover.Node) error           { return nil }
   114  func (t fakeTable) GetNodeFromDB(id discover.NodeID) (*discover.Node, error) { return nil, nil }
   115  func (t fakeTable) DeleteNodeFromDB(n *discover.Node) error                  { return nil }
   116  func (t fakeTable) DeleteNodeFromTable(n *discover.Node) error               { return nil }
   117  func (t fakeTable) GetBucketEntries() []*discover.Node                       { return nil }
   118  func (t fakeTable) GetReplacements() []*discover.Node                        { return nil }
   119  func (t fakeTable) HasBond(id discover.NodeID) bool                          { return true }
   120  func (t fakeTable) Bond(pinged bool, id discover.NodeID, addr *net.UDPAddr, tcpPort uint16, nType discover.NodeType) (*discover.Node, error) {
   121  	return nil, nil
   122  }
   123  
   124  func (t fakeTable) IsAuthorized(id discover.NodeID, ntype discover.NodeType) bool {
   125  	return true
   126  }
   127  
   128  func (t fakeTable) GetAuthorizedNodes() []*discover.Node         { return nil }
   129  func (t fakeTable) PutAuthorizedNodes(nodes []*discover.Node)    {}
   130  func (t fakeTable) DeleteAuthorizedNodes(nodes []*discover.Node) {}
   131  
   132  // This test checks that dynamic dials are launched from discovery results.
   133  func TestDialStateDynDial(t *testing.T) {
   134  	runDialTest(t, dialtest{
   135  		init: newDialState(nil, nil, fakeTable{}, 5, nil, nil, nil),
   136  		rounds: []round{
   137  			// A discovery query is launched.
   138  			{
   139  				peers: []*Peer{
   140  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   141  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   142  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   143  				},
   144  				new: []task{&discoverTask{}},
   145  			},
   146  			// Dynamic dials are launched when it completes.
   147  			{
   148  				peers: []*Peer{
   149  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   150  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   151  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   152  				},
   153  				done: []task{
   154  					&discoverTask{results: []*discover.Node{
   155  						{ID: uintID(2)}, // this one is already connected and not dialed.
   156  						{ID: uintID(3)},
   157  						{ID: uintID(4)},
   158  						{ID: uintID(5)},
   159  						{ID: uintID(6)}, // these are not tried because max dyn dials is 5
   160  						{ID: uintID(7)}, // ...
   161  					}},
   162  				},
   163  				new: []task{
   164  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   165  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   166  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   167  				},
   168  			},
   169  			// Some of the dials complete but no new ones are launched yet because
   170  			// the sum of active dial count and dynamic peer count is == maxDynDials.
   171  			{
   172  				peers: []*Peer{
   173  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   174  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   175  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   176  					{rws: []*conn{{flags: dynDialedConn, id: uintID(3)}}},
   177  					{rws: []*conn{{flags: dynDialedConn, id: uintID(4)}}},
   178  				},
   179  				done: []task{
   180  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   181  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   182  				},
   183  			},
   184  			// No new dial tasks are launched in the this round because
   185  			// maxDynDials has been reached.
   186  			{
   187  				peers: []*Peer{
   188  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   189  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   190  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   191  					{rws: []*conn{{flags: dynDialedConn, id: uintID(3)}}},
   192  					{rws: []*conn{{flags: dynDialedConn, id: uintID(4)}}},
   193  					{rws: []*conn{{flags: dynDialedConn, id: uintID(5)}}},
   194  				},
   195  				done: []task{
   196  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   197  				},
   198  				new: []task{
   199  					&waitExpireTask{Duration: 14 * time.Second},
   200  				},
   201  			},
   202  			// In this round, the peer with id 2 drops off. The query
   203  			// results from last discovery lookup are reused.
   204  			{
   205  				peers: []*Peer{
   206  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   207  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   208  					{rws: []*conn{{flags: dynDialedConn, id: uintID(3)}}},
   209  					{rws: []*conn{{flags: dynDialedConn, id: uintID(4)}}},
   210  					{rws: []*conn{{flags: dynDialedConn, id: uintID(5)}}},
   211  				},
   212  				new: []task{
   213  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   214  				},
   215  			},
   216  			// More peers (3,4) drop off and dial for ID 6 completes.
   217  			// The last query result from the discovery lookup is reused
   218  			// and a new one is spawned because more candidates are needed.
   219  			{
   220  				peers: []*Peer{
   221  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   222  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   223  					{rws: []*conn{{flags: dynDialedConn, id: uintID(5)}}},
   224  				},
   225  				done: []task{
   226  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   227  				},
   228  				new: []task{
   229  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   230  					&discoverTask{},
   231  				},
   232  			},
   233  			// Peer 7 is connected, but there still aren't enough dynamic peers
   234  			// (4 out of 5). However, a discovery is already running, so ensure
   235  			// no new is started.
   236  			{
   237  				peers: []*Peer{
   238  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   239  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   240  					{rws: []*conn{{flags: dynDialedConn, id: uintID(5)}}},
   241  					{rws: []*conn{{flags: dynDialedConn, id: uintID(7)}}},
   242  				},
   243  				done: []task{
   244  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   245  				},
   246  			},
   247  			// Finish the running node discovery with an empty set. A new lookup
   248  			// should be immediately requested.
   249  			{
   250  				peers: []*Peer{
   251  					{rws: []*conn{{flags: staticDialedConn, id: uintID(0)}}},
   252  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   253  					{rws: []*conn{{flags: dynDialedConn, id: uintID(5)}}},
   254  					{rws: []*conn{{flags: dynDialedConn, id: uintID(7)}}},
   255  				},
   256  				done: []task{
   257  					&discoverTask{},
   258  				},
   259  				new: []task{
   260  					&discoverTask{},
   261  				},
   262  			},
   263  		},
   264  	})
   265  }
   266  
   267  func TestDialStateDynDialFromTable(t *testing.T) {
   268  	// This table always returns the same random nodes
   269  	// in the order given below.
   270  	table := fakeTable{
   271  		{ID: uintID(1)},
   272  		{ID: uintID(2)},
   273  		{ID: uintID(3)},
   274  		{ID: uintID(4)},
   275  		{ID: uintID(5)},
   276  		{ID: uintID(6)},
   277  		{ID: uintID(7)},
   278  		{ID: uintID(8)},
   279  	}
   280  
   281  	runDialTest(t, dialtest{
   282  		init: newDialState(nil, nil, table, 10, nil, nil, nil),
   283  		rounds: []round{
   284  			// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
   285  			{
   286  				new: []task{
   287  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   288  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   289  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   290  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   291  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   292  					&discoverTask{},
   293  				},
   294  			},
   295  			// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
   296  			{
   297  				peers: []*Peer{
   298  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   299  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   300  				},
   301  				done: []task{
   302  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   303  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   304  					&discoverTask{results: []*discover.Node{
   305  						{ID: uintID(10)},
   306  						{ID: uintID(11)},
   307  						{ID: uintID(12)},
   308  					}},
   309  				},
   310  				new: []task{
   311  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   312  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   313  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   314  					&discoverTask{},
   315  				},
   316  			},
   317  			// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
   318  			{
   319  				peers: []*Peer{
   320  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   321  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   322  					{rws: []*conn{{flags: dynDialedConn, id: uintID(10)}}},
   323  					{rws: []*conn{{flags: dynDialedConn, id: uintID(11)}}},
   324  					{rws: []*conn{{flags: dynDialedConn, id: uintID(12)}}},
   325  				},
   326  				done: []task{
   327  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   328  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   329  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   330  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   331  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   332  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   333  				},
   334  			},
   335  			// Waiting for expiry. No waitExpireTask is launched because the
   336  			// discovery query is still running.
   337  			{
   338  				peers: []*Peer{
   339  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   340  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   341  					{rws: []*conn{{flags: dynDialedConn, id: uintID(10)}}},
   342  					{rws: []*conn{{flags: dynDialedConn, id: uintID(11)}}},
   343  					{rws: []*conn{{flags: dynDialedConn, id: uintID(12)}}},
   344  				},
   345  			},
   346  			// Nodes 3,4 are not tried again because only the first two
   347  			// returned random nodes (nodes 1,2) are tried and they're
   348  			// already connected.
   349  			{
   350  				peers: []*Peer{
   351  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   352  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   353  					{rws: []*conn{{flags: dynDialedConn, id: uintID(10)}}},
   354  					{rws: []*conn{{flags: dynDialedConn, id: uintID(11)}}},
   355  					{rws: []*conn{{flags: dynDialedConn, id: uintID(12)}}},
   356  				},
   357  			},
   358  		},
   359  	})
   360  }
   361  
   362  // This test checks that candidates that do not match the netrestrict list are not dialed.
   363  func TestDialStateNetRestrict(t *testing.T) {
   364  	// This table always returns the same random nodes
   365  	// in the order given below.
   366  	table := fakeTable{
   367  		{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
   368  		{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
   369  		{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
   370  		{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
   371  		{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
   372  		{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
   373  		{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
   374  		{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
   375  	}
   376  	restrict := new(netutil.Netlist)
   377  	restrict.Add("127.0.2.0/24")
   378  
   379  	runDialTest(t, dialtest{
   380  		init: newDialState(nil, nil, table, 10, restrict, nil, nil),
   381  		rounds: []round{
   382  			{
   383  				new: []task{
   384  					&dialTask{flags: dynDialedConn, dest: table[4]},
   385  					&discoverTask{},
   386  				},
   387  			},
   388  		},
   389  	})
   390  }
   391  
   392  // This test checks that static dials are launched.
   393  func TestDialStateStaticDial(t *testing.T) {
   394  	wantStatic := []*discover.Node{
   395  		{ID: uintID(1)},
   396  		{ID: uintID(2)},
   397  		{ID: uintID(3)},
   398  		{ID: uintID(4)},
   399  		{ID: uintID(5)},
   400  	}
   401  
   402  	runDialTest(t, dialtest{
   403  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil, nil, nil),
   404  		rounds: []round{
   405  			// Static dials are launched for the nodes that
   406  			// aren't yet connected.
   407  			{
   408  				peers: []*Peer{
   409  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   410  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   411  				},
   412  				new: []task{
   413  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}, dialType: DT_UNLIMITED},
   414  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}, dialType: DT_UNLIMITED},
   415  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}, dialType: DT_UNLIMITED},
   416  				},
   417  			},
   418  			// No new tasks are launched in this round because all static
   419  			// nodes are either connected or still being dialed.
   420  			{
   421  				peers: []*Peer{
   422  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   423  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   424  					{rws: []*conn{{flags: staticDialedConn, id: uintID(3)}}},
   425  				},
   426  				done: []task{
   427  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}, dialType: DT_UNLIMITED},
   428  				},
   429  			},
   430  			// No new dial tasks are launched because all static
   431  			// nodes are now connected.
   432  			{
   433  				peers: []*Peer{
   434  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   435  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   436  					{rws: []*conn{{flags: staticDialedConn, id: uintID(3)}}},
   437  					{rws: []*conn{{flags: staticDialedConn, id: uintID(4)}}},
   438  					{rws: []*conn{{flags: staticDialedConn, id: uintID(5)}}},
   439  				},
   440  				done: []task{
   441  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}, dialType: DT_UNLIMITED},
   442  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}, dialType: DT_UNLIMITED},
   443  				},
   444  				new: []task{
   445  					&waitExpireTask{Duration: 14 * time.Second},
   446  				},
   447  			},
   448  			// Wait a round for dial history to expire, no new tasks should spawn.
   449  			{
   450  				peers: []*Peer{
   451  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   452  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   453  					{rws: []*conn{{flags: staticDialedConn, id: uintID(3)}}},
   454  					{rws: []*conn{{flags: staticDialedConn, id: uintID(4)}}},
   455  					{rws: []*conn{{flags: staticDialedConn, id: uintID(5)}}},
   456  				},
   457  			},
   458  			// If a static node is dropped, it should be immediately redialed,
   459  			// irrespective whether it was originally static or dynamic.
   460  			{
   461  				peers: []*Peer{
   462  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   463  					{rws: []*conn{{flags: staticDialedConn, id: uintID(3)}}},
   464  					{rws: []*conn{{flags: staticDialedConn, id: uintID(5)}}},
   465  				},
   466  				new: []task{
   467  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}, dialType: DT_UNLIMITED},
   468  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}, dialType: DT_UNLIMITED},
   469  				},
   470  			},
   471  		},
   472  	})
   473  }
   474  
   475  // This test check expired task removed from static
   476  func TestDialStateTypeStaticDialExpired(t *testing.T) {
   477  	tdt := dialType("test")
   478  
   479  	tsMap := make(map[dialType]typedStatic)
   480  	tsMap[tdt] = typedStatic{maxNodeCount: math.MaxInt64, maxTry: 3}
   481  
   482  	ds := newDialState(nil, nil, fakeTable{}, 0, nil, nil, tsMap)
   483  	dt := dialtest{
   484  		init: ds,
   485  		rounds: []round{
   486  			{
   487  				new: []task{
   488  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(4)}, dialType: tdt, failedTry: 2},
   489  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(5)}, dialType: tdt, failedTry: 3},
   490  					&discoverTypedStaticTask{name: tdt, max: math.MaxInt64 - 2},
   491  				},
   492  			},
   493  		},
   494  	}
   495  
   496  	ds.addTypedStatic(&discover.Node{ID: uintID(4)}, tdt)
   497  	ds.static[discover.Node{ID: uintID(4)}.ID].failedTry = 2
   498  	ds.addTypedStatic(&discover.Node{ID: uintID(5)}, tdt)
   499  	ds.static[discover.Node{ID: uintID(5)}.ID].failedTry = 3
   500  	ds.addTypedStatic(&discover.Node{ID: uintID(6)}, tdt) // Expired DialTask, will removed from static
   501  	ds.static[discover.Node{ID: uintID(6)}.ID].failedTry = 4
   502  
   503  	runDialTest(t, dt)
   504  }
   505  
   506  func TestDialStateTypeStaticDialExpired2(t *testing.T) {
   507  	tdt := dialType("test")
   508  
   509  	tsMap := make(map[dialType]typedStatic)
   510  	tsMap[tdt] = typedStatic{maxNodeCount: 6, maxTry: 3}
   511  
   512  	ds := newDialState(nil, nil, fakeTable{}, 0, nil, nil, tsMap)
   513  	ds.addTypedStatic(&discover.Node{ID: uintID(4)}, tdt)
   514  	ds.addTypedStatic(&discover.Node{ID: uintID(5)}, tdt)
   515  	ds.addTypedStatic(&discover.Node{ID: uintID(6)}, tdt)
   516  	dt := dialtest{
   517  		init: ds,
   518  		rounds: []round{
   519  			{
   520  				peers: []*Peer{
   521  					{rws: []*conn{{flags: staticDialedConn, id: uintID(1)}}},
   522  				},
   523  				new: []task{
   524  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(4)}, dialType: tdt},
   525  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(5)}, dialType: tdt},
   526  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(6)}, dialType: tdt},
   527  					&discoverTypedStaticTask{name: tdt, max: 6 - 3},
   528  				},
   529  			},
   530  			{
   531  				// all dialTask are failed to connect and 4, 6 dialTask is expired
   532  				peers: []*Peer{
   533  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   534  				},
   535  				done: []task{
   536  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(4)}, dialType: tdt},
   537  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(5)}, dialType: tdt},
   538  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(6)}, dialType: tdt},
   539  				},
   540  				expired: []failedInfo{
   541  					{discover.Node{ID: uintID(4)}.ID, 4},
   542  					{discover.Node{ID: uintID(6)}.ID, 6},
   543  				},
   544  			},
   545  			{
   546  				// Wait expired task is returned to normal
   547  				peers: []*Peer{
   548  					{rws: []*conn{{flags: staticDialedConn | trustedConn, id: uintID(1)}}},
   549  				},
   550  			},
   551  			{
   552  				peers: []*Peer{
   553  					{rws: []*conn{{flags: staticDialedConn | trustedConn, id: uintID(1)}}},
   554  				},
   555  				new: []task{
   556  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(5)}, dialType: tdt},
   557  				},
   558  			},
   559  		},
   560  	}
   561  	runDialTest(t, dt)
   562  }
   563  
   564  func TestDialStateDiscoverTypedStatic(t *testing.T) {
   565  	tdt := dialType("test")
   566  
   567  	tsMap := make(map[dialType]typedStatic)
   568  	tsMap[tdt] = typedStatic{maxNodeCount: 6, maxTry: 3}
   569  
   570  	ds := newDialState(nil, nil, fakeTable{}, 0, nil, nil, tsMap)
   571  	ds.addTypedStatic(&discover.Node{ID: uintID(4)}, tdt)
   572  	ds.addTypedStatic(&discover.Node{ID: uintID(5)}, tdt)
   573  	ds.addTypedStatic(&discover.Node{ID: uintID(6)}, tdt)
   574  
   575  	dt := dialtest{
   576  		init: ds,
   577  		rounds: []round{
   578  			{
   579  				peers: []*Peer{
   580  					{rws: []*conn{{flags: staticDialedConn, id: uintID(1)}}},
   581  				},
   582  				new: []task{
   583  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(4)}, dialType: tdt},
   584  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(5)}, dialType: tdt},
   585  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(6)}, dialType: tdt},
   586  					&discoverTypedStaticTask{name: tdt, max: 6 - 3},
   587  				},
   588  			},
   589  			{
   590  				peers: []*Peer{
   591  					{rws: []*conn{{flags: staticDialedConn, id: uintID(1)}}},
   592  				},
   593  				done: []task{
   594  					&discoverTypedStaticTask{name: tdt, max: 6 - 3},
   595  				},
   596  				new: []task{
   597  					&discoverTypedStaticTask{name: tdt, max: 6 - 3},
   598  				},
   599  			},
   600  		},
   601  	}
   602  	runDialTest(t, dt)
   603  }
   604  
   605  func TestDialStateTypedStaticMaxConn(t *testing.T) {
   606  	tdt := dialType("test")
   607  
   608  	tsMap := make(map[dialType]typedStatic)
   609  	tsMap[tdt] = typedStatic{maxNodeCount: 3, maxTry: math.MaxInt64}
   610  
   611  	ds := newDialState(nil, nil, fakeTable{}, 0, nil, nil, tsMap)
   612  	ds.addTypedStatic(&discover.Node{ID: uintID(1)}, tdt)
   613  	ds.addTypedStatic(&discover.Node{ID: uintID(2)}, tdt)
   614  	ds.addTypedStatic(&discover.Node{ID: uintID(3)}, tdt) // will be delete cause exceed allowed typed conntection
   615  	dt := dialtest{
   616  		init: ds,
   617  		rounds: []round{
   618  			{
   619  				new: []task{
   620  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(1)}, dialType: tdt},
   621  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(2)}, dialType: tdt},
   622  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(3)}, dialType: tdt},
   623  				},
   624  			},
   625  		},
   626  	}
   627  	runDialTest(t, dt)
   628  }
   629  
   630  func TestDialStateTypedStaticMaxConn2(t *testing.T) {
   631  	tdt := dialType("test")
   632  
   633  	tsMap := make(map[dialType]typedStatic)
   634  	tsMap[tdt] = typedStatic{maxNodeCount: 3, maxTry: math.MaxInt64}
   635  
   636  	ds := newDialState(nil, nil, fakeTable{}, 0, nil, nil, tsMap)
   637  	ds.addTypedStatic(&discover.Node{ID: uintID(1)}, tdt)
   638  	ds.addTypedStatic(&discover.Node{ID: uintID(2)}, tdt)
   639  	ds.addTypedStatic(&discover.Node{ID: uintID(3)}, tdt) // will be delete cause exceed allowed typed conntection
   640  	dt := dialtest{
   641  		init: ds,
   642  		rounds: []round{
   643  			{
   644  				peers: []*Peer{
   645  					{rws: []*conn{{flags: staticDialedConn | trustedConn, id: uintID(1)}}},
   646  					{rws: []*conn{{flags: staticDialedConn | trustedConn, id: uintID(2)}}},
   647  				},
   648  				new: []task{
   649  					&dialTask{flags: staticDialedConn | trustedConn, dest: &discover.Node{ID: uintID(3)}, dialType: tdt},
   650  				},
   651  			},
   652  		},
   653  	}
   654  	runDialTest(t, dt)
   655  }
   656  
   657  func TestDialStateTypedStaticMaxConn3(t *testing.T) {
   658  	tdt := dialType("test")
   659  
   660  	tsMap := make(map[dialType]typedStatic)
   661  	tsMap[tdt] = typedStatic{maxNodeCount: 3, maxTry: math.MaxInt64}
   662  
   663  	ds := newDialState(nil, nil, fakeTable{}, 0, nil, nil, tsMap)
   664  	ds.addTypedStatic(&discover.Node{ID: uintID(1)}, tdt)
   665  	ds.addTypedStatic(&discover.Node{ID: uintID(2)}, tdt)
   666  	ds.addTypedStatic(&discover.Node{ID: uintID(3)}, tdt) // will be delete cause exceed allowed typed conntection
   667  	ds.addTypedStatic(&discover.Node{ID: uintID(4)}, tdt)
   668  	ds.addTypedStatic(&discover.Node{ID: uintID(5)}, tdt)
   669  	ds.addTypedStatic(&discover.Node{ID: uintID(6)}, tdt)
   670  	dt := dialtest{
   671  		init: ds,
   672  		rounds: []round{
   673  			{
   674  				peers: []*Peer{
   675  					{rws: []*conn{{flags: staticDialedConn, id: uintID(1)}}},
   676  					{rws: []*conn{{flags: staticDialedConn, id: uintID(2)}}},
   677  					{rws: []*conn{{flags: staticDialedConn, id: uintID(3)}}},
   678  				},
   679  				new: []task{},
   680  			},
   681  		},
   682  	}
   683  	runDialTest(t, dt)
   684  }
   685  
   686  // This test checks if static dials can ignore adding self ID to static node list.
   687  func TestDialStateAddingSelfNode(t *testing.T) {
   688  	privateKey := newkey()
   689  	nodeID := discover.PubkeyID(&privateKey.PublicKey)
   690  
   691  	fakePrivateKey := newkey()
   692  
   693  	wantStatic := []*discover.Node{
   694  		{ID: uintID(1)},
   695  		{ID: uintID(2)},
   696  		{ID: nodeID},
   697  		{ID: uintID(3)},
   698  		{ID: uintID(4)},
   699  	}
   700  
   701  	dialState_nil := newDialState(wantStatic, nil, fakeTable{}, 0, nil, nil, nil)
   702  	dialState_func := newDialState(wantStatic, nil, fakeTable{}, 0, nil, privateKey, nil)
   703  	dialState_normal := newDialState(wantStatic, nil, fakeTable{}, 0, nil, fakePrivateKey, nil)
   704  
   705  	if len(dialState_nil.static) != 5 {
   706  		t.Errorf("newDialState() can't process nil privateKey")
   707  	}
   708  
   709  	for _, n := range dialState_func.static {
   710  		if n.dest.ID == nodeID {
   711  			t.Errorf("newDialState() can't ignore adding self node to the static node list")
   712  		}
   713  	}
   714  
   715  	if len(dialState_normal.static) != 5 {
   716  		t.Errorf("newDialState() can't deal with normal case")
   717  	}
   718  }
   719  
   720  // This test checks that static peers will be redialed immediately if they were re-added to a static list.
   721  func TestDialStaticAfterReset(t *testing.T) {
   722  	wantStatic := []*discover.Node{
   723  		{ID: uintID(1)},
   724  		{ID: uintID(2)},
   725  	}
   726  
   727  	rounds := []round{
   728  		// Static dials are launched for the nodes that aren't yet connected.
   729  		{
   730  			peers: nil,
   731  			new: []task{
   732  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}, dialType: DT_UNLIMITED},
   733  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}, dialType: DT_UNLIMITED},
   734  			},
   735  		},
   736  		// No new dial tasks, all peers are connected.
   737  		{
   738  			peers: []*Peer{
   739  				{rws: []*conn{{flags: staticDialedConn, id: uintID(1)}}},
   740  				{rws: []*conn{{flags: staticDialedConn, id: uintID(2)}}},
   741  			},
   742  			done: []task{
   743  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}, dialType: DT_UNLIMITED},
   744  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}, dialType: DT_UNLIMITED},
   745  			},
   746  			new: []task{
   747  				&waitExpireTask{Duration: 30 * time.Second},
   748  			},
   749  		},
   750  	}
   751  	dTest := dialtest{
   752  		init:   newDialState(wantStatic, nil, fakeTable{}, 0, nil, nil, nil),
   753  		rounds: rounds,
   754  	}
   755  	runDialTest(t, dTest)
   756  	for _, n := range wantStatic {
   757  		dTest.init.removeStatic(n)
   758  		dTest.init.addStatic(n)
   759  	}
   760  	// without removing peers they will be considered recently dialed
   761  	runDialTest(t, dTest)
   762  }
   763  
   764  // This test checks that past dials are not retried for some time.
   765  func TestDialStateCache(t *testing.T) {
   766  	wantStatic := []*discover.Node{
   767  		{ID: uintID(1)},
   768  		{ID: uintID(2)},
   769  		{ID: uintID(3)},
   770  	}
   771  
   772  	runDialTest(t, dialtest{
   773  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil, nil, nil),
   774  		rounds: []round{
   775  			// Static dials are launched for the nodes that
   776  			// aren't yet connected.
   777  			{
   778  				peers: nil,
   779  				new: []task{
   780  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}, dialType: DT_UNLIMITED},
   781  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}, dialType: DT_UNLIMITED},
   782  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}, dialType: DT_UNLIMITED},
   783  				},
   784  			},
   785  			// No new tasks are launched in this round because all static
   786  			// nodes are either connected or still being dialed.
   787  			{
   788  				peers: []*Peer{
   789  					{rws: []*conn{{flags: staticDialedConn, id: uintID(1)}}},
   790  					{rws: []*conn{{flags: staticDialedConn, id: uintID(2)}}},
   791  				},
   792  				done: []task{
   793  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}, dialType: DT_UNLIMITED},
   794  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}, dialType: DT_UNLIMITED},
   795  				},
   796  			},
   797  			// A salvage task is launched to wait for node 3's history
   798  			// entry to expire.
   799  			{
   800  				peers: []*Peer{
   801  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   802  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   803  				},
   804  				done: []task{
   805  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   806  				},
   807  				new: []task{
   808  					&waitExpireTask{Duration: 14 * time.Second},
   809  				},
   810  			},
   811  			// Still waiting for node 3's entry to expire in the cache.
   812  			{
   813  				peers: []*Peer{
   814  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   815  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   816  				},
   817  			},
   818  			// The cache entry for node 3 has expired and is retried.
   819  			{
   820  				peers: []*Peer{
   821  					{rws: []*conn{{flags: dynDialedConn, id: uintID(1)}}},
   822  					{rws: []*conn{{flags: dynDialedConn, id: uintID(2)}}},
   823  				},
   824  				new: []task{
   825  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}, dialType: DT_UNLIMITED},
   826  				},
   827  			},
   828  		},
   829  	})
   830  }
   831  
   832  func TestDialResolve(t *testing.T) {
   833  	resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444, nil, discover.NodeTypeUnknown)
   834  	table := &resolveMock{answer: resolved}
   835  	state := newDialState(nil, nil, table, 0, nil, nil, nil)
   836  
   837  	// Check that the task is generated with an incomplete ID.
   838  	dest := discover.NewNode(uintID(1), nil, 0, 0, nil, discover.NodeTypeUnknown)
   839  	state.addStatic(dest)
   840  	tasks := state.newTasks(0, nil, time.Time{})
   841  	if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest, dialType: DT_UNLIMITED}}) {
   842  		t.Fatalf("expected dial task, got %#v", tasks)
   843  	}
   844  
   845  	// Now run the task, it should resolve the ID once.
   846  	config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
   847  	srv := &SingleChannelServer{&BaseServer{ntab: table, Config: config}}
   848  	tasks[0].Do(srv)
   849  	if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) {
   850  		t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
   851  	}
   852  
   853  	// Report it as done to the dialer, which should update the static node record.
   854  	state.taskDone(tasks[0], time.Now())
   855  	if state.static[uintID(1)].dest != resolved {
   856  		t.Fatalf("state.dest not updated")
   857  	}
   858  }
   859  
   860  // compares task lists but doesn't care about the order.
   861  func sametasks(a, b []task) bool {
   862  	if len(a) != len(b) {
   863  		return false
   864  	}
   865  next:
   866  	for _, ta := range a {
   867  		for _, tb := range b {
   868  			if reflect.DeepEqual(ta, tb) {
   869  				continue next
   870  			}
   871  		}
   872  		return false
   873  	}
   874  	return true
   875  }
   876  
   877  func uintID(i uint32) discover.NodeID {
   878  	var id discover.NodeID
   879  	binary.BigEndian.PutUint32(id[:], i)
   880  	return id
   881  }
   882  
   883  // implements discoverTable for TestDialResolve
   884  type resolveMock struct {
   885  	resolveCalls []discover.NodeID
   886  	answer       *discover.Node
   887  }
   888  
   889  func (t *resolveMock) GetNodes(targetType discover.NodeType, max int) []*discover.Node {
   890  	panic("implement me")
   891  }
   892  
   893  func (t *resolveMock) LookupByType(target discover.NodeID, dt discover.DiscoveryType, nType discover.NodeType) []*discover.Node {
   894  	panic("implement me")
   895  }
   896  
   897  func (t *resolveMock) Name() string {
   898  	panic("implement me")
   899  }
   900  
   901  func (t *resolveMock) RetrieveNodes(target common.Hash, nType discover.NodeType, nresults int) []*discover.Node {
   902  	panic("implement me")
   903  }
   904  
   905  func (t *resolveMock) HasBond(id discover.NodeID) bool {
   906  	panic("implement me")
   907  }
   908  
   909  func (t *resolveMock) Bond(pinged bool, id discover.NodeID, addr *net.UDPAddr, tcpPort uint16, nType discover.NodeType) (*discover.Node, error) {
   910  	panic("implement me")
   911  }
   912  
   913  func (t *resolveMock) CreateUpdateNodeOnDB(n *discover.Node) error {
   914  	panic("implement me")
   915  }
   916  
   917  func (t *resolveMock) CreateUpdateNodeOnTable(n *discover.Node) error {
   918  	panic("implement me")
   919  }
   920  
   921  func (t *resolveMock) GetNodeFromDB(id discover.NodeID) (*discover.Node, error) {
   922  	panic("implement me")
   923  }
   924  
   925  func (t *resolveMock) DeleteNodeFromDB(n *discover.Node) error {
   926  	panic("implement me")
   927  }
   928  
   929  func (t *resolveMock) DeleteNodeFromTable(n *discover.Node) error {
   930  	panic("implement me")
   931  }
   932  
   933  func (t *resolveMock) GetBucketEntries() []*discover.Node {
   934  	panic("implement me")
   935  }
   936  
   937  func (t *resolveMock) GetReplacements() []*discover.Node {
   938  	panic("implement me")
   939  }
   940  
   941  func (t *resolveMock) Resolve(target discover.NodeID, nType discover.NodeType) *discover.Node {
   942  	t.resolveCalls = append(t.resolveCalls, target)
   943  	return t.answer
   944  }
   945  
   946  func (t *resolveMock) Self() *discover.Node { return new(discover.Node) }
   947  
   948  func (t *resolveMock) Close()                     {}
   949  func (t *resolveMock) Bootstrap([]*discover.Node) {}
   950  func (t *resolveMock) Lookup(target discover.NodeID, nType discover.NodeType) []*discover.Node {
   951  	return nil
   952  }
   953  func (t *resolveMock) ReadRandomNodes(buf []*discover.Node, nType discover.NodeType) int { return 0 }
   954  func (t *resolveMock) IsAuthorized(id discover.NodeID, ntype discover.NodeType) bool {
   955  	panic("implement me")
   956  }
   957  
   958  func (t *resolveMock) GetAuthorizedNodes() []*discover.Node {
   959  	panic("implement me")
   960  }
   961  
   962  func (t *resolveMock) PutAuthorizedNodes(nodes []*discover.Node) {
   963  	panic("implement me")
   964  }
   965  
   966  func (t *resolveMock) DeleteAuthorizedNodes(nodes []*discover.Node) {
   967  	panic("implement me")
   968  }