github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discv5/topic.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  //版权所有2016 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 discv5
    26  
    27  import (
    28  	"container/heap"
    29  	"fmt"
    30  	"math"
    31  	"math/rand"
    32  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum/common/mclock"
    35  	"github.com/ethereum/go-ethereum/log"
    36  )
    37  
    38  const (
    39  	maxEntries         = 10000
    40  	maxEntriesPerTopic = 50
    41  
    42  	fallbackRegistrationExpiry = 1 * time.Hour
    43  )
    44  
    45  type Topic string
    46  
    47  type topicEntry struct {
    48  	topic   Topic
    49  	fifoIdx uint64
    50  	node    *Node
    51  	expire  mclock.AbsTime
    52  }
    53  
    54  type topicInfo struct {
    55  	entries            map[uint64]*topicEntry
    56  	fifoHead, fifoTail uint64
    57  	rqItem             *topicRequestQueueItem
    58  	wcl                waitControlLoop
    59  }
    60  
    61  //从FIFO中删除尾部元素
    62  func (t *topicInfo) getFifoTail() *topicEntry {
    63  	for t.entries[t.fifoTail] == nil {
    64  		t.fifoTail++
    65  	}
    66  	tail := t.entries[t.fifoTail]
    67  	t.fifoTail++
    68  	return tail
    69  }
    70  
    71  type nodeInfo struct {
    72  	entries                          map[Topic]*topicEntry
    73  	lastIssuedTicket, lastUsedTicket uint32
    74  //您不能在noreguntil(绝对时间)之前注册比lastusedticket更新的票据。
    75  	noRegUntil mclock.AbsTime
    76  }
    77  
    78  type topicTable struct {
    79  	db                    *nodeDB
    80  	self                  *Node
    81  	nodes                 map[*Node]*nodeInfo
    82  	topics                map[Topic]*topicInfo
    83  	globalEntries         uint64
    84  	requested             topicRequestQueue
    85  	requestCnt            uint64
    86  	lastGarbageCollection mclock.AbsTime
    87  }
    88  
    89  func newTopicTable(db *nodeDB, self *Node) *topicTable {
    90  	if printTestImgLogs {
    91  		fmt.Printf("*N %016x\n", self.sha[:8])
    92  	}
    93  	return &topicTable{
    94  		db:     db,
    95  		nodes:  make(map[*Node]*nodeInfo),
    96  		topics: make(map[Topic]*topicInfo),
    97  		self:   self,
    98  	}
    99  }
   100  
   101  func (t *topicTable) getOrNewTopic(topic Topic) *topicInfo {
   102  	ti := t.topics[topic]
   103  	if ti == nil {
   104  		rqItem := &topicRequestQueueItem{
   105  			topic:    topic,
   106  			priority: t.requestCnt,
   107  		}
   108  		ti = &topicInfo{
   109  			entries: make(map[uint64]*topicEntry),
   110  			rqItem:  rqItem,
   111  		}
   112  		t.topics[topic] = ti
   113  		heap.Push(&t.requested, rqItem)
   114  	}
   115  	return ti
   116  }
   117  
   118  func (t *topicTable) checkDeleteTopic(topic Topic) {
   119  	ti := t.topics[topic]
   120  	if ti == nil {
   121  		return
   122  	}
   123  	if len(ti.entries) == 0 && ti.wcl.hasMinimumWaitPeriod() {
   124  		delete(t.topics, topic)
   125  		heap.Remove(&t.requested, ti.rqItem.index)
   126  	}
   127  }
   128  
   129  func (t *topicTable) getOrNewNode(node *Node) *nodeInfo {
   130  	n := t.nodes[node]
   131  	if n == nil {
   132  //fmt.printf(“newnode%016x%016x\n”,t.self.sha[:8],node.sha[:8])
   133  		var issued, used uint32
   134  		if t.db != nil {
   135  			issued, used = t.db.fetchTopicRegTickets(node.ID)
   136  		}
   137  		n = &nodeInfo{
   138  			entries:          make(map[Topic]*topicEntry),
   139  			lastIssuedTicket: issued,
   140  			lastUsedTicket:   used,
   141  		}
   142  		t.nodes[node] = n
   143  	}
   144  	return n
   145  }
   146  
   147  func (t *topicTable) checkDeleteNode(node *Node) {
   148  	if n, ok := t.nodes[node]; ok && len(n.entries) == 0 && n.noRegUntil < mclock.Now() {
   149  //fmt.printf(“删除节点%016x%016x\n”,t.self.sha[:8],节点.sha[:8])
   150  		delete(t.nodes, node)
   151  	}
   152  }
   153  
   154  func (t *topicTable) storeTicketCounters(node *Node) {
   155  	n := t.getOrNewNode(node)
   156  	if t.db != nil {
   157  		t.db.updateTopicRegTickets(node.ID, n.lastIssuedTicket, n.lastUsedTicket)
   158  	}
   159  }
   160  
   161  func (t *topicTable) getEntries(topic Topic) []*Node {
   162  	t.collectGarbage()
   163  
   164  	te := t.topics[topic]
   165  	if te == nil {
   166  		return nil
   167  	}
   168  	nodes := make([]*Node, len(te.entries))
   169  	i := 0
   170  	for _, e := range te.entries {
   171  		nodes[i] = e.node
   172  		i++
   173  	}
   174  	t.requestCnt++
   175  	t.requested.update(te.rqItem, t.requestCnt)
   176  	return nodes
   177  }
   178  
   179  func (t *topicTable) addEntry(node *Node, topic Topic) {
   180  	n := t.getOrNewNode(node)
   181  //按同一节点清除以前的条目
   182  	for _, e := range n.entries {
   183  		t.deleteEntry(e)
   184  	}
   185  //***
   186  	n = t.getOrNewNode(node)
   187  
   188  	tm := mclock.Now()
   189  	te := t.getOrNewTopic(topic)
   190  
   191  	if len(te.entries) == maxEntriesPerTopic {
   192  		t.deleteEntry(te.getFifoTail())
   193  	}
   194  
   195  	if t.globalEntries == maxEntries {
   196  t.deleteEntry(t.leastRequested()) //不是空的,不需要检查零
   197  	}
   198  
   199  	fifoIdx := te.fifoHead
   200  	te.fifoHead++
   201  	entry := &topicEntry{
   202  		topic:   topic,
   203  		fifoIdx: fifoIdx,
   204  		node:    node,
   205  		expire:  tm + mclock.AbsTime(fallbackRegistrationExpiry),
   206  	}
   207  	if printTestImgLogs {
   208  		fmt.Printf("*+ %d %v %016x %016x\n", tm/1000000, topic, t.self.sha[:8], node.sha[:8])
   209  	}
   210  	te.entries[fifoIdx] = entry
   211  	n.entries[topic] = entry
   212  	t.globalEntries++
   213  	te.wcl.registered(tm)
   214  }
   215  
   216  //从FIFO中删除请求最少的元素
   217  func (t *topicTable) leastRequested() *topicEntry {
   218  	for t.requested.Len() > 0 && t.topics[t.requested[0].topic] == nil {
   219  		heap.Pop(&t.requested)
   220  	}
   221  	if t.requested.Len() == 0 {
   222  		return nil
   223  	}
   224  	return t.topics[t.requested[0].topic].getFifoTail()
   225  }
   226  
   227  //条目应该存在
   228  func (t *topicTable) deleteEntry(e *topicEntry) {
   229  	if printTestImgLogs {
   230  		fmt.Printf("*- %d %v %016x %016x\n", mclock.Now()/1000000, e.topic, t.self.sha[:8], e.node.sha[:8])
   231  	}
   232  	ne := t.nodes[e.node].entries
   233  	delete(ne, e.topic)
   234  	if len(ne) == 0 {
   235  		t.checkDeleteNode(e.node)
   236  	}
   237  	te := t.topics[e.topic]
   238  	delete(te.entries, e.fifoIdx)
   239  	if len(te.entries) == 0 {
   240  		t.checkDeleteTopic(e.topic)
   241  	}
   242  	t.globalEntries--
   243  }
   244  
   245  //假设主题和等待期的长度相同。
   246  func (t *topicTable) useTicket(node *Node, serialNo uint32, topics []Topic, idx int, issueTime uint64, waitPeriods []uint32) (registered bool) {
   247  	log.Trace("Using discovery ticket", "serial", serialNo, "topics", topics, "waits", waitPeriods)
   248  //fmt.println(“useticket”,serialno,topics,waitperiods)
   249  	t.collectGarbage()
   250  
   251  	n := t.getOrNewNode(node)
   252  	if serialNo < n.lastUsedTicket {
   253  		return false
   254  	}
   255  
   256  	tm := mclock.Now()
   257  	if serialNo > n.lastUsedTicket && tm < n.noRegUntil {
   258  		return false
   259  	}
   260  	if serialNo != n.lastUsedTicket {
   261  		n.lastUsedTicket = serialNo
   262  		n.noRegUntil = tm + mclock.AbsTime(noRegTimeout())
   263  		t.storeTicketCounters(node)
   264  	}
   265  
   266  	currTime := uint64(tm / mclock.AbsTime(time.Second))
   267  	regTime := issueTime + uint64(waitPeriods[idx])
   268  	relTime := int64(currTime - regTime)
   269  if relTime >= -1 && relTime <= regTimeWindow+1 { //在两端给客户一点安全边际
   270  		if e := n.entries[topics[idx]]; e == nil {
   271  			t.addEntry(node, topics[idx])
   272  		} else {
   273  //如果有活动条目,不要移动到FIFO的前面,而是延长过期时间
   274  			e.expire = tm + mclock.AbsTime(fallbackRegistrationExpiry)
   275  		}
   276  		return true
   277  	}
   278  
   279  	return false
   280  }
   281  
   282  func (t *topicTable) getTicket(node *Node, topics []Topic) *ticket {
   283  	t.collectGarbage()
   284  
   285  	now := mclock.Now()
   286  	n := t.getOrNewNode(node)
   287  	n.lastIssuedTicket++
   288  	t.storeTicketCounters(node)
   289  
   290  	tic := &ticket{
   291  		issueTime: now,
   292  		topics:    topics,
   293  		serial:    n.lastIssuedTicket,
   294  		regTime:   make([]mclock.AbsTime, len(topics)),
   295  	}
   296  	for i, topic := range topics {
   297  		var waitPeriod time.Duration
   298  		if topic := t.topics[topic]; topic != nil {
   299  			waitPeriod = topic.wcl.waitPeriod
   300  		} else {
   301  			waitPeriod = minWaitPeriod
   302  		}
   303  
   304  		tic.regTime[i] = now + mclock.AbsTime(waitPeriod)
   305  	}
   306  	return tic
   307  }
   308  
   309  const gcInterval = time.Minute
   310  
   311  func (t *topicTable) collectGarbage() {
   312  	tm := mclock.Now()
   313  	if time.Duration(tm-t.lastGarbageCollection) < gcInterval {
   314  		return
   315  	}
   316  	t.lastGarbageCollection = tm
   317  
   318  	for node, n := range t.nodes {
   319  		for _, e := range n.entries {
   320  			if e.expire <= tm {
   321  				t.deleteEntry(e)
   322  			}
   323  		}
   324  
   325  		t.checkDeleteNode(node)
   326  	}
   327  
   328  	for topic := range t.topics {
   329  		t.checkDeleteTopic(topic)
   330  	}
   331  }
   332  
   333  const (
   334  	minWaitPeriod   = time.Minute
   335  regTimeWindow   = 10 //秒
   336  	avgnoRegTimeout = time.Minute * 10
   337  //两个传入AD请求之间的目标平均间隔
   338  	wcTargetRegInterval = time.Minute * 10 / maxEntriesPerTopic
   339  //
   340  	wcTimeConst = time.Minute * 10
   341  )
   342  
   343  //不需要初始化,将在首次注册时设置为minwaitperiod
   344  type waitControlLoop struct {
   345  	lastIncoming mclock.AbsTime
   346  	waitPeriod   time.Duration
   347  }
   348  
   349  func (w *waitControlLoop) registered(tm mclock.AbsTime) {
   350  	w.waitPeriod = w.nextWaitPeriod(tm)
   351  	w.lastIncoming = tm
   352  }
   353  
   354  func (w *waitControlLoop) nextWaitPeriod(tm mclock.AbsTime) time.Duration {
   355  	period := tm - w.lastIncoming
   356  	wp := time.Duration(float64(w.waitPeriod) * math.Exp((float64(wcTargetRegInterval)-float64(period))/float64(wcTimeConst)))
   357  	if wp < minWaitPeriod {
   358  		wp = minWaitPeriod
   359  	}
   360  	return wp
   361  }
   362  
   363  func (w *waitControlLoop) hasMinimumWaitPeriod() bool {
   364  	return w.nextWaitPeriod(mclock.Now()) == minWaitPeriod
   365  }
   366  
   367  func noRegTimeout() time.Duration {
   368  	e := rand.ExpFloat64()
   369  	if e > 100 {
   370  		e = 100
   371  	}
   372  	return time.Duration(float64(avgnoRegTimeout) * e)
   373  }
   374  
   375  type topicRequestQueueItem struct {
   376  	topic    Topic
   377  	priority uint64
   378  	index    int
   379  }
   380  
   381  //TopicRequestQueue实现heap.interface并保存TopicRequestQueueitems。
   382  type topicRequestQueue []*topicRequestQueueItem
   383  
   384  func (tq topicRequestQueue) Len() int { return len(tq) }
   385  
   386  func (tq topicRequestQueue) Less(i, j int) bool {
   387  	return tq[i].priority < tq[j].priority
   388  }
   389  
   390  func (tq topicRequestQueue) Swap(i, j int) {
   391  	tq[i], tq[j] = tq[j], tq[i]
   392  	tq[i].index = i
   393  	tq[j].index = j
   394  }
   395  
   396  func (tq *topicRequestQueue) Push(x interface{}) {
   397  	n := len(*tq)
   398  	item := x.(*topicRequestQueueItem)
   399  	item.index = n
   400  	*tq = append(*tq, item)
   401  }
   402  
   403  func (tq *topicRequestQueue) Pop() interface{} {
   404  	old := *tq
   405  	n := len(old)
   406  	item := old[n-1]
   407  	item.index = -1
   408  	*tq = old[0 : n-1]
   409  	return item
   410  }
   411  
   412  func (tq *topicRequestQueue) update(item *topicRequestQueueItem, priority uint64) {
   413  	item.priority = priority
   414  	heap.Fix(tq, item.index)
   415  }