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