github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/network/stream/intervals_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 // 10 // 11 // 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 25 package stream 26 27 import ( 28 "context" 29 crand "crypto/rand" 30 "encoding/binary" 31 "fmt" 32 "io" 33 "os" 34 "sync" 35 "testing" 36 "time" 37 38 "github.com/ethereum/go-ethereum/log" 39 "github.com/ethereum/go-ethereum/node" 40 "github.com/ethereum/go-ethereum/p2p" 41 "github.com/ethereum/go-ethereum/p2p/discover" 42 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 43 "github.com/ethereum/go-ethereum/swarm/network" 44 "github.com/ethereum/go-ethereum/swarm/network/simulation" 45 "github.com/ethereum/go-ethereum/swarm/state" 46 "github.com/ethereum/go-ethereum/swarm/storage" 47 ) 48 49 func TestIntervals(t *testing.T) { 50 testIntervals(t, true, nil, false) 51 testIntervals(t, false, NewRange(9, 26), false) 52 testIntervals(t, true, NewRange(9, 26), false) 53 54 testIntervals(t, true, nil, true) 55 testIntervals(t, false, NewRange(9, 26), true) 56 testIntervals(t, true, NewRange(9, 26), true) 57 } 58 59 func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { 60 nodes := 2 61 chunkCount := dataChunkCount 62 externalStreamName := "externalStream" 63 externalStreamSessionAt := uint64(50) 64 externalStreamMaxKeys := uint64(100) 65 66 sim := simulation.New(map[string]simulation.ServiceFunc{ 67 "intervalsStreamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { 68 69 id := ctx.Config.ID 70 addr := network.NewAddrFromNodeID(id) 71 store, datadir, err := createTestLocalStorageForID(id, addr) 72 if err != nil { 73 return nil, nil, err 74 } 75 bucket.Store(bucketKeyStore, store) 76 cleanup = func() { 77 store.Close() 78 os.RemoveAll(datadir) 79 } 80 localStore := store.(*storage.LocalStore) 81 db := storage.NewDBAPI(localStore) 82 kad := network.NewKademlia(addr.Over(), network.NewKadParams()) 83 delivery := NewDelivery(kad, db) 84 85 r := NewRegistry(addr, delivery, db, state.NewInmemoryStore(), &RegistryOptions{ 86 SkipCheck: skipCheck, 87 }) 88 bucket.Store(bucketKeyRegistry, r) 89 90 r.RegisterClientFunc(externalStreamName, func(p *Peer, t string, live bool) (Client, error) { 91 return newTestExternalClient(db), nil 92 }) 93 r.RegisterServerFunc(externalStreamName, func(p *Peer, t string, live bool) (Server, error) { 94 return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil 95 }) 96 97 fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams()) 98 bucket.Store(bucketKeyFileStore, fileStore) 99 100 return r, cleanup, nil 101 102 }, 103 }) 104 defer sim.Close() 105 106 log.Info("Adding nodes to simulation") 107 _, err := sim.AddNodesAndConnectChain(nodes) 108 if err != nil { 109 t.Fatal(err) 110 } 111 112 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second) 113 defer cancel() 114 115 result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { 116 nodeIDs := sim.UpNodeIDs() 117 storer := nodeIDs[0] 118 checker := nodeIDs[1] 119 120 item, ok := sim.NodeItem(storer, bucketKeyFileStore) 121 if !ok { 122 return fmt.Errorf("No filestore") 123 } 124 fileStore := item.(*storage.FileStore) 125 126 size := chunkCount * chunkSize 127 _, wait, err := fileStore.Store(ctx, io.LimitReader(crand.Reader, int64(size)), int64(size), false) 128 if err != nil { 129 log.Error("Store error: %v", "err", err) 130 t.Fatal(err) 131 } 132 err = wait(ctx) 133 if err != nil { 134 log.Error("Wait error: %v", "err", err) 135 t.Fatal(err) 136 } 137 138 item, ok = sim.NodeItem(checker, bucketKeyRegistry) 139 if !ok { 140 return fmt.Errorf("No registry") 141 } 142 registry := item.(*Registry) 143 144 liveErrC := make(chan error) 145 historyErrC := make(chan error) 146 147 if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { 148 log.Error("WaitKademlia error: %v", "err", err) 149 return err 150 } 151 152 log.Debug("Watching for disconnections") 153 disconnections := sim.PeerEvents( 154 context.Background(), 155 sim.NodeIDs(), 156 simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), 157 ) 158 159 go func() { 160 for d := range disconnections { 161 if d.Error != nil { 162 log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) 163 t.Fatal(d.Error) 164 } 165 } 166 }() 167 168 go func() { 169 if !live { 170 close(liveErrC) 171 return 172 } 173 174 var err error 175 defer func() { 176 liveErrC <- err 177 }() 178 179 // 180 var liveHashesChan chan []byte 181 liveHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", true)) 182 if err != nil { 183 log.Error("Subscription error: %v", "err", err) 184 return 185 } 186 i := externalStreamSessionAt 187 188 // 189 err = enableNotifications(registry, storer, NewStream(externalStreamName, "", true)) 190 if err != nil { 191 return 192 } 193 194 for { 195 select { 196 case hash := <-liveHashesChan: 197 h := binary.BigEndian.Uint64(hash) 198 if h != i { 199 err = fmt.Errorf("expected live hash %d, got %d", i, h) 200 return 201 } 202 i++ 203 if i > externalStreamMaxKeys { 204 return 205 } 206 case <-ctx.Done(): 207 return 208 } 209 } 210 }() 211 212 go func() { 213 if live && history == nil { 214 close(historyErrC) 215 return 216 } 217 218 var err error 219 defer func() { 220 historyErrC <- err 221 }() 222 223 // 224 var historyHashesChan chan []byte 225 historyHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", false)) 226 if err != nil { 227 return 228 } 229 230 var i uint64 231 historyTo := externalStreamMaxKeys 232 if history != nil { 233 i = history.From 234 if history.To != 0 { 235 historyTo = history.To 236 } 237 } 238 239 // 240 err = enableNotifications(registry, storer, NewStream(externalStreamName, "", false)) 241 if err != nil { 242 return 243 } 244 245 for { 246 select { 247 case hash := <-historyHashesChan: 248 h := binary.BigEndian.Uint64(hash) 249 if h != i { 250 err = fmt.Errorf("expected history hash %d, got %d", i, h) 251 return 252 } 253 i++ 254 if i > historyTo { 255 return 256 } 257 case <-ctx.Done(): 258 return 259 } 260 } 261 }() 262 263 err = registry.Subscribe(storer, NewStream(externalStreamName, "", live), history, Top) 264 if err != nil { 265 return err 266 } 267 if err := <-liveErrC; err != nil { 268 return err 269 } 270 if err := <-historyErrC; err != nil { 271 return err 272 } 273 274 return nil 275 }) 276 277 if result.Error != nil { 278 t.Fatal(result.Error) 279 } 280 } 281 282 func getHashes(ctx context.Context, r *Registry, peerID discover.NodeID, s Stream) (chan []byte, error) { 283 peer := r.getPeer(peerID) 284 285 client, err := peer.getClient(ctx, s) 286 if err != nil { 287 return nil, err 288 } 289 290 c := client.Client.(*testExternalClient) 291 292 return c.hashes, nil 293 } 294 295 func enableNotifications(r *Registry, peerID discover.NodeID, s Stream) error { 296 peer := r.getPeer(peerID) 297 298 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 299 defer cancel() 300 301 client, err := peer.getClient(ctx, s) 302 if err != nil { 303 return err 304 } 305 306 close(client.Client.(*testExternalClient).enableNotificationsC) 307 308 return nil 309 } 310 311 type testExternalClient struct { 312 hashes chan []byte 313 db *storage.DBAPI 314 enableNotificationsC chan struct{} 315 } 316 317 func newTestExternalClient(db *storage.DBAPI) *testExternalClient { 318 return &testExternalClient{ 319 hashes: make(chan []byte), 320 db: db, 321 enableNotificationsC: make(chan struct{}), 322 } 323 } 324 325 func (c *testExternalClient) NeedData(ctx context.Context, hash []byte) func() { 326 chunk, _ := c.db.GetOrCreateRequest(ctx, hash) 327 if chunk.ReqC == nil { 328 return nil 329 } 330 c.hashes <- hash 331 // 332 // 333 // 334 // 335 /* 336 337 338 339 */ 340 341 return nil 342 } 343 344 func (c *testExternalClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) { 345 return nil 346 } 347 348 func (c *testExternalClient) Close() {} 349 350 const testExternalServerBatchSize = 10 351 352 type testExternalServer struct { 353 t string 354 keyFunc func(key []byte, index uint64) 355 sessionAt uint64 356 maxKeys uint64 357 } 358 359 func newTestExternalServer(t string, sessionAt, maxKeys uint64, keyFunc func(key []byte, index uint64)) *testExternalServer { 360 if keyFunc == nil { 361 keyFunc = binary.BigEndian.PutUint64 362 } 363 return &testExternalServer{ 364 t: t, 365 keyFunc: keyFunc, 366 sessionAt: sessionAt, 367 maxKeys: maxKeys, 368 } 369 } 370 371 func (s *testExternalServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { 372 if from == 0 && to == 0 { 373 from = s.sessionAt 374 to = s.sessionAt + testExternalServerBatchSize 375 } 376 if to-from > testExternalServerBatchSize { 377 to = from + testExternalServerBatchSize - 1 378 } 379 if from >= s.maxKeys && to > s.maxKeys { 380 return nil, 0, 0, nil, io.EOF 381 } 382 if to > s.maxKeys { 383 to = s.maxKeys 384 } 385 b := make([]byte, HashSize*(to-from+1)) 386 for i := from; i <= to; i++ { 387 s.keyFunc(b[(i-from)*HashSize:(i-from+1)*HashSize], i) 388 } 389 return b, from, to, nil, nil 390 } 391 392 func (s *testExternalServer) GetData(context.Context, []byte) ([]byte, error) { 393 return make([]byte, 4096), nil 394 } 395 396 func (s *testExternalServer) Close() {}