github.com/shirikatsu/go-ethereum@v1.8.19/cmd/swarm/swarm-smoke/feed_upload_and_sync.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "crypto/md5" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "os/exec" 12 "strings" 13 "sync" 14 "time" 15 16 "github.com/ethereum/go-ethereum/common/hexutil" 17 "github.com/ethereum/go-ethereum/crypto" 18 "github.com/ethereum/go-ethereum/log" 19 "github.com/ethereum/go-ethereum/swarm/storage/feed" 20 colorable "github.com/mattn/go-colorable" 21 "github.com/pborman/uuid" 22 cli "gopkg.in/urfave/cli.v1" 23 ) 24 25 const ( 26 feedRandomDataLength = 8 27 ) 28 29 // TODO: retrieve with manifest + extract repeating code 30 func cliFeedUploadAndSync(c *cli.Context) error { 31 32 log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(verbosity), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))) 33 34 defer func(now time.Time) { log.Info("total time", "time", time.Since(now), "size (kb)", filesize) }(time.Now()) 35 36 generateEndpoints(scheme, cluster, from, to) 37 38 log.Info("generating and uploading feeds to " + endpoints[0] + " and syncing") 39 40 // create a random private key to sign updates with and derive the address 41 pkFile, err := ioutil.TempFile("", "swarm-feed-smoke-test") 42 if err != nil { 43 return err 44 } 45 defer pkFile.Close() 46 defer os.Remove(pkFile.Name()) 47 48 privkeyHex := "0000000000000000000000000000000000000000000000000000000000001976" 49 privKey, err := crypto.HexToECDSA(privkeyHex) 50 if err != nil { 51 return err 52 } 53 user := crypto.PubkeyToAddress(privKey.PublicKey) 54 userHex := hexutil.Encode(user.Bytes()) 55 56 // save the private key to a file 57 _, err = io.WriteString(pkFile, privkeyHex) 58 if err != nil { 59 return err 60 } 61 62 // keep hex strings for topic and subtopic 63 var topicHex string 64 var subTopicHex string 65 66 // and create combination hex topics for bzz-feed retrieval 67 // xor'ed with topic (zero-value topic if no topic) 68 var subTopicOnlyHex string 69 var mergedSubTopicHex string 70 71 // generate random topic and subtopic and put a hex on them 72 topicBytes, err := generateRandomData(feed.TopicLength) 73 topicHex = hexutil.Encode(topicBytes) 74 subTopicBytes, err := generateRandomData(8) 75 subTopicHex = hexutil.Encode(subTopicBytes) 76 if err != nil { 77 return err 78 } 79 mergedSubTopic, err := feed.NewTopic(subTopicHex, topicBytes) 80 if err != nil { 81 return err 82 } 83 mergedSubTopicHex = hexutil.Encode(mergedSubTopic[:]) 84 subTopicOnlyBytes, err := feed.NewTopic(subTopicHex, nil) 85 if err != nil { 86 return err 87 } 88 subTopicOnlyHex = hexutil.Encode(subTopicOnlyBytes[:]) 89 90 // create feed manifest, topic only 91 var out bytes.Buffer 92 cmd := exec.Command("swarm", "--bzzapi", endpoints[0], "feed", "create", "--topic", topicHex, "--user", userHex) 93 cmd.Stdout = &out 94 log.Debug("create feed manifest topic cmd", "cmd", cmd) 95 err = cmd.Run() 96 if err != nil { 97 return err 98 } 99 manifestWithTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) 100 if len(manifestWithTopic) != 64 { 101 return fmt.Errorf("unknown feed create manifest hash format (topic): (%d) %s", len(out.String()), manifestWithTopic) 102 } 103 log.Debug("create topic feed", "manifest", manifestWithTopic) 104 out.Reset() 105 106 // create feed manifest, subtopic only 107 cmd = exec.Command("swarm", "--bzzapi", endpoints[0], "feed", "create", "--name", subTopicHex, "--user", userHex) 108 cmd.Stdout = &out 109 log.Debug("create feed manifest subtopic cmd", "cmd", cmd) 110 err = cmd.Run() 111 if err != nil { 112 return err 113 } 114 manifestWithSubTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) 115 if len(manifestWithSubTopic) != 64 { 116 return fmt.Errorf("unknown feed create manifest hash format (subtopic): (%d) %s", len(out.String()), manifestWithSubTopic) 117 } 118 log.Debug("create subtopic feed", "manifest", manifestWithTopic) 119 out.Reset() 120 121 // create feed manifest, merged topic 122 cmd = exec.Command("swarm", "--bzzapi", endpoints[0], "feed", "create", "--topic", topicHex, "--name", subTopicHex, "--user", userHex) 123 cmd.Stdout = &out 124 log.Debug("create feed manifest mergetopic cmd", "cmd", cmd) 125 err = cmd.Run() 126 if err != nil { 127 log.Error(err.Error()) 128 return err 129 } 130 manifestWithMergedTopic := strings.TrimRight(out.String(), string([]byte{0x0a})) 131 if len(manifestWithMergedTopic) != 64 { 132 return fmt.Errorf("unknown feed create manifest hash format (mergedtopic): (%d) %s", len(out.String()), manifestWithMergedTopic) 133 } 134 log.Debug("create mergedtopic feed", "manifest", manifestWithMergedTopic) 135 out.Reset() 136 137 // create test data 138 data, err := generateRandomData(feedRandomDataLength) 139 if err != nil { 140 return err 141 } 142 h := md5.New() 143 h.Write(data) 144 dataHash := h.Sum(nil) 145 dataHex := hexutil.Encode(data) 146 147 // update with topic 148 cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, dataHex) 149 cmd.Stdout = &out 150 log.Debug("update feed manifest topic cmd", "cmd", cmd) 151 err = cmd.Run() 152 if err != nil { 153 return err 154 } 155 log.Debug("feed update topic", "out", out) 156 out.Reset() 157 158 // update with subtopic 159 cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--name", subTopicHex, dataHex) 160 cmd.Stdout = &out 161 log.Debug("update feed manifest subtopic cmd", "cmd", cmd) 162 err = cmd.Run() 163 if err != nil { 164 return err 165 } 166 log.Debug("feed update subtopic", "out", out) 167 out.Reset() 168 169 // update with merged topic 170 cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, "--name", subTopicHex, dataHex) 171 cmd.Stdout = &out 172 log.Debug("update feed manifest merged topic cmd", "cmd", cmd) 173 err = cmd.Run() 174 if err != nil { 175 return err 176 } 177 log.Debug("feed update mergedtopic", "out", out) 178 out.Reset() 179 180 time.Sleep(3 * time.Second) 181 182 // retrieve the data 183 wg := sync.WaitGroup{} 184 for _, endpoint := range endpoints { 185 // raw retrieve, topic only 186 for _, hex := range []string{topicHex, subTopicOnlyHex, mergedSubTopicHex} { 187 wg.Add(1) 188 ruid := uuid.New()[:8] 189 go func(hex string, endpoint string, ruid string) { 190 for { 191 err := fetchFeed(hex, userHex, endpoint, dataHash, ruid) 192 if err != nil { 193 continue 194 } 195 196 wg.Done() 197 return 198 } 199 }(hex, endpoint, ruid) 200 201 } 202 } 203 wg.Wait() 204 log.Info("all endpoints synced random data successfully") 205 206 // upload test file 207 log.Info("uploading to " + endpoints[0] + " and syncing") 208 209 f, cleanup := generateRandomFile(filesize * 1000) 210 defer cleanup() 211 212 hash, err := upload(f, endpoints[0]) 213 if err != nil { 214 return err 215 } 216 hashBytes, err := hexutil.Decode("0x" + hash) 217 if err != nil { 218 return err 219 } 220 multihashHex := hexutil.Encode(hashBytes) 221 fileHash, err := digest(f) 222 if err != nil { 223 return err 224 } 225 226 log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fileHash)) 227 228 // update file with topic 229 cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, multihashHex) 230 cmd.Stdout = &out 231 err = cmd.Run() 232 if err != nil { 233 return err 234 } 235 log.Debug("feed update topic", "out", out) 236 out.Reset() 237 238 // update file with subtopic 239 cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--name", subTopicHex, multihashHex) 240 cmd.Stdout = &out 241 err = cmd.Run() 242 if err != nil { 243 return err 244 } 245 log.Debug("feed update subtopic", "out", out) 246 out.Reset() 247 248 // update file with merged topic 249 cmd = exec.Command("swarm", "--bzzaccount", pkFile.Name(), "--bzzapi", endpoints[0], "feed", "update", "--topic", topicHex, "--name", subTopicHex, multihashHex) 250 cmd.Stdout = &out 251 err = cmd.Run() 252 if err != nil { 253 return err 254 } 255 log.Debug("feed update mergedtopic", "out", out) 256 out.Reset() 257 258 time.Sleep(3 * time.Second) 259 260 for _, endpoint := range endpoints { 261 262 // manifest retrieve, topic only 263 for _, url := range []string{manifestWithTopic, manifestWithSubTopic, manifestWithMergedTopic} { 264 wg.Add(1) 265 ruid := uuid.New()[:8] 266 go func(url string, endpoint string, ruid string) { 267 for { 268 err := fetch(url, endpoint, fileHash, ruid) 269 if err != nil { 270 continue 271 } 272 273 wg.Done() 274 return 275 } 276 }(url, endpoint, ruid) 277 } 278 279 } 280 wg.Wait() 281 log.Info("all endpoints synced random file successfully") 282 283 return nil 284 } 285 286 func fetchFeed(topic string, user string, endpoint string, original []byte, ruid string) error { 287 log.Trace("sleeping", "ruid", ruid) 288 time.Sleep(3 * time.Second) 289 290 log.Trace("http get request (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user) 291 res, err := http.Get(endpoint + "/bzz-feed:/?topic=" + topic + "&user=" + user) 292 if err != nil { 293 return err 294 } 295 log.Trace("http get response (feed)", "ruid", ruid, "api", endpoint, "topic", topic, "user", user, "code", res.StatusCode, "len", res.ContentLength) 296 297 if res.StatusCode != 200 { 298 return fmt.Errorf("expected status code %d, got %v (ruid %v)", 200, res.StatusCode, ruid) 299 } 300 301 defer res.Body.Close() 302 303 rdigest, err := digest(res.Body) 304 if err != nil { 305 log.Warn(err.Error(), "ruid", ruid) 306 return err 307 } 308 309 if !bytes.Equal(rdigest, original) { 310 err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) 311 log.Warn(err.Error(), "ruid", ruid) 312 return err 313 } 314 315 log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) 316 317 return nil 318 }