github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/dial_test.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package p2p
    26  
    27  import (
    28  	"encoding/binary"
    29  	"net"
    30  	"reflect"
    31  	"testing"
    32  	"time"
    33  
    34  	"github.com/davecgh/go-spew/spew"
    35  	"github.com/ethereum/go-ethereum/p2p/discover"
    36  	"github.com/ethereum/go-ethereum/p2p/netutil"
    37  )
    38  
    39  func init() {
    40  	spew.Config.Indent = "\t"
    41  }
    42  
    43  type dialtest struct {
    44  init   *dialstate //测试前后的状态。
    45  	rounds []round
    46  }
    47  
    48  type round struct {
    49  peers []*Peer //当前对等集
    50  done  []task  //这一轮完成的任务
    51  new   []task  //结果必须与此匹配
    52  }
    53  
    54  func runDialTest(t *testing.T, test dialtest) {
    55  	var (
    56  		vtime   time.Time
    57  		running int
    58  	)
    59  	pm := func(ps []*Peer) map[discover.NodeID]*Peer {
    60  		m := make(map[discover.NodeID]*Peer)
    61  		for _, p := range ps {
    62  			m[p.rw.id] = p
    63  		}
    64  		return m
    65  	}
    66  	for i, round := range test.rounds {
    67  		for _, task := range round.done {
    68  			running--
    69  			if running < 0 {
    70  				panic("running task counter underflow")
    71  			}
    72  			test.init.taskDone(task, vtime)
    73  		}
    74  
    75  		new := test.init.newTasks(running, pm(round.peers), vtime)
    76  		if !sametasks(new, round.new) {
    77  			t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n",
    78  				i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running))
    79  		}
    80  
    81  //每轮时间提前16秒。
    82  		vtime = vtime.Add(16 * time.Second)
    83  		running += len(new)
    84  	}
    85  }
    86  
    87  type fakeTable []*discover.Node
    88  
    89  func (t fakeTable) Self() *discover.Node                     { return new(discover.Node) }
    90  func (t fakeTable) Close()                                   {}
    91  func (t fakeTable) Lookup(discover.NodeID) []*discover.Node  { return nil }
    92  func (t fakeTable) Resolve(discover.NodeID) *discover.Node   { return nil }
    93  func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) }
    94  
    95  //此测试检查是否从发现结果启动动态拨号。
    96  func TestDialStateDynDial(t *testing.T) {
    97  	runDialTest(t, dialtest{
    98  		init: newDialState(nil, nil, fakeTable{}, 5, nil),
    99  		rounds: []round{
   100  //将启动发现查询。
   101  			{
   102  				peers: []*Peer{
   103  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   104  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   105  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   106  				},
   107  				new: []task{&discoverTask{}},
   108  			},
   109  //动态拨号完成后启动。
   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  				},
   116  				done: []task{
   117  					&discoverTask{results: []*discover.Node{
   118  {ID: uintID(2)}, //这个已经连接,没有拨号。
   119  						{ID: uintID(3)},
   120  						{ID: uintID(4)},
   121  						{ID: uintID(5)},
   122  {ID: uintID(6)}, //因为最大动态拨号是5,所以不尝试使用。
   123  {ID: uintID(7)}, //…
   124  					}},
   125  				},
   126  				new: []task{
   127  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   128  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   129  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   130  				},
   131  			},
   132  //有些拨号盘已完成,但尚未启动新的拨号盘,因为
   133  //活动拨号计数和动态对等计数之和=MaxDynDials。
   134  			{
   135  				peers: []*Peer{
   136  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   137  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   138  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   139  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   140  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   141  				},
   142  				done: []task{
   143  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   144  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   145  				},
   146  			},
   147  //此轮中没有启动新的拨号任务,因为
   148  //已达到MaxDynDials。
   149  			{
   150  				peers: []*Peer{
   151  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   152  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   153  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   154  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   155  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   156  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   157  				},
   158  				done: []task{
   159  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   160  				},
   161  				new: []task{
   162  					&waitExpireTask{Duration: 14 * time.Second},
   163  				},
   164  			},
   165  //在这一轮中,ID为2的对等机将关闭。查询
   166  //重新使用上次发现查找的结果。
   167  			{
   168  				peers: []*Peer{
   169  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   170  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   171  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   172  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   173  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   174  				},
   175  				new: []task{
   176  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   177  				},
   178  			},
   179  //更多的对等端(3,4)停止并拨出ID 6完成。
   180  //重新使用发现查找的最后一个查询结果
   181  //因为需要更多的候选人,所以产生了一个新的候选人。
   182  			{
   183  				peers: []*Peer{
   184  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   185  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   186  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   187  				},
   188  				done: []task{
   189  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   190  				},
   191  				new: []task{
   192  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   193  					&discoverTask{},
   194  				},
   195  			},
   196  //对等7已连接,但仍然没有足够的动态对等
   197  //(5个中有4个)。但是,发现已经在运行,因此请确保
   198  //没有新的开始。
   199  			{
   200  				peers: []*Peer{
   201  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   202  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   203  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   204  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   205  				},
   206  				done: []task{
   207  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   208  				},
   209  			},
   210  //使用空集完成正在运行的节点发现。一种新的查找
   211  //应立即请求。
   212  			{
   213  				peers: []*Peer{
   214  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   215  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   216  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   217  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   218  				},
   219  				done: []task{
   220  					&discoverTask{},
   221  				},
   222  				new: []task{
   223  					&discoverTask{},
   224  				},
   225  			},
   226  		},
   227  	})
   228  }
   229  
   230  //测试在没有连接对等机的情况下是否拨号引导节点,否则不拨号。
   231  func TestDialStateDynDialBootnode(t *testing.T) {
   232  	bootnodes := []*discover.Node{
   233  		{ID: uintID(1)},
   234  		{ID: uintID(2)},
   235  		{ID: uintID(3)},
   236  	}
   237  	table := fakeTable{
   238  		{ID: uintID(4)},
   239  		{ID: uintID(5)},
   240  		{ID: uintID(6)},
   241  		{ID: uintID(7)},
   242  		{ID: uintID(8)},
   243  	}
   244  	runDialTest(t, dialtest{
   245  		init: newDialState(nil, bootnodes, table, 5, nil),
   246  		rounds: []round{
   247  //已尝试2个动态拨号,启动节点挂起回退间隔
   248  			{
   249  				new: []task{
   250  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   251  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   252  					&discoverTask{},
   253  				},
   254  			},
   255  //没有拨号成功,引导节点仍挂起回退间隔
   256  			{
   257  				done: []task{
   258  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   259  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   260  				},
   261  			},
   262  //没有拨号成功,引导节点仍挂起回退间隔
   263  			{},
   264  //没有成功的拨号,尝试了2个动态拨号,同时达到了回退间隔,还尝试了1个引导节点。
   265  			{
   266  				new: []task{
   267  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   268  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   269  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   270  				},
   271  			},
   272  //没有拨号成功,尝试第二个bootnode
   273  			{
   274  				done: []task{
   275  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   276  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   277  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   278  				},
   279  				new: []task{
   280  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   281  				},
   282  			},
   283  //没有拨号成功,尝试第三个启动节点
   284  			{
   285  				done: []task{
   286  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   287  				},
   288  				new: []task{
   289  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   290  				},
   291  			},
   292  //没有拨号成功,再次尝试第一个bootnode,重试过期的随机节点
   293  			{
   294  				done: []task{
   295  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   296  				},
   297  				new: []task{
   298  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   299  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   300  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   301  				},
   302  			},
   303  //随机拨号成功,不再尝试启动节点
   304  			{
   305  				peers: []*Peer{
   306  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   307  				},
   308  				done: []task{
   309  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   310  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   311  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   312  				},
   313  			},
   314  		},
   315  	})
   316  }
   317  
   318  func TestDialStateDynDialFromTable(t *testing.T) {
   319  //此表始终返回相同的随机节点
   320  //按照下面给出的顺序。
   321  	table := fakeTable{
   322  		{ID: uintID(1)},
   323  		{ID: uintID(2)},
   324  		{ID: uintID(3)},
   325  		{ID: uintID(4)},
   326  		{ID: uintID(5)},
   327  		{ID: uintID(6)},
   328  		{ID: uintID(7)},
   329  		{ID: uintID(8)},
   330  	}
   331  
   332  	runDialTest(t, dialtest{
   333  		init: newDialState(nil, nil, table, 10, nil),
   334  		rounds: []round{
   335  //readrandomnodes返回的8个节点中有5个被拨号。
   336  			{
   337  				new: []task{
   338  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   339  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   340  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   341  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   342  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   343  					&discoverTask{},
   344  				},
   345  			},
   346  //拨号节点1、2成功。启动查找中的拨号。
   347  			{
   348  				peers: []*Peer{
   349  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   350  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   351  				},
   352  				done: []task{
   353  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   354  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   355  					&discoverTask{results: []*discover.Node{
   356  						{ID: uintID(10)},
   357  						{ID: uintID(11)},
   358  						{ID: uintID(12)},
   359  					}},
   360  				},
   361  				new: []task{
   362  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   363  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   364  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   365  					&discoverTask{},
   366  				},
   367  			},
   368  //拨号节点3、4、5失败。查找中的拨号成功。
   369  			{
   370  				peers: []*Peer{
   371  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   372  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   373  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   374  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   375  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   376  				},
   377  				done: []task{
   378  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   379  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   380  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   381  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   382  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   383  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   384  				},
   385  			},
   386  //正在等待到期。没有启动waitexpiretask,因为
   387  //发现查询仍在运行。
   388  			{
   389  				peers: []*Peer{
   390  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   391  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   392  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   393  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   394  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   395  				},
   396  			},
   397  //节点3,4不会再次尝试,因为只有前两个
   398  //返回的随机节点(节点1,2)将被尝试
   399  //已经连接。
   400  			{
   401  				peers: []*Peer{
   402  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   403  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   404  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   405  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   406  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   407  				},
   408  			},
   409  		},
   410  	})
   411  }
   412  
   413  //此测试检查是否未拨出与NetRestrict列表不匹配的候选人。
   414  func TestDialStateNetRestrict(t *testing.T) {
   415  //此表始终返回相同的随机节点
   416  //按照下面给出的顺序。
   417  	table := fakeTable{
   418  		{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
   419  		{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
   420  		{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
   421  		{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
   422  		{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
   423  		{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
   424  		{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
   425  		{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
   426  	}
   427  	restrict := new(netutil.Netlist)
   428  	restrict.Add("127.0.2.0/24")
   429  
   430  	runDialTest(t, dialtest{
   431  		init: newDialState(nil, nil, table, 10, restrict),
   432  		rounds: []round{
   433  			{
   434  				new: []task{
   435  					&dialTask{flags: dynDialedConn, dest: table[4]},
   436  					&discoverTask{},
   437  				},
   438  			},
   439  		},
   440  	})
   441  }
   442  
   443  //此测试检查是否启动了静态拨号。
   444  func TestDialStateStaticDial(t *testing.T) {
   445  	wantStatic := []*discover.Node{
   446  		{ID: uintID(1)},
   447  		{ID: uintID(2)},
   448  		{ID: uintID(3)},
   449  		{ID: uintID(4)},
   450  		{ID: uintID(5)},
   451  	}
   452  
   453  	runDialTest(t, dialtest{
   454  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   455  		rounds: []round{
   456  //为以下节点启动静态拨号:
   457  //尚未连接。
   458  			{
   459  				peers: []*Peer{
   460  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   461  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   462  				},
   463  				new: []task{
   464  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   465  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   466  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   467  				},
   468  			},
   469  //由于所有静态任务
   470  //节点已连接或仍在拨号。
   471  			{
   472  				peers: []*Peer{
   473  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   474  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   475  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   476  				},
   477  				done: []task{
   478  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   479  				},
   480  			},
   481  //没有启动新的拨号任务,因为所有的拨号任务都是静态的
   482  //节点现在已连接。
   483  			{
   484  				peers: []*Peer{
   485  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   486  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   487  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   488  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   489  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   490  				},
   491  				done: []task{
   492  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   493  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   494  				},
   495  				new: []task{
   496  					&waitExpireTask{Duration: 14 * time.Second},
   497  				},
   498  			},
   499  //等待一轮拨号历史记录过期,不应生成新任务。
   500  			{
   501  				peers: []*Peer{
   502  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   503  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   504  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   505  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   506  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   507  				},
   508  			},
   509  //如果一个静态节点被删除,它应该立即被重新拨号,
   510  //不管它最初是静态的还是动态的。
   511  			{
   512  				peers: []*Peer{
   513  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   514  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   515  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   516  				},
   517  				new: []task{
   518  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   519  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   520  				},
   521  			},
   522  		},
   523  	})
   524  }
   525  
   526  //此测试检查静态对等点如果被重新添加到静态列表中,是否会立即重新启用。
   527  func TestDialStaticAfterReset(t *testing.T) {
   528  	wantStatic := []*discover.Node{
   529  		{ID: uintID(1)},
   530  		{ID: uintID(2)},
   531  	}
   532  
   533  	rounds := []round{
   534  //为尚未连接的节点启动静态拨号。
   535  		{
   536  			peers: nil,
   537  			new: []task{
   538  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   539  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   540  			},
   541  		},
   542  //没有新的拨号任务,所有对等端都已连接。
   543  		{
   544  			peers: []*Peer{
   545  				{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   546  				{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   547  			},
   548  			done: []task{
   549  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   550  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   551  			},
   552  			new: []task{
   553  				&waitExpireTask{Duration: 30 * time.Second},
   554  			},
   555  		},
   556  	}
   557  	dTest := dialtest{
   558  		init:   newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   559  		rounds: rounds,
   560  	}
   561  	runDialTest(t, dTest)
   562  	for _, n := range wantStatic {
   563  		dTest.init.removeStatic(n)
   564  		dTest.init.addStatic(n)
   565  	}
   566  //如果不删除同龄人,他们将被视为最近拨打过电话。
   567  	runDialTest(t, dTest)
   568  }
   569  
   570  //此测试检查过去的拨号是否有一段时间没有重试。
   571  func TestDialStateCache(t *testing.T) {
   572  	wantStatic := []*discover.Node{
   573  		{ID: uintID(1)},
   574  		{ID: uintID(2)},
   575  		{ID: uintID(3)},
   576  	}
   577  
   578  	runDialTest(t, dialtest{
   579  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   580  		rounds: []round{
   581  //为以下节点启动静态拨号:
   582  //尚未连接。
   583  			{
   584  				peers: nil,
   585  				new: []task{
   586  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   587  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   588  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   589  				},
   590  			},
   591  //由于所有静态任务
   592  //节点已连接或仍在拨号。
   593  			{
   594  				peers: []*Peer{
   595  					{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   596  					{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   597  				},
   598  				done: []task{
   599  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   600  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   601  				},
   602  			},
   603  //启动补救任务以等待节点3的历史记录
   604  //条目将过期。
   605  			{
   606  				peers: []*Peer{
   607  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   608  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   609  				},
   610  				done: []task{
   611  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   612  				},
   613  				new: []task{
   614  					&waitExpireTask{Duration: 14 * time.Second},
   615  				},
   616  			},
   617  //仍在等待节点3的条目在缓存中过期。
   618  			{
   619  				peers: []*Peer{
   620  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   621  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   622  				},
   623  			},
   624  //节点3的缓存项已过期并重试。
   625  			{
   626  				peers: []*Peer{
   627  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   628  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   629  				},
   630  				new: []task{
   631  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   632  				},
   633  			},
   634  		},
   635  	})
   636  }
   637  
   638  func TestDialResolve(t *testing.T) {
   639  	resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444)
   640  	table := &resolveMock{answer: resolved}
   641  	state := newDialState(nil, nil, table, 0, nil)
   642  
   643  //检查是否使用不完整的ID生成任务。
   644  	dest := discover.NewNode(uintID(1), nil, 0, 0)
   645  	state.addStatic(dest)
   646  	tasks := state.newTasks(0, nil, time.Time{})
   647  	if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
   648  		t.Fatalf("expected dial task, got %#v", tasks)
   649  	}
   650  
   651  //现在运行任务,它应该解析一次ID。
   652  	config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
   653  	srv := &Server{ntab: table, Config: config}
   654  	tasks[0].Do(srv)
   655  	if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) {
   656  		t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
   657  	}
   658  
   659  //向拨号程序报告完成情况,拨号程序应更新静态节点记录。
   660  	state.taskDone(tasks[0], time.Now())
   661  	if state.static[uintID(1)].dest != resolved {
   662  		t.Fatalf("state.dest not updated")
   663  	}
   664  }
   665  
   666  //比较任务列表,但不关心顺序。
   667  func sametasks(a, b []task) bool {
   668  	if len(a) != len(b) {
   669  		return false
   670  	}
   671  next:
   672  	for _, ta := range a {
   673  		for _, tb := range b {
   674  			if reflect.DeepEqual(ta, tb) {
   675  				continue next
   676  			}
   677  		}
   678  		return false
   679  	}
   680  	return true
   681  }
   682  
   683  func uintID(i uint32) discover.NodeID {
   684  	var id discover.NodeID
   685  	binary.BigEndian.PutUint32(id[:], i)
   686  	return id
   687  }
   688  
   689  //实现TestDialResolve的discovertable
   690  type resolveMock struct {
   691  	resolveCalls []discover.NodeID
   692  	answer       *discover.Node
   693  }
   694  
   695  func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node {
   696  	t.resolveCalls = append(t.resolveCalls, id)
   697  	return t.answer
   698  }
   699  
   700  func (t *resolveMock) Self() *discover.Node                     { return new(discover.Node) }
   701  func (t *resolveMock) Close()                                   {}
   702  func (t *resolveMock) Bootstrap([]*discover.Node)               {}
   703  func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node  { return nil }
   704  func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }