github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discv5/table_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 //版权所有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 "crypto/ecdsa" 29 "fmt" 30 "math/rand" 31 32 "net" 33 "reflect" 34 "testing" 35 "testing/quick" 36 "time" 37 38 "github.com/ethereum/go-ethereum/common" 39 "github.com/ethereum/go-ethereum/crypto" 40 ) 41 42 type nullTransport struct{} 43 44 func (nullTransport) sendPing(remote *Node, remoteAddr *net.UDPAddr) []byte { return []byte{1} } 45 func (nullTransport) sendPong(remote *Node, pingHash []byte) {} 46 func (nullTransport) sendFindnode(remote *Node, target NodeID) {} 47 func (nullTransport) sendNeighbours(remote *Node, nodes []*Node) {} 48 func (nullTransport) localAddr() *net.UDPAddr { return new(net.UDPAddr) } 49 func (nullTransport) Close() {} 50 51 //func测试表_pingreplace(t*testing.t) 52 //doit:=func(newnodeisresponding,lastinbuckettisresponding bool) 53 //传输:=newPingRecorder()) 54 //tab,:=newTable(传输,节点ID,&net.udpaddr) 55 //延迟tab.close() 56 //Pinsender:=新节点(musthexid(“A502AF0F59B2AAB774695408C79E9CA312D2793CC997E44FC55EDA62F0150BBB8C59A6F9269BA3A081518B62699EE807C7C19C20125DDFCCCA872608AF9E370”),net.ip,99,99) 57 // 58 ////填满发送方的桶。 59 //最后:=FillBucket(tab,253) 60 // 61 ////此绑定调用应替换最后一个节点 62 ////如果节点没有响应,则在其存储桶中。 63 //transport.responding[last.id]=上次BucketisResponding 64 //transport.responding[pinsender.id]=新节点响应 65 //tab.bond(真,pinsender.id,&net.udpaddr,0) 66 // 67 ////第一个ping转到发送方(绑定pingback) 68 //如果!transport.pinged[pingender.id] 69 //t.error(“表没有ping回发送方”) 70 //} 71 //如果newnodeisresponding 72 ////第二个ping转到bucket中最早的节点 73 //看它是否还活着。 74 //如果!transport.pinged[上一个.id] 75 //t.error(“table did not ping last node in bucket”)。 76 //} 77 //} 78 // 79 //tab.mutex.lock()。 80 //延迟tab.mutex.unlock() 81 //如果l:=len(tab.buckets[253].entries);l!= BukStige{ 82 //t.errorf(“绑定后的存储桶大小错误:得到%d,想要%d”,l,bucket size) 83 //} 84 // 85 //如果最后一个问题是响应!新节点响应 86 //如果!包含(tab.buckets[253].entries,last.id) 87 //t.error(“删除最后一个条目”) 88 //} 89 //如果包含(tab.buckets[253].entries,pinsender.id) 90 //t.error(“添加新条目”) 91 //} 92 //}否则{ 93 //如果包含(tab.buckets[253].entries,last.id) 94 //t.error(“最后一项未删除”) 95 //} 96 //如果!包含(tab.buckets[253].entries,pinsender.id) 97 //t.error(“未添加新条目”) 98 //} 99 //} 100 //} 101 // 102 //doit(真,真) 103 //doit(假,真) 104 //doit(对,错) 105 //doit(假,假) 106 //} 107 108 func TestBucket_bumpNoDuplicates(t *testing.T) { 109 t.Parallel() 110 cfg := &quick.Config{ 111 MaxCount: 1000, 112 Rand: rand.New(rand.NewSource(time.Now().Unix())), 113 Values: func(args []reflect.Value, rand *rand.Rand) { 114 //生成节点的随机列表。这将是存储桶的内容。 115 n := rand.Intn(bucketSize-1) + 1 116 nodes := make([]*Node, n) 117 for i := range nodes { 118 nodes[i] = nodeAtDistance(common.Hash{}, 200) 119 } 120 args[0] = reflect.ValueOf(nodes) 121 //生成随机凹凸位置。 122 bumps := make([]int, rand.Intn(100)) 123 for i := range bumps { 124 bumps[i] = rand.Intn(len(nodes)) 125 } 126 args[1] = reflect.ValueOf(bumps) 127 }, 128 } 129 130 prop := func(nodes []*Node, bumps []int) (ok bool) { 131 b := &bucket{entries: make([]*Node, len(nodes))} 132 copy(b.entries, nodes) 133 for i, pos := range bumps { 134 b.bump(b.entries[pos]) 135 if hasDuplicates(b.entries) { 136 t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps)) 137 for _, n := range b.entries { 138 t.Logf(" %p", n) 139 } 140 return false 141 } 142 } 143 return true 144 } 145 if err := quick.Check(prop, cfg); err != nil { 146 t.Error(err) 147 } 148 } 149 150 //FillBucket将节点插入给定的bucket,直到 151 //它已经满了。节点的ID与 152 //散列。 153 func fillBucket(tab *Table, ld int) (last *Node) { 154 b := tab.buckets[ld] 155 for len(b.entries) < bucketSize { 156 b.entries = append(b.entries, nodeAtDistance(tab.self.sha, ld)) 157 } 158 return b.entries[bucketSize-1] 159 } 160 161 //nodeAtDistance为其创建logDist(base,n.sha)=ld的节点。 162 //节点的ID与n.sha不对应。 163 func nodeAtDistance(base common.Hash, ld int) (n *Node) { 164 n = new(Node) 165 n.sha = hashAtDistance(base, ld) 166 copy(n.ID[:], n.sha[:]) //确保节点仍然具有唯一的ID 167 return n 168 } 169 170 type pingRecorder struct{ responding, pinged map[NodeID]bool } 171 172 func newPingRecorder() *pingRecorder { 173 return &pingRecorder{make(map[NodeID]bool), make(map[NodeID]bool)} 174 } 175 176 func (t *pingRecorder) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) { 177 panic("findnode called on pingRecorder") 178 } 179 func (t *pingRecorder) close() {} 180 func (t *pingRecorder) waitping(from NodeID) error { 181 return nil //远程总是ping 182 } 183 func (t *pingRecorder) ping(toid NodeID, toaddr *net.UDPAddr) error { 184 t.pinged[toid] = true 185 if t.responding[toid] { 186 return nil 187 } else { 188 return errTimeout 189 } 190 } 191 192 func TestTable_closest(t *testing.T) { 193 t.Parallel() 194 195 test := func(test *closeTest) bool { 196 //对于任何节点表、目标和n 197 tab := newTable(test.Self, &net.UDPAddr{}) 198 tab.stuff(test.All) 199 200 //检查doclosest(target,n)是否返回节点 201 result := tab.closest(test.Target, test.N).entries 202 if hasDuplicates(result) { 203 t.Errorf("result contains duplicates") 204 return false 205 } 206 if !sortedByDistanceTo(test.Target, result) { 207 t.Errorf("result is not sorted by distance to target") 208 return false 209 } 210 211 //检查结果数是否为min(n,tablen) 212 wantN := test.N 213 if tab.count < test.N { 214 wantN = tab.count 215 } 216 if len(result) != wantN { 217 t.Errorf("wrong number of nodes: got %d, want %d", len(result), wantN) 218 return false 219 } else if len(result) == 0 { 220 return true //不需要检查距离 221 } 222 223 //检查结果节点与目标的距离是否最小。 224 for _, b := range tab.buckets { 225 for _, n := range b.entries { 226 if contains(result, n.ID) { 227 continue //不要对结果中的节点运行下面的检查 228 } 229 farthestResult := result[len(result)-1].sha 230 if distcmp(test.Target, n.sha, farthestResult) < 0 { 231 t.Errorf("table contains node that is closer to target but it's not in result") 232 t.Logf(" Target: %v", test.Target) 233 t.Logf(" Farthest Result: %v", farthestResult) 234 t.Logf(" ID: %v", n.ID) 235 return false 236 } 237 } 238 } 239 return true 240 } 241 if err := quick.Check(test, quickcfg()); err != nil { 242 t.Error(err) 243 } 244 } 245 246 func TestTable_ReadRandomNodesGetAll(t *testing.T) { 247 cfg := &quick.Config{ 248 MaxCount: 200, 249 Rand: rand.New(rand.NewSource(time.Now().Unix())), 250 Values: func(args []reflect.Value, rand *rand.Rand) { 251 args[0] = reflect.ValueOf(make([]*Node, rand.Intn(1000))) 252 }, 253 } 254 test := func(buf []*Node) bool { 255 tab := newTable(NodeID{}, &net.UDPAddr{}) 256 for i := 0; i < len(buf); i++ { 257 ld := cfg.Rand.Intn(len(tab.buckets)) 258 tab.stuff([]*Node{nodeAtDistance(tab.self.sha, ld)}) 259 } 260 gotN := tab.readRandomNodes(buf) 261 if gotN != tab.count { 262 t.Errorf("wrong number of nodes, got %d, want %d", gotN, tab.count) 263 return false 264 } 265 if hasDuplicates(buf[:gotN]) { 266 t.Errorf("result contains duplicates") 267 return false 268 } 269 return true 270 } 271 if err := quick.Check(test, cfg); err != nil { 272 t.Error(err) 273 } 274 } 275 276 type closeTest struct { 277 Self NodeID 278 Target common.Hash 279 All []*Node 280 N int 281 } 282 283 func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { 284 t := &closeTest{ 285 Self: gen(NodeID{}, rand).(NodeID), 286 Target: gen(common.Hash{}, rand).(common.Hash), 287 N: rand.Intn(bucketSize), 288 } 289 for _, id := range gen([]NodeID{}, rand).([]NodeID) { 290 t.All = append(t.All, &Node{ID: id}) 291 } 292 return reflect.ValueOf(t) 293 } 294 295 func hasDuplicates(slice []*Node) bool { 296 seen := make(map[NodeID]bool) 297 for i, e := range slice { 298 if e == nil { 299 panic(fmt.Sprintf("nil *Node at %d", i)) 300 } 301 if seen[e.ID] { 302 return true 303 } 304 seen[e.ID] = true 305 } 306 return false 307 } 308 309 func sortedByDistanceTo(distbase common.Hash, slice []*Node) bool { 310 var last common.Hash 311 for i, e := range slice { 312 if i > 0 && distcmp(distbase, e.sha, last) < 0 { 313 return false 314 } 315 last = e.sha 316 } 317 return true 318 } 319 320 func contains(ns []*Node, id NodeID) bool { 321 for _, n := range ns { 322 if n.ID == id { 323 return true 324 } 325 } 326 return false 327 } 328 329 //Gen包装速度快,价值高,使用方便。 330 //它生成给定值类型的随机值。 331 func gen(typ interface{}, rand *rand.Rand) interface{} { 332 v, ok := quick.Value(reflect.TypeOf(typ), rand) 333 if !ok { 334 panic(fmt.Sprintf("couldn't generate random value of type %T", typ)) 335 } 336 return v.Interface() 337 } 338 339 func newkey() *ecdsa.PrivateKey { 340 key, err := crypto.GenerateKey() 341 if err != nil { 342 panic("couldn't generate key: " + err.Error()) 343 } 344 return key 345 }