github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/p2p/dial_test.go (about)

     1  package p2p
     2  
     3  import (
     4  	"encoding/binary"
     5  	"net"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/davecgh/go-spew/spew"
    11  	"github.com/quickchainproject/quickchain/p2p/discover"
    12  	"github.com/quickchainproject/quickchain/p2p/netutil"
    13  )
    14  
    15  func init() {
    16  	spew.Config.Indent = "\t"
    17  }
    18  
    19  type dialtest struct {
    20  	init   *dialstate // state before and after the test.
    21  	rounds []round
    22  }
    23  
    24  type round struct {
    25  	peers []*Peer // current peer set
    26  	done  []task  // tasks that got done this round
    27  	new   []task  // the result must match this one
    28  }
    29  
    30  func runDialTest(t *testing.T, test dialtest) {
    31  	var (
    32  		vtime   time.Time
    33  		running int
    34  	)
    35  	pm := func(ps []*Peer) map[discover.NodeID]*Peer {
    36  		m := make(map[discover.NodeID]*Peer)
    37  		for _, p := range ps {
    38  			m[p.rw.id] = p
    39  		}
    40  		return m
    41  	}
    42  	for i, round := range test.rounds {
    43  		for _, task := range round.done {
    44  			running--
    45  			if running < 0 {
    46  				panic("running task counter underflow")
    47  			}
    48  			test.init.taskDone(task, vtime)
    49  		}
    50  
    51  		new := test.init.newTasks(running, pm(round.peers), vtime)
    52  		if !sametasks(new, round.new) {
    53  			t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n",
    54  				i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running))
    55  		}
    56  
    57  		// Time advances by 16 seconds on every round.
    58  		vtime = vtime.Add(16 * time.Second)
    59  		running += len(new)
    60  	}
    61  }
    62  
    63  type fakeTable []*discover.Node
    64  
    65  func (t fakeTable) Self() *discover.Node                     { return new(discover.Node) }
    66  func (t fakeTable) Close()                                   {}
    67  func (t fakeTable) Lookup(discover.NodeID) []*discover.Node  { return nil }
    68  func (t fakeTable) Resolve(discover.NodeID) *discover.Node   { return nil }
    69  func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) }
    70  
    71  // This test checks that dynamic dials are launched from discovery results.
    72  func TestDialStateDynDial(t *testing.T) {
    73  	runDialTest(t, dialtest{
    74  		init: newDialState(nil, nil, fakeTable{}, 5, nil),
    75  		rounds: []round{
    76  			// A discovery query is launched.
    77  			{
    78  				peers: []*Peer{
    79  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
    80  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
    81  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
    82  				},
    83  				new: []task{&discoverTask{}},
    84  			},
    85  			// Dynamic dials are launched when it completes.
    86  			{
    87  				peers: []*Peer{
    88  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
    89  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
    90  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
    91  				},
    92  				done: []task{
    93  					&discoverTask{results: []*discover.Node{
    94  						{ID: uintID(2)}, // this one is already connected and not dialed.
    95  						{ID: uintID(3)},
    96  						{ID: uintID(4)},
    97  						{ID: uintID(5)},
    98  						{ID: uintID(6)}, // these are not tried because max dyn dials is 5
    99  						{ID: uintID(7)}, // ...
   100  					}},
   101  				},
   102  				new: []task{
   103  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   104  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   105  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   106  				},
   107  			},
   108  			// Some of the dials complete but no new ones are launched yet because
   109  			// the sum of active dial count and dynamic peer count is == maxDynDials.
   110  			{
   111  				peers: []*Peer{
   112  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   113  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   114  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   115  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   116  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   117  				},
   118  				done: []task{
   119  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   120  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   121  				},
   122  			},
   123  			// No new dial tasks are launched in the this round because
   124  			// maxDynDials has been reached.
   125  			{
   126  				peers: []*Peer{
   127  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   128  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   129  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   130  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   131  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   132  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   133  				},
   134  				done: []task{
   135  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   136  				},
   137  				new: []task{
   138  					&waitExpireTask{Duration: 14 * time.Second},
   139  				},
   140  			},
   141  			// In this round, the peer with id 2 drops off. The query
   142  			// results from last discovery lookup are reused.
   143  			{
   144  				peers: []*Peer{
   145  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   146  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   147  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   148  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   149  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   150  				},
   151  				new: []task{
   152  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   153  				},
   154  			},
   155  			// More peers (3,4) drop off and dial for ID 6 completes.
   156  			// The last query result from the discovery lookup is reused
   157  			// and a new one is spawned because more candidates are needed.
   158  			{
   159  				peers: []*Peer{
   160  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   161  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   162  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   163  				},
   164  				done: []task{
   165  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   166  				},
   167  				new: []task{
   168  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   169  					&discoverTask{},
   170  				},
   171  			},
   172  			// Peer 7 is connected, but there still aren't enough dynamic peers
   173  			// (4 out of 5). However, a discovery is already running, so ensure
   174  			// no new is started.
   175  			{
   176  				peers: []*Peer{
   177  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   178  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   179  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   180  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   181  				},
   182  				done: []task{
   183  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   184  				},
   185  			},
   186  			// Finish the running node discovery with an empty set. A new lookup
   187  			// should be immediately requested.
   188  			{
   189  				peers: []*Peer{
   190  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   191  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   192  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   193  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   194  				},
   195  				done: []task{
   196  					&discoverTask{},
   197  				},
   198  				new: []task{
   199  					&discoverTask{},
   200  				},
   201  			},
   202  		},
   203  	})
   204  }
   205  
   206  // Tests that bootnodes are dialed if no peers are connectd, but not otherwise.
   207  func TestDialStateDynDialBootnode(t *testing.T) {
   208  	bootnodes := []*discover.Node{
   209  		{ID: uintID(1)},
   210  		{ID: uintID(2)},
   211  		{ID: uintID(3)},
   212  	}
   213  	table := fakeTable{
   214  		{ID: uintID(4)},
   215  		{ID: uintID(5)},
   216  		{ID: uintID(6)},
   217  		{ID: uintID(7)},
   218  		{ID: uintID(8)},
   219  	}
   220  	runDialTest(t, dialtest{
   221  		init: newDialState(nil, bootnodes, table, 5, nil),
   222  		rounds: []round{
   223  			// 2 dynamic dials attempted, bootnodes pending fallback interval
   224  			{
   225  				new: []task{
   226  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   227  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   228  					&discoverTask{},
   229  				},
   230  			},
   231  			// No dials succeed, bootnodes still pending fallback interval
   232  			{
   233  				done: []task{
   234  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   235  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   236  				},
   237  			},
   238  			// No dials succeed, bootnodes still pending fallback interval
   239  			{},
   240  			// No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached
   241  			{
   242  				new: []task{
   243  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   244  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   245  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   246  				},
   247  			},
   248  			// No dials succeed, 2nd bootnode is attempted
   249  			{
   250  				done: []task{
   251  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   252  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   253  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   254  				},
   255  				new: []task{
   256  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   257  				},
   258  			},
   259  			// No dials succeed, 3rd bootnode is attempted
   260  			{
   261  				done: []task{
   262  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   263  				},
   264  				new: []task{
   265  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   266  				},
   267  			},
   268  			// No dials succeed, 1st bootnode is attempted again, expired random nodes retried
   269  			{
   270  				done: []task{
   271  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   272  				},
   273  				new: []task{
   274  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   275  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   276  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   277  				},
   278  			},
   279  			// Random dial succeeds, no more bootnodes are attempted
   280  			{
   281  				peers: []*Peer{
   282  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   283  				},
   284  				done: []task{
   285  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   286  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   287  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   288  				},
   289  			},
   290  		},
   291  	})
   292  }
   293  
   294  func TestDialStateDynDialFromTable(t *testing.T) {
   295  	// This table always returns the same random nodes
   296  	// in the order given below.
   297  	table := fakeTable{
   298  		{ID: uintID(1)},
   299  		{ID: uintID(2)},
   300  		{ID: uintID(3)},
   301  		{ID: uintID(4)},
   302  		{ID: uintID(5)},
   303  		{ID: uintID(6)},
   304  		{ID: uintID(7)},
   305  		{ID: uintID(8)},
   306  	}
   307  
   308  	runDialTest(t, dialtest{
   309  		init: newDialState(nil, nil, table, 10, nil),
   310  		rounds: []round{
   311  			// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
   312  			{
   313  				new: []task{
   314  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   315  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   316  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   317  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   318  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   319  					&discoverTask{},
   320  				},
   321  			},
   322  			// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
   323  			{
   324  				peers: []*Peer{
   325  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   326  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   327  				},
   328  				done: []task{
   329  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   330  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   331  					&discoverTask{results: []*discover.Node{
   332  						{ID: uintID(10)},
   333  						{ID: uintID(11)},
   334  						{ID: uintID(12)},
   335  					}},
   336  				},
   337  				new: []task{
   338  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   339  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   340  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   341  					&discoverTask{},
   342  				},
   343  			},
   344  			// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
   345  			{
   346  				peers: []*Peer{
   347  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   348  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   349  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   350  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   351  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   352  				},
   353  				done: []task{
   354  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   355  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   356  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   357  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   358  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   359  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   360  				},
   361  			},
   362  			// Waiting for expiry. No waitExpireTask is launched because the
   363  			// discovery query is still running.
   364  			{
   365  				peers: []*Peer{
   366  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   367  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   368  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   369  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   370  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   371  				},
   372  			},
   373  			// Nodes 3,4 are not tried again because only the first two
   374  			// returned random nodes (nodes 1,2) are tried and they're
   375  			// already connected.
   376  			{
   377  				peers: []*Peer{
   378  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   379  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   380  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   381  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   382  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   383  				},
   384  			},
   385  		},
   386  	})
   387  }
   388  
   389  // This test checks that candidates that do not match the netrestrict list are not dialed.
   390  func TestDialStateNetRestrict(t *testing.T) {
   391  	// This table always returns the same random nodes
   392  	// in the order given below.
   393  	table := fakeTable{
   394  		{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
   395  		{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
   396  		{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
   397  		{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
   398  		{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
   399  		{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
   400  		{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
   401  		{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
   402  	}
   403  	restrict := new(netutil.Netlist)
   404  	restrict.Add("127.0.2.0/24")
   405  
   406  	runDialTest(t, dialtest{
   407  		init: newDialState(nil, nil, table, 10, restrict),
   408  		rounds: []round{
   409  			{
   410  				new: []task{
   411  					&dialTask{flags: dynDialedConn, dest: table[4]},
   412  					&discoverTask{},
   413  				},
   414  			},
   415  		},
   416  	})
   417  }
   418  
   419  // This test checks that static dials are launched.
   420  func TestDialStateStaticDial(t *testing.T) {
   421  	wantStatic := []*discover.Node{
   422  		{ID: uintID(1)},
   423  		{ID: uintID(2)},
   424  		{ID: uintID(3)},
   425  		{ID: uintID(4)},
   426  		{ID: uintID(5)},
   427  	}
   428  
   429  	runDialTest(t, dialtest{
   430  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   431  		rounds: []round{
   432  			// Static dials are launched for the nodes that
   433  			// aren't yet connected.
   434  			{
   435  				peers: []*Peer{
   436  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   437  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   438  				},
   439  				new: []task{
   440  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   441  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   442  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   443  				},
   444  			},
   445  			// No new tasks are launched in this round because all static
   446  			// nodes are either connected or still being dialed.
   447  			{
   448  				peers: []*Peer{
   449  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   450  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   451  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   452  				},
   453  				done: []task{
   454  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   455  				},
   456  			},
   457  			// No new dial tasks are launched because all static
   458  			// nodes are now connected.
   459  			{
   460  				peers: []*Peer{
   461  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   462  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   463  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   464  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   465  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   466  				},
   467  				done: []task{
   468  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   469  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   470  				},
   471  				new: []task{
   472  					&waitExpireTask{Duration: 14 * time.Second},
   473  				},
   474  			},
   475  			// Wait a round for dial history to expire, no new tasks should spawn.
   476  			{
   477  				peers: []*Peer{
   478  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   479  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   480  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   481  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   482  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   483  				},
   484  			},
   485  			// If a static node is dropped, it should be immediately redialed,
   486  			// irrespective whether it was originally static or dynamic.
   487  			{
   488  				peers: []*Peer{
   489  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   490  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   491  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   492  				},
   493  				new: []task{
   494  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   495  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   496  				},
   497  			},
   498  		},
   499  	})
   500  }
   501  
   502  // This test checks that static peers will be redialed immediately if they were re-added to a static list.
   503  func TestDialStaticAfterReset(t *testing.T) {
   504  	wantStatic := []*discover.Node{
   505  		{ID: uintID(1)},
   506  		{ID: uintID(2)},
   507  	}
   508  
   509  	rounds := []round{
   510  		// Static dials are launched for the nodes that aren't yet connected.
   511  		{
   512  			peers: nil,
   513  			new: []task{
   514  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   515  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   516  			},
   517  		},
   518  		// No new dial tasks, all peers are connected.
   519  		{
   520  			peers: []*Peer{
   521  				{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   522  				{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   523  			},
   524  			done: []task{
   525  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   526  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   527  			},
   528  			new: []task{
   529  				&waitExpireTask{Duration: 30 * time.Second},
   530  			},
   531  		},
   532  	}
   533  	dTest := dialtest{
   534  		init:   newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   535  		rounds: rounds,
   536  	}
   537  	runDialTest(t, dTest)
   538  	for _, n := range wantStatic {
   539  		dTest.init.removeStatic(n)
   540  		dTest.init.addStatic(n)
   541  	}
   542  	// without removing peers they will be considered recently dialed
   543  	runDialTest(t, dTest)
   544  }
   545  
   546  // This test checks that past dials are not retried for some time.
   547  func TestDialStateCache(t *testing.T) {
   548  	wantStatic := []*discover.Node{
   549  		{ID: uintID(1)},
   550  		{ID: uintID(2)},
   551  		{ID: uintID(3)},
   552  	}
   553  
   554  	runDialTest(t, dialtest{
   555  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   556  		rounds: []round{
   557  			// Static dials are launched for the nodes that
   558  			// aren't yet connected.
   559  			{
   560  				peers: nil,
   561  				new: []task{
   562  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   563  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   564  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   565  				},
   566  			},
   567  			// No new tasks are launched in this round because all static
   568  			// nodes are either connected or still being dialed.
   569  			{
   570  				peers: []*Peer{
   571  					{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   572  					{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   573  				},
   574  				done: []task{
   575  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   576  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   577  				},
   578  			},
   579  			// A salvage task is launched to wait for node 3's history
   580  			// entry to expire.
   581  			{
   582  				peers: []*Peer{
   583  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   584  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   585  				},
   586  				done: []task{
   587  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   588  				},
   589  				new: []task{
   590  					&waitExpireTask{Duration: 14 * time.Second},
   591  				},
   592  			},
   593  			// Still waiting for node 3's entry to expire in the cache.
   594  			{
   595  				peers: []*Peer{
   596  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   597  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   598  				},
   599  			},
   600  			// The cache entry for node 3 has expired and is retried.
   601  			{
   602  				peers: []*Peer{
   603  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   604  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   605  				},
   606  				new: []task{
   607  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   608  				},
   609  			},
   610  		},
   611  	})
   612  }
   613  
   614  func TestDialResolve(t *testing.T) {
   615  	resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444)
   616  	table := &resolveMock{answer: resolved}
   617  	state := newDialState(nil, nil, table, 0, nil)
   618  
   619  	// Check that the task is generated with an incomplete ID.
   620  	dest := discover.NewNode(uintID(1), nil, 0, 0)
   621  	state.addStatic(dest)
   622  	tasks := state.newTasks(0, nil, time.Time{})
   623  	if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
   624  		t.Fatalf("expected dial task, got %#v", tasks)
   625  	}
   626  
   627  	// Now run the task, it should resolve the ID once.
   628  	config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
   629  	srv := &Server{ntab: table, Config: config}
   630  	tasks[0].Do(srv)
   631  	if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) {
   632  		t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
   633  	}
   634  
   635  	// Report it as done to the dialer, which should update the static node record.
   636  	state.taskDone(tasks[0], time.Now())
   637  	if state.static[uintID(1)].dest != resolved {
   638  		t.Fatalf("state.dest not updated")
   639  	}
   640  }
   641  
   642  // compares task lists but doesn't care about the order.
   643  func sametasks(a, b []task) bool {
   644  	if len(a) != len(b) {
   645  		return false
   646  	}
   647  next:
   648  	for _, ta := range a {
   649  		for _, tb := range b {
   650  			if reflect.DeepEqual(ta, tb) {
   651  				continue next
   652  			}
   653  		}
   654  		return false
   655  	}
   656  	return true
   657  }
   658  
   659  func uintID(i uint32) discover.NodeID {
   660  	var id discover.NodeID
   661  	binary.BigEndian.PutUint32(id[:], i)
   662  	return id
   663  }
   664  
   665  // implements discoverTable for TestDialResolve
   666  type resolveMock struct {
   667  	resolveCalls []discover.NodeID
   668  	answer       *discover.Node
   669  }
   670  
   671  func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node {
   672  	t.resolveCalls = append(t.resolveCalls, id)
   673  	return t.answer
   674  }
   675  
   676  func (t *resolveMock) Self() *discover.Node                     { return new(discover.Node) }
   677  func (t *resolveMock) Close()                                   {}
   678  func (t *resolveMock) Bootstrap([]*discover.Node)               {}
   679  func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node  { return nil }
   680  func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }