// load fetches the saved renter data from disk. func (r *Renter) load() error { // Load all files found in renter directory. dir, err := os.Open(r.persistDir) // TODO: store in a subdir? if err != nil { return err } defer dir.Close() filenames, err := dir.Readdirnames(-1) if err != nil { return err } for _, path := range filenames { // Skip non-sia files. if filepath.Ext(path) != ShareExtension { continue } file, err := os.Open(filepath.Join(r.persistDir, path)) if err != nil { // maybe just skip? return err } _, err = r.loadSharedFiles(file) file.Close() // defer is probably a bad idea if err != nil { // maybe just skip? return err } } // Load contracts, repair set, and entropy. data := struct { Contracts map[string]types.FileContract Tracking map[string]trackedFile Repairing map[string]string // COMPATv0.4.8 Entropy [32]byte }{} err = persist.LoadFile(saveMetadata, &data, filepath.Join(r.persistDir, PersistFilename)) if err != nil { return err } if data.Tracking != nil { r.tracking = data.Tracking } else if data.Repairing != nil { // COMPATv0.4.8 for nick, path := range data.Repairing { // these files will be renewed indefinitely r.tracking[nick] = trackedFile{RepairPath: path, EndHeight: 0} } } r.entropy = data.Entropy var fcid types.FileContractID for id, fc := range data.Contracts { fcid.UnmarshalJSON([]byte(id)) r.contracts[fcid] = fc } return nil }
// applyMissedStorageProof adds the outputs and diffs that result from a file // contract expiring. func (cs *State) applyMissedStorageProof(bn *blockNode, fcid types.FileContractID) { // Sanity checks. fc, exists := cs.fileContracts[fcid] if build.DEBUG { // Check that the file contract in question exists. if !exists { panic("misuse of applyMissedProof") } // Check that the file contract in question expires at bn.height. if fc.WindowEnd != bn.height { panic("applyMissedStorageProof being called at the wrong height") } } // Add all of the outputs in the missed proof outputs to the consensus set. for i, mpo := range fc.MissedProofOutputs { // Sanity check - output should not already exist. spid := fcid.StorageProofOutputID(types.ProofMissed, i) if build.DEBUG { _, exists := cs.delayedSiacoinOutputs[bn.height+types.MaturityDelay][spid] if exists { panic("missed proof output already exists in the delayed outputs set") } _, exists = cs.siacoinOutputs[spid] if exists { panic("missed proof output already exists in the siacoin outputs set") } } dscod := modules.DelayedSiacoinOutputDiff{ Direction: modules.DiffApply, ID: spid, SiacoinOutput: mpo, MaturityHeight: bn.height + types.MaturityDelay, } bn.delayedSiacoinOutputDiffs = append(bn.delayedSiacoinOutputDiffs, dscod) cs.commitDelayedSiacoinOutputDiff(dscod, modules.DiffApply) } // Remove the contract from the State and record the diff in the blockNode. delete(cs.fileContracts, fcid) bn.fileContractDiffs = append(bn.fileContractDiffs, modules.FileContractDiff{ Direction: modules.DiffRevert, ID: fcid, FileContract: fc, }) return }
// load fetches the saved renter data from disk. func (r *Renter) load() error { // Load all files found in renter directory. dir, err := os.Open(r.persistDir) // TODO: store in a subdir? if err != nil { return err } filenames, err := dir.Readdirnames(-1) if err != nil { return err } for _, path := range filenames { // Skip non-sia files. if filepath.Ext(path) != ShareExtension { continue } file, err := os.Open(filepath.Join(r.persistDir, path)) if err != nil { // maybe just skip? return err } _, err = r.loadSharedFiles(file) if err != nil { // maybe just skip? return err } } // Load contracts, repair set, and entropy. data := struct { Contracts map[string]types.FileContract Repairing map[string]string Entropy [32]byte }{} err = persist.LoadFile(saveMetadata, &data, filepath.Join(r.persistDir, PersistFilename)) if err != nil { return err } r.repairSet = data.Repairing r.entropy = data.Entropy var fcid types.FileContractID for id, fc := range data.Contracts { fcid.UnmarshalJSON([]byte(id)) r.contracts[fcid] = fc } return nil }
// applyMissedStorageProof adds the outputs and diffs that result from a file // contract expiring. func (cs *ConsensusSet) applyTxMissedStorageProof(tx *bolt.Tx, pb *processedBlock, fcid types.FileContractID) error { // Sanity checks. fc, err := getFileContract(tx, fcid) if err != nil { return err } if build.DEBUG { // Check that the file contract in question expires at pb.Height. if fc.WindowEnd != pb.Height { panic(errStorageProofTiming) } } // Add all of the outputs in the missed proof outputs to the consensus set. for i, mpo := range fc.MissedProofOutputs { // Sanity check - output should not already exist. spoid := fcid.StorageProofOutputID(types.ProofMissed, uint64(i)) if build.DEBUG { exists := isSiacoinOutput(tx, spoid) if exists { panic(errPayoutsAlreadyPaid) } } dscod := modules.DelayedSiacoinOutputDiff{ Direction: modules.DiffApply, ID: spoid, SiacoinOutput: mpo, MaturityHeight: pb.Height + types.MaturityDelay, } pb.DelayedSiacoinOutputDiffs = append(pb.DelayedSiacoinOutputDiffs, dscod) err = cs.commitTxDelayedSiacoinOutputDiff(tx, dscod, modules.DiffApply) if err != nil { return err } } // Remove the file contract from the consensus set and record the diff in // the blockNode. fcd := modules.FileContractDiff{ Direction: modules.DiffRevert, ID: fcid, FileContract: fc, } pb.FileContractDiffs = append(pb.FileContractDiffs, fcd) return cs.commitTxFileContractDiff(tx, fcd, modules.DiffApply) }
// applyMissedStorageProof adds the outputs and diffs that result from a file // contract expiring. func applyMissedStorageProof(tx *bolt.Tx, pb *processedBlock, fcid types.FileContractID) (dscods []modules.DelayedSiacoinOutputDiff, fcd modules.FileContractDiff) { // Sanity checks. fc, err := getFileContract(tx, fcid) if build.DEBUG && err != nil { panic(err) } if build.DEBUG { // Check that the file contract in question expires at pb.Height. if fc.WindowEnd != pb.Height { panic(errStorageProofTiming) } } // Add all of the outputs in the missed proof outputs to the consensus set. for i, mpo := range fc.MissedProofOutputs { // Sanity check - output should not already exist. spoid := fcid.StorageProofOutputID(types.ProofMissed, uint64(i)) if build.DEBUG && isSiacoinOutput(tx, spoid) { panic(errPayoutsAlreadyPaid) } // Don't add the output if the value is zero. dscod := modules.DelayedSiacoinOutputDiff{ Direction: modules.DiffApply, ID: spoid, SiacoinOutput: mpo, MaturityHeight: pb.Height + types.MaturityDelay, } dscods = append(dscods, dscod) } // Remove the file contract from the consensus set and record the diff in // the blockNode. fcd = modules.FileContractDiff{ Direction: modules.DiffRevert, ID: fcid, FileContract: fc, } return dscods, fcd }
// managedVerifyChallengeResponse will verify that the renter's response to the // challenge provided by the host is correct. In the process, the storage // obligation and file contract revision will be loaded and returned. // // The storage obligation is returned under a storage obligation lock. func (h *Host) managedVerifyChallengeResponse(fcid types.FileContractID, challenge crypto.Hash, challengeResponse crypto.Signature) (so storageObligation, recentRevision types.FileContractRevision, revisionSigs []types.TransactionSignature, err error) { // Grab a lock before it is possible to perform any operations on the // storage obligation. Defer a call to unlock in the event of an error. If // there is no error, the storage obligation will be returned with a lock. err = h.managedTryLockStorageObligation(fcid) if err != nil { err = extendErr("could not get "+fcid.String()+" lock: ", ErrorInternal(err.Error())) return storageObligation{}, types.FileContractRevision{}, nil, err } defer func() { if err != nil { h.managedUnlockStorageObligation(fcid) } }() // Fetch the storage obligation, which has the revision, which has the // renter's public key. h.mu.RLock() defer h.mu.RUnlock() err = h.db.View(func(tx *bolt.Tx) error { so, err = getStorageObligation(tx, fcid) return err }) if err != nil { err = extendErr("could not fetch "+fcid.String()+": ", ErrorInternal(err.Error())) return storageObligation{}, types.FileContractRevision{}, nil, err } // Pull out the file contract revision and the revision's signatures from // the transaction. revisionTxn := so.RevisionTransactionSet[len(so.RevisionTransactionSet)-1] recentRevision = revisionTxn.FileContractRevisions[0] for _, sig := range revisionTxn.TransactionSignatures { // Checking for just the parent id is sufficient, an over-signed file // contract is invalid. if sig.ParentID == crypto.Hash(fcid) { revisionSigs = append(revisionSigs, sig) } } // Verify that the challegne response matches the public key. var renterPK crypto.PublicKey // Sanity check - there should be two public keys. if len(recentRevision.UnlockConditions.PublicKeys) != 2 { // The error has to be set here so that the defered error check will // unlock the storage obligation. h.log.Critical("wrong public key count in file contract revision") err = errRevisionWrongPublicKeyCount err = extendErr("wrong public key count for "+fcid.String()+": ", ErrorInternal(err.Error())) return storageObligation{}, types.FileContractRevision{}, nil, err } copy(renterPK[:], recentRevision.UnlockConditions.PublicKeys[0].Key) err = crypto.VerifyHash(challenge, renterPK, challengeResponse) if err != nil { err = extendErr("bad signature from renter: ", ErrorCommunication(err.Error())) return storageObligation{}, types.FileContractRevision{}, nil, err } return so, recentRevision, revisionSigs, nil }