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