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 }