github.com/dotlike13/wemix30_go@v1.8.23/swarm/network/stream/syncer_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package stream 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "io/ioutil" 24 "math" 25 "os" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/node" 32 "github.com/ethereum/go-ethereum/p2p/enode" 33 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 34 "github.com/ethereum/go-ethereum/swarm/log" 35 "github.com/ethereum/go-ethereum/swarm/network" 36 "github.com/ethereum/go-ethereum/swarm/network/simulation" 37 "github.com/ethereum/go-ethereum/swarm/state" 38 "github.com/ethereum/go-ethereum/swarm/storage" 39 "github.com/ethereum/go-ethereum/swarm/storage/mock" 40 "github.com/ethereum/go-ethereum/swarm/testutil" 41 ) 42 43 const dataChunkCount = 200 44 45 func TestSyncerSimulation(t *testing.T) { 46 testSyncBetweenNodes(t, 2, dataChunkCount, true, 1) 47 // This test uses much more memory when running with 48 // race detector. Allow it to finish successfully by 49 // reducing its scope, and still check for data races 50 // with the smallest number of nodes. 51 if !raceTest { 52 testSyncBetweenNodes(t, 4, dataChunkCount, true, 1) 53 testSyncBetweenNodes(t, 8, dataChunkCount, true, 1) 54 testSyncBetweenNodes(t, 16, dataChunkCount, true, 1) 55 } 56 } 57 58 func createMockStore(globalStore mock.GlobalStorer, id enode.ID, addr *network.BzzAddr) (lstore storage.ChunkStore, datadir string, err error) { 59 address := common.BytesToAddress(id.Bytes()) 60 mockStore := globalStore.NewNodeStore(address) 61 params := storage.NewDefaultLocalStoreParams() 62 63 datadir, err = ioutil.TempDir("", "localMockStore-"+id.TerminalString()) 64 if err != nil { 65 return nil, "", err 66 } 67 params.Init(datadir) 68 params.BaseKey = addr.Over() 69 lstore, err = storage.NewLocalStore(params, mockStore) 70 if err != nil { 71 return nil, "", err 72 } 73 return lstore, datadir, nil 74 } 75 76 func testSyncBetweenNodes(t *testing.T, nodes, chunkCount int, skipCheck bool, po uint8) { 77 78 sim := simulation.New(map[string]simulation.ServiceFunc{ 79 "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { 80 addr := network.NewAddr(ctx.Config.Node()) 81 //hack to put addresses in same space 82 addr.OAddr[0] = byte(0) 83 84 netStore, delivery, clean, err := newNetStoreAndDeliveryWithBzzAddr(ctx, bucket, addr) 85 if err != nil { 86 return nil, nil, err 87 } 88 89 var dir string 90 var store *state.DBStore 91 if raceTest { 92 // Use on-disk DBStore to reduce memory consumption in race tests. 93 dir, err = ioutil.TempDir("", "swarm-stream-") 94 if err != nil { 95 return nil, nil, err 96 } 97 store, err = state.NewDBStore(dir) 98 if err != nil { 99 return nil, nil, err 100 } 101 } else { 102 store = state.NewInmemoryStore() 103 } 104 105 r := NewRegistry(addr.ID(), delivery, netStore, store, &RegistryOptions{ 106 Retrieval: RetrievalDisabled, 107 Syncing: SyncingAutoSubscribe, 108 SkipCheck: skipCheck, 109 }, nil) 110 111 cleanup = func() { 112 r.Close() 113 clean() 114 if dir != "" { 115 os.RemoveAll(dir) 116 } 117 } 118 119 return r, cleanup, nil 120 }, 121 }) 122 defer sim.Close() 123 124 // create context for simulation run 125 timeout := 30 * time.Second 126 ctx, cancel := context.WithTimeout(context.Background(), timeout) 127 // defer cancel should come before defer simulation teardown 128 defer cancel() 129 130 _, err := sim.AddNodesAndConnectChain(nodes) 131 if err != nil { 132 t.Fatal(err) 133 } 134 result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) { 135 nodeIDs := sim.UpNodeIDs() 136 137 nodeIndex := make(map[enode.ID]int) 138 for i, id := range nodeIDs { 139 nodeIndex[id] = i 140 } 141 142 disconnected := watchDisconnections(ctx, sim) 143 defer func() { 144 if err != nil && disconnected.bool() { 145 err = errors.New("disconnect events received") 146 } 147 }() 148 149 // each node Subscribes to each other's swarmChunkServerStreamName 150 for j := 0; j < nodes-1; j++ { 151 id := nodeIDs[j] 152 client, err := sim.Net.GetNode(id).Client() 153 if err != nil { 154 return fmt.Errorf("node %s client: %v", id, err) 155 } 156 sid := nodeIDs[j+1] 157 client.CallContext(ctx, nil, "stream_subscribeStream", sid, NewStream("SYNC", FormatSyncBinKey(1), false), NewRange(0, 0), Top) 158 if err != nil { 159 return err 160 } 161 if j > 0 || nodes == 2 { 162 item, ok := sim.NodeItem(nodeIDs[j], bucketKeyFileStore) 163 if !ok { 164 return fmt.Errorf("No filestore") 165 } 166 fileStore := item.(*storage.FileStore) 167 size := chunkCount * chunkSize 168 _, wait, err := fileStore.Store(ctx, testutil.RandomReader(j, size), int64(size), false) 169 if err != nil { 170 return fmt.Errorf("fileStore.Store: %v", err) 171 } 172 wait(ctx) 173 } 174 } 175 // here we distribute chunks of a random file into stores 1...nodes 176 if _, err := sim.WaitTillHealthy(ctx); err != nil { 177 return err 178 } 179 180 // collect hashes in po 1 bin for each node 181 hashes := make([][]storage.Address, nodes) 182 totalHashes := 0 183 hashCounts := make([]int, nodes) 184 for i := nodes - 1; i >= 0; i-- { 185 if i < nodes-1 { 186 hashCounts[i] = hashCounts[i+1] 187 } 188 item, ok := sim.NodeItem(nodeIDs[i], bucketKeyDB) 189 if !ok { 190 return fmt.Errorf("No DB") 191 } 192 netStore := item.(*storage.NetStore) 193 netStore.Iterator(0, math.MaxUint64, po, func(addr storage.Address, index uint64) bool { 194 hashes[i] = append(hashes[i], addr) 195 totalHashes++ 196 hashCounts[i]++ 197 return true 198 }) 199 } 200 var total, found int 201 for _, node := range nodeIDs { 202 i := nodeIndex[node] 203 204 for j := i; j < nodes; j++ { 205 total += len(hashes[j]) 206 for _, key := range hashes[j] { 207 item, ok := sim.NodeItem(nodeIDs[j], bucketKeyDB) 208 if !ok { 209 return fmt.Errorf("No DB") 210 } 211 db := item.(*storage.NetStore) 212 _, err := db.Get(ctx, key) 213 if err == nil { 214 found++ 215 } 216 } 217 } 218 log.Debug("sync check", "node", node, "index", i, "bin", po, "found", found, "total", total) 219 } 220 if total == found && total > 0 { 221 return nil 222 } 223 return fmt.Errorf("Total not equallying found: total is %d", total) 224 }) 225 226 if result.Error != nil { 227 t.Fatal(result.Error) 228 } 229 } 230 231 //TestSameVersionID just checks that if the version is not changed, 232 //then streamer peers see each other 233 func TestSameVersionID(t *testing.T) { 234 //test version ID 235 v := uint(1) 236 sim := simulation.New(map[string]simulation.ServiceFunc{ 237 "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { 238 addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) 239 if err != nil { 240 return nil, nil, err 241 } 242 243 r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ 244 Retrieval: RetrievalDisabled, 245 Syncing: SyncingAutoSubscribe, 246 }, nil) 247 bucket.Store(bucketKeyRegistry, r) 248 249 //assign to each node the same version ID 250 r.spec.Version = v 251 252 cleanup = func() { 253 r.Close() 254 clean() 255 } 256 257 return r, cleanup, nil 258 }, 259 }) 260 defer sim.Close() 261 262 //connect just two nodes 263 log.Info("Adding nodes to simulation") 264 _, err := sim.AddNodesAndConnectChain(2) 265 if err != nil { 266 t.Fatal(err) 267 } 268 269 log.Info("Starting simulation") 270 ctx := context.Background() 271 //make sure they have time to connect 272 time.Sleep(200 * time.Millisecond) 273 result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { 274 //get the pivot node's filestore 275 nodes := sim.UpNodeIDs() 276 277 item, ok := sim.NodeItem(nodes[0], bucketKeyRegistry) 278 if !ok { 279 return fmt.Errorf("No filestore") 280 } 281 registry := item.(*Registry) 282 283 //the peers should connect, thus getting the peer should not return nil 284 if registry.getPeer(nodes[1]) == nil { 285 return errors.New("Expected the peer to not be nil, but it is") 286 } 287 return nil 288 }) 289 if result.Error != nil { 290 t.Fatal(result.Error) 291 } 292 log.Info("Simulation ended") 293 } 294 295 //TestDifferentVersionID proves that if the streamer protocol version doesn't match, 296 //then the peers are not connected at streamer level 297 func TestDifferentVersionID(t *testing.T) { 298 //create a variable to hold the version ID 299 v := uint(0) 300 sim := simulation.New(map[string]simulation.ServiceFunc{ 301 "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { 302 addr, netStore, delivery, clean, err := newNetStoreAndDelivery(ctx, bucket) 303 if err != nil { 304 return nil, nil, err 305 } 306 307 r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{ 308 Retrieval: RetrievalDisabled, 309 Syncing: SyncingAutoSubscribe, 310 }, nil) 311 bucket.Store(bucketKeyRegistry, r) 312 313 //increase the version ID for each node 314 v++ 315 r.spec.Version = v 316 317 cleanup = func() { 318 r.Close() 319 clean() 320 } 321 322 return r, cleanup, nil 323 }, 324 }) 325 defer sim.Close() 326 327 //connect the nodes 328 log.Info("Adding nodes to simulation") 329 _, err := sim.AddNodesAndConnectChain(2) 330 if err != nil { 331 t.Fatal(err) 332 } 333 334 log.Info("Starting simulation") 335 ctx := context.Background() 336 //make sure they have time to connect 337 time.Sleep(200 * time.Millisecond) 338 result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { 339 //get the pivot node's filestore 340 nodes := sim.UpNodeIDs() 341 342 item, ok := sim.NodeItem(nodes[0], bucketKeyRegistry) 343 if !ok { 344 return fmt.Errorf("No filestore") 345 } 346 registry := item.(*Registry) 347 348 //getting the other peer should fail due to the different version numbers 349 if registry.getPeer(nodes[1]) != nil { 350 return errors.New("Expected the peer to be nil, but it is not") 351 } 352 return nil 353 }) 354 if result.Error != nil { 355 t.Fatal(result.Error) 356 } 357 log.Info("Simulation ended") 358 359 }