github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/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 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, func() {}, 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 return nil, nil, nil, removeDataDir, err 167 } 168 169 netStore, err := storage.NewNetStore(localStore, nil) 170 if err != nil { 171 return nil, nil, nil, removeDataDir, err 172 } 173 174 delivery := NewDelivery(to, netStore) 175 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 176 streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil) 177 teardown := func() { 178 streamer.Close() 179 removeDataDir() 180 } 181 protocolTester := p2ptest.NewProtocolTester(addr.ID(), 1, streamer.runProtocol) 182 183 err = waitForPeers(streamer, 1*time.Second, 1) 184 if err != nil { 185 return nil, nil, nil, nil, errors.New("timeout: peer is not created") 186 } 187 188 return protocolTester, streamer, localStore, teardown, nil 189 } 190 191 func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { 192 ticker := time.NewTicker(10 * time.Millisecond) 193 timeoutTimer := time.NewTimer(timeout) 194 for { 195 select { 196 case <-ticker.C: 197 if streamer.peersCount() >= expectedPeers { 198 return nil 199 } 200 case <-timeoutTimer.C: 201 return errors.New("timeout") 202 } 203 } 204 } 205 206 type roundRobinStore struct { 207 index uint32 208 stores []storage.ChunkStore 209 } 210 211 func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { 212 return &roundRobinStore{ 213 stores: stores, 214 } 215 } 216 217 func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) { 218 return nil, errors.New("get not well defined on round robin store") 219 } 220 221 func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error { 222 i := atomic.AddUint32(&rrs.index, 1) 223 idx := int(i) % len(rrs.stores) 224 return rrs.stores[idx].Put(ctx, chunk) 225 } 226 227 func (rrs *roundRobinStore) Close() { 228 for _, store := range rrs.stores { 229 store.Close() 230 } 231 } 232 233 func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { 234 r, _ := fileStore.Retrieve(context.TODO(), hash) 235 buf := make([]byte, 1024) 236 var n int 237 var total int64 238 var err error 239 for (total == 0 || n > 0) && err == nil { 240 n, err = r.ReadAt(buf, total) 241 total += int64(n) 242 } 243 if err != nil && err != io.EOF { 244 return total, err 245 } 246 return total, nil 247 } 248 249 func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { 250 nodes := sim.UpNodeIDs() 251 nodeCnt := len(nodes) 252 log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) 253 //array holding generated files 254 rfiles := make([]string, nodeCnt) 255 //array holding the root hashes of the files 256 rootAddrs := make([]storage.Address, nodeCnt) 257 258 var err error 259 //for every node, generate a file and upload 260 for i, id := range nodes { 261 item, ok := sim.NodeItem(id, bucketKeyFileStore) 262 if !ok { 263 return nil, nil, fmt.Errorf("Error accessing localstore") 264 } 265 fileStore := item.(*storage.FileStore) 266 //generate a file 267 rfiles[i], err = generateRandomFile() 268 if err != nil { 269 return nil, nil, err 270 } 271 //store it (upload it) on the FileStore 272 ctx := context.TODO() 273 rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) 274 log.Debug("Uploaded random string file to node") 275 if err != nil { 276 return nil, nil, err 277 } 278 err = wait(ctx) 279 if err != nil { 280 return nil, nil, err 281 } 282 rootAddrs[i] = rk 283 } 284 return rootAddrs, rfiles, nil 285 } 286 287 //generate a random file (string) 288 func generateRandomFile() (string, error) { 289 //generate a random file size between minFileSize and maxFileSize 290 fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize 291 log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) 292 b := testutil.RandomBytes(1, fileSize*1024) 293 return string(b), nil 294 } 295 296 //create a local store for the given node 297 func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) { 298 var datadir string 299 var err error 300 datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString())) 301 if err != nil { 302 return nil, "", err 303 } 304 var store storage.ChunkStore 305 params := storage.NewDefaultLocalStoreParams() 306 params.ChunkDbPath = datadir 307 params.BaseKey = addr.Over() 308 store, err = storage.NewTestLocalStoreForAddr(params) 309 if err != nil { 310 os.RemoveAll(datadir) 311 return nil, "", err 312 } 313 return store, datadir, nil 314 }