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