github.com/xxRanger/go-ethereum@v1.8.23/swarm/storage/feed/handler_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 feed
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"flag"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"github.com/ethereum/go-ethereum/swarm/chunk"
    32  	"github.com/ethereum/go-ethereum/swarm/storage"
    33  	"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
    34  )
    35  
    36  var (
    37  	loglevel  = flag.Int("loglevel", 3, "loglevel")
    38  	startTime = Timestamp{
    39  		Time: uint64(4200),
    40  	}
    41  	cleanF       func()
    42  	subtopicName = "føø.bar"
    43  )
    44  
    45  func init() {
    46  	flag.Parse()
    47  	log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))))
    48  }
    49  
    50  // simulated timeProvider
    51  type fakeTimeProvider struct {
    52  	currentTime uint64
    53  }
    54  
    55  func (f *fakeTimeProvider) Tick() {
    56  	f.currentTime++
    57  }
    58  
    59  func (f *fakeTimeProvider) Set(time uint64) {
    60  	f.currentTime = time
    61  }
    62  
    63  func (f *fakeTimeProvider) FastForward(offset uint64) {
    64  	f.currentTime += offset
    65  }
    66  
    67  func (f *fakeTimeProvider) Now() Timestamp {
    68  	return Timestamp{
    69  		Time: f.currentTime,
    70  	}
    71  }
    72  
    73  // make updates and retrieve them based on periods and versions
    74  func TestFeedsHandler(t *testing.T) {
    75  
    76  	// make fake timeProvider
    77  	clock := &fakeTimeProvider{
    78  		currentTime: startTime.Time, // clock starts at t=4200
    79  	}
    80  
    81  	// signer containing private key
    82  	signer := newAliceSigner()
    83  
    84  	feedsHandler, datadir, teardownTest, err := setupTest(clock, signer)
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	defer teardownTest()
    89  
    90  	// create a new feed
    91  	ctx, cancel := context.WithCancel(context.Background())
    92  	defer cancel()
    93  
    94  	topic, _ := NewTopic("Mess with Swarm feeds code and see what ghost catches you", nil)
    95  	fd := Feed{
    96  		Topic: topic,
    97  		User:  signer.Address(),
    98  	}
    99  
   100  	// data for updates:
   101  	updates := []string{
   102  		"blinky", // t=4200
   103  		"pinky",  // t=4242
   104  		"inky",   // t=4284
   105  		"clyde",  // t=4285
   106  	}
   107  
   108  	request := NewFirstRequest(fd.Topic) // this timestamps the update at t = 4200 (start time)
   109  	chunkAddress := make(map[string]storage.Address)
   110  	data := []byte(updates[0])
   111  	request.SetData(data)
   112  	if err := request.Sign(signer); err != nil {
   113  		t.Fatal(err)
   114  	}
   115  	chunkAddress[updates[0]], err = feedsHandler.Update(ctx, request)
   116  	if err != nil {
   117  		t.Fatal(err)
   118  	}
   119  
   120  	// move the clock ahead 21 seconds
   121  	clock.FastForward(21) // t=4221
   122  
   123  	request, err = feedsHandler.NewRequest(ctx, &request.Feed) // this timestamps the update at t = 4221
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  	if request.Epoch.Base() != 0 || request.Epoch.Level != lookup.HighestLevel-1 {
   128  		t.Fatalf("Suggested epoch BaseTime should be 0 and Epoch level should be %d", lookup.HighestLevel-1)
   129  	}
   130  
   131  	request.Epoch.Level = lookup.HighestLevel // force level 25 instead of 24 to make it fail
   132  	data = []byte(updates[1])
   133  	request.SetData(data)
   134  	if err := request.Sign(signer); err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request)
   138  	if err == nil {
   139  		t.Fatal("Expected update to fail since an update in this epoch already exists")
   140  	}
   141  
   142  	// move the clock ahead 21 seconds
   143  	clock.FastForward(21) // t=4242
   144  	request, err = feedsHandler.NewRequest(ctx, &request.Feed)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  	request.SetData(data)
   149  	if err := request.Sign(signer); err != nil {
   150  		t.Fatal(err)
   151  	}
   152  	chunkAddress[updates[1]], err = feedsHandler.Update(ctx, request)
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	}
   156  
   157  	// move the clock ahead 42 seconds
   158  	clock.FastForward(42) // t=4284
   159  	request, err = feedsHandler.NewRequest(ctx, &request.Feed)
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  	data = []byte(updates[2])
   164  	request.SetData(data)
   165  	if err := request.Sign(signer); err != nil {
   166  		t.Fatal(err)
   167  	}
   168  	chunkAddress[updates[2]], err = feedsHandler.Update(ctx, request)
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  
   173  	// move the clock ahead 1 second
   174  	clock.FastForward(1) // t=4285
   175  	request, err = feedsHandler.NewRequest(ctx, &request.Feed)
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  	if request.Epoch.Base() != 0 || request.Epoch.Level != 22 {
   180  		t.Fatalf("Expected epoch base time to be %d, got %d. Expected epoch level to be %d, got %d", 0, request.Epoch.Base(), 22, request.Epoch.Level)
   181  	}
   182  	data = []byte(updates[3])
   183  	request.SetData(data)
   184  
   185  	if err := request.Sign(signer); err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	chunkAddress[updates[3]], err = feedsHandler.Update(ctx, request)
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  
   193  	time.Sleep(time.Second)
   194  	feedsHandler.Close()
   195  
   196  	// check we can retrieve the updates after close
   197  	clock.FastForward(2000) // t=6285
   198  
   199  	feedParams := &HandlerParams{}
   200  
   201  	feedsHandler2, err := NewTestHandler(datadir, feedParams)
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  
   206  	update2, err := feedsHandler2.Lookup(ctx, NewQueryLatest(&request.Feed, lookup.NoClue))
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	// last update should be "clyde"
   212  	if !bytes.Equal(update2.data, []byte(updates[len(updates)-1])) {
   213  		t.Fatalf("feed update data was %v, expected %v", string(update2.data), updates[len(updates)-1])
   214  	}
   215  	if update2.Level != 22 {
   216  		t.Fatalf("feed update epoch level was %d, expected 22", update2.Level)
   217  	}
   218  	if update2.Base() != 0 {
   219  		t.Fatalf("feed update epoch base time was %d, expected 0", update2.Base())
   220  	}
   221  	log.Debug("Latest lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data)
   222  
   223  	// specific point in time
   224  	update, err := feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, 4284, lookup.NoClue))
   225  	if err != nil {
   226  		t.Fatal(err)
   227  	}
   228  	// check data
   229  	if !bytes.Equal(update.data, []byte(updates[2])) {
   230  		t.Fatalf("feed update data (historical) was %v, expected %v", string(update2.data), updates[2])
   231  	}
   232  	log.Debug("Historical lookup", "epoch base time", update2.Base(), "epoch level", update2.Level, "data", update2.data)
   233  
   234  	// beyond the first should yield an error
   235  	update, err = feedsHandler2.Lookup(ctx, NewQuery(&request.Feed, startTime.Time-1, lookup.NoClue))
   236  	if err == nil {
   237  		t.Fatalf("expected previous to fail, returned epoch %s data %v", update.Epoch.String(), update.data)
   238  	}
   239  
   240  }
   241  
   242  const Day = 60 * 60 * 24
   243  const Year = Day * 365
   244  const Month = Day * 30
   245  
   246  func generateData(x uint64) []byte {
   247  	return []byte(fmt.Sprintf("%d", x))
   248  }
   249  
   250  func TestSparseUpdates(t *testing.T) {
   251  
   252  	// make fake timeProvider
   253  	timeProvider := &fakeTimeProvider{
   254  		currentTime: startTime.Time,
   255  	}
   256  
   257  	// signer containing private key
   258  	signer := newAliceSigner()
   259  
   260  	rh, datadir, teardownTest, err := setupTest(timeProvider, signer)
   261  	if err != nil {
   262  		t.Fatal(err)
   263  	}
   264  	defer teardownTest()
   265  	defer os.RemoveAll(datadir)
   266  
   267  	// create a new feed
   268  	ctx, cancel := context.WithCancel(context.Background())
   269  	defer cancel()
   270  	topic, _ := NewTopic("Very slow updates", nil)
   271  	fd := Feed{
   272  		Topic: topic,
   273  		User:  signer.Address(),
   274  	}
   275  
   276  	// publish one update every 5 years since Unix 0 until today
   277  	today := uint64(1533799046)
   278  	var epoch lookup.Epoch
   279  	var lastUpdateTime uint64
   280  	for T := uint64(0); T < today; T += 5 * Year {
   281  		request := NewFirstRequest(fd.Topic)
   282  		request.Epoch = lookup.GetNextEpoch(epoch, T)
   283  		request.data = generateData(T) // this generates some data that depends on T, so we can check later
   284  		request.Sign(signer)
   285  		if err != nil {
   286  			t.Fatal(err)
   287  		}
   288  
   289  		if _, err := rh.Update(ctx, request); err != nil {
   290  			t.Fatal(err)
   291  		}
   292  		epoch = request.Epoch
   293  		lastUpdateTime = T
   294  	}
   295  
   296  	query := NewQuery(&fd, today, lookup.NoClue)
   297  
   298  	_, err = rh.Lookup(ctx, query)
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  
   303  	_, content, err := rh.GetContent(&fd)
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  
   308  	if !bytes.Equal(generateData(lastUpdateTime), content) {
   309  		t.Fatalf("Expected to recover last written value %d, got %s", lastUpdateTime, string(content))
   310  	}
   311  
   312  	// lookup the closest update to 35*Year + 6* Month (~ June 2005):
   313  	// it should find the update we put on 35*Year, since we were updating every 5 years.
   314  
   315  	query.TimeLimit = 35*Year + 6*Month
   316  
   317  	_, err = rh.Lookup(ctx, query)
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  
   322  	_, content, err = rh.GetContent(&fd)
   323  	if err != nil {
   324  		t.Fatal(err)
   325  	}
   326  
   327  	if !bytes.Equal(generateData(35*Year), content) {
   328  		t.Fatalf("Expected to recover %d, got %s", 35*Year, string(content))
   329  	}
   330  }
   331  
   332  func TestValidator(t *testing.T) {
   333  
   334  	// make fake timeProvider
   335  	timeProvider := &fakeTimeProvider{
   336  		currentTime: startTime.Time,
   337  	}
   338  
   339  	// signer containing private key. Alice will be the good girl
   340  	signer := newAliceSigner()
   341  
   342  	// set up  sim timeProvider
   343  	rh, _, teardownTest, err := setupTest(timeProvider, signer)
   344  	if err != nil {
   345  		t.Fatal(err)
   346  	}
   347  	defer teardownTest()
   348  
   349  	// create new feed
   350  	topic, _ := NewTopic(subtopicName, nil)
   351  	fd := Feed{
   352  		Topic: topic,
   353  		User:  signer.Address(),
   354  	}
   355  	mr := NewFirstRequest(fd.Topic)
   356  
   357  	// chunk with address
   358  	data := []byte("foo")
   359  	mr.SetData(data)
   360  	if err := mr.Sign(signer); err != nil {
   361  		t.Fatalf("sign fail: %v", err)
   362  	}
   363  
   364  	chunk, err := mr.toChunk()
   365  	if err != nil {
   366  		t.Fatal(err)
   367  	}
   368  	if !rh.Validate(chunk) {
   369  		t.Fatal("Chunk validator fail on update chunk")
   370  	}
   371  
   372  	address := chunk.Address()
   373  	// mess with the address
   374  	address[0] = 11
   375  	address[15] = 99
   376  
   377  	if rh.Validate(storage.NewChunk(address, chunk.Data())) {
   378  		t.Fatal("Expected Validate to fail with false chunk address")
   379  	}
   380  }
   381  
   382  // tests that the content address validator correctly checks the data
   383  // tests that feed update chunks are passed through content address validator
   384  // there is some redundancy in this test as it also tests content addressed chunks,
   385  // which should be evaluated as invalid chunks by this validator
   386  func TestValidatorInStore(t *testing.T) {
   387  
   388  	// make fake timeProvider
   389  	TimestampProvider = &fakeTimeProvider{
   390  		currentTime: startTime.Time,
   391  	}
   392  
   393  	// signer containing private key
   394  	signer := newAliceSigner()
   395  
   396  	// set up localstore
   397  	datadir, err := ioutil.TempDir("", "storage-testfeedsvalidator")
   398  	if err != nil {
   399  		t.Fatal(err)
   400  	}
   401  	defer os.RemoveAll(datadir)
   402  
   403  	handlerParams := storage.NewDefaultLocalStoreParams()
   404  	handlerParams.Init(datadir)
   405  	store, err := storage.NewLocalStore(handlerParams, nil)
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	// set up Swarm feeds handler and add is as a validator to the localstore
   411  	fhParams := &HandlerParams{}
   412  	fh := NewHandler(fhParams)
   413  	store.Validators = append(store.Validators, fh)
   414  
   415  	// create content addressed chunks, one good, one faulty
   416  	chunks := storage.GenerateRandomChunks(chunk.DefaultSize, 2)
   417  	goodChunk := chunks[0]
   418  	badChunk := storage.NewChunk(chunks[1].Address(), goodChunk.Data())
   419  
   420  	topic, _ := NewTopic("xyzzy", nil)
   421  	fd := Feed{
   422  		Topic: topic,
   423  		User:  signer.Address(),
   424  	}
   425  
   426  	// create a feed update chunk with correct publickey
   427  	id := ID{
   428  		Epoch: lookup.Epoch{Time: 42,
   429  			Level: 1,
   430  		},
   431  		Feed: fd,
   432  	}
   433  
   434  	updateAddr := id.Addr()
   435  	data := []byte("bar")
   436  
   437  	r := new(Request)
   438  	r.idAddr = updateAddr
   439  	r.Update.ID = id
   440  	r.data = data
   441  
   442  	r.Sign(signer)
   443  
   444  	uglyChunk, err := r.toChunk()
   445  	if err != nil {
   446  		t.Fatal(err)
   447  	}
   448  
   449  	// put the chunks in the store and check their error status
   450  	err = store.Put(context.Background(), goodChunk)
   451  	if err == nil {
   452  		t.Fatal("expected error on good content address chunk with feed update validator only, but got nil")
   453  	}
   454  	err = store.Put(context.Background(), badChunk)
   455  	if err == nil {
   456  		t.Fatal("expected error on bad content address chunk with feed update validator only, but got nil")
   457  	}
   458  	err = store.Put(context.Background(), uglyChunk)
   459  	if err != nil {
   460  		t.Fatalf("expected no error on feed update chunk with feed update validator only, but got: %s", err)
   461  	}
   462  }
   463  
   464  // create rpc and feeds Handler
   465  func setupTest(timeProvider timestampProvider, signer Signer) (fh *TestHandler, datadir string, teardown func(), err error) {
   466  
   467  	var fsClean func()
   468  	var rpcClean func()
   469  	cleanF = func() {
   470  		if fsClean != nil {
   471  			fsClean()
   472  		}
   473  		if rpcClean != nil {
   474  			rpcClean()
   475  		}
   476  	}
   477  
   478  	// temp datadir
   479  	datadir, err = ioutil.TempDir("", "fh")
   480  	if err != nil {
   481  		return nil, "", nil, err
   482  	}
   483  	fsClean = func() {
   484  		os.RemoveAll(datadir)
   485  	}
   486  
   487  	TimestampProvider = timeProvider
   488  	fhParams := &HandlerParams{}
   489  	fh, err = NewTestHandler(datadir, fhParams)
   490  	return fh, datadir, cleanF, err
   491  }
   492  
   493  func newAliceSigner() *GenericSigner {
   494  	privKey, _ := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
   495  	return NewGenericSigner(privKey)
   496  }
   497  
   498  func newBobSigner() *GenericSigner {
   499  	privKey, _ := crypto.HexToECDSA("accedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedecaca")
   500  	return NewGenericSigner(privKey)
   501  }
   502  
   503  func newCharlieSigner() *GenericSigner {
   504  	privKey, _ := crypto.HexToECDSA("facadefacadefacadefacadefacadefacadefacadefacadefacadefacadefaca")
   505  	return NewGenericSigner(privKey)
   506  }