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  }