gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/snapshotsession.go (about) 1 package renter 2 3 // snapshotsession.go contains methods related to fetching snapshot data over a 4 // session with a host. 5 // 6 // TODO: The implementation for managedDownloadSnapshotTable currently silences 7 // several errors, these errors should be handled explicitly. 8 9 import ( 10 "bytes" 11 "strings" 12 13 "gitlab.com/NebulousLabs/errors" 14 "gitlab.com/NebulousLabs/fastrand" 15 16 "gitlab.com/SiaPrime/SiaPrime/crypto" 17 "gitlab.com/SiaPrime/SiaPrime/encoding" 18 "gitlab.com/SiaPrime/SiaPrime/modules" 19 "gitlab.com/SiaPrime/SiaPrime/modules/renter/contractor" 20 "gitlab.com/SiaPrime/SiaPrime/modules/renter/proto" 21 ) 22 23 // managedDownloadSnapshotTable will fetch the snapshot table from the host. 24 func (r *Renter) managedDownloadSnapshotTable(session contractor.Session) ([]snapshotEntry, error) { 25 // Get the wallet seed. 26 ws, _, err := r.w.PrimarySeed() 27 if err != nil { 28 return nil, errors.AddContext(err, "failed to get wallet's primary seed") 29 } 30 // Derive the renter seed and wipe the memory once we are done using it. 31 rs := proto.DeriveRenterSeed(ws) 32 defer fastrand.Read(rs[:]) 33 // Derive the secret and wipe it afterwards. 34 secret := crypto.HashAll(rs, snapshotKeySpecifier) 35 defer fastrand.Read(secret[:]) 36 37 // Download the table of snapshots that the host is storing. 38 tableSector, err := session.DownloadIndex(0, 0, uint32(modules.SectorSize)) 39 if err != nil { 40 if strings.Contains(err.Error(), "invalid sector bounds") { 41 // host is not storing any data yet; return an empty table. 42 // 43 // TODO: Should retrun an error that the host does not have any 44 // snapshots / has not been prepared for snapshots yet. 45 return nil, nil 46 } 47 return nil, err 48 } 49 // decrypt the table 50 c, _ := crypto.NewSiaKey(crypto.TypeThreefish, secret[:]) 51 encTable, err := c.DecryptBytesInPlace(tableSector, 0) 52 if err != nil || !bytes.Equal(encTable[:16], snapshotTableSpecifier[:]) { 53 // either the first sector was not an entry table, or it got corrupted 54 // somehow; either way, it's not retrievable, so we'll treat this as 55 // equivalent to having no entry table at all. This is not an error; it 56 // just means that when we upload a snapshot, we'll have to create a new 57 // table. 58 // 59 // TODO: Should return an error that decryption failed / there appears 60 // to be corruption. 61 return nil, nil 62 } 63 64 var entryTable []snapshotEntry 65 if err := encoding.Unmarshal(encTable[16:], &entryTable); err != nil { 66 return nil, err 67 } 68 return entryTable, nil 69 } 70 71 // callDownloadSnapshotTable downloads the snapshot entry table from the 72 // worker's host. 73 func (r *Renter) callFetchHostBackups(session contractor.Session) ([]modules.UploadedBackup, error) { 74 entryTable, err := r.managedDownloadSnapshotTable(session) 75 if err != nil { 76 return nil, errors.AddContext(err, "unable to download snapshot table") 77 } 78 79 // Format the reponse and return the response to the requester. 80 uploadedBackups := make([]modules.UploadedBackup, len(entryTable)) 81 for i, e := range entryTable { 82 uploadedBackups[i] = modules.UploadedBackup{ 83 Name: string(bytes.TrimRight(e.Name[:], string(0))), 84 UID: e.UID, 85 CreationDate: e.CreationDate, 86 Size: e.Size, 87 UploadProgress: 100, 88 } 89 } 90 return uploadedBackups, nil 91 }