github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/swarm/network/stream/common_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 "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/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/p2p/enode" 35 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 36 p2ptest "github.com/ethereum/go-ethereum/p2p/testing" 37 "github.com/ethereum/go-ethereum/swarm/network" 38 "github.com/ethereum/go-ethereum/swarm/network/simulation" 39 "github.com/ethereum/go-ethereum/swarm/state" 40 "github.com/ethereum/go-ethereum/swarm/storage" 41 mockmem "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" 42 "github.com/ethereum/go-ethereum/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 // for the kademlia object, we use the global key from the simulation package, 138 // as the simulation will try to access it in the WaitTillHealthy with that key 139 bucket.Store(simulation.BucketKeyKademlia, kad) 140 141 cleanup := func() { 142 netStore.Close() 143 os.RemoveAll(datadir) 144 } 145 146 return netStore, delivery, cleanup, nil 147 } 148 149 func newStreamerTester(registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) { 150 // setup 151 addr := network.RandomAddr() // tested peers peer address 152 to := network.NewKademlia(addr.OAddr, network.NewKadParams()) 153 154 // temp datadir 155 datadir, err := ioutil.TempDir("", "streamer") 156 if err != nil { 157 return nil, nil, nil, nil, err 158 } 159 removeDataDir := func() { 160 os.RemoveAll(datadir) 161 } 162 163 params := storage.NewDefaultLocalStoreParams() 164 params.Init(datadir) 165 params.BaseKey = addr.Over() 166 167 localStore, err := storage.NewTestLocalStoreForAddr(params) 168 if err != nil { 169 removeDataDir() 170 return nil, nil, nil, nil, err 171 } 172 173 netStore, err := storage.NewNetStore(localStore, nil) 174 if err != nil { 175 removeDataDir() 176 return nil, nil, nil, nil, err 177 } 178 179 delivery := NewDelivery(to, netStore) 180 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 181 streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil) 182 teardown := func() { 183 streamer.Close() 184 removeDataDir() 185 } 186 protocolTester := p2ptest.NewProtocolTester(addr.ID(), 1, streamer.runProtocol) 187 188 err = waitForPeers(streamer, 10*time.Second, 1) 189 if err != nil { 190 teardown() 191 return nil, nil, nil, nil, errors.New("timeout: peer is not created") 192 } 193 194 return protocolTester, streamer, localStore, teardown, nil 195 } 196 197 func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { 198 ticker := time.NewTicker(10 * time.Millisecond) 199 timeoutTimer := time.NewTimer(timeout) 200 for { 201 select { 202 case <-ticker.C: 203 if streamer.peersCount() >= expectedPeers { 204 return nil 205 } 206 case <-timeoutTimer.C: 207 return errors.New("timeout") 208 } 209 } 210 } 211 212 type roundRobinStore struct { 213 index uint32 214 stores []storage.ChunkStore 215 } 216 217 func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { 218 return &roundRobinStore{ 219 stores: stores, 220 } 221 } 222 223 // not used in this context, only to fulfill ChunkStore interface 224 func (rrs *roundRobinStore) Has(ctx context.Context, addr storage.Address) bool { 225 panic("RoundRobinStor doesn't support HasChunk") 226 } 227 228 func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) { 229 return nil, errors.New("get not well defined on round robin store") 230 } 231 232 func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error { 233 i := atomic.AddUint32(&rrs.index, 1) 234 idx := int(i) % len(rrs.stores) 235 return rrs.stores[idx].Put(ctx, chunk) 236 } 237 238 func (rrs *roundRobinStore) Close() { 239 for _, store := range rrs.stores { 240 store.Close() 241 } 242 } 243 244 func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { 245 r, _ := fileStore.Retrieve(context.TODO(), hash) 246 buf := make([]byte, 1024) 247 var n int 248 var total int64 249 var err error 250 for (total == 0 || n > 0) && err == nil { 251 n, err = r.ReadAt(buf, total) 252 total += int64(n) 253 } 254 if err != nil && err != io.EOF { 255 return total, err 256 } 257 return total, nil 258 } 259 260 func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { 261 nodes := sim.UpNodeIDs() 262 nodeCnt := len(nodes) 263 log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) 264 //array holding generated files 265 rfiles := make([]string, nodeCnt) 266 //array holding the root hashes of the files 267 rootAddrs := make([]storage.Address, nodeCnt) 268 269 var err error 270 //for every node, generate a file and upload 271 for i, id := range nodes { 272 item, ok := sim.NodeItem(id, bucketKeyFileStore) 273 if !ok { 274 return nil, nil, fmt.Errorf("Error accessing localstore") 275 } 276 fileStore := item.(*storage.FileStore) 277 //generate a file 278 rfiles[i], err = generateRandomFile() 279 if err != nil { 280 return nil, nil, err 281 } 282 //store it (upload it) on the FileStore 283 ctx := context.TODO() 284 rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) 285 log.Debug("Uploaded random string file to node") 286 if err != nil { 287 return nil, nil, err 288 } 289 err = wait(ctx) 290 if err != nil { 291 return nil, nil, err 292 } 293 rootAddrs[i] = rk 294 } 295 return rootAddrs, rfiles, nil 296 } 297 298 //generate a random file (string) 299 func generateRandomFile() (string, error) { 300 //generate a random file size between minFileSize and maxFileSize 301 fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize 302 log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) 303 b := testutil.RandomBytes(1, fileSize*1024) 304 return string(b), nil 305 } 306 307 //create a local store for the given node 308 func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) { 309 var datadir string 310 var err error 311 datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString())) 312 if err != nil { 313 return nil, "", err 314 } 315 var store storage.ChunkStore 316 params := storage.NewDefaultLocalStoreParams() 317 params.ChunkDbPath = datadir 318 params.BaseKey = addr.Over() 319 store, err = storage.NewTestLocalStoreForAddr(params) 320 if err != nil { 321 os.RemoveAll(datadir) 322 return nil, "", err 323 } 324 return store, datadir, nil 325 } 326 327 // watchDisconnections receives simulation peer events in a new goroutine and sets atomic value 328 // disconnected to true in case of a disconnect event. 329 func watchDisconnections(ctx context.Context, sim *simulation.Simulation) (disconnected *boolean) { 330 log.Debug("Watching for disconnections") 331 disconnections := sim.PeerEvents( 332 ctx, 333 sim.NodeIDs(), 334 simulation.NewPeerEventsFilter().Drop(), 335 ) 336 disconnected = new(boolean) 337 go func() { 338 for { 339 select { 340 case <-ctx.Done(): 341 return 342 case d := <-disconnections: 343 if d.Error != nil { 344 log.Error("peer drop event error", "node", d.NodeID, "peer", d.PeerID, "err", d.Error) 345 } else { 346 log.Error("peer drop", "node", d.NodeID, "peer", d.PeerID) 347 } 348 disconnected.set(true) 349 } 350 } 351 }() 352 return disconnected 353 } 354 355 // boolean is used to concurrently set 356 // and read a boolean value. 357 type boolean struct { 358 v bool 359 mu sync.RWMutex 360 } 361 362 // set sets the value. 363 func (b *boolean) set(v bool) { 364 b.mu.Lock() 365 defer b.mu.Unlock() 366 367 b.v = v 368 } 369 370 // bool reads the value. 371 func (b *boolean) bool() bool { 372 b.mu.RLock() 373 defer b.mu.RUnlock() 374 375 return b.v 376 }