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  }