github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/dial.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  	"container/heap"
    29  	"crypto/rand"
    30  	"errors"
    31  	"fmt"
    32  	"net"
    33  	"time"
    34  
    35  	"github.com/ethereum/go-ethereum/log"
    36  	"github.com/ethereum/go-ethereum/p2p/discover"
    37  	"github.com/ethereum/go-ethereum/p2p/netutil"
    38  )
    39  
    40  const (
    41  //这是介于
    42  //重拨某个节点。
    43  	dialHistoryExpiration = 30 * time.Second
    44  
    45  //发现查找受到限制,只能运行
    46  //每隔几秒钟一次。
    47  	lookupInterval = 4 * time.Second
    48  
    49  //如果在这段时间内找不到对等点,则初始引导节点为
    50  //试图连接。
    51  	fallbackInterval = 20 * time.Second
    52  
    53  //端点分辨率通过有界退避进行限制。
    54  	initialResolveDelay = 60 * time.Second
    55  	maxResolveDelay     = time.Hour
    56  )
    57  
    58  //nodeadialer用于连接到网络中的节点,通常使用
    59  //一个底层的net.dialer,但在测试中也使用了net.pipe
    60  type NodeDialer interface {
    61  	Dial(*discover.Node) (net.Conn, error)
    62  }
    63  
    64  //tcpDialer通过使用net.dialer
    65  //创建到网络中节点的TCP连接
    66  type TCPDialer struct {
    67  	*net.Dialer
    68  }
    69  
    70  //拨号创建到节点的TCP连接
    71  func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) {
    72  	addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
    73  	return t.Dialer.Dial("tcp", addr.String())
    74  }
    75  
    76  //拨号状态计划拨号和查找。
    77  //每次迭代都有机会计算新任务
    78  //在server.run中的主循环。
    79  type dialstate struct {
    80  	maxDynDials int
    81  	ntab        discoverTable
    82  	netrestrict *netutil.Netlist
    83  
    84  	lookupRunning bool
    85  	dialing       map[discover.NodeID]connFlag
    86  lookupBuf     []*discover.Node //当前发现查找结果
    87  randomNodes   []*discover.Node //从表中填充
    88  	static        map[discover.NodeID]*dialTask
    89  	hist          *dialHistory
    90  
    91  start     time.Time        //拨号器首次使用的时间
    92  bootnodes []*discover.Node //没有对等机时的默认拨号
    93  }
    94  
    95  type discoverTable interface {
    96  	Self() *discover.Node
    97  	Close()
    98  	Resolve(target discover.NodeID) *discover.Node
    99  	Lookup(target discover.NodeID) []*discover.Node
   100  	ReadRandomNodes([]*discover.Node) int
   101  }
   102  
   103  //拨号历史记录会记住最近的拨号。
   104  type dialHistory []pastDial
   105  
   106  //PastDial是拨号历史记录中的一个条目。
   107  type pastDial struct {
   108  	id  discover.NodeID
   109  	exp time.Time
   110  }
   111  
   112  type task interface {
   113  	Do(*Server)
   114  }
   115  
   116  //为所拨的每个节点生成一个拨号任务。它的
   117  //任务运行时无法访问字段。
   118  type dialTask struct {
   119  	flags        connFlag
   120  	dest         *discover.Node
   121  	lastResolved time.Time
   122  	resolveDelay time.Duration
   123  }
   124  
   125  //discovertask运行发现表操作。
   126  //任何时候只有一个discovertask处于活动状态。
   127  //discovertask.do执行随机查找。
   128  type discoverTask struct {
   129  	results []*discover.Node
   130  }
   131  
   132  //如果没有其他任务,则生成waitexpiretask
   133  //在server.run中保持循环。
   134  type waitExpireTask struct {
   135  	time.Duration
   136  }
   137  
   138  func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate {
   139  	s := &dialstate{
   140  		maxDynDials: maxdyn,
   141  		ntab:        ntab,
   142  		netrestrict: netrestrict,
   143  		static:      make(map[discover.NodeID]*dialTask),
   144  		dialing:     make(map[discover.NodeID]connFlag),
   145  		bootnodes:   make([]*discover.Node, len(bootnodes)),
   146  		randomNodes: make([]*discover.Node, maxdyn/2),
   147  		hist:        new(dialHistory),
   148  	}
   149  	copy(s.bootnodes, bootnodes)
   150  	for _, n := range static {
   151  		s.addStatic(n)
   152  	}
   153  	return s
   154  }
   155  
   156  func (s *dialstate) addStatic(n *discover.Node) {
   157  //这将覆盖任务,而不是更新现有的
   158  //输入,让用户有机会强制执行解决操作。
   159  	s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n}
   160  }
   161  
   162  func (s *dialstate) removeStatic(n *discover.Node) {
   163  //这将删除一个任务,因此将来不会尝试连接。
   164  	delete(s.static, n.ID)
   165  //这将删除以前的拨号时间戳,以便应用程序
   166  //可以强制服务器立即与所选对等机重新连接。
   167  	s.hist.remove(n.ID)
   168  }
   169  
   170  func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task {
   171  	if s.start.IsZero() {
   172  		s.start = now
   173  	}
   174  
   175  	var newtasks []task
   176  	addDial := func(flag connFlag, n *discover.Node) bool {
   177  		if err := s.checkDial(n, peers); err != nil {
   178  			log.Trace("Skipping dial candidate", "id", n.ID, "addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err)
   179  			return false
   180  		}
   181  		s.dialing[n.ID] = flag
   182  		newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
   183  		return true
   184  	}
   185  
   186  //计算此时所需的动态拨号数。
   187  	needDynDials := s.maxDynDials
   188  	for _, p := range peers {
   189  		if p.rw.is(dynDialedConn) {
   190  			needDynDials--
   191  		}
   192  	}
   193  	for _, flag := range s.dialing {
   194  		if flag&dynDialedConn != 0 {
   195  			needDynDials--
   196  		}
   197  	}
   198  
   199  //每次调用时使拨号历史记录过期。
   200  	s.hist.expire(now)
   201  
   202  //如果静态节点未连接,则为其创建拨号。
   203  	for id, t := range s.static {
   204  		err := s.checkDial(t.dest, peers)
   205  		switch err {
   206  		case errNotWhitelisted, errSelf:
   207  			log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err)
   208  			delete(s.static, t.dest.ID)
   209  		case nil:
   210  			s.dialing[id] = t.flags
   211  			newtasks = append(newtasks, t)
   212  		}
   213  	}
   214  //如果我们没有任何对等点,请尝试拨打随机引导节点。这个
   215  //场景对于发现
   216  //桌子上可能满是坏同学,很难找到好同学。
   217  	if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 && now.Sub(s.start) > fallbackInterval {
   218  		bootnode := s.bootnodes[0]
   219  		s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...)
   220  		s.bootnodes = append(s.bootnodes, bootnode)
   221  
   222  		if addDial(dynDialedConn, bootnode) {
   223  			needDynDials--
   224  		}
   225  	}
   226  //将表中的随机节点用于所需的一半
   227  //动态拨号。
   228  	randomCandidates := needDynDials / 2
   229  	if randomCandidates > 0 {
   230  		n := s.ntab.ReadRandomNodes(s.randomNodes)
   231  		for i := 0; i < randomCandidates && i < n; i++ {
   232  			if addDial(dynDialedConn, s.randomNodes[i]) {
   233  				needDynDials--
   234  			}
   235  		}
   236  	}
   237  //从随机查找结果创建动态拨号,已尝试删除
   238  //结果缓冲区中的项。
   239  	i := 0
   240  	for ; i < len(s.lookupBuf) && needDynDials > 0; i++ {
   241  		if addDial(dynDialedConn, s.lookupBuf[i]) {
   242  			needDynDials--
   243  		}
   244  	}
   245  	s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])]
   246  //如果需要更多候选项,则启动查找。
   247  	if len(s.lookupBuf) < needDynDials && !s.lookupRunning {
   248  		s.lookupRunning = true
   249  		newtasks = append(newtasks, &discoverTask{})
   250  	}
   251  
   252  //启动计时器,等待下一个节点全部过期
   253  //候选人已被试用,目前没有活动任务。
   254  //这样可以防止拨号程序逻辑没有勾选的情况发生。
   255  //因为没有挂起的事件。
   256  	if nRunning == 0 && len(newtasks) == 0 && s.hist.Len() > 0 {
   257  		t := &waitExpireTask{s.hist.min().exp.Sub(now)}
   258  		newtasks = append(newtasks, t)
   259  	}
   260  	return newtasks
   261  }
   262  
   263  var (
   264  	errSelf             = errors.New("is self")
   265  	errAlreadyDialing   = errors.New("already dialing")
   266  	errAlreadyConnected = errors.New("already connected")
   267  	errRecentlyDialed   = errors.New("recently dialed")
   268  	errNotWhitelisted   = errors.New("not contained in netrestrict whitelist")
   269  )
   270  
   271  func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error {
   272  	_, dialing := s.dialing[n.ID]
   273  	switch {
   274  	case dialing:
   275  		return errAlreadyDialing
   276  	case peers[n.ID] != nil:
   277  		return errAlreadyConnected
   278  	case s.ntab != nil && n.ID == s.ntab.Self().ID:
   279  		return errSelf
   280  	case s.netrestrict != nil && !s.netrestrict.Contains(n.IP):
   281  		return errNotWhitelisted
   282  	case s.hist.contains(n.ID):
   283  		return errRecentlyDialed
   284  	}
   285  	return nil
   286  }
   287  
   288  func (s *dialstate) taskDone(t task, now time.Time) {
   289  	switch t := t.(type) {
   290  	case *dialTask:
   291  		s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration))
   292  		delete(s.dialing, t.dest.ID)
   293  	case *discoverTask:
   294  		s.lookupRunning = false
   295  		s.lookupBuf = append(s.lookupBuf, t.results...)
   296  	}
   297  }
   298  
   299  func (t *dialTask) Do(srv *Server) {
   300  	if t.dest.Incomplete() {
   301  		if !t.resolve(srv) {
   302  			return
   303  		}
   304  	}
   305  	err := t.dial(srv, t.dest)
   306  	if err != nil {
   307  		log.Trace("Dial error", "task", t, "err", err)
   308  //如果拨号失败,请尝试解析静态节点的ID。
   309  		if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 {
   310  			if t.resolve(srv) {
   311  				t.dial(srv, t.dest)
   312  			}
   313  		}
   314  	}
   315  }
   316  
   317  //解决查找目标的当前终结点的尝试
   318  //使用发现。
   319  //
   320  //解决操作通过后退进行节流,以避免淹没
   321  //对不存在的节点进行无用查询的发现网络。
   322  //当找到节点时,退避延迟重置。
   323  func (t *dialTask) resolve(srv *Server) bool {
   324  	if srv.ntab == nil {
   325  		log.Debug("Can't resolve node", "id", t.dest.ID, "err", "discovery is disabled")
   326  		return false
   327  	}
   328  	if t.resolveDelay == 0 {
   329  		t.resolveDelay = initialResolveDelay
   330  	}
   331  	if time.Since(t.lastResolved) < t.resolveDelay {
   332  		return false
   333  	}
   334  	resolved := srv.ntab.Resolve(t.dest.ID)
   335  	t.lastResolved = time.Now()
   336  	if resolved == nil {
   337  		t.resolveDelay *= 2
   338  		if t.resolveDelay > maxResolveDelay {
   339  			t.resolveDelay = maxResolveDelay
   340  		}
   341  		log.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay)
   342  		return false
   343  	}
   344  //找到节点。
   345  	t.resolveDelay = initialResolveDelay
   346  	t.dest = resolved
   347  	log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)})
   348  	return true
   349  }
   350  
   351  type dialError struct {
   352  	error
   353  }
   354  
   355  //拨号执行实际连接尝试。
   356  func (t *dialTask) dial(srv *Server, dest *discover.Node) error {
   357  	fd, err := srv.Dialer.Dial(dest)
   358  	if err != nil {
   359  		return &dialError{err}
   360  	}
   361  	mfd := newMeteredConn(fd, false)
   362  	return srv.SetupConn(mfd, t.flags, dest)
   363  }
   364  
   365  func (t *dialTask) String() string {
   366  	return fmt.Sprintf("%v %x %v:%d", t.flags, t.dest.ID[:8], t.dest.IP, t.dest.TCP)
   367  }
   368  
   369  func (t *discoverTask) Do(srv *Server) {
   370  //每当动态拨号
   371  //必要的。查找需要花费一些时间,否则
   372  //事件循环旋转过快。
   373  	next := srv.lastLookup.Add(lookupInterval)
   374  	if now := time.Now(); now.Before(next) {
   375  		time.Sleep(next.Sub(now))
   376  	}
   377  	srv.lastLookup = time.Now()
   378  	var target discover.NodeID
   379  	rand.Read(target[:])
   380  	t.results = srv.ntab.Lookup(target)
   381  }
   382  
   383  func (t *discoverTask) String() string {
   384  	s := "discovery lookup"
   385  	if len(t.results) > 0 {
   386  		s += fmt.Sprintf(" (%d results)", len(t.results))
   387  	}
   388  	return s
   389  }
   390  
   391  func (t waitExpireTask) Do(*Server) {
   392  	time.Sleep(t.Duration)
   393  }
   394  func (t waitExpireTask) String() string {
   395  	return fmt.Sprintf("wait for dial hist expire (%v)", t.Duration)
   396  }
   397  
   398  //仅使用这些方法访问或修改拨号历史记录。
   399  func (h dialHistory) min() pastDial {
   400  	return h[0]
   401  }
   402  func (h *dialHistory) add(id discover.NodeID, exp time.Time) {
   403  	heap.Push(h, pastDial{id, exp})
   404  
   405  }
   406  func (h *dialHistory) remove(id discover.NodeID) bool {
   407  	for i, v := range *h {
   408  		if v.id == id {
   409  			heap.Remove(h, i)
   410  			return true
   411  		}
   412  	}
   413  	return false
   414  }
   415  func (h dialHistory) contains(id discover.NodeID) bool {
   416  	for _, v := range h {
   417  		if v.id == id {
   418  			return true
   419  		}
   420  	}
   421  	return false
   422  }
   423  func (h *dialHistory) expire(now time.Time) {
   424  	for h.Len() > 0 && h.min().exp.Before(now) {
   425  		heap.Pop(h)
   426  	}
   427  }
   428  
   429  //堆接口样板
   430  func (h dialHistory) Len() int           { return len(h) }
   431  func (h dialHistory) Less(i, j int) bool { return h[i].exp.Before(h[j].exp) }
   432  func (h dialHistory) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
   433  func (h *dialHistory) Push(x interface{}) {
   434  	*h = append(*h, x.(pastDial))
   435  }
   436  func (h *dialHistory) Pop() interface{} {
   437  	old := *h
   438  	n := len(old)
   439  	x := old[n-1]
   440  	*h = old[0 : n-1]
   441  	return x
   442  }