github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/storage/mru/resource_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 mru 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/rand" 23 "encoding/binary" 24 "flag" 25 "io/ioutil" 26 "os" 27 "testing" 28 "time" 29 30 "github.com/FusionFoundation/efsn/contracts/ens" 31 "github.com/FusionFoundation/efsn/crypto" 32 "github.com/FusionFoundation/efsn/log" 33 "github.com/FusionFoundation/efsn/swarm/chunk" 34 "github.com/FusionFoundation/efsn/swarm/multihash" 35 "github.com/FusionFoundation/efsn/swarm/storage" 36 ) 37 38 var ( 39 loglevel = flag.Int("loglevel", 3, "loglevel") 40 testHasher = storage.MakeHashFunc(resourceHashAlgorithm)() 41 startTime = Timestamp{ 42 Time: uint64(4200), 43 } 44 resourceFrequency = uint64(42) 45 cleanF func() 46 resourceName = "føø.bar" 47 hashfunc = storage.MakeHashFunc(storage.DefaultHash) 48 ) 49 50 func init() { 51 flag.Parse() 52 log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))) 53 } 54 55 // simulated timeProvider 56 type fakeTimeProvider struct { 57 currentTime uint64 58 } 59 60 func (f *fakeTimeProvider) Tick() { 61 f.currentTime++ 62 } 63 64 func (f *fakeTimeProvider) Now() Timestamp { 65 return Timestamp{ 66 Time: f.currentTime, 67 } 68 } 69 70 func TestUpdateChunkSerializationErrorChecking(t *testing.T) { 71 72 // Test that parseUpdate fails if the chunk is too small 73 var r SignedResourceUpdate 74 if err := r.fromChunk(storage.ZeroAddr, make([]byte, minimumUpdateDataLength-1)); err == nil { 75 t.Fatalf("Expected parseUpdate to fail when chunkData contains less than %d bytes", minimumUpdateDataLength) 76 } 77 78 r = SignedResourceUpdate{} 79 // Test that parseUpdate fails when the length header does not match the data array length 80 fakeChunk := make([]byte, 150) 81 binary.LittleEndian.PutUint16(fakeChunk, 44) 82 if err := r.fromChunk(storage.ZeroAddr, fakeChunk); err == nil { 83 t.Fatal("Expected parseUpdate to fail when the header length does not match the actual data array passed in") 84 } 85 86 r = SignedResourceUpdate{ 87 resourceUpdate: resourceUpdate{ 88 updateHeader: updateHeader{ 89 UpdateLookup: UpdateLookup{ 90 rootAddr: make([]byte, 79), // put the wrong length, should be storage.AddressLength 91 }, 92 metaHash: nil, 93 multihash: false, 94 }, 95 }, 96 } 97 _, err := r.toChunk() 98 if err == nil { 99 t.Fatal("Expected newUpdateChunk to fail when rootAddr or metaHash have the wrong length") 100 } 101 r.rootAddr = make([]byte, storage.AddressLength) 102 r.metaHash = make([]byte, storage.AddressLength) 103 _, err = r.toChunk() 104 if err == nil { 105 t.Fatal("Expected newUpdateChunk to fail when there is no data") 106 } 107 r.data = make([]byte, 79) // put some arbitrary length data 108 _, err = r.toChunk() 109 if err == nil { 110 t.Fatal("expected newUpdateChunk to fail when there is no signature", err) 111 } 112 113 alice := newAliceSigner() 114 if err := r.Sign(alice); err != nil { 115 t.Fatalf("error signing:%s", err) 116 117 } 118 _, err = r.toChunk() 119 if err != nil { 120 t.Fatalf("error creating update chunk:%s", err) 121 } 122 123 r.multihash = true 124 r.data[1] = 79 // mess with the multihash, corrupting one byte of it. 125 if err := r.Sign(alice); err == nil { 126 t.Fatal("expected Sign() to fail when an invalid multihash is in data and multihash=true", err) 127 } 128 } 129 130 // check that signature address matches update signer address 131 func TestReverse(t *testing.T) { 132 133 period := uint32(4) 134 version := uint32(2) 135 136 // make fake timeProvider 137 timeProvider := &fakeTimeProvider{ 138 currentTime: startTime.Time, 139 } 140 141 // signer containing private key 142 signer := newAliceSigner() 143 144 // set up rpc and create resourcehandler 145 _, _, teardownTest, err := setupTest(timeProvider, signer) 146 if err != nil { 147 t.Fatal(err) 148 } 149 defer teardownTest() 150 151 metadata := ResourceMetadata{ 152 Name: resourceName, 153 StartTime: startTime, 154 Frequency: resourceFrequency, 155 Owner: signer.Address(), 156 } 157 158 rootAddr, metaHash, _, err := metadata.serializeAndHash() 159 if err != nil { 160 t.Fatal(err) 161 } 162 163 // generate some bogus data for the chunk and sign it 164 data := make([]byte, 8) 165 _, err = rand.Read(data) 166 if err != nil { 167 t.Fatal(err) 168 } 169 testHasher.Reset() 170 testHasher.Write(data) 171 172 update := &SignedResourceUpdate{ 173 resourceUpdate: resourceUpdate{ 174 updateHeader: updateHeader{ 175 UpdateLookup: UpdateLookup{ 176 period: period, 177 version: version, 178 rootAddr: rootAddr, 179 }, 180 metaHash: metaHash, 181 }, 182 data: data, 183 }, 184 } 185 // generate a hash for t=4200 version 1 186 key := update.UpdateAddr() 187 188 if err = update.Sign(signer); err != nil { 189 t.Fatal(err) 190 } 191 192 chunk, err := update.toChunk() 193 if err != nil { 194 t.Fatal(err) 195 } 196 197 // check that we can recover the owner account from the update chunk's signature 198 var checkUpdate SignedResourceUpdate 199 if err := checkUpdate.fromChunk(chunk.Address(), chunk.Data()); err != nil { 200 t.Fatal(err) 201 } 202 checkdigest, err := checkUpdate.GetDigest() 203 if err != nil { 204 t.Fatal(err) 205 } 206 recoveredaddress, err := getOwner(checkdigest, *checkUpdate.signature) 207 if err != nil { 208 t.Fatalf("Retrieve address from signature fail: %v", err) 209 } 210 originaladdress := crypto.PubkeyToAddress(signer.PrivKey.PublicKey) 211 212 // check that the metadata retrieved from the chunk matches what we gave it 213 if recoveredaddress != originaladdress { 214 t.Fatalf("addresses dont match: %x != %x", originaladdress, recoveredaddress) 215 } 216 217 if !bytes.Equal(key[:], chunk.Address()[:]) { 218 t.Fatalf("Expected chunk key '%x', was '%x'", key, chunk.Address()) 219 } 220 if period != checkUpdate.period { 221 t.Fatalf("Expected period '%d', was '%d'", period, checkUpdate.period) 222 } 223 if version != checkUpdate.version { 224 t.Fatalf("Expected version '%d', was '%d'", version, checkUpdate.version) 225 } 226 if !bytes.Equal(data, checkUpdate.data) { 227 t.Fatalf("Expectedn data '%x', was '%x'", data, checkUpdate.data) 228 } 229 } 230 231 // make updates and retrieve them based on periods and versions 232 func TestResourceHandler(t *testing.T) { 233 234 // make fake timeProvider 235 timeProvider := &fakeTimeProvider{ 236 currentTime: startTime.Time, 237 } 238 239 // signer containing private key 240 signer := newAliceSigner() 241 242 rh, datadir, teardownTest, err := setupTest(timeProvider, signer) 243 if err != nil { 244 t.Fatal(err) 245 } 246 defer teardownTest() 247 248 // create a new resource 249 ctx, cancel := context.WithCancel(context.Background()) 250 defer cancel() 251 252 metadata := &ResourceMetadata{ 253 Name: resourceName, 254 Frequency: resourceFrequency, 255 StartTime: Timestamp{Time: timeProvider.Now().Time}, 256 Owner: signer.Address(), 257 } 258 259 request, err := NewCreateUpdateRequest(metadata) 260 if err != nil { 261 t.Fatal(err) 262 } 263 request.Sign(signer) 264 if err != nil { 265 t.Fatal(err) 266 } 267 err = rh.New(ctx, request) 268 if err != nil { 269 t.Fatal(err) 270 } 271 272 chunk, err := rh.chunkStore.Get(ctx, storage.Address(request.rootAddr)) 273 if err != nil { 274 t.Fatal(err) 275 } else if len(chunk.Data()) < 16 { 276 t.Fatalf("chunk data must be minimum 16 bytes, is %d", len(chunk.Data())) 277 } 278 279 var recoveredMetadata ResourceMetadata 280 281 recoveredMetadata.binaryGet(chunk.Data()) 282 if err != nil { 283 t.Fatal(err) 284 } 285 if recoveredMetadata.StartTime.Time != timeProvider.currentTime { 286 t.Fatalf("stored startTime %d does not match provided startTime %d", recoveredMetadata.StartTime.Time, timeProvider.currentTime) 287 } 288 if recoveredMetadata.Frequency != resourceFrequency { 289 t.Fatalf("stored frequency %d does not match provided frequency %d", recoveredMetadata.Frequency, resourceFrequency) 290 } 291 292 // data for updates: 293 updates := []string{ 294 "blinky", 295 "pinky", 296 "inky", 297 "clyde", 298 } 299 300 // update halfway to first period. period=1, version=1 301 resourcekey := make(map[string]storage.Address) 302 fwdClock(int(resourceFrequency/2), timeProvider) 303 data := []byte(updates[0]) 304 request.SetData(data, false) 305 if err := request.Sign(signer); err != nil { 306 t.Fatal(err) 307 } 308 resourcekey[updates[0]], err = rh.Update(ctx, &request.SignedResourceUpdate) 309 if err != nil { 310 t.Fatal(err) 311 } 312 313 // update on first period with version = 1 to make it fail since there is already one update with version=1 314 request, err = rh.NewUpdateRequest(ctx, request.rootAddr) 315 if err != nil { 316 t.Fatal(err) 317 } 318 if request.version != 2 || request.period != 1 { 319 t.Fatal("Suggested period should be 1 and version should be 2") 320 } 321 322 request.version = 1 // force version 1 instead of 2 to make it fail 323 data = []byte(updates[1]) 324 request.SetData(data, false) 325 if err := request.Sign(signer); err != nil { 326 t.Fatal(err) 327 } 328 resourcekey[updates[1]], err = rh.Update(ctx, &request.SignedResourceUpdate) 329 if err == nil { 330 t.Fatal("Expected update to fail since this version already exists") 331 } 332 333 // update on second period with version = 1, correct. period=2, version=1 334 fwdClock(int(resourceFrequency/2), timeProvider) 335 request, err = rh.NewUpdateRequest(ctx, request.rootAddr) 336 if err != nil { 337 t.Fatal(err) 338 } 339 request.SetData(data, false) 340 if err := request.Sign(signer); err != nil { 341 t.Fatal(err) 342 } 343 resourcekey[updates[1]], err = rh.Update(ctx, &request.SignedResourceUpdate) 344 if err != nil { 345 t.Fatal(err) 346 } 347 348 fwdClock(int(resourceFrequency), timeProvider) 349 // Update on third period, with version = 1 350 request, err = rh.NewUpdateRequest(ctx, request.rootAddr) 351 if err != nil { 352 t.Fatal(err) 353 } 354 data = []byte(updates[2]) 355 request.SetData(data, false) 356 if err := request.Sign(signer); err != nil { 357 t.Fatal(err) 358 } 359 resourcekey[updates[2]], err = rh.Update(ctx, &request.SignedResourceUpdate) 360 if err != nil { 361 t.Fatal(err) 362 } 363 364 // update just after third period 365 fwdClock(1, timeProvider) 366 request, err = rh.NewUpdateRequest(ctx, request.rootAddr) 367 if err != nil { 368 t.Fatal(err) 369 } 370 if request.period != 3 || request.version != 2 { 371 t.Fatal("Suggested period should be 3 and version should be 2") 372 } 373 data = []byte(updates[3]) 374 request.SetData(data, false) 375 376 if err := request.Sign(signer); err != nil { 377 t.Fatal(err) 378 } 379 resourcekey[updates[3]], err = rh.Update(ctx, &request.SignedResourceUpdate) 380 if err != nil { 381 t.Fatal(err) 382 } 383 384 time.Sleep(time.Second) 385 rh.Close() 386 387 // check we can retrieve the updates after close 388 // it will match on second iteration startTime + (resourceFrequency * 3) 389 fwdClock(int(resourceFrequency*2)-1, timeProvider) 390 391 rhparams := &HandlerParams{} 392 393 rh2, err := NewTestHandler(datadir, rhparams) 394 if err != nil { 395 t.Fatal(err) 396 } 397 398 rsrc2, err := rh2.Load(context.TODO(), request.rootAddr) 399 if err != nil { 400 t.Fatal(err) 401 } 402 403 _, err = rh2.Lookup(ctx, LookupLatest(request.rootAddr)) 404 if err != nil { 405 t.Fatal(err) 406 } 407 408 // last update should be "clyde", version two, time= startTime + (resourcefrequency * 3) 409 if !bytes.Equal(rsrc2.data, []byte(updates[len(updates)-1])) { 410 t.Fatalf("resource data was %v, expected %v", string(rsrc2.data), updates[len(updates)-1]) 411 } 412 if rsrc2.version != 2 { 413 t.Fatalf("resource version was %d, expected 2", rsrc2.version) 414 } 415 if rsrc2.period != 3 { 416 t.Fatalf("resource period was %d, expected 3", rsrc2.period) 417 } 418 log.Debug("Latest lookup", "period", rsrc2.period, "version", rsrc2.version, "data", rsrc2.data) 419 420 // specific period, latest version 421 rsrc, err := rh2.Lookup(ctx, LookupLatestVersionInPeriod(request.rootAddr, 3)) 422 if err != nil { 423 t.Fatal(err) 424 } 425 // check data 426 if !bytes.Equal(rsrc.data, []byte(updates[len(updates)-1])) { 427 t.Fatalf("resource data (historical) was %v, expected %v", string(rsrc2.data), updates[len(updates)-1]) 428 } 429 log.Debug("Historical lookup", "period", rsrc2.period, "version", rsrc2.version, "data", rsrc2.data) 430 431 // specific period, specific version 432 lookupParams := LookupVersion(request.rootAddr, 3, 1) 433 rsrc, err = rh2.Lookup(ctx, lookupParams) 434 if err != nil { 435 t.Fatal(err) 436 } 437 // check data 438 if !bytes.Equal(rsrc.data, []byte(updates[2])) { 439 t.Fatalf("resource data (historical) was %v, expected %v", string(rsrc2.data), updates[2]) 440 } 441 log.Debug("Specific version lookup", "period", rsrc2.period, "version", rsrc2.version, "data", rsrc2.data) 442 443 // we are now at third update 444 // check backwards stepping to the first 445 for i := 1; i >= 0; i-- { 446 rsrc, err := rh2.LookupPrevious(ctx, lookupParams) 447 if err != nil { 448 t.Fatal(err) 449 } 450 if !bytes.Equal(rsrc.data, []byte(updates[i])) { 451 t.Fatalf("resource data (previous) was %v, expected %v", rsrc.data, updates[i]) 452 453 } 454 } 455 456 // beyond the first should yield an error 457 rsrc, err = rh2.LookupPrevious(ctx, lookupParams) 458 if err == nil { 459 t.Fatalf("expected previous to fail, returned period %d version %d data %v", rsrc.period, rsrc.version, rsrc.data) 460 } 461 462 } 463 464 func TestMultihash(t *testing.T) { 465 466 // make fake timeProvider 467 timeProvider := &fakeTimeProvider{ 468 currentTime: startTime.Time, 469 } 470 471 // signer containing private key 472 signer := newAliceSigner() 473 474 // set up rpc and create resourcehandler 475 rh, datadir, teardownTest, err := setupTest(timeProvider, signer) 476 if err != nil { 477 t.Fatal(err) 478 } 479 defer teardownTest() 480 481 // create a new resource 482 ctx, cancel := context.WithCancel(context.Background()) 483 defer cancel() 484 485 metadata := &ResourceMetadata{ 486 Name: resourceName, 487 Frequency: resourceFrequency, 488 StartTime: Timestamp{Time: timeProvider.Now().Time}, 489 Owner: signer.Address(), 490 } 491 492 mr, err := NewCreateRequest(metadata) 493 if err != nil { 494 t.Fatal(err) 495 } 496 err = rh.New(ctx, mr) 497 if err != nil { 498 t.Fatal(err) 499 } 500 501 // we're naïvely assuming keccak256 for swarm hashes 502 // if it ever changes this test should also change 503 multihashbytes := ens.EnsNode("foo") 504 multihashmulti := multihash.ToMultihash(multihashbytes.Bytes()) 505 if err != nil { 506 t.Fatal(err) 507 } 508 mr.SetData(multihashmulti, true) 509 mr.Sign(signer) 510 if err != nil { 511 t.Fatal(err) 512 } 513 multihashkey, err := rh.Update(ctx, &mr.SignedResourceUpdate) 514 if err != nil { 515 t.Fatal(err) 516 } 517 518 sha1bytes := make([]byte, multihash.MultihashLength) 519 sha1multi := multihash.ToMultihash(sha1bytes) 520 if err != nil { 521 t.Fatal(err) 522 } 523 mr, err = rh.NewUpdateRequest(ctx, mr.rootAddr) 524 if err != nil { 525 t.Fatal(err) 526 } 527 mr.SetData(sha1multi, true) 528 mr.Sign(signer) 529 if err != nil { 530 t.Fatal(err) 531 } 532 sha1key, err := rh.Update(ctx, &mr.SignedResourceUpdate) 533 if err != nil { 534 t.Fatal(err) 535 } 536 537 // invalid multihashes 538 mr, err = rh.NewUpdateRequest(ctx, mr.rootAddr) 539 if err != nil { 540 t.Fatal(err) 541 } 542 mr.SetData(multihashmulti[1:], true) 543 mr.Sign(signer) 544 if err != nil { 545 t.Fatal(err) 546 } 547 _, err = rh.Update(ctx, &mr.SignedResourceUpdate) 548 if err == nil { 549 t.Fatalf("Expected update to fail with first byte skipped") 550 } 551 mr, err = rh.NewUpdateRequest(ctx, mr.rootAddr) 552 if err != nil { 553 t.Fatal(err) 554 } 555 mr.SetData(multihashmulti[:len(multihashmulti)-2], true) 556 mr.Sign(signer) 557 if err != nil { 558 t.Fatal(err) 559 } 560 561 _, err = rh.Update(ctx, &mr.SignedResourceUpdate) 562 if err == nil { 563 t.Fatalf("Expected update to fail with last byte skipped") 564 } 565 566 data, err := getUpdateDirect(rh.Handler, multihashkey) 567 if err != nil { 568 t.Fatal(err) 569 } 570 multihashdecode, err := multihash.FromMultihash(data) 571 if err != nil { 572 t.Fatal(err) 573 } 574 if !bytes.Equal(multihashdecode, multihashbytes.Bytes()) { 575 t.Fatalf("Decoded hash '%x' does not match original hash '%x'", multihashdecode, multihashbytes.Bytes()) 576 } 577 data, err = getUpdateDirect(rh.Handler, sha1key) 578 if err != nil { 579 t.Fatal(err) 580 } 581 shadecode, err := multihash.FromMultihash(data) 582 if err != nil { 583 t.Fatal(err) 584 } 585 if !bytes.Equal(shadecode, sha1bytes) { 586 t.Fatalf("Decoded hash '%x' does not match original hash '%x'", shadecode, sha1bytes) 587 } 588 rh.Close() 589 590 rhparams := &HandlerParams{} 591 // test with signed data 592 rh2, err := NewTestHandler(datadir, rhparams) 593 if err != nil { 594 t.Fatal(err) 595 } 596 mr, err = NewCreateRequest(metadata) 597 if err != nil { 598 t.Fatal(err) 599 } 600 err = rh2.New(ctx, mr) 601 if err != nil { 602 t.Fatal(err) 603 } 604 605 mr.SetData(multihashmulti, true) 606 mr.Sign(signer) 607 608 if err != nil { 609 t.Fatal(err) 610 } 611 multihashsignedkey, err := rh2.Update(ctx, &mr.SignedResourceUpdate) 612 if err != nil { 613 t.Fatal(err) 614 } 615 616 mr, err = rh2.NewUpdateRequest(ctx, mr.rootAddr) 617 if err != nil { 618 t.Fatal(err) 619 } 620 mr.SetData(sha1multi, true) 621 mr.Sign(signer) 622 if err != nil { 623 t.Fatal(err) 624 } 625 626 sha1signedkey, err := rh2.Update(ctx, &mr.SignedResourceUpdate) 627 if err != nil { 628 t.Fatal(err) 629 } 630 631 data, err = getUpdateDirect(rh2.Handler, multihashsignedkey) 632 if err != nil { 633 t.Fatal(err) 634 } 635 multihashdecode, err = multihash.FromMultihash(data) 636 if err != nil { 637 t.Fatal(err) 638 } 639 if !bytes.Equal(multihashdecode, multihashbytes.Bytes()) { 640 t.Fatalf("Decoded hash '%x' does not match original hash '%x'", multihashdecode, multihashbytes.Bytes()) 641 } 642 data, err = getUpdateDirect(rh2.Handler, sha1signedkey) 643 if err != nil { 644 t.Fatal(err) 645 } 646 shadecode, err = multihash.FromMultihash(data) 647 if err != nil { 648 t.Fatal(err) 649 } 650 if !bytes.Equal(shadecode, sha1bytes) { 651 t.Fatalf("Decoded hash '%x' does not match original hash '%x'", shadecode, sha1bytes) 652 } 653 } 654 655 // \TODO verify testing of signature validation and enforcement 656 func TestValidator(t *testing.T) { 657 658 // make fake timeProvider 659 timeProvider := &fakeTimeProvider{ 660 currentTime: startTime.Time, 661 } 662 663 // signer containing private key. Alice will be the good girl 664 signer := newAliceSigner() 665 666 // fake signer for false results. Bob will play the bad guy today. 667 falseSigner := newBobSigner() 668 669 // set up sim timeProvider 670 rh, _, teardownTest, err := setupTest(timeProvider, signer) 671 if err != nil { 672 t.Fatal(err) 673 } 674 defer teardownTest() 675 676 // create new resource 677 ctx, cancel := context.WithCancel(context.Background()) 678 defer cancel() 679 metadata := &ResourceMetadata{ 680 Name: resourceName, 681 Frequency: resourceFrequency, 682 StartTime: Timestamp{Time: timeProvider.Now().Time}, 683 Owner: signer.Address(), 684 } 685 mr, err := NewCreateRequest(metadata) 686 if err != nil { 687 t.Fatal(err) 688 } 689 mr.Sign(signer) 690 691 err = rh.New(ctx, mr) 692 if err != nil { 693 t.Fatalf("Create resource fail: %v", err) 694 } 695 696 // chunk with address 697 data := []byte("foo") 698 mr.SetData(data, false) 699 if err := mr.Sign(signer); err != nil { 700 t.Fatalf("sign fail: %v", err) 701 } 702 chunk, err := mr.SignedResourceUpdate.toChunk() 703 if err != nil { 704 t.Fatal(err) 705 } 706 if !rh.Validate(chunk.Address(), chunk.Data()) { 707 t.Fatal("Chunk validator fail on update chunk") 708 } 709 710 // chunk with address made from different publickey 711 if err := mr.Sign(falseSigner); err == nil { 712 t.Fatalf("Expected Sign to fail since we are using a different OwnerAddr: %v", err) 713 } 714 715 // chunk with address made from different publickey 716 mr.metadata.Owner = zeroAddr // set to zero to bypass .Sign() check 717 if err := mr.Sign(falseSigner); err != nil { 718 t.Fatalf("sign fail: %v", err) 719 } 720 721 chunk, err = mr.SignedResourceUpdate.toChunk() 722 if err != nil { 723 t.Fatal(err) 724 } 725 726 if rh.Validate(chunk.Address(), chunk.Data()) { 727 t.Fatal("Chunk validator did not fail on update chunk with false address") 728 } 729 730 ctx, cancel = context.WithTimeout(context.Background(), time.Second) 731 defer cancel() 732 733 metadata = &ResourceMetadata{ 734 Name: resourceName, 735 StartTime: TimestampProvider.Now(), 736 Frequency: resourceFrequency, 737 Owner: signer.Address(), 738 } 739 chunk, _, err = metadata.newChunk() 740 if err != nil { 741 t.Fatal(err) 742 } 743 744 if !rh.Validate(chunk.Address(), chunk.Data()) { 745 t.Fatal("Chunk validator fail on metadata chunk") 746 } 747 } 748 749 // tests that the content address validator correctly checks the data 750 // tests that resource update chunks are passed through content address validator 751 // there is some redundancy in this test as it also tests content addressed chunks, 752 // which should be evaluated as invalid chunks by this validator 753 func TestValidatorInStore(t *testing.T) { 754 755 // make fake timeProvider 756 TimestampProvider = &fakeTimeProvider{ 757 currentTime: startTime.Time, 758 } 759 760 // signer containing private key 761 signer := newAliceSigner() 762 763 // set up localstore 764 datadir, err := ioutil.TempDir("", "storage-testresourcevalidator") 765 if err != nil { 766 t.Fatal(err) 767 } 768 defer os.RemoveAll(datadir) 769 770 params := storage.NewDefaultLocalStoreParams() 771 params.Init(datadir) 772 store, err := storage.NewLocalStore(params, nil) 773 if err != nil { 774 t.Fatal(err) 775 } 776 777 // set up resource handler and add is as a validator to the localstore 778 rhParams := &HandlerParams{} 779 rh := NewHandler(rhParams) 780 store.Validators = append(store.Validators, rh) 781 782 // create content addressed chunks, one good, one faulty 783 chunks := storage.GenerateRandomChunks(chunk.DefaultSize, 2) 784 goodChunk := chunks[0] 785 badChunk := storage.NewChunk(chunks[1].Address(), goodChunk.Data()) 786 787 metadata := &ResourceMetadata{ 788 StartTime: startTime, 789 Name: "xyzzy", 790 Frequency: resourceFrequency, 791 Owner: signer.Address(), 792 } 793 794 rootChunk, metaHash, err := metadata.newChunk() 795 if err != nil { 796 t.Fatal(err) 797 } 798 // create a resource update chunk with correct publickey 799 updateLookup := UpdateLookup{ 800 period: 42, 801 version: 1, 802 rootAddr: rootChunk.Address(), 803 } 804 805 updateAddr := updateLookup.UpdateAddr() 806 data := []byte("bar") 807 808 r := SignedResourceUpdate{ 809 updateAddr: updateAddr, 810 resourceUpdate: resourceUpdate{ 811 updateHeader: updateHeader{ 812 UpdateLookup: updateLookup, 813 metaHash: metaHash, 814 }, 815 data: data, 816 }, 817 } 818 819 r.Sign(signer) 820 821 uglyChunk, err := r.toChunk() 822 if err != nil { 823 t.Fatal(err) 824 } 825 826 // put the chunks in the store and check their error status 827 err = store.Put(context.Background(), goodChunk) 828 if err == nil { 829 t.Fatal("expected error on good content address chunk with resource validator only, but got nil") 830 } 831 err = store.Put(context.Background(), badChunk) 832 if err == nil { 833 t.Fatal("expected error on bad content address chunk with resource validator only, but got nil") 834 } 835 err = store.Put(context.Background(), uglyChunk) 836 if err != nil { 837 t.Fatalf("expected no error on resource update chunk with resource validator only, but got: %s", err) 838 } 839 } 840 841 // fast-forward clock 842 func fwdClock(count int, timeProvider *fakeTimeProvider) { 843 for i := 0; i < count; i++ { 844 timeProvider.Tick() 845 } 846 } 847 848 // create rpc and resourcehandler 849 func setupTest(timeProvider timestampProvider, signer Signer) (rh *TestHandler, datadir string, teardown func(), err error) { 850 851 var fsClean func() 852 var rpcClean func() 853 cleanF = func() { 854 if fsClean != nil { 855 fsClean() 856 } 857 if rpcClean != nil { 858 rpcClean() 859 } 860 } 861 862 // temp datadir 863 datadir, err = ioutil.TempDir("", "rh") 864 if err != nil { 865 return nil, "", nil, err 866 } 867 fsClean = func() { 868 os.RemoveAll(datadir) 869 } 870 871 TimestampProvider = timeProvider 872 rhparams := &HandlerParams{} 873 rh, err = NewTestHandler(datadir, rhparams) 874 return rh, datadir, cleanF, err 875 } 876 877 func newAliceSigner() *GenericSigner { 878 privKey, _ := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") 879 return NewGenericSigner(privKey) 880 } 881 882 func newBobSigner() *GenericSigner { 883 privKey, _ := crypto.HexToECDSA("accedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedeaccedecaca") 884 return NewGenericSigner(privKey) 885 } 886 887 func newCharlieSigner() *GenericSigner { 888 privKey, _ := crypto.HexToECDSA("facadefacadefacadefacadefacadefacadefacadefacadefacadefacadefaca") 889 return NewGenericSigner(privKey) 890 } 891 892 func getUpdateDirect(rh *Handler, addr storage.Address) ([]byte, error) { 893 chunk, err := rh.chunkStore.Get(context.TODO(), addr) 894 if err != nil { 895 return nil, err 896 } 897 var r SignedResourceUpdate 898 if err := r.fromChunk(addr, chunk.Data()); err != nil { 899 return nil, err 900 } 901 return r.data, nil 902 }