github.com/alexdevranger/node-1.8.27@v0.0.0-20221128213301-aa5841e41d2d/swarm/network/stream/common_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-dubxcoin library. 3 // 4 // The go-dubxcoin 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-dubxcoin 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-dubxcoin library. If not, see <http://www.gnu.org/licenses/>. 16 17 package stream 18 19 import ( 20 "context" 21 "errors" 22 "flag" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "math/rand" 27 "os" 28 "strings" 29 "sync" 30 "sync/atomic" 31 "time" 32 33 "github.com/alexdevranger/node-1.8.27/log" 34 "github.com/alexdevranger/node-1.8.27/p2p/enode" 35 "github.com/alexdevranger/node-1.8.27/p2p/simulations/adapters" 36 p2ptest "github.com/alexdevranger/node-1.8.27/p2p/testing" 37 "github.com/alexdevranger/node-1.8.27/swarm/network" 38 "github.com/alexdevranger/node-1.8.27/swarm/network/simulation" 39 "github.com/alexdevranger/node-1.8.27/swarm/state" 40 "github.com/alexdevranger/node-1.8.27/swarm/storage" 41 mockmem "github.com/alexdevranger/node-1.8.27/swarm/storage/mock/mem" 42 "github.com/alexdevranger/node-1.8.27/swarm/testutil" 43 colorable "github.com/mattn/go-colorable" 44 ) 45 46 var ( 47 loglevel = flag.Int("loglevel", 2, "verbosity of logs") 48 nodes = flag.Int("nodes", 0, "number of nodes") 49 chunks = flag.Int("chunks", 0, "number of chunks") 50 useMockStore = flag.Bool("mockstore", false, "disabled mock store (default: enabled)") 51 longrunning = flag.Bool("longrunning", false, "do run long-running tests") 52 53 bucketKeyDB = simulation.BucketKey("db") 54 bucketKeyStore = simulation.BucketKey("store") 55 bucketKeyFileStore = simulation.BucketKey("filestore") 56 bucketKeyNetStore = simulation.BucketKey("netstore") 57 bucketKeyDelivery = simulation.BucketKey("delivery") 58 bucketKeyRegistry = simulation.BucketKey("registry") 59 60 chunkSize = 4096 61 pof = network.Pof 62 ) 63 64 func init() { 65 flag.Parse() 66 rand.Seed(time.Now().UnixNano()) 67 68 log.PrintOrigins(true) 69 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) 70 } 71 72 // newNetStoreAndDelivery is a default constructor for BzzAddr, NetStore and Delivery, used in Simulations 73 func newNetStoreAndDelivery(ctx *adapters.ServiceContext, bucket *sync.Map) (*network.BzzAddr, *storage.NetStore, *Delivery, func(), error) { 74 addr := network.NewAddr(ctx.Config.Node()) 75 76 netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) 77 if err != nil { 78 return nil, nil, nil, nil, err 79 } 80 81 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 82 83 return addr, netStore, delivery, cleanup, nil 84 } 85 86 // newNetStoreAndDeliveryWithBzzAddr is a constructor for NetStore and Delivery, used in Simulations, accepting any BzzAddr 87 func newNetStoreAndDeliveryWithBzzAddr(ctx *adapters.ServiceContext, bucket *sync.Map, addr *network.BzzAddr) (*storage.NetStore, *Delivery, func(), error) { 88 netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) 89 if err != nil { 90 return nil, nil, nil, err 91 } 92 93 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 94 95 return netStore, delivery, cleanup, nil 96 } 97 98 // newNetStoreAndDeliveryWithRequestFunc is a constructor for NetStore and Delivery, used in Simulations, accepting any NetStore.RequestFunc 99 func newNetStoreAndDeliveryWithRequestFunc(ctx *adapters.ServiceContext, bucket *sync.Map, rf network.RequestFunc) (*network.BzzAddr, *storage.NetStore, *Delivery, func(), error) { 100 addr := network.NewAddr(ctx.Config.Node()) 101 102 netStore, delivery, cleanup, err := netStoreAndDeliveryWithAddr(ctx, bucket, addr) 103 if err != nil { 104 return nil, nil, nil, nil, err 105 } 106 107 netStore.NewNetFetcherFunc = network.NewFetcherFactory(rf, true).New 108 109 return addr, netStore, delivery, cleanup, nil 110 } 111 112 func netStoreAndDeliveryWithAddr(ctx *adapters.ServiceContext, bucket *sync.Map, addr *network.BzzAddr) (*storage.NetStore, *Delivery, func(), error) { 113 n := ctx.Config.Node() 114 115 store, datadir, err := createTestLocalStorageForID(n.ID(), addr) 116 if *useMockStore { 117 store, datadir, err = createMockStore(mockmem.NewGlobalStore(), n.ID(), addr) 118 } 119 if err != nil { 120 return nil, nil, nil, err 121 } 122 localStore := store.(*storage.LocalStore) 123 netStore, err := storage.NewNetStore(localStore, nil) 124 if err != nil { 125 return nil, nil, nil, err 126 } 127 128 fileStore := storage.NewFileStore(netStore, storage.NewFileStoreParams()) 129 130 kad := network.NewKademlia(addr.Over(), network.NewKadParams()) 131 delivery := NewDelivery(kad, netStore) 132 133 bucket.Store(bucketKeyStore, store) 134 bucket.Store(bucketKeyDB, netStore) 135 bucket.Store(bucketKeyDelivery, delivery) 136 bucket.Store(bucketKeyFileStore, fileStore) 137 138 cleanup := func() { 139 netStore.Close() 140 os.RemoveAll(datadir) 141 } 142 143 return netStore, delivery, cleanup, nil 144 } 145 146 func newStreamerTester(registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) { 147 // setup 148 addr := network.RandomAddr() // tested peers peer address 149 to := network.NewKademlia(addr.OAddr, network.NewKadParams()) 150 151 // temp datadir 152 datadir, err := ioutil.TempDir("", "streamer") 153 if err != nil { 154 return nil, nil, nil, nil, err 155 } 156 removeDataDir := func() { 157 os.RemoveAll(datadir) 158 } 159 160 params := storage.NewDefaultLocalStoreParams() 161 params.Init(datadir) 162 params.BaseKey = addr.Over() 163 164 localStore, err := storage.NewTestLocalStoreForAddr(params) 165 if err != nil { 166 removeDataDir() 167 return nil, nil, nil, nil, err 168 } 169 170 netStore, err := storage.NewNetStore(localStore, nil) 171 if err != nil { 172 removeDataDir() 173 return nil, nil, nil, nil, err 174 } 175 176 delivery := NewDelivery(to, netStore) 177 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 178 streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil) 179 teardown := func() { 180 streamer.Close() 181 removeDataDir() 182 } 183 protocolTester := p2ptest.NewProtocolTester(addr.ID(), 1, streamer.runProtocol) 184 185 err = waitForPeers(streamer, 10*time.Second, 1) 186 if err != nil { 187 teardown() 188 return nil, nil, nil, nil, errors.New("timeout: peer is not created") 189 } 190 191 return protocolTester, streamer, localStore, teardown, nil 192 } 193 194 func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { 195 ticker := time.NewTicker(10 * time.Millisecond) 196 timeoutTimer := time.NewTimer(timeout) 197 for { 198 select { 199 case <-ticker.C: 200 if streamer.peersCount() >= expectedPeers { 201 return nil 202 } 203 case <-timeoutTimer.C: 204 return errors.New("timeout") 205 } 206 } 207 } 208 209 type roundRobinStore struct { 210 index uint32 211 stores []storage.ChunkStore 212 } 213 214 func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { 215 return &roundRobinStore{ 216 stores: stores, 217 } 218 } 219 220 // not used in this context, only to fulfill ChunkStore interface 221 func (rrs *roundRobinStore) Has(ctx context.Context, addr storage.Address) bool { 222 panic("RoundRobinStor doesn't support HasChunk") 223 } 224 225 func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) { 226 return nil, errors.New("get not well defined on round robin store") 227 } 228 229 func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error { 230 i := atomic.AddUint32(&rrs.index, 1) 231 idx := int(i) % len(rrs.stores) 232 return rrs.stores[idx].Put(ctx, chunk) 233 } 234 235 func (rrs *roundRobinStore) Close() { 236 for _, store := range rrs.stores { 237 store.Close() 238 } 239 } 240 241 func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { 242 r, _ := fileStore.Retrieve(context.TODO(), hash) 243 buf := make([]byte, 1024) 244 var n int 245 var total int64 246 var err error 247 for (total == 0 || n > 0) && err == nil { 248 n, err = r.ReadAt(buf, total) 249 total += int64(n) 250 } 251 if err != nil && err != io.EOF { 252 return total, err 253 } 254 return total, nil 255 } 256 257 func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { 258 nodes := sim.UpNodeIDs() 259 nodeCnt := len(nodes) 260 log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) 261 //array holding generated files 262 rfiles := make([]string, nodeCnt) 263 //array holding the root hashes of the files 264 rootAddrs := make([]storage.Address, nodeCnt) 265 266 var err error 267 //for every node, generate a file and upload 268 for i, id := range nodes { 269 item, ok := sim.NodeItem(id, bucketKeyFileStore) 270 if !ok { 271 return nil, nil, fmt.Errorf("Error accessing localstore") 272 } 273 fileStore := item.(*storage.FileStore) 274 //generate a file 275 rfiles[i], err = generateRandomFile() 276 if err != nil { 277 return nil, nil, err 278 } 279 //store it (upload it) on the FileStore 280 ctx := context.TODO() 281 rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) 282 log.Debug("Uploaded random string file to node") 283 if err != nil { 284 return nil, nil, err 285 } 286 err = wait(ctx) 287 if err != nil { 288 return nil, nil, err 289 } 290 rootAddrs[i] = rk 291 } 292 return rootAddrs, rfiles, nil 293 } 294 295 //generate a random file (string) 296 func generateRandomFile() (string, error) { 297 //generate a random file size between minFileSize and maxFileSize 298 fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize 299 log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) 300 b := testutil.RandomBytes(1, fileSize*1024) 301 return string(b), nil 302 } 303 304 //create a local store for the given node 305 func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) { 306 var datadir string 307 var err error 308 datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString())) 309 if err != nil { 310 return nil, "", err 311 } 312 var store storage.ChunkStore 313 params := storage.NewDefaultLocalStoreParams() 314 params.ChunkDbPath = datadir 315 params.BaseKey = addr.Over() 316 store, err = storage.NewTestLocalStoreForAddr(params) 317 if err != nil { 318 os.RemoveAll(datadir) 319 return nil, "", err 320 } 321 return store, datadir, nil 322 } 323 324 // watchDisconnections receives simulation peer events in a new goroutine and sets atomic value 325 // disconnected to true in case of a disconnect event. 326 func watchDisconnections(ctx context.Context, sim *simulation.Simulation) (disconnected *boolean) { 327 log.Debug("Watching for disconnections") 328 disconnections := sim.PeerEvents( 329 ctx, 330 sim.NodeIDs(), 331 simulation.NewPeerEventsFilter().Drop(), 332 ) 333 disconnected = new(boolean) 334 go func() { 335 for { 336 select { 337 case <-ctx.Done(): 338 return 339 case d := <-disconnections: 340 if d.Error != nil { 341 log.Error("peer drop event error", "node", d.NodeID, "peer", d.PeerID, "err", d.Error) 342 } else { 343 log.Error("peer drop", "node", d.NodeID, "peer", d.PeerID) 344 } 345 disconnected.set(true) 346 } 347 } 348 }() 349 return disconnected 350 } 351 352 // boolean is used to concurrently set 353 // and read a boolean value. 354 type boolean struct { 355 v bool 356 mu sync.RWMutex 357 } 358 359 // set sets the value. 360 func (b *boolean) set(v bool) { 361 b.mu.Lock() 362 defer b.mu.Unlock() 363 364 b.v = v 365 } 366 367 // bool reads the value. 368 func (b *boolean) bool() bool { 369 b.mu.RLock() 370 defer b.mu.RUnlock() 371 372 return b.v 373 }